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 21a844cb8a 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

23 KiB

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

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

-- 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

# 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

# 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

# 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

// 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

  1. Stalwart konfigurieren
  2. SOGo als Webclient
  3. LDAP/OAuth Bridge

Phase 3: Anonymisierung

  1. Anonymisierungs-Service
  2. E-Mail-Archive-Bereinigung
  3. DSGVO-Export-Funktion

Phase 4: Frontend

  1. Admin-UI erstellen
  2. Offboarding-Wizard
  3. Audit-Dashboard

Phase 5: Kalender & Jitsi

  1. CalDAV Integration
  2. Jitsi-Meeting-Einladungen aus Kalender
  3. 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

-- 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

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

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