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>
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-Erstellungemail_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)
- Datenbank-Schema erstellen
- RBAC-Mail-Bridge Backend
- Basic API-Endpunkte
Phase 2: Mail-Server Integration
- Stalwart konfigurieren
- SOGo als Webclient
- LDAP/OAuth Bridge
Phase 3: Anonymisierung
- Anonymisierungs-Service
- E-Mail-Archive-Bereinigung
- DSGVO-Export-Funktion
Phase 4: Frontend
- Admin-UI erstellen
- Offboarding-Wizard
- Audit-Dashboard
Phase 5: Kalender & Jitsi
- CalDAV Integration
- Jitsi-Meeting-Einladungen aus Kalender
- Mobile Sync (ActiveSync/CardDAV)
10. Existiert das schon?
Kurze Antwort: Nein, nicht in dieser Form.
Ähnliche Konzepte:
-
Funktionale Mailboxen (existiert)
- Shared Mailboxes in Exchange/Microsoft 365
- Group Addresses in Google Workspace
- → Aber: Keine RBAC-Integration, keine Anonymisierung
-
DSGVO-Löschung (existiert)
- Standard: Konto komplett löschen
- → Aber: Verlust der Geschäftshistorie
-
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
- Entscheidung: Vollständiges System oder minimale Variante?
- Proof of Concept: Functional Mailboxes mit bestehendem RBAC
- Evaluierung: Stalwart Mail Server in Testumgebung
- Architektur-Review: Mit Datenschutzbeauftragtem abstimmen
Anhang A: Referenzen
- Stalwart Mail Server
- SOGo Groupware
- Roundcube Webmail
- CalDAV Standard
- DSGVO Art. 17 - Recht auf Löschung
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