# 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
