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>
This commit is contained in:
1177
docs/klausur-modul/DEVELOPER_SPECIFICATION.md
Normal file
1177
docs/klausur-modul/DEVELOPER_SPECIFICATION.md
Normal file
File diff suppressed because it is too large
Load Diff
463
docs/klausur-modul/MAIL-DEVELOPER-GUIDE.md
Normal file
463
docs/klausur-modul/MAIL-DEVELOPER-GUIDE.md
Normal file
@@ -0,0 +1,463 @@
|
||||
# Unified Inbox - Developer Guide
|
||||
|
||||
**Version:** 1.0.0
|
||||
**Datum:** 2026-01-10
|
||||
**Status:** Implementiert
|
||||
|
||||
---
|
||||
|
||||
## 1. Architektur-Übersicht
|
||||
|
||||
Das Unified Inbox System besteht aus folgenden Komponenten:
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────────┐
|
||||
│ FRONTEND │
|
||||
├─────────────────────────────────────────────────────────────────┤
|
||||
│ website/app/admin/mail/page.tsx - Admin UI │
|
||||
│ website/app/mail/page.tsx - User Inbox │
|
||||
│ website/app/mail/tasks/page.tsx - Arbeitsvorrat │
|
||||
└───────────────────────────┬─────────────────────────────────────┘
|
||||
│ HTTP (Port 8086)
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────────────┐
|
||||
│ KLAUSUR-SERVICE │
|
||||
├─────────────────────────────────────────────────────────────────┤
|
||||
│ klausur-service/backend/mail/ │
|
||||
│ ├── __init__.py - Module exports │
|
||||
│ ├── models.py - Pydantic Models & Enums │
|
||||
│ ├── mail_db.py - PostgreSQL operations (asyncpg) │
|
||||
│ ├── credentials.py - Vault/encrypted credential storage │
|
||||
│ ├── aggregator.py - IMAP/SMTP multi-account sync │
|
||||
│ ├── ai_service.py - LLM-powered email analysis │
|
||||
│ ├── task_service.py - Arbeitsvorrat (task management) │
|
||||
│ └── api.py - FastAPI router (30+ endpoints) │
|
||||
└───────────────────────────┬─────────────────────────────────────┘
|
||||
│
|
||||
┌───────────────────┼───────────────────┐
|
||||
▼ ▼ ▼
|
||||
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
|
||||
│ PostgreSQL │ │ Vault │ │ LLM Gateway │
|
||||
│ (Port 5432) │ │ (Port 8200) │ │ (Port 8000) │
|
||||
└──────────────┘ └──────────────┘ └──────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 2. Schnellstart
|
||||
|
||||
### 2.1 Service starten
|
||||
|
||||
```bash
|
||||
# Klausur-Service starten
|
||||
cd klausur-service/backend
|
||||
uvicorn main:app --host 0.0.0.0 --port 8086 --reload
|
||||
|
||||
# Frontend starten
|
||||
cd website
|
||||
npm run dev
|
||||
```
|
||||
|
||||
### 2.2 API testen
|
||||
|
||||
```bash
|
||||
# Health Check
|
||||
curl http://localhost:8086/api/v1/mail/health
|
||||
|
||||
# Konto hinzufügen (mit Auth)
|
||||
curl -X POST http://localhost:8086/api/v1/mail/accounts \
|
||||
-H "Authorization: Bearer $TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"email": "schulleitung@example.de",
|
||||
"imap_host": "imap.example.de",
|
||||
"imap_port": 993,
|
||||
"smtp_host": "smtp.example.de",
|
||||
"smtp_port": 587,
|
||||
"username": "schulleitung",
|
||||
"password": "secret"
|
||||
}'
|
||||
|
||||
# Inbox abrufen
|
||||
curl http://localhost:8086/api/v1/mail/inbox \
|
||||
-H "Authorization: Bearer $TOKEN"
|
||||
|
||||
# E-Mail analysieren
|
||||
curl -X POST http://localhost:8086/api/v1/mail/analyze/{email_id} \
|
||||
-H "Authorization: Bearer $TOKEN"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. Module im Detail
|
||||
|
||||
### 3.1 Models (`models.py`)
|
||||
|
||||
#### Enums
|
||||
|
||||
```python
|
||||
class SenderType(str, Enum):
|
||||
"""Klassifizierung des Absender-Typs."""
|
||||
KULTUSMINISTERIUM = "kultusministerium"
|
||||
LANDESSCHULBEHOERDE = "landesschulbehoerde"
|
||||
RLSB = "rlsb"
|
||||
SCHULAMT = "schulamt"
|
||||
NIBIS = "nibis"
|
||||
SCHULTRAEGER = "schultraeger"
|
||||
ELTERNVERTRETER = "elternvertreter"
|
||||
GEWERKSCHAFT = "gewerkschaft"
|
||||
FORTBILDUNGSINSTITUT = "fortbildungsinstitut"
|
||||
PRIVATPERSON = "privatperson"
|
||||
UNTERNEHMEN = "unternehmen"
|
||||
UNBEKANNT = "unbekannt"
|
||||
|
||||
class TaskPriority(str, Enum):
|
||||
"""Aufgaben-Priorität."""
|
||||
URGENT = "urgent" # Sofort bearbeiten
|
||||
HIGH = "high" # Zeitnah bearbeiten
|
||||
MEDIUM = "medium" # Normale Bearbeitung
|
||||
LOW = "low" # Kann warten
|
||||
```
|
||||
|
||||
#### Bekannte Behörden (Niedersachsen)
|
||||
|
||||
```python
|
||||
KNOWN_AUTHORITIES_NI = {
|
||||
"@mk.niedersachsen.de": {
|
||||
"type": SenderType.KULTUSMINISTERIUM,
|
||||
"name": "Kultusministerium Niedersachsen",
|
||||
"priority_boost": 2,
|
||||
},
|
||||
"@rlsb.de": {
|
||||
"type": SenderType.RLSB,
|
||||
"name": "Regionales Landesamt für Schule und Bildung",
|
||||
"priority_boost": 2,
|
||||
},
|
||||
"@landesschulbehoerde-nds.de": {
|
||||
"type": SenderType.LANDESSCHULBEHOERDE,
|
||||
"name": "Landesschulbehörde Niedersachsen",
|
||||
"priority_boost": 2,
|
||||
},
|
||||
"@nibis.de": {
|
||||
"type": SenderType.NIBIS,
|
||||
"name": "Niedersächsischer Bildungsserver",
|
||||
"priority_boost": 1,
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
### 3.2 Database (`mail_db.py`)
|
||||
|
||||
#### Tabellen
|
||||
|
||||
| Tabelle | Beschreibung |
|
||||
|---------|--------------|
|
||||
| `external_email_accounts` | IMAP/SMTP-Konfiguration |
|
||||
| `aggregated_emails` | Gecachte E-Mails |
|
||||
| `inbox_tasks` | Extrahierte Aufgaben |
|
||||
| `email_templates` | Antwortvorlagen |
|
||||
| `mail_audit_log` | Audit-Trail |
|
||||
| `mail_sync_status` | Sync-Status pro Konto |
|
||||
|
||||
#### Beispiel: E-Mail speichern
|
||||
|
||||
```python
|
||||
from mail.mail_db import store_email
|
||||
|
||||
email_id = await store_email(
|
||||
account_id="acc_123",
|
||||
message_id="<msg@example.de>",
|
||||
subject="Einladung zur Fortbildung",
|
||||
sender_email="info@mk.niedersachsen.de",
|
||||
sender_name="Kultusministerium",
|
||||
recipients=["schulleitung@example.de"],
|
||||
date=datetime.now(),
|
||||
body_preview="Sehr geehrte Schulleitung...",
|
||||
body_text="Vollständiger Text...",
|
||||
has_attachments=True,
|
||||
attachment_count=2,
|
||||
user_id="user_456",
|
||||
tenant_id="tenant_789",
|
||||
)
|
||||
```
|
||||
|
||||
### 3.3 Credentials (`credentials.py`)
|
||||
|
||||
Sichere Speicherung von IMAP/SMTP-Passwörtern:
|
||||
|
||||
```python
|
||||
from mail.credentials import get_credentials_service
|
||||
|
||||
creds = get_credentials_service()
|
||||
|
||||
# Passwort speichern (verschlüsselt)
|
||||
await creds.store_credentials(
|
||||
account_id="acc_123",
|
||||
username="user@example.de",
|
||||
password="secret123"
|
||||
)
|
||||
|
||||
# Passwort abrufen
|
||||
username, password = await creds.get_credentials("acc_123")
|
||||
```
|
||||
|
||||
**Verschlüsselung:**
|
||||
- Produktion: HashiCorp Vault (KV v2)
|
||||
- Entwicklung: Fernet-Verschlüsselung mit lokalem Key
|
||||
|
||||
### 3.4 Aggregator (`aggregator.py`)
|
||||
|
||||
IMAP-Synchronisation und SMTP-Versand:
|
||||
|
||||
```python
|
||||
from mail.aggregator import get_mail_aggregator
|
||||
|
||||
aggregator = get_mail_aggregator()
|
||||
|
||||
# Verbindung testen
|
||||
result = await aggregator.test_account_connection(account_id)
|
||||
if result.success:
|
||||
print(f"Verbunden: {result.folder_count} Ordner")
|
||||
|
||||
# Konto synchronisieren
|
||||
synced = await aggregator.sync_account(
|
||||
account_id="acc_123",
|
||||
user_id="user_456",
|
||||
tenant_id="tenant_789",
|
||||
full_sync=False # Nur neue E-Mails
|
||||
)
|
||||
print(f"{synced} neue E-Mails synchronisiert")
|
||||
|
||||
# E-Mail senden
|
||||
await aggregator.send_email(
|
||||
account_id="acc_123",
|
||||
to_addresses=["empfaenger@example.de"],
|
||||
subject="Antwort",
|
||||
body_html="<p>Vielen Dank für Ihre Anfrage...</p>"
|
||||
)
|
||||
```
|
||||
|
||||
### 3.5 AI Service (`ai_service.py`)
|
||||
|
||||
KI-gestützte E-Mail-Analyse:
|
||||
|
||||
```python
|
||||
from mail.ai_service import get_ai_email_service
|
||||
|
||||
ai = get_ai_email_service()
|
||||
|
||||
# Vollständige Analyse
|
||||
result = await ai.analyze_email(email_id, user_id)
|
||||
|
||||
print(f"Absender: {result.sender.sender_type}")
|
||||
print(f"Kategorie: {result.category}")
|
||||
print(f"Priorität: {result.suggested_priority}")
|
||||
print(f"Fristen: {len(result.deadlines)}")
|
||||
for deadline in result.deadlines:
|
||||
print(f" - {deadline.deadline_date}: {deadline.description}")
|
||||
```
|
||||
|
||||
#### Absender-Klassifikation
|
||||
|
||||
1. **Domain-Matching:** Bekannte Behörden-Domains
|
||||
2. **LLM-Fallback:** Bei unbekannten Absendern
|
||||
|
||||
#### Fristen-Erkennung
|
||||
|
||||
1. **Regex-Patterns:** Deutsche Datumsformate
|
||||
2. **LLM-Verstärkung:** Kontextuelle Deadline-Erkennung
|
||||
|
||||
### 3.6 Task Service (`task_service.py`)
|
||||
|
||||
Arbeitsvorrat-Management:
|
||||
|
||||
```python
|
||||
from mail.task_service import get_task_service
|
||||
|
||||
tasks = get_task_service()
|
||||
|
||||
# Task aus E-Mail erstellen
|
||||
task_id = await tasks.create_task_from_email(
|
||||
user_id="user_456",
|
||||
tenant_id="tenant_789",
|
||||
email_id="email_123",
|
||||
deadlines=[...], # Aus AI-Analyse
|
||||
sender_type=SenderType.KULTUSMINISTERIUM,
|
||||
auto_created=True
|
||||
)
|
||||
|
||||
# Dashboard-Statistiken
|
||||
stats = await tasks.get_dashboard_stats(user_id)
|
||||
print(f"Gesamt: {stats.total_tasks}")
|
||||
print(f"Überfällig: {stats.overdue_tasks}")
|
||||
print(f"Heute fällig: {stats.due_today}")
|
||||
|
||||
# Überfällige Tasks
|
||||
overdue = await tasks.get_overdue_tasks(user_id)
|
||||
for task in overdue:
|
||||
print(f"ÜBERFÄLLIG: {task['title']}")
|
||||
```
|
||||
|
||||
#### Prioritäts-Berechnung
|
||||
|
||||
```python
|
||||
# Absender-basierte Priorität
|
||||
KULTUSMINISTERIUM → HIGH
|
||||
NIBIS → MEDIUM
|
||||
PRIVATPERSON → LOW
|
||||
|
||||
# Deadline-Anpassung
|
||||
≤ 1 Tag → URGENT
|
||||
≤ 3 Tage → min. HIGH
|
||||
≤ 7 Tage → min. MEDIUM
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. API-Endpoints
|
||||
|
||||
### 4.1 Account Management
|
||||
|
||||
| Method | Endpoint | Beschreibung |
|
||||
|--------|----------|--------------|
|
||||
| `POST` | `/api/v1/mail/accounts` | Konto hinzufügen |
|
||||
| `GET` | `/api/v1/mail/accounts` | Alle Konten |
|
||||
| `GET` | `/api/v1/mail/accounts/{id}` | Einzelnes Konto |
|
||||
| `DELETE` | `/api/v1/mail/accounts/{id}` | Konto entfernen |
|
||||
| `POST` | `/api/v1/mail/accounts/{id}/test` | Verbindung testen |
|
||||
| `POST` | `/api/v1/mail/accounts/{id}/sync` | Konto synchronisieren |
|
||||
|
||||
### 4.2 Unified Inbox
|
||||
|
||||
| Method | Endpoint | Beschreibung |
|
||||
|--------|----------|--------------|
|
||||
| `GET` | `/api/v1/mail/inbox` | Aggregierte Inbox |
|
||||
| `GET` | `/api/v1/mail/inbox/{id}` | Einzelne E-Mail |
|
||||
| `POST` | `/api/v1/mail/inbox/{id}/read` | Als gelesen markieren |
|
||||
| `POST` | `/api/v1/mail/send` | E-Mail senden |
|
||||
|
||||
### 4.3 AI Analysis
|
||||
|
||||
| Method | Endpoint | Beschreibung |
|
||||
|--------|----------|--------------|
|
||||
| `POST` | `/api/v1/mail/analyze/{id}` | E-Mail analysieren |
|
||||
| `GET` | `/api/v1/mail/suggestions/{id}` | Antwortvorschläge |
|
||||
|
||||
### 4.4 Tasks (Arbeitsvorrat)
|
||||
|
||||
| Method | Endpoint | Beschreibung |
|
||||
|--------|----------|--------------|
|
||||
| `GET` | `/api/v1/mail/tasks` | Alle Tasks |
|
||||
| `POST` | `/api/v1/mail/tasks` | Manuelle Task |
|
||||
| `GET` | `/api/v1/mail/tasks/{id}` | Einzelne Task |
|
||||
| `PATCH` | `/api/v1/mail/tasks/{id}` | Task aktualisieren |
|
||||
| `POST` | `/api/v1/mail/tasks/{id}/complete` | Als erledigt markieren |
|
||||
| `GET` | `/api/v1/mail/tasks/dashboard` | Dashboard-Stats |
|
||||
|
||||
---
|
||||
|
||||
## 5. Tests
|
||||
|
||||
### 5.1 Unit Tests ausführen
|
||||
|
||||
```bash
|
||||
cd klausur-service/backend
|
||||
pytest tests/test_mail_service.py -v
|
||||
```
|
||||
|
||||
### 5.2 Testabdeckung
|
||||
|
||||
```bash
|
||||
pytest tests/test_mail_service.py --cov=mail --cov-report=html
|
||||
```
|
||||
|
||||
### 5.3 Testfälle
|
||||
|
||||
- **Absender-Erkennung:** Behörden-Domains
|
||||
- **Prioritäts-Berechnung:** Sender-basiert, Deadline-basiert
|
||||
- **Fristen-Extraktion:** Deutsche Datumsformate
|
||||
- **Kategorie-Regeln:** Fortbildung, Personal, Finanzen
|
||||
|
||||
---
|
||||
|
||||
## 6. Konfiguration
|
||||
|
||||
### 6.1 Umgebungsvariablen
|
||||
|
||||
```env
|
||||
# Datenbank
|
||||
DATABASE_URL=postgresql://user:pass@localhost:5432/breakpilot
|
||||
|
||||
# Vault (Produktion)
|
||||
VAULT_ADDR=http://vault:8200
|
||||
VAULT_TOKEN=hvs.xxxxx
|
||||
|
||||
# Entwicklung (ohne Vault)
|
||||
MAIL_ENCRYPTION_KEY=base64-encoded-fernet-key
|
||||
|
||||
# LLM Gateway
|
||||
LLM_GATEWAY_URL=http://localhost:8000
|
||||
DEFAULT_MODEL=breakpilot-teacher-8b
|
||||
```
|
||||
|
||||
### 6.2 Playbook-Konfiguration
|
||||
|
||||
Das Mail-Analyse-Playbook ist in `/backend/llm_gateway/services/playbook_service.py` definiert:
|
||||
|
||||
```python
|
||||
"mail_analysis": Playbook(
|
||||
id="mail_analysis",
|
||||
name="E-Mail-Analyse",
|
||||
system_prompt="...", # Niedersachsen-spezifisch
|
||||
recommended_models=["breakpilot-teacher-8b"],
|
||||
)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 7. Erweiterung
|
||||
|
||||
### 7.1 Neue Bundesländer hinzufügen
|
||||
|
||||
1. `KNOWN_AUTHORITIES_{KÜRZEL}` in `models.py` definieren
|
||||
2. Domain-Patterns für Behörden hinzufügen
|
||||
3. Playbook-Prompt anpassen
|
||||
|
||||
### 7.2 Neue Kategorien hinzufügen
|
||||
|
||||
1. `EmailCategory` Enum erweitern
|
||||
2. Regeln in `ai_service._apply_category_rules()` hinzufügen
|
||||
3. Frontend-Labels in `page.tsx` ergänzen
|
||||
|
||||
---
|
||||
|
||||
## 8. Troubleshooting
|
||||
|
||||
### IMAP-Verbindungsfehler
|
||||
|
||||
```
|
||||
IMAPConnectionError: Connection refused
|
||||
```
|
||||
→ Port/SSL-Einstellungen prüfen, Firewall-Regeln
|
||||
|
||||
### Vault-Authentifizierungsfehler
|
||||
|
||||
```
|
||||
VaultError: permission denied
|
||||
```
|
||||
→ Token prüfen, Policy für `secret/mail/*` erforderlich
|
||||
|
||||
### LLM-Timeout
|
||||
|
||||
```
|
||||
HTTPException: 504 Gateway Timeout
|
||||
```
|
||||
→ LLM Gateway Status prüfen, Modell-Verfügbarkeit
|
||||
|
||||
---
|
||||
|
||||
## 9. Referenzen
|
||||
|
||||
- [UNIFIED-INBOX-SPECIFICATION.md](./UNIFIED-INBOX-SPECIFICATION.md) - Vollständige Spezifikation
|
||||
- [MAIL-RBAC-DEVELOPER-SPECIFICATION.md](./MAIL-RBAC-DEVELOPER-SPECIFICATION.md) - DSGVO & RBAC Details
|
||||
- [mail-rbac-architecture.md](../architecture/mail-rbac-architecture.md) - Architektur-Dokument
|
||||
1834
docs/klausur-modul/MAIL-RBAC-DEVELOPER-SPECIFICATION.md
Normal file
1834
docs/klausur-modul/MAIL-RBAC-DEVELOPER-SPECIFICATION.md
Normal file
File diff suppressed because it is too large
Load Diff
1555
docs/klausur-modul/UNIFIED-INBOX-SPECIFICATION.md
Normal file
1555
docs/klausur-modul/UNIFIED-INBOX-SPECIFICATION.md
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user