This repository has been archived on 2026-02-15. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
breakpilot-pwa/docs/architecture/mail-rbac-architecture.md
Benjamin Admin bfdaf63ba9 fix: Restore all files lost during destructive rebase
A previous `git pull --rebase origin main` dropped 177 local commits,
losing 3400+ files across admin-v2, backend, studio-v2, website,
klausur-service, and many other services. The partial restore attempt
(660295e2) only recovered some files.

This commit restores all missing files from pre-rebase ref 98933f5e
while preserving post-rebase additions (night-scheduler, night-mode UI,
NightModeWidget dashboard integration).

Restored features include:
- AI Module Sidebar (FAB), OCR Labeling, OCR Compare
- GPU Dashboard, RAG Pipeline, Magic Help
- Klausur-Korrektur (8 files), Abitur-Archiv (5+ files)
- Companion, Zeugnisse-Crawler, Screen Flow
- Full backend, studio-v2, website, klausur-service
- All compliance SDKs, agent-core, voice-service
- CI/CD configs, documentation, scripts

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-09 09:51:32 +01:00

723 lines
23 KiB
Markdown

# Mail-RBAC Architektur mit Mitarbeiter-Anonymisierung
**Version:** 1.0.0
**Datum:** 2026-01-10
**Status:** Architekturplanung
---
## Executive Summary
Dieses Dokument beschreibt eine neuartige Architektur, die E-Mail, Kalender und Videokonferenzen mit rollenbasierter Zugriffskontrolle (RBAC) verbindet. Das Kernkonzept ermöglicht die **vollständige Anonymisierung von Mitarbeiterdaten** bei Verlassen des Unternehmens, während geschäftliche Kommunikationshistorie erhalten bleibt.
**Wichtig:** Dieses Konzept existiert in dieser Form noch nicht als fertige Lösung auf dem Markt. Es handelt sich um eine innovative Architektur, die entwickelt werden muss.
---
## 1. Das Problem
### Traditionelle E-Mail-Systeme
```
max.mustermann@firma.de → Person gebunden
→ DSGVO: Daten müssen gelöscht werden
→ Geschäftshistorie geht verloren
```
### BreakPilot-Lösung: Rollenbasierte E-Mail
```
klassenlehrer.5a@schule.breakpilot.app → Rolle gebunden
→ Person kann anonymisiert werden
→ Kommunikationshistorie bleibt erhalten
```
---
## 2. Architektur-Übersicht
```
┌─────────────────────────────────────────────────────────────────┐
│ BreakPilot Groupware │
├─────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ Webmail │ │ Kalender │ │ Jitsi │ │
│ │ (SOGo) │ │ (SOGo) │ │ Meeting │ │
│ └──────┬──────┘ └──────┬──────┘ └──────┬──────┘ │
│ │ │ │ │
│ └────────────────┼────────────────┘ │
│ │ │
│ ┌───────────┴───────────┐ │
│ │ RBAC-Mail-Bridge │ ◄─── Neue Komponente │
│ │ (Python/Go) │ │
│ └───────────┬───────────┘ │
│ │ │
│ ┌─────────────────────┼─────────────────────┐ │
│ │ │ │ │
│ ▼ ▼ ▼ │
│ ┌──────────┐ ┌──────────────┐ ┌────────────┐ │
│ │PostgreSQL│ │ Mail Server │ │ MinIO │ │
│ │(RBAC DB) │ │ (Stalwart) │ │ (Backups) │ │
│ └──────────┘ └──────────────┘ └────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────┘
```
---
## 3. Komponenten-Auswahl
### 3.1 E-Mail Server: Stalwart Mail Server
**Empfehlung:** [Stalwart Mail Server](https://stalw.art/)
| Kriterium | Bewertung |
|-----------|-----------|
| Lizenz | AGPL-3.0 (Open Source) |
| Sprache | Rust (performant, sicher) |
| Features | IMAP, SMTP, JMAP, WebSocket |
| Kalender | CalDAV integriert |
| Kontakte | CardDAV integriert |
| Spam/Virus | Integriert |
| API | REST API für Administration |
**Lizenz-Implikation für kommerzielle Nutzung:**
- AGPL-3.0 erfordert Veröffentlichung von Änderungen am Stalwart-Code selbst
- Nutzung als Service ohne Code-Änderungen: keine Veröffentlichungspflicht
- Unsere RBAC-Bridge ist separater Code: kann proprietär bleiben
### 3.2 Webmail-Client: SOGo oder Roundcube
**Option A: SOGo** (empfohlen)
- Lizenz: GPL-2.0 / LGPL-2.1
- Kalender, Kontakte, Mail in einem
- ActiveSync Support
- Outlook-ähnliche Oberfläche
**Option B: Roundcube**
- Lizenz: GPL-3.0
- Nur Webmail
- Benötigt separaten Kalender
### 3.3 Kalender-Integration
Stalwart bietet CalDAV, kann mit:
- SOGo Webinterface
- Thunderbird
- iOS/Android Kalender
- Outlook (via CalDAV Plugin)
### 3.4 Jitsi-Integration
Bereits vorhanden in BreakPilot:
- `backend/jitsi_api.py` - Meeting-Erstellung
- `email_service.py` - Jitsi-Einladungen per E-Mail
- Kalender-Events können Jitsi-Links enthalten
---
## 4. Datenmodell für Rollen-E-Mail
### 4.1 Neue Datenbank-Tabellen
```sql
-- Funktionale E-Mail-Adressen (rollengebunden)
CREATE TABLE functional_mailboxes (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
-- Rolle und Mailbox
role_key VARCHAR(100) NOT NULL, -- z.B. "klassenlehrer_5a"
email_address VARCHAR(255) UNIQUE NOT NULL, -- z.B. "klassenlehrer.5a@schule.bp.app"
display_name VARCHAR(255) NOT NULL, -- z.B. "Klassenlehrer 5a"
-- Zuordnung
tenant_id UUID NOT NULL REFERENCES tenants(id),
resource_type VARCHAR(50) DEFAULT 'class', -- class, department, function
resource_id VARCHAR(100), -- z.B. "5a" oder "mathematik"
-- Status
is_active BOOLEAN DEFAULT true,
created_at TIMESTAMP DEFAULT NOW(),
CONSTRAINT fk_role FOREIGN KEY (role_key)
REFERENCES roles(role_key) ON DELETE RESTRICT
);
-- Zuordnung: Welche Person hat welche funktionale Mailbox
CREATE TABLE mailbox_assignments (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
mailbox_id UUID NOT NULL REFERENCES functional_mailboxes(id),
user_id UUID NOT NULL REFERENCES users(id),
-- Zeitraum
valid_from TIMESTAMP DEFAULT NOW(),
valid_to TIMESTAMP,
-- Audit
assigned_by UUID REFERENCES users(id),
assigned_at TIMESTAMP DEFAULT NOW(),
revoked_by UUID,
revoked_at TIMESTAMP,
-- Constraints
CONSTRAINT unique_active_assignment
UNIQUE (mailbox_id, user_id)
WHERE revoked_at IS NULL
);
-- Persönliche E-Mail-Adressen (für Anonymisierung)
CREATE TABLE personal_email_accounts (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id UUID NOT NULL REFERENCES users(id),
-- E-Mail
email_address VARCHAR(255) UNIQUE NOT NULL,
-- Anonymisierungsstatus
is_anonymized BOOLEAN DEFAULT false,
anonymized_at TIMESTAMP,
anonymized_by UUID,
-- Original-Daten (verschlüsselt, für DSGVO-Auskunft)
original_name_encrypted BYTEA,
original_email_encrypted BYTEA,
encryption_key_id VARCHAR(100),
-- Audit
created_at TIMESTAMP DEFAULT NOW()
);
-- Audit-Trail für E-Mail-Kommunikation (ohne personenbezogene Daten)
CREATE TABLE email_audit_trail (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
-- Kommunikation
mailbox_id UUID REFERENCES functional_mailboxes(id),
direction VARCHAR(10) NOT NULL, -- 'inbound', 'outbound'
-- Metadaten (keine Inhalte!)
subject_hash VARCHAR(64), -- SHA-256 für Deduplizierung
timestamp TIMESTAMP NOT NULL,
external_party_domain VARCHAR(255), -- z.B. "eltern.de" (nicht volle Adresse)
-- Rolle zum Zeitpunkt
role_key VARCHAR(100) NOT NULL,
-- Person NICHT gespeichert - nur über Assignment nachvollziehbar
-- Bei Anonymisierung: Assignment-User wird anonymisiert
created_at TIMESTAMP DEFAULT NOW()
);
-- Anonymisierungsprotokoll (DSGVO-Nachweis)
CREATE TABLE anonymization_log (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
-- Was wurde anonymisiert
entity_type VARCHAR(50) NOT NULL, -- 'user', 'email_account'
entity_id UUID NOT NULL,
-- Wie
anonymization_type VARCHAR(50) NOT NULL, -- 'pseudonymization', 'deletion'
fields_affected JSONB NOT NULL,
-- Warum
reason VARCHAR(100) NOT NULL, -- 'employee_departure', 'dsgvo_request'
-- Audit
performed_by UUID NOT NULL,
performed_at TIMESTAMP DEFAULT NOW(),
-- Bestätigung
legal_basis VARCHAR(255), -- z.B. "Art. 17 DSGVO"
retention_period_days INTEGER
);
```
### 4.2 Anonymisierungs-Workflow
```
Mitarbeiter kündigt
┌───────────────────────────┐
│ 1. Functional Mailboxes │
│ → Neu zuweisen oder │
│ → Deaktivieren │
└───────────┬───────────────┘
┌───────────────────────────┐
│ 2. Personal Email Account │
│ → Anonymisieren: │
│ max.mustermann@... │
│ → mitarbeiter_a7x2@... │
└───────────────────────────┘
┌───────────────────────────┐
│ 3. Users-Tabelle │
│ → Pseudonymisieren: │
│ name: "Max Mustermann" │
│ → "Ehem. Mitarbeiter" │
└───────────────────────────┘
┌───────────────────────────┐
│ 4. Mailbox Assignments │
│ → Bleiben für Audit │
│ → User-Referenz zeigt │
│ auf anonymisierte │
│ Daten │
└───────────────────────────┘
┌───────────────────────────┐
│ 5. E-Mail-Archiv │
│ → Header anonymisieren │
│ → Inhalte optional │
│ löschen │
└───────────────────────────┘
```
---
## 5. RBAC-Mail-Bridge Implementierung
### 5.1 Python-Komponente
```python
# rbac_mail_bridge/anonymizer.py
class EmployeeAnonymizer:
"""
Anonymisiert Mitarbeiterdaten bei Ausscheiden.
Erhält Audit-Trail und funktionale Zuordnungen.
"""
async def anonymize_employee(
self,
user_id: str,
reason: str,
performed_by: str
) -> AnonymizationResult:
"""
Vollständige Anonymisierung eines Mitarbeiters.
Schritte:
1. Functional Mailboxes neu zuweisen
2. Personal Email anonymisieren
3. User-Daten pseudonymisieren
4. E-Mail-Archive bereinigen
5. Audit-Log erstellen
"""
async with self.db.transaction():
# 1. Functional Mailboxes
assignments = await self.get_active_assignments(user_id)
for assignment in assignments:
await self.revoke_assignment(
assignment.id,
revoked_by=performed_by,
reason="employee_departure"
)
# 2. Personal Email
personal_email = await self.get_personal_email(user_id)
if personal_email:
# Verschlüssele Original für DSGVO-Auskunft
encrypted = await self.encrypt_for_retention(
personal_email.email_address,
personal_email.display_name
)
# Anonymisiere
anon_email = f"user_{generate_random_id()}@anon.local"
await self.db.execute("""
UPDATE personal_email_accounts
SET
email_address = $1,
is_anonymized = true,
anonymized_at = NOW(),
original_email_encrypted = $2
WHERE user_id = $3
""", anon_email, encrypted, user_id)
# 3. User-Daten
await self.db.execute("""
UPDATE users SET
name = 'Ehemaliger Mitarbeiter',
email = $1,
is_active = false,
anonymized_at = NOW()
WHERE id = $2
""", f"anon_{user_id[:8]}@deleted.local", user_id)
# 4. E-Mail-Archive
await self.mail_server.anonymize_mailbox(user_id)
# 5. Audit-Log
await self.create_anonymization_log(
entity_type="user",
entity_id=user_id,
reason=reason,
performed_by=performed_by
)
return AnonymizationResult(success=True)
```
### 5.2 API-Endpunkte
```python
# rbac_mail_bridge/api.py
router = APIRouter(prefix="/api/v1/mail-rbac", tags=["mail-rbac"])
@router.get("/mailboxes")
async def list_functional_mailboxes(
user: Dict = Depends(get_current_admin)
) -> List[FunctionalMailbox]:
"""Liste aller funktionalen Mailboxen"""
pass
@router.post("/mailboxes")
async def create_functional_mailbox(
mailbox: FunctionalMailboxCreate,
user: Dict = Depends(get_current_admin)
) -> FunctionalMailbox:
"""Erstellt eine rollengebundene Mailbox"""
pass
@router.post("/mailboxes/{mailbox_id}/assign")
async def assign_mailbox_to_user(
mailbox_id: str,
assignment: MailboxAssignment,
user: Dict = Depends(get_current_admin)
) -> Assignment:
"""Weist eine Mailbox einem Benutzer zu"""
pass
@router.post("/users/{user_id}/anonymize")
async def anonymize_user(
user_id: str,
request: AnonymizationRequest,
user: Dict = Depends(get_current_admin)
) -> AnonymizationResult:
"""Anonymisiert einen ausgeschiedenen Mitarbeiter"""
pass
@router.get("/audit/anonymizations")
async def list_anonymizations(
user: Dict = Depends(get_current_admin)
) -> List[AnonymizationLog]:
"""Liste aller Anonymisierungen (DSGVO-Nachweis)"""
pass
```
---
## 6. Docker-Compose Integration
```yaml
# docker-compose.yml Erweiterung
services:
# ... bestehende Services ...
# Stalwart Mail Server
stalwart:
image: stalwartlabs/mail-server:latest
container_name: breakpilot-mail
hostname: mail.breakpilot.local
ports:
- "25:25" # SMTP
- "143:143" # IMAP
- "465:465" # SMTPS
- "993:993" # IMAPS
- "4190:4190" # ManageSieve
- "8080:8080" # Web Admin
volumes:
- stalwart-data:/opt/stalwart-mail/data
- ./config/stalwart:/opt/stalwart-mail/etc
environment:
- STALWART_HOSTNAME=mail.breakpilot.local
networks:
- breakpilot-pwa-network
depends_on:
- postgres
profiles:
- mail # Nur mit --profile mail starten
# SOGo Groupware (Webmail + Kalender)
sogo:
image: sogo/sogo:latest
container_name: breakpilot-sogo
ports:
- "20000:20000"
volumes:
- ./config/sogo:/etc/sogo
environment:
- SOGO_HOSTNAME=groupware.breakpilot.local
depends_on:
- stalwart
- postgres
networks:
- breakpilot-pwa-network
profiles:
- mail
# RBAC-Mail-Bridge
rbac-mail-bridge:
build:
context: ./rbac-mail-bridge
dockerfile: Dockerfile
container_name: breakpilot-rbac-mail
environment:
- DATABASE_URL=${DATABASE_URL}
- STALWART_API_URL=http://stalwart:8080
- STALWART_API_KEY=${STALWART_API_KEY}
depends_on:
- postgres
- stalwart
networks:
- breakpilot-pwa-network
profiles:
- mail
volumes:
stalwart-data:
```
---
## 7. Admin-UI im Frontend
### 7.1 Neue Admin-Seite: `/admin/mail-management`
```tsx
// website/app/admin/mail-management/page.tsx
// Tabs:
// 1. Funktionale Mailboxen
// - Liste aller rollengebundenen Adressen
// - Zuweisungen verwalten
//
// 2. Mitarbeiter E-Mail
// - Persönliche Accounts
// - Anonymisierungs-Status
//
// 3. Anonymisierung
// - Mitarbeiter-Offboarding
// - Anonymisierungs-Wizard
//
// 4. Audit-Log
// - Alle Anonymisierungen
// - DSGVO-Export
```
---
## 8. Lizenz-Übersicht
| Komponente | Lizenz | Kommerzielle Nutzung | Veröffentlichungspflicht |
|------------|--------|---------------------|-------------------------|
| Stalwart Mail | AGPL-3.0 | Ja | Nur bei Code-Änderungen |
| SOGo | GPL-2.0/LGPL | Ja | Nur bei Code-Änderungen |
| Roundcube | GPL-3.0 | Ja | Nur bei Code-Änderungen |
| RBAC-Mail-Bridge | Eigene | N/A | Kann proprietär bleiben |
| BreakPilot Backend | Eigene | N/A | Proprietär |
**Empfehlung:** Bei reiner Nutzung der Open-Source-Komponenten ohne Code-Änderungen besteht keine Veröffentlichungspflicht. Die RBAC-Mail-Bridge ist unser eigener Code.
---
## 9. Implementierungsreihenfolge
### Phase 1: Grundlagen (2-3 Wochen Entwicklung)
1. Datenbank-Schema erstellen
2. RBAC-Mail-Bridge Backend
3. Basic API-Endpunkte
### Phase 2: Mail-Server Integration
4. Stalwart konfigurieren
5. SOGo als Webclient
6. LDAP/OAuth Bridge
### Phase 3: Anonymisierung
7. Anonymisierungs-Service
8. E-Mail-Archive-Bereinigung
9. DSGVO-Export-Funktion
### Phase 4: Frontend
10. Admin-UI erstellen
11. Offboarding-Wizard
12. Audit-Dashboard
### Phase 5: Kalender & Jitsi
13. CalDAV Integration
14. Jitsi-Meeting-Einladungen aus Kalender
15. Mobile Sync (ActiveSync/CardDAV)
---
## 10. Existiert das schon?
**Kurze Antwort: Nein, nicht in dieser Form.**
### Ähnliche Konzepte:
1. **Funktionale Mailboxen** (existiert)
- Shared Mailboxes in Exchange/Microsoft 365
- Group Addresses in Google Workspace
- → Aber: Keine RBAC-Integration, keine Anonymisierung
2. **DSGVO-Löschung** (existiert)
- Standard: Konto komplett löschen
- → Aber: Verlust der Geschäftshistorie
3. **Pseudonymisierung** (existiert als Konzept)
- In Forschungsdatenbanken üblich
- → Aber: Nicht für E-Mail-Systeme implementiert
### Was BreakPilot anders macht:
```
Traditionell:
max.mustermann@firma.de → Kündigung → Löschen → Historie weg
BreakPilot:
klassenlehrer.5a@schule.bp.app ← Max Mustermann zugeordnet
← Maria Müller übernimmt
← Historie bleibt, Person anonymisiert
```
**Fazit:** Das Konzept ist innovativ und müsste entwickelt werden. Es gibt keine fertige Open-Source-Lösung, die all diese Features kombiniert.
---
## 11. Alternative: Minimale Implementation
Falls das vollständige System zu komplex ist, gibt es eine minimale Variante:
### 11.1 Nur Functional Mailboxes
```sql
-- Minimales Schema
CREATE TABLE role_email_aliases (
id UUID PRIMARY KEY,
role_key VARCHAR(100) UNIQUE NOT NULL,
email_alias VARCHAR(255) UNIQUE NOT NULL, -- klassenlehrer.5a@...
forward_to UUID REFERENCES users(id), -- Aktuelle Person
is_active BOOLEAN DEFAULT true
);
```
- Keine eigene Mail-Infrastruktur
- Aliases werden an persönliche Adressen weitergeleitet
- Bei Kündigung: Alias umleiten
- Limitation: Keine echte Anonymisierung der Historie
### 11.2 Mailpit als Development-Only
Bestehendes Mailpit bleibt für Entwicklung:
- Kein Produktions-Mailserver
- Externe Mails über Gmail/Microsoft
- Functional Mailboxes als Konzept in DB
---
## 12. Nächste Schritte
1. **Entscheidung:** Vollständiges System oder minimale Variante?
2. **Proof of Concept:** Functional Mailboxes mit bestehendem RBAC
3. **Evaluierung:** Stalwart Mail Server in Testumgebung
4. **Architektur-Review:** Mit Datenschutzbeauftragtem abstimmen
---
## Anhang A: Referenzen
- [Stalwart Mail Server](https://stalw.art/)
- [SOGo Groupware](https://www.sogo.nu/)
- [Roundcube Webmail](https://roundcube.net/)
- [CalDAV Standard](https://tools.ietf.org/html/rfc4791)
- [DSGVO Art. 17 - Recht auf Löschung](https://dsgvo-gesetz.de/art-17-dsgvo/)
## Anhang B: Bestehende BreakPilot-Integration
- RBAC-System: `/backend/rbac_api.py`
- E-Mail-Service: `/backend/email_service.py`
- Jitsi-Integration: `/backend/jitsi_api.py`
- Mailpit-Config: `docker-compose.yml:193-202`
---
## Anhang C: Unified Inbox Implementation (2026-01)
### Implementierte Komponenten
Die Unified Inbox wurde als Teil des klausur-service implementiert:
| Komponente | Pfad | Beschreibung |
|------------|------|--------------|
| **Models** | `klausur-service/backend/mail/models.py` | Pydantic Models für Accounts, E-Mails, Tasks |
| **Database** | `klausur-service/backend/mail/mail_db.py` | PostgreSQL-Operationen mit asyncpg |
| **Credentials** | `klausur-service/backend/mail/credentials.py` | Vault-Integration für IMAP/SMTP-Passwörter |
| **Aggregator** | `klausur-service/backend/mail/aggregator.py` | Multi-Account IMAP Sync |
| **AI Service** | `klausur-service/backend/mail/ai_service.py` | KI-Analyse (Absender, Fristen, Kategorien) |
| **Task Service** | `klausur-service/backend/mail/task_service.py` | Arbeitsvorrat-Management |
| **API** | `klausur-service/backend/mail/api.py` | FastAPI Router mit 30+ Endpoints |
### Frontend-Komponenten
| Komponente | Pfad | Beschreibung |
|------------|------|--------------|
| **Admin UI** | `website/app/admin/mail/page.tsx` | Kontenverwaltung, KI-Einstellungen |
| **User Inbox** | `website/app/mail/page.tsx` | Unified Inbox mit KI-Panel |
| **Arbeitsvorrat** | `website/app/mail/tasks/page.tsx` | Task-Management Dashboard |
### API-Endpoints (Port 8086)
```
# Account Management
POST /api/v1/mail/accounts - Neues Konto hinzufügen
GET /api/v1/mail/accounts - Alle Konten auflisten
DELETE /api/v1/mail/accounts/{id} - Konto entfernen
POST /api/v1/mail/accounts/{id}/test - Verbindung testen
# Unified Inbox
GET /api/v1/mail/inbox - Aggregierte Inbox
GET /api/v1/mail/inbox/{id} - Einzelne E-Mail
POST /api/v1/mail/send - E-Mail senden
# KI-Features
POST /api/v1/mail/analyze/{id} - E-Mail analysieren
GET /api/v1/mail/suggestions/{id} - Antwortvorschläge
# Arbeitsvorrat
GET /api/v1/mail/tasks - Alle Tasks
POST /api/v1/mail/tasks - Manuelle Task erstellen
PATCH /api/v1/mail/tasks/{id} - Task aktualisieren
GET /api/v1/mail/tasks/dashboard - Dashboard-Statistiken
```
### Niedersachsen-spezifische Absendererkennung
```python
KNOWN_AUTHORITIES_NI = {
"@mk.niedersachsen.de": "Kultusministerium Niedersachsen",
"@rlsb.de": "Regionales Landesamt für Schule und Bildung",
"@landesschulbehoerde-nds.de": "Landesschulbehörde",
"@nibis.de": "NiBiS",
}
```
### LLM-Playbook für E-Mail-Analyse
Das Playbook `mail_analysis` in `/backend/llm_gateway/services/playbook_service.py` enthält:
- Absender-Klassifikation (12 Typen)
- Fristenerkennung mit Datumsextraktion
- Kategorisierung (11 Kategorien)
- Prioritätsvorschlag