{"config":{"lang":["de"],"separator":"[\\s\\-]+","pipeline":["stopWordFilter"],"fields":{"title":{"boost":1000.0},"text":{"boost":1.0},"tags":{"boost":1000000.0}}},"docs":[{"location":"","title":"Breakpilot Dokumentation","text":"

Willkommen zur zentralen Dokumentation des Breakpilot-Projekts.

"},{"location":"#was-ist-breakpilot","title":"Was ist Breakpilot?","text":"

Breakpilot ist eine DSGVO-konforme Bildungsplattform fuer Lehrkraefte mit folgenden Kernfunktionen:

"},{"location":"#schnellstart","title":"Schnellstart","text":""},{"location":"#architektur","title":"Architektur","text":""},{"location":"#services","title":"Services","text":"Service Port Beschreibung Backend (Python) 8000 FastAPI Backend mit Panel UI Consent Service (Go) 8081 DSGVO-konforme Einwilligungsverwaltung Klausur Service 8086 KI-gestuetzte Klausurkorrektur Agent Core - Multi-Agent Infrastructure PostgreSQL 5432 Relationale Datenbank Qdrant 6333 Vektor-Datenbank fuer RAG MinIO 9000 Object Storage Vault 8200 Secrets Management"},{"location":"#entwicklung","title":"Entwicklung","text":""},{"location":"#weitere-ressourcen","title":"Weitere Ressourcen","text":""},{"location":"#projektstruktur","title":"Projektstruktur","text":"
breakpilot-pwa/\n\u251c\u2500\u2500 backend/                 # Python FastAPI Backend\n\u251c\u2500\u2500 consent-service/         # Go Consent Service\n\u251c\u2500\u2500 klausur-service/         # Klausur-Korrektur Service\n\u251c\u2500\u2500 agent-core/              # Multi-Agent Infrastructure\n\u251c\u2500\u2500 voice-service/           # Voice/Audio Processing\n\u251c\u2500\u2500 website/                 # Next.js Frontend\n\u251c\u2500\u2500 studio-v2/               # Admin Dashboard (Next.js)\n\u251c\u2500\u2500 docs-src/                # Diese Dokumentation\n\u2514\u2500\u2500 docker-compose.yml       # Container-Orchestrierung\n
"},{"location":"#support","title":"Support","text":"

Bei Fragen oder Problemen:

  1. Pruefen Sie zuerst die relevante Dokumentation
  2. Suchen Sie im Issue Tracker nach aehnlichen Problemen
  3. Erstellen Sie ein neues Issue mit detaillierter Beschreibung
"},{"location":"api/backend-api/","title":"BreakPilot Backend API Dokumentation","text":""},{"location":"api/backend-api/#ubersicht","title":"\u00dcbersicht","text":"

Base URL: http://localhost:8000/api

Alle Endpoints erfordern Authentifizierung via JWT im Authorization-Header:

Authorization: Bearer <token>\n

"},{"location":"api/backend-api/#worksheets-api","title":"Worksheets API","text":"

Generiert Lernmaterialien (MC-Tests, L\u00fcckentexte, Mindmaps, Quiz).

"},{"location":"api/backend-api/#post-worksheetsgeneratemultiple-choice","title":"POST /worksheets/generate/multiple-choice","text":"

Generiert Multiple-Choice-Fragen aus Quelltext.

Request Body:

{\n  \"source_text\": \"Der Text, aus dem Fragen generiert werden sollen...\",\n  \"num_questions\": 5,\n  \"difficulty\": \"medium\",\n  \"topic\": \"Thema\",\n  \"subject\": \"Deutsch\"\n}\n

Response (200):

{\n  \"success\": true,\n  \"content\": {\n    \"type\": \"multiple_choice\",\n    \"data\": {\n      \"questions\": [\n        {\n          \"question\": \"Was ist...?\",\n          \"options\": [\"A\", \"B\", \"C\", \"D\"],\n          \"correct\": 0,\n          \"explanation\": \"Erkl\u00e4rung...\"\n        }\n      ]\n    }\n  }\n}\n

"},{"location":"api/backend-api/#post-worksheetsgeneratecloze","title":"POST /worksheets/generate/cloze","text":"

Generiert L\u00fcckentexte.

"},{"location":"api/backend-api/#post-worksheetsgeneratemindmap","title":"POST /worksheets/generate/mindmap","text":"

Generiert Mindmap als Mermaid-Diagramm.

"},{"location":"api/backend-api/#post-worksheetsgeneratequiz","title":"POST /worksheets/generate/quiz","text":"

Generiert Mix aus verschiedenen Fragetypen.

"},{"location":"api/backend-api/#corrections-api","title":"Corrections API","text":"

OCR-basierte Klausurkorrektur mit automatischer Bewertung.

"},{"location":"api/backend-api/#post-corrections","title":"POST /corrections/","text":"

Erstellt neue Korrektur-Session.

"},{"location":"api/backend-api/#post-correctionsidupload","title":"POST /corrections/{id}/upload","text":"

L\u00e4dt gescannte Klausur hoch und startet OCR im Hintergrund.

"},{"location":"api/backend-api/#get-correctionsid","title":"GET /corrections/{id}","text":"

Ruft Korrektur-Status ab.

Status-Werte: - uploaded - Datei hochgeladen - processing - OCR l\u00e4uft - ocr_complete - OCR fertig - analyzing - Analyse l\u00e4uft - analyzed - Analyse abgeschlossen - completed - Fertig - error - Fehler

"},{"location":"api/backend-api/#post-correctionsidanalyze","title":"POST /corrections/{id}/analyze","text":"

Analysiert extrahierten Text und bewertet Antworten.

"},{"location":"api/backend-api/#get-correctionsidexport-pdf","title":"GET /corrections/{id}/export-pdf","text":"

Exportiert korrigierte Arbeit als PDF.

"},{"location":"api/backend-api/#letters-api","title":"Letters API","text":"

Elternbriefe mit GFK-Integration und PDF-Export.

"},{"location":"api/backend-api/#post-letters","title":"POST /letters/","text":"

Erstellt neuen Elternbrief.

letter_type Werte: - general - Allgemeine Information - halbjahr - Halbjahresinformation - fehlzeiten - Fehlzeiten-Mitteilung - elternabend - Einladung Elternabend - lob - Positives Feedback - custom - Benutzerdefiniert

"},{"location":"api/backend-api/#post-lettersimprove","title":"POST /letters/improve","text":"

Verbessert Text nach GFK-Prinzipien.

"},{"location":"api/backend-api/#state-engine-api","title":"State Engine API","text":"

Begleiter-Modus mit Phasen-Management und Antizipation.

"},{"location":"api/backend-api/#get-statedashboard","title":"GET /state/dashboard","text":"

Komplettes Dashboard f\u00fcr Begleiter-Modus.

"},{"location":"api/backend-api/#get-statesuggestions","title":"GET /state/suggestions","text":"

Ruft Vorschl\u00e4ge f\u00fcr Lehrer ab.

"},{"location":"api/backend-api/#post-statemilestone","title":"POST /state/milestone","text":"

Schlie\u00dft Meilenstein ab.

"},{"location":"api/backend-api/#klausur-korrektur-api-abitur","title":"Klausur-Korrektur API (Abitur)","text":"

Abitur-Klausurkorrektur mit 15-Punkte-System, Erst-/Zweitpr\u00fcfer-Workflow und KI-gest\u00fctzter Bewertung.

"},{"location":"api/backend-api/#klausur-modi","title":"Klausur-Modi","text":"Modus Beschreibung landes_abitur NiBiS Niedersachsen - rechtlich gekl\u00e4rte Aufgaben vorabitur Lehrer-erstellte Klausuren mit Rights-Gate"},{"location":"api/backend-api/#post-klausur-korrekturklausuren","title":"POST /klausur-korrektur/klausuren","text":"

Erstellt neue Abitur-Klausur.

"},{"location":"api/backend-api/#post-klausur-korrekturstudentsidevaluate","title":"POST /klausur-korrektur/students/{id}/evaluate","text":"

Startet KI-Bewertung.

Response (200):

{\n  \"criteria_scores\": {\n    \"rechtschreibung\": {\"score\": 85, \"weight\": 0.15},\n    \"grammatik\": {\"score\": 90, \"weight\": 0.15},\n    \"inhalt\": {\"score\": 75, \"weight\": 0.40},\n    \"struktur\": {\"score\": 80, \"weight\": 0.15},\n    \"stil\": {\"score\": 85, \"weight\": 0.15}\n  },\n  \"raw_points\": 80,\n  \"grade_points\": 11,\n  \"grade_label\": \"2\"\n}\n

"},{"location":"api/backend-api/#15-punkte-notenschlussel","title":"15-Punkte-Notenschl\u00fcssel","text":"Punkte Prozent Note 15 \u226595% 1+ 14 \u226590% 1 13 \u226585% 1- 12 \u226580% 2+ 11 \u226575% 2 10 \u226570% 2- 9 \u226565% 3+ 8 \u226560% 3 7 \u226555% 3- 6 \u226550% 4+ 5 \u226545% 4 4 \u226540% 4- 3 \u226533% 5+ 2 \u226527% 5 1 \u226520% 5- 0 <20% 6"},{"location":"api/backend-api/#bewertungskriterien","title":"Bewertungskriterien","text":"Kriterium Gewicht Beschreibung rechtschreibung 15% Orthografie grammatik 15% Grammatik & Syntax inhalt 40% Inhaltliche Qualit\u00e4t struktur 15% Aufbau & Gliederung stil 15% Ausdruck & Stil"},{"location":"api/backend-api/#security-api-devsecops-dashboard","title":"Security API (DevSecOps Dashboard)","text":"

API fuer das Security Dashboard mit DevSecOps-Tools Integration.

"},{"location":"api/backend-api/#get-v1securitytools","title":"GET /v1/security/tools","text":"

Gibt Status aller DevSecOps-Tools zurueck.

"},{"location":"api/backend-api/#get-v1securityfindings","title":"GET /v1/security/findings","text":"

Gibt alle Security-Findings zurueck.

"},{"location":"api/backend-api/#get-v1securitysbom","title":"GET /v1/security/sbom","text":"

Gibt SBOM (Software Bill of Materials) zurueck.

"},{"location":"api/backend-api/#post-v1securityscantype","title":"POST /v1/security/scan/{type}","text":"

Startet einen Security-Scan.

Path Parameter: - type: Scan-Typ (secrets, sast, deps, containers, sbom, all)

"},{"location":"api/backend-api/#fehler-responses","title":"Fehler-Responses","text":""},{"location":"api/backend-api/#400-bad-request","title":"400 Bad Request","text":"
{\n  \"detail\": \"Beschreibung des Fehlers\"\n}\n
"},{"location":"api/backend-api/#401-unauthorized","title":"401 Unauthorized","text":"
{\n  \"detail\": \"Not authenticated\"\n}\n
"},{"location":"api/backend-api/#404-not-found","title":"404 Not Found","text":"
{\n  \"detail\": \"Ressource nicht gefunden\"\n}\n
"},{"location":"api/backend-api/#500-internal-server-error","title":"500 Internal Server Error","text":"
{\n  \"detail\": \"Interner Serverfehler\"\n}\n
"},{"location":"architecture/auth-system/","title":"BreakPilot Authentifizierung & Autorisierung","text":""},{"location":"architecture/auth-system/#uebersicht","title":"Uebersicht","text":"

BreakPilot verwendet einen Hybrid-Ansatz fuer Authentifizierung und Autorisierung:

\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502                        AUTHENTIFIZIERUNG                                 \u2502\n\u2502                     \"Wer bist du?\"                                       \u2502\n\u2502  \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510 \u2502\n\u2502  \u2502                    HybridAuthenticator                              \u2502 \u2502\n\u2502  \u2502  \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510      \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510  \u2502 \u2502\n\u2502  \u2502  \u2502   Keycloak          \u2502      \u2502   Lokales JWT                   \u2502  \u2502 \u2502\n\u2502  \u2502  \u2502   (Produktion)      \u2502  OR  \u2502   (Entwicklung)                 \u2502  \u2502 \u2502\n\u2502  \u2502  \u2502   RS256 + JWKS      \u2502      \u2502   HS256 + Secret                \u2502  \u2502 \u2502\n\u2502  \u2502  \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518      \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518  \u2502 \u2502\n\u2502  \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518 \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n                                    \u2502\n                                    \u25bc\n\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502                         AUTORISIERUNG                                    \u2502\n\u2502                      \"Was darfst du?\"                                    \u2502\n\u2502  \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510 \u2502\n\u2502  \u2502                    rbac.py (Eigenentwicklung)                       \u2502 \u2502\n\u2502  \u2502  \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510  \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510  \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510   \u2502 \u2502\n\u2502  \u2502  \u2502 Rollen-Hierarchie\u2502  \u2502 PolicySet       \u2502  \u2502 DEFAULT_PERMISSIONS\u2502   \u2502 \u2502\n\u2502  \u2502  \u2502 15+ Rollen       \u2502  \u2502 Bundesland-     \u2502  \u2502 Matrix            \u2502   \u2502 \u2502\n\u2502  \u2502  \u2502 - Erstkorrektor  \u2502  \u2502 spezifisch      \u2502  \u2502 Rolle\u2192Ressource\u2192  \u2502   \u2502 \u2502\n\u2502  \u2502  \u2502 - Klassenlehrer  \u2502  \u2502 - Niedersachsen \u2502  \u2502 Aktion            \u2502   \u2502 \u2502\n\u2502  \u2502  \u2502 - Schulleitung   \u2502  \u2502 - Bayern        \u2502  \u2502                   \u2502   \u2502 \u2502\n\u2502  \u2502  \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518  \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518  \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518   \u2502 \u2502\n\u2502  \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518 \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n
"},{"location":"architecture/auth-system/#warum-dieser-ansatz","title":"Warum dieser Ansatz?","text":""},{"location":"architecture/auth-system/#alternative-loesungen-verworfen","title":"Alternative Loesungen (verworfen)","text":"Tool Problem fuer BreakPilot Casbin Zu generisch fuer Bundesland-spezifische Policies Cerbos Overhead: Externer PDP-Service fuer ~15 Rollen ueberdimensioniert OpenFGA Zanzibar-Modell optimiert fuer Graph-Beziehungen, nicht Hierarchien Keycloak RBAC Kann keine ressourcen-spezifischen Zuweisungen (User X ist Erstkorrektor fuer Package Y)"},{"location":"architecture/auth-system/#vorteile-des-hybrid-ansatzes","title":"Vorteile des Hybrid-Ansatzes","text":"
  1. Keycloak fuer Authentifizierung:
  2. Bew\u00e4hrtes IAM-System
  3. SSO, Federation, MFA
  4. Apache-2.0 Lizenz

  5. Eigenes rbac.py fuer Autorisierung:

  6. Domaenenspezifische Logik (Korrekturkette, Zeugnis-Workflow)
  7. Bundesland-spezifische Regeln
  8. Zeitlich begrenzte Zuweisungen
  9. Key-Sharing fuer verschluesselte Klausuren
"},{"location":"architecture/auth-system/#authentifizierung-authkeycloak_authpy","title":"Authentifizierung (auth/keycloak_auth.py)","text":""},{"location":"architecture/auth-system/#konfiguration","title":"Konfiguration","text":"
# Entwicklung: Lokales JWT (Standard)\nJWT_SECRET=your-secret-key\n\n# Produktion: Keycloak\nKEYCLOAK_SERVER_URL=https://keycloak.breakpilot.app\nKEYCLOAK_REALM=breakpilot\nKEYCLOAK_CLIENT_ID=breakpilot-backend\nKEYCLOAK_CLIENT_SECRET=your-client-secret\n
"},{"location":"architecture/auth-system/#token-erkennung","title":"Token-Erkennung","text":"

Der HybridAuthenticator erkennt automatisch den Token-Typ:

# Keycloak-Token (RS256)\n{\n  \"iss\": \"https://keycloak.breakpilot.app/realms/breakpilot\",\n  \"sub\": \"user-uuid\",\n  \"realm_access\": {\"roles\": [\"teacher\", \"admin\"]},\n  ...\n}\n\n# Lokales JWT (HS256)\n{\n  \"iss\": \"breakpilot\",\n  \"user_id\": \"user-uuid\",\n  \"role\": \"admin\",\n  ...\n}\n
"},{"location":"architecture/auth-system/#fastapi-integration","title":"FastAPI Integration","text":"
from auth import get_current_user\n\n@app.get(\"/api/protected\")\nasync def protected_endpoint(user: dict = Depends(get_current_user)):\n    # user enth\u00e4lt: user_id, email, role, realm_roles, tenant_id\n    return {\"user_id\": user[\"user_id\"]}\n
"},{"location":"architecture/auth-system/#autorisierung-klausur-servicebackendrbacpy","title":"Autorisierung (klausur-service/backend/rbac.py)","text":""},{"location":"architecture/auth-system/#rollen-15","title":"Rollen (15+)","text":"Rolle Beschreibung Bereich erstkorrektor Erster Pr\u00fcfer Klausur zweitkorrektor Zweiter Pr\u00fcfer Klausur drittkorrektor Dritter Pr\u00fcfer Klausur klassenlehrer Klassenleitung Zeugnis fachlehrer Fachlehrkraft Noten fachvorsitz Fachkonferenz-Leitung Fachschaft schulleitung Schulleiter/in Schule zeugnisbeauftragter Zeugnis-Koordination Zeugnis sekretariat Verwaltung Schule data_protection_officer DSB DSGVO ..."},{"location":"architecture/auth-system/#ressourcentypen-25","title":"Ressourcentypen (25+)","text":"
class ResourceType(str, Enum):\n    EXAM_PACKAGE = \"exam_package\"         # Klausurpaket\n    STUDENT_SUBMISSION = \"student_submission\"\n    CORRECTION = \"correction\"\n    ZEUGNIS = \"zeugnis\"\n    FACHNOTE = \"fachnote\"\n    KOPFNOTE = \"kopfnote\"\n    BEMERKUNG = \"bemerkung\"\n    ...\n
"},{"location":"architecture/auth-system/#aktionen-17","title":"Aktionen (17)","text":"
class Action(str, Enum):\n    CREATE = \"create\"\n    READ = \"read\"\n    UPDATE = \"update\"\n    DELETE = \"delete\"\n    SIGN_OFF = \"sign_off\"        # Freigabe\n    BREAK_GLASS = \"break_glass\"  # Notfall-Zugriff\n    SHARE_KEY = \"share_key\"      # Schl\u00fcssel teilen\n    ...\n
"},{"location":"architecture/auth-system/#permission-pruefung","title":"Permission-Pruefung","text":"
from klausur_service.backend.rbac import PolicyEngine\n\nengine = PolicyEngine()\n\n# Pruefe ob User X Klausur Y korrigieren darf\nallowed = engine.check_permission(\n    user_id=\"user-uuid\",\n    action=Action.UPDATE,\n    resource_type=ResourceType.CORRECTION,\n    resource_id=\"klausur-uuid\"\n)\n
"},{"location":"architecture/auth-system/#bundesland-spezifische-policies","title":"Bundesland-spezifische Policies","text":"
@dataclass\nclass PolicySet:\n    bundesland: str\n    abitur_type: str  # \"landesabitur\" | \"zentralabitur\"\n\n    # Korrekturkette\n    korrektoren_anzahl: int  # 2 oder 3\n    anonyme_erstkorrektur: bool\n\n    # Sichtbarkeit\n    zk_visibility_mode: ZKVisibilityMode  # BLIND | SEMI | FULL\n    eh_visibility_mode: EHVisibilityMode\n\n    # Zeugnis\n    kopfnoten_enabled: bool\n    ...\n
"},{"location":"architecture/auth-system/#beispiel-niedersachsen","title":"Beispiel: Niedersachsen","text":"
NIEDERSACHSEN_POLICY = PolicySet(\n    bundesland=\"niedersachsen\",\n    abitur_type=\"landesabitur\",\n    korrektoren_anzahl=2,\n    anonyme_erstkorrektur=True,\n    zk_visibility_mode=ZKVisibilityMode.BLIND,\n    eh_visibility_mode=EHVisibilityMode.SUMMARY_ONLY,\n    kopfnoten_enabled=True,\n)\n
"},{"location":"architecture/auth-system/#workflow-beispiele","title":"Workflow-Beispiele","text":""},{"location":"architecture/auth-system/#klausurkorrektur-workflow","title":"Klausurkorrektur-Workflow","text":"
1. Lehrer laedt Klausuren hoch\n   \u2514\u2500\u2500 Rolle: \"lehrer\" + Action.CREATE auf EXAM_PACKAGE\n\n2. Erstkorrektor korrigiert\n   \u2514\u2500\u2500 Rolle: \"erstkorrektor\" (ressourcen-spezifisch) + Action.UPDATE auf CORRECTION\n\n3. Zweitkorrektor ueberprueft\n   \u2514\u2500\u2500 Rolle: \"zweitkorrektor\" + Action.READ auf CORRECTION\n   \u2514\u2500\u2500 Policy: zk_visibility_mode bestimmt Sichtbarkeit\n\n4. Drittkorrektor (bei Abweichung)\n   \u2514\u2500\u2500 Rolle: \"drittkorrektor\" + Action.SIGN_OFF\n
"},{"location":"architecture/auth-system/#zeugnis-workflow","title":"Zeugnis-Workflow","text":"
1. Fachlehrer traegt Noten ein\n   \u2514\u2500\u2500 Rolle: \"fachlehrer\" + Action.CREATE auf FACHNOTE\n\n2. Klassenlehrer prueft\n   \u2514\u2500\u2500 Rolle: \"klassenlehrer\" + Action.READ auf ZEUGNIS\n   \u2514\u2500\u2500 Action.SIGN_OFF freigeben\n\n3. Zeugnisbeauftragter final\n   \u2514\u2500\u2500 Rolle: \"zeugnisbeauftragter\" + Action.SIGN_OFF\n\n4. Schulleitung unterzeichnet\n   \u2514\u2500\u2500 Rolle: \"schulleitung\" + Action.SIGN_OFF\n
"},{"location":"architecture/auth-system/#dateien","title":"Dateien","text":"Datei Beschreibung backend/auth/__init__.py Auth-Modul Exports backend/auth/keycloak_auth.py Hybrid-Authentifizierung klausur-service/backend/rbac.py Autorisierungs-Engine backend/rbac_api.py REST API fuer Rollenverwaltung"},{"location":"architecture/auth-system/#konfiguration_1","title":"Konfiguration","text":""},{"location":"architecture/auth-system/#entwicklung-ohne-keycloak","title":"Entwicklung (ohne Keycloak)","text":"
# .env\nENVIRONMENT=development\nJWT_SECRET=dev-secret-32-chars-minimum-here\n
"},{"location":"architecture/auth-system/#produktion-mit-keycloak","title":"Produktion (mit Keycloak)","text":"
# .env\nENVIRONMENT=production\nJWT_SECRET=<openssl rand -hex 32>\nKEYCLOAK_SERVER_URL=https://keycloak.breakpilot.app\nKEYCLOAK_REALM=breakpilot\nKEYCLOAK_CLIENT_ID=breakpilot-backend\nKEYCLOAK_CLIENT_SECRET=<from keycloak admin console>\n
"},{"location":"architecture/auth-system/#sicherheitshinweise","title":"Sicherheitshinweise","text":"
  1. Secrets niemals im Code - Immer Umgebungsvariablen verwenden
  2. JWT_SECRET in Produktion - Mindestens 32 Bytes, generiert mit openssl rand -hex 32
  3. Keycloak HTTPS - KEYCLOAK_VERIFY_SSL=true in Produktion
  4. Token-Expiration - Keycloak-Tokens kurz halten (5-15 Minuten)
  5. Audit-Trail - Alle Berechtigungspruefungen werden geloggt
"},{"location":"architecture/devsecops/","title":"BreakPilot DevSecOps Architecture","text":""},{"location":"architecture/devsecops/#uebersicht","title":"Uebersicht","text":"

BreakPilot implementiert einen umfassenden DevSecOps-Ansatz mit Security-by-Design fuer die Entwicklung und den Betrieb der Bildungsplattform.

\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502                        DEVSECOPS PIPELINE                                    \u2502\n\u2502                                                                              \u2502\n\u2502  \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510    \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510    \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510    \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510   \u2502\n\u2502  \u2502  Pre-Commit \u2502\u2500\u2500\u2500\u25ba\u2502  CI/CD      \u2502\u2500\u2500\u2500\u25ba\u2502  Build      \u2502\u2500\u2500\u2500\u25ba\u2502  Deploy     \u2502   \u2502\n\u2502  \u2502  Hooks      \u2502    \u2502  Pipeline   \u2502    \u2502  & Scan     \u2502    \u2502  & Monitor  \u2502   \u2502\n\u2502  \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518    \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518    \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518    \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518   \u2502\n\u2502        \u2502                  \u2502                  \u2502                  \u2502           \u2502\n\u2502        \u25bc                  \u25bc                  \u25bc                  \u25bc           \u2502\n\u2502  \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510    \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510    \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510    \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510   \u2502\n\u2502  \u2502 Gitleaks    \u2502    \u2502 Semgrep     \u2502    \u2502 Trivy       \u2502    \u2502 Falco       \u2502   \u2502\n\u2502  \u2502 Bandit      \u2502    \u2502 OWASP DC    \u2502    \u2502 Grype       \u2502    \u2502 (optional)  \u2502   \u2502\n\u2502  \u2502 Secrets     \u2502    \u2502 SAST/SCA    \u2502    \u2502 SBOM        \u2502    \u2502 Runtime     \u2502   \u2502\n\u2502  \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518    \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518    \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518    \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518   \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n
"},{"location":"architecture/devsecops/#security-tools-stack","title":"Security Tools Stack","text":""},{"location":"architecture/devsecops/#1-secrets-detection","title":"1. Secrets Detection","text":"Tool Version Lizenz Verwendung Gitleaks 8.18.x MIT Pre-commit Hook, CI/CD detect-secrets 1.4.x Apache-2.0 Zusaetzliche Baseline-Pruefung

Konfiguration: .gitleaks.toml

# Lokal ausfuehren\ngitleaks detect --source . -v\n\n# Pre-commit (automatisch)\ngitleaks protect --staged -v\n
"},{"location":"architecture/devsecops/#2-static-application-security-testing-sast","title":"2. Static Application Security Testing (SAST)","text":"Tool Version Lizenz Sprachen Semgrep 1.52.x LGPL-2.1 Python, Go, JavaScript, TypeScript Bandit 1.7.x Apache-2.0 Python (spezialisiert)

Konfiguration: .semgrep.yml

# Semgrep ausfuehren\nsemgrep scan --config auto --config .semgrep.yml\n\n# Bandit ausfuehren\nbandit -r backend/ -ll\n
"},{"location":"architecture/devsecops/#3-software-composition-analysis-sca","title":"3. Software Composition Analysis (SCA)","text":"Tool Version Lizenz Verwendung Trivy 0.48.x Apache-2.0 Filesystem, Container, IaC Grype 0.74.x Apache-2.0 Vulnerability Scanning OWASP Dependency-Check 9.x Apache-2.0 CVE/NVD Abgleich

Konfiguration: .trivy.yaml

# Filesystem-Scan\ntrivy fs . --severity HIGH,CRITICAL\n\n# Container-Scan\ntrivy image breakpilot-pwa-backend:latest\n
"},{"location":"architecture/devsecops/#4-sbom-software-bill-of-materials","title":"4. SBOM (Software Bill of Materials)","text":"Tool Version Lizenz Formate Syft 0.100.x Apache-2.0 CycloneDX, SPDX
# SBOM generieren\nsyft dir:. -o cyclonedx-json=sbom.json\nsyft dir:. -o spdx-json=sbom-spdx.json\n
"},{"location":"architecture/devsecops/#5-dynamic-application-security-testing-dast","title":"5. Dynamic Application Security Testing (DAST)","text":"Tool Version Lizenz Verwendung OWASP ZAP 2.14.x Apache-2.0 Staging-Scans (nightly)
# ZAP Scan gegen Staging\ndocker run -t owasp/zap2docker-stable zap-baseline.py \\\n    -t http://staging.breakpilot.app -r zap-report.html\n
"},{"location":"architecture/devsecops/#pre-commit-hooks","title":"Pre-Commit Hooks","text":"

Die Pre-Commit-Konfiguration (.pre-commit-config.yaml) fuehrt automatisch bei jedem Commit aus:

  1. Schnelle Checks (< 10 Sekunden):
  2. Gitleaks (Secrets)
  3. Trailing Whitespace
  4. YAML/JSON Validierung

  5. Code Quality (< 30 Sekunden):

  6. Black/Ruff (Python Formatting)
  7. Go fmt/vet
  8. ESLint (JavaScript)

  9. Security Checks (< 60 Sekunden):

  10. Bandit (Python Security)
  11. Semgrep (Error-Severity)
"},{"location":"architecture/devsecops/#installation","title":"Installation","text":"
# Pre-commit installieren\npip install pre-commit\n\n# Hooks aktivieren\npre-commit install\n\n# Alle Checks manuell ausfuehren\npre-commit run --all-files\n
"},{"location":"architecture/devsecops/#severity-gates","title":"Severity-Gates","text":"Phase Severity Aktion Pre-Commit ERROR Commit blockiert PR/CI CRITICAL, HIGH Pipeline blockiert Nightly Scan MEDIUM+ Report generiert Production Deploy CRITICAL Deploy blockiert"},{"location":"architecture/devsecops/#security-dashboard","title":"Security Dashboard","text":"

Das BreakPilot Admin Panel enthaelt ein integriertes Security Dashboard unter Verwaltung > Security.

"},{"location":"architecture/devsecops/#features","title":"Features","text":"

Fuer Entwickler: - Scan-Ergebnisse auf einen Blick - Pre-commit Hook Status - Quick-Fix Suggestions - SBOM Viewer mit Suchfunktion

Fuer Security-Experten: - Vulnerability Severity Distribution (Critical/High/Medium/Low) - CVE-Tracking mit Fix-Verfuegbarkeit - Compliance-Status (OWASP Top 10, DSGVO) - Secrets Detection History

Fuer Ops: - Container Image Scan Results - Dependency Update Status - Security Scan Scheduling - Auto-Refresh alle 30 Sekunden

"},{"location":"architecture/devsecops/#api-endpoints","title":"API Endpoints","text":"
GET  /api/v1/security/tools      - Tool-Status\nGET  /api/v1/security/findings   - Alle Findings\nGET  /api/v1/security/summary    - Severity-Zusammenfassung\nGET  /api/v1/security/sbom       - SBOM-Daten\nGET  /api/v1/security/history    - Scan-Historie\nGET  /api/v1/security/reports/{tool} - Tool-spezifischer Report\nPOST /api/v1/security/scan/{type} - Scan starten\nGET  /api/v1/security/health     - Health-Check\n
"},{"location":"architecture/devsecops/#compliance","title":"Compliance","text":"

Die DevSecOps-Pipeline unterstuetzt folgende Compliance-Anforderungen:

"},{"location":"architecture/devsecops/#tool-installation","title":"Tool-Installation","text":""},{"location":"architecture/devsecops/#macos-homebrew","title":"macOS (Homebrew)","text":"
# Security Tools\nbrew install gitleaks\nbrew install trivy\nbrew install syft\nbrew install grype\n\n# Python Tools\npip install semgrep bandit pre-commit\n
"},{"location":"architecture/devsecops/#linux-aptsnap","title":"Linux (apt/snap)","text":"
# Gitleaks\nsudo snap install gitleaks\n\n# Trivy\nsudo apt-get install trivy\n\n# Python Tools\npip install semgrep bandit pre-commit\n
"},{"location":"architecture/environments/","title":"Umgebungs-Architektur","text":""},{"location":"architecture/environments/#ubersicht","title":"\u00dcbersicht","text":"

BreakPilot verwendet eine 3-Umgebungs-Strategie f\u00fcr sichere Entwicklung und Deployment:

\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510     \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510     \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502   Development   \u2502\u2500\u2500\u2500\u2500\u25b6\u2502     Staging     \u2502\u2500\u2500\u2500\u2500\u25b6\u2502   Production    \u2502\n\u2502   (develop)     \u2502     \u2502    (staging)    \u2502     \u2502     (main)      \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518     \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518     \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n     T\u00e4gliche            Getesteter Code         Produktionsreif\n     Entwicklung\n
"},{"location":"architecture/environments/#umgebungen","title":"Umgebungen","text":""},{"location":"architecture/environments/#development-dev","title":"Development (Dev)","text":"

Zweck: T\u00e4gliche Entwicklungsarbeit

Eigenschaft Wert Git Branch develop Compose File docker-compose.yml + docker-compose.override.yml (auto) Env File .env.dev Database breakpilot_dev Debug Aktiviert Hot-Reload Aktiviert

Start:

./scripts/start.sh dev\n# oder einfach:\ndocker compose up -d\n

"},{"location":"architecture/environments/#staging","title":"Staging","text":"

Zweck: Getesteter, freigegebener Code vor Produktion

Eigenschaft Wert Git Branch staging Compose File docker-compose.yml + docker-compose.staging.yml Env File .env.staging Database breakpilot_staging (separates Volume) Debug Deaktiviert Hot-Reload Deaktiviert

Start:

./scripts/start.sh staging\n# oder:\ndocker compose -f docker-compose.yml -f docker-compose.staging.yml up -d\n

"},{"location":"architecture/environments/#production-prod","title":"Production (Prod)","text":"

Zweck: Live-System f\u00fcr Endbenutzer (ab Launch)

Eigenschaft Wert Git Branch main Compose File docker-compose.yml + docker-compose.prod.yml Env File .env.prod (NICHT im Repository!) Database breakpilot_prod (separates Volume) Debug Deaktiviert Vault Pflicht (keine Env-Fallbacks)"},{"location":"architecture/environments/#datenbank-trennung","title":"Datenbank-Trennung","text":"

Jede Umgebung verwendet separate Docker Volumes f\u00fcr vollst\u00e4ndige Datenisolierung:

\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502                    PostgreSQL Volumes                        \u2502\n\u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n\u2502  breakpilot-dev_postgres_data      \u2502 Development Database   \u2502\n\u2502  breakpilot_staging_postgres       \u2502 Staging Database       \u2502\n\u2502  breakpilot_prod_postgres          \u2502 Production Database    \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n
"},{"location":"architecture/environments/#port-mapping","title":"Port-Mapping","text":"

Um mehrere Umgebungen gleichzeitig laufen zu lassen, verwenden sie unterschiedliche Ports:

Service Dev Port Staging Port Prod Port Backend 8000 8001 8000 PostgreSQL 5432 5433 - (intern) MinIO 9000/9001 9002/9003 - (intern) Qdrant 6333/6334 6335/6336 - (intern) Mailpit 8025/1025 8026/1026 - (deaktiviert)"},{"location":"architecture/environments/#git-branching-strategie","title":"Git Branching Strategie","text":"
main (Prod)     \u2190 Nur Release-Merges, gesch\u00fctzt\n    \u2502\n    \u25bc\nstaging         \u2190 Getesteter Code, Review erforderlich\n    \u2502\n    \u25bc\ndevelop (Dev)   \u2190 T\u00e4gliche Arbeit, Default-Branch\n    \u2502\n    \u25bc\nfeature/*       \u2190 Feature-Branches (optional)\n
"},{"location":"architecture/environments/#workflow","title":"Workflow","text":"
  1. Entwicklung: Arbeite auf develop
  2. Code-Review: Erstelle PR von Feature-Branch \u2192 develop
  3. Staging: Promote develop \u2192 staging mit Tests
  4. Release: Promote staging \u2192 main nach Freigabe
"},{"location":"architecture/environments/#promotion-befehle","title":"Promotion-Befehle","text":"
# develop \u2192 staging\n./scripts/promote.sh dev-to-staging\n\n# staging \u2192 main (Production)\n./scripts/promote.sh staging-to-prod\n
"},{"location":"architecture/environments/#secrets-management","title":"Secrets Management","text":""},{"location":"architecture/environments/#development","title":"Development","text":""},{"location":"architecture/environments/#staging_1","title":"Staging","text":""},{"location":"architecture/environments/#production","title":"Production","text":"

Siehe auch: Secrets Management

"},{"location":"architecture/environments/#docker-compose-architektur","title":"Docker Compose Architektur","text":"
docker-compose.yml              \u2190 Basis-Konfiguration\n        \u2502\n        \u251c\u2500\u2500 docker-compose.override.yml  \u2190 Dev (auto-geladen)\n        \u2502\n        \u251c\u2500\u2500 docker-compose.staging.yml   \u2190 Staging (explizit)\n        \u2502\n        \u2514\u2500\u2500 docker-compose.prod.yml      \u2190 Production (explizit)\n
"},{"location":"architecture/environments/#automatisches-laden","title":"Automatisches Laden","text":"

Docker Compose l\u00e4dt automatisch: 1. docker-compose.yml 2. docker-compose.override.yml (falls vorhanden)

Daher startet docker compose up automatisch die Dev-Umgebung.

"},{"location":"architecture/environments/#helper-scripts","title":"Helper Scripts","text":"Script Beschreibung scripts/env-switch.sh Wechselt zwischen Umgebungen scripts/start.sh Startet Services f\u00fcr Umgebung scripts/stop.sh Stoppt Services scripts/promote.sh Promotet Code zwischen Branches scripts/status.sh Zeigt aktuellen Status"},{"location":"architecture/environments/#verifikation","title":"Verifikation","text":"

Nach Setup pr\u00fcfen:

# Status anzeigen\n./scripts/status.sh\n\n# Branches pr\u00fcfen\ngit branch -v\n\n# Volumes pr\u00fcfen\ndocker volume ls | grep breakpilot\n
"},{"location":"architecture/environments/#verwandte-dokumentation","title":"Verwandte Dokumentation","text":""},{"location":"architecture/mail-rbac-architecture/","title":"Mail-RBAC Architektur mit Mitarbeiter-Anonymisierung","text":"

Version: 1.0.0 Status: Architekturplanung

"},{"location":"architecture/mail-rbac-architecture/#executive-summary","title":"Executive Summary","text":"

Dieses Dokument beschreibt eine neuartige Architektur, die E-Mail, Kalender und Videokonferenzen mit rollenbasierter Zugriffskontrolle (RBAC) verbindet. Das Kernkonzept erm\u00f6glicht die vollst\u00e4ndige Anonymisierung von Mitarbeiterdaten bei Verlassen des Unternehmens, w\u00e4hrend gesch\u00e4ftliche Kommunikationshistorie erhalten bleibt.

"},{"location":"architecture/mail-rbac-architecture/#1-das-problem","title":"1. Das Problem","text":""},{"location":"architecture/mail-rbac-architecture/#traditionelle-e-mail-systeme","title":"Traditionelle E-Mail-Systeme","text":"
max.mustermann@firma.de \u2192 Person gebunden\n                        \u2192 DSGVO: Daten m\u00fcssen gel\u00f6scht werden\n                        \u2192 Gesch\u00e4ftshistorie geht verloren\n
"},{"location":"architecture/mail-rbac-architecture/#breakpilot-losung-rollenbasierte-e-mail","title":"BreakPilot-L\u00f6sung: Rollenbasierte E-Mail","text":"
klassenlehrer.5a@schule.breakpilot.app \u2192 Rolle gebunden\n                                       \u2192 Person kann anonymisiert werden\n                                       \u2192 Kommunikationshistorie bleibt erhalten\n
"},{"location":"architecture/mail-rbac-architecture/#2-architektur-ubersicht","title":"2. Architektur-\u00dcbersicht","text":"
\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502                     BreakPilot Groupware                        \u2502\n\u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n\u2502                                                                 \u2502\n\u2502  \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510  \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510  \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510             \u2502\n\u2502  \u2502   Webmail   \u2502  \u2502  Kalender   \u2502  \u2502   Jitsi     \u2502             \u2502\n\u2502  \u2502   (SOGo)    \u2502  \u2502   (SOGo)    \u2502  \u2502  Meeting    \u2502             \u2502\n\u2502  \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2518  \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2518  \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2518             \u2502\n\u2502         \u2502                \u2502                \u2502                     \u2502\n\u2502         \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518                     \u2502\n\u2502                          \u2502                                      \u2502\n\u2502              \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510                         \u2502\n\u2502              \u2502   RBAC-Mail-Bridge    \u2502 \u25c4\u2500\u2500\u2500 Neue Komponente    \u2502\n\u2502              \u2502   (Python/Go)         \u2502                         \u2502\n\u2502              \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518                         \u2502\n\u2502                          \u2502                                      \u2502\n\u2502    \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510               \u2502\n\u2502    \u2502                     \u2502                     \u2502                \u2502\n\u2502    \u25bc                     \u25bc                     \u25bc                \u2502\n\u2502 \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510     \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510     \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510           \u2502\n\u2502 \u2502PostgreSQL\u2502     \u2502 Mail Server  \u2502     \u2502  MinIO     \u2502           \u2502\n\u2502 \u2502(RBAC DB) \u2502     \u2502 (Stalwart)   \u2502     \u2502 (Backups)  \u2502           \u2502\n\u2502 \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518     \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518     \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518           \u2502\n\u2502                                                                 \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n
"},{"location":"architecture/mail-rbac-architecture/#3-komponenten-auswahl","title":"3. Komponenten-Auswahl","text":""},{"location":"architecture/mail-rbac-architecture/#31-e-mail-server-stalwart-mail-server","title":"3.1 E-Mail Server: Stalwart Mail Server","text":"

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\u00fcr Administration"},{"location":"architecture/mail-rbac-architecture/#32-webmail-client-sogo-oder-roundcube","title":"3.2 Webmail-Client: SOGo oder Roundcube","text":"

Option A: SOGo (empfohlen) - Lizenz: GPL-2.0 / LGPL-2.1 - Kalender, Kontakte, Mail in einem - ActiveSync Support - Outlook-\u00e4hnliche Oberfl\u00e4che

Option B: Roundcube - Lizenz: GPL-3.0 - Nur Webmail - Ben\u00f6tigt separaten Kalender

"},{"location":"architecture/mail-rbac-architecture/#4-anonymisierungs-workflow","title":"4. Anonymisierungs-Workflow","text":"
Mitarbeiter k\u00fcndigt\n        \u2502\n        \u25bc\n\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502 1. Functional Mailboxes   \u2502\n\u2502    \u2192 Neu zuweisen oder    \u2502\n\u2502    \u2192 Deaktivieren         \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n            \u2502\n            \u25bc\n\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502 2. Personal Email Account \u2502\n\u2502    \u2192 Anonymisieren:       \u2502\n\u2502    max.mustermann@...     \u2502\n\u2502    \u2192 mitarbeiter_a7x2@... \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n            \u2502\n            \u25bc\n\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502 3. Users-Tabelle          \u2502\n\u2502    \u2192 Pseudonymisieren:    \u2502\n\u2502    name: \"Max Mustermann\" \u2502\n\u2502    \u2192 \"Ehem. Mitarbeiter\"  \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n            \u2502\n            \u25bc\n\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502 4. Mailbox Assignments    \u2502\n\u2502    \u2192 Bleiben f\u00fcr Audit    \u2502\n\u2502    \u2192 User-Referenz zeigt  \u2502\n\u2502      auf anonymisierte    \u2502\n\u2502      Daten                \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n            \u2502\n            \u25bc\n\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502 5. E-Mail-Archiv          \u2502\n\u2502    \u2192 Header anonymisieren \u2502\n\u2502    \u2192 Inhalte optional     \u2502\n\u2502      l\u00f6schen              \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n
"},{"location":"architecture/mail-rbac-architecture/#5-unified-inbox-implementation","title":"5. Unified Inbox Implementation","text":""},{"location":"architecture/mail-rbac-architecture/#implementierte-komponenten","title":"Implementierte Komponenten","text":"

Die Unified Inbox wurde als Teil des klausur-service implementiert:

Komponente Pfad Beschreibung Models klausur-service/backend/mail/models.py Pydantic Models f\u00fcr 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\u00fcr IMAP/SMTP-Passw\u00f6rter 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"},{"location":"architecture/mail-rbac-architecture/#api-endpoints-port-8086","title":"API-Endpoints (Port 8086)","text":"
# Account Management\nPOST   /api/v1/mail/accounts              - Neues Konto hinzuf\u00fcgen\nGET    /api/v1/mail/accounts              - Alle Konten auflisten\nDELETE /api/v1/mail/accounts/{id}         - Konto entfernen\nPOST   /api/v1/mail/accounts/{id}/test    - Verbindung testen\n\n# Unified Inbox\nGET    /api/v1/mail/inbox                 - Aggregierte Inbox\nGET    /api/v1/mail/inbox/{id}            - Einzelne E-Mail\nPOST   /api/v1/mail/send                  - E-Mail senden\n\n# KI-Features\nPOST   /api/v1/mail/analyze/{id}          - E-Mail analysieren\nGET    /api/v1/mail/suggestions/{id}      - Antwortvorschl\u00e4ge\n\n# Arbeitsvorrat\nGET    /api/v1/mail/tasks                 - Alle Tasks\nPOST   /api/v1/mail/tasks                 - Manuelle Task erstellen\nPATCH  /api/v1/mail/tasks/{id}            - Task aktualisieren\nGET    /api/v1/mail/tasks/dashboard       - Dashboard-Statistiken\n
"},{"location":"architecture/mail-rbac-architecture/#niedersachsen-spezifische-absendererkennung","title":"Niedersachsen-spezifische Absendererkennung","text":"
KNOWN_AUTHORITIES_NI = {\n    \"@mk.niedersachsen.de\": \"Kultusministerium Niedersachsen\",\n    \"@rlsb.de\": \"Regionales Landesamt f\u00fcr Schule und Bildung\",\n    \"@landesschulbehoerde-nds.de\": \"Landesschulbeh\u00f6rde\",\n    \"@nibis.de\": \"NiBiS\",\n}\n
"},{"location":"architecture/mail-rbac-architecture/#6-lizenz-ubersicht","title":"6. Lizenz-\u00dcbersicht","text":"Komponente Lizenz Kommerzielle Nutzung Ver\u00f6ffentlichungspflicht Stalwart Mail AGPL-3.0 Ja Nur bei Code-\u00c4nderungen SOGo GPL-2.0/LGPL Ja Nur bei Code-\u00c4nderungen Roundcube GPL-3.0 Ja Nur bei Code-\u00c4nderungen RBAC-Mail-Bridge Eigene N/A Kann propriet\u00e4r bleiben BreakPilot Backend Eigene N/A Propriet\u00e4r"},{"location":"architecture/mail-rbac-architecture/#7-referenzen","title":"7. Referenzen","text":""},{"location":"architecture/multi-agent/","title":"Multi-Agent Architektur - Entwicklerdokumentation","text":"

Status: Implementiert Modul: /agent-core/

"},{"location":"architecture/multi-agent/#1-ubersicht","title":"1. \u00dcbersicht","text":"

Die Multi-Agent-Architektur erweitert Breakpilot um ein verteiltes Agent-System basierend auf Mission Control Konzepten.

"},{"location":"architecture/multi-agent/#kernkomponenten","title":"Kernkomponenten","text":"Komponente Pfad Beschreibung Session Management /agent-core/sessions/ Lifecycle & Recovery Shared Brain /agent-core/brain/ Langzeit-Ged\u00e4chtnis Orchestrator /agent-core/orchestrator/ Koordination SOUL Files /agent-core/soul/ Agent-Pers\u00f6nlichkeiten"},{"location":"architecture/multi-agent/#2-agent-typen","title":"2. Agent-Typen","text":"Agent Aufgabe SOUL-Datei TutorAgent Lernbegleitung, Fragen beantworten tutor-agent.soul.md GraderAgent Klausur-Korrektur, Bewertung grader-agent.soul.md QualityJudge BQAS Qualit\u00e4tspr\u00fcfung quality-judge.soul.md AlertAgent Monitoring, Benachrichtigungen alert-agent.soul.md Orchestrator Task-Koordination orchestrator.soul.md"},{"location":"architecture/multi-agent/#3-wichtige-dateien","title":"3. Wichtige Dateien","text":""},{"location":"architecture/multi-agent/#session-management","title":"Session Management","text":"
agent-core/sessions/\n\u251c\u2500\u2500 session_manager.py   # AgentSession, SessionManager, SessionState\n\u251c\u2500\u2500 heartbeat.py         # HeartbeatMonitor, HeartbeatClient\n\u2514\u2500\u2500 checkpoint.py        # CheckpointManager\n
"},{"location":"architecture/multi-agent/#shared-brain","title":"Shared Brain","text":"
agent-core/brain/\n\u251c\u2500\u2500 memory_store.py      # MemoryStore, Memory (mit TTL)\n\u251c\u2500\u2500 context_manager.py   # ConversationContext, ContextManager\n\u2514\u2500\u2500 knowledge_graph.py   # KnowledgeGraph, Entity, Relationship\n
"},{"location":"architecture/multi-agent/#orchestrator","title":"Orchestrator","text":"
agent-core/orchestrator/\n\u251c\u2500\u2500 message_bus.py       # MessageBus, AgentMessage, MessagePriority\n\u251c\u2500\u2500 supervisor.py        # AgentSupervisor, AgentInfo, AgentStatus\n\u2514\u2500\u2500 task_router.py       # TaskRouter, RoutingRule, RoutingResult\n
"},{"location":"architecture/multi-agent/#4-datenbank-schema","title":"4. Datenbank-Schema","text":"

Die Migration befindet sich in: /backend/migrations/add_agent_core_tables.sql

"},{"location":"architecture/multi-agent/#tabellen","title":"Tabellen","text":"
  1. agent_sessions - Session-Daten mit Checkpoints
  2. agent_memory - Langzeit-Ged\u00e4chtnis mit TTL
  3. agent_messages - Audit-Trail f\u00fcr Inter-Agent Kommunikation
"},{"location":"architecture/multi-agent/#helper-funktionen","title":"Helper-Funktionen","text":"
-- Abgelaufene Memories bereinigen\nSELECT cleanup_expired_agent_memory();\n\n-- Inaktive Sessions bereinigen\nSELECT cleanup_stale_agent_sessions(48); -- 48 Stunden\n
"},{"location":"architecture/multi-agent/#5-integration-voice-service","title":"5. Integration Voice-Service","text":"

Der EnhancedTaskOrchestrator erweitert den bestehenden TaskOrchestrator:

# voice-service/services/enhanced_task_orchestrator.py\n\nfrom agent_core.sessions import SessionManager\nfrom agent_core.orchestrator import MessageBus\n\nclass EnhancedTaskOrchestrator(TaskOrchestrator):\n    # Nutzt Session-Checkpoints f\u00fcr Recovery\n    # Routet komplexe Tasks an spezialisierte Agents\n    # F\u00fchrt Quality-Checks via BQAS durch\n

Wichtig: Der Enhanced Orchestrator ist abw\u00e4rtskompatibel und kann parallel zum Original verwendet werden.

"},{"location":"architecture/multi-agent/#6-integration-bqas","title":"6. Integration BQAS","text":"

Der QualityJudgeAgent integriert BQAS mit dem Multi-Agent-System:

# voice-service/bqas/quality_judge_agent.py\n\nfrom bqas.judge import LLMJudge\nfrom agent_core.orchestrator import MessageBus\n\nclass QualityJudgeAgent:\n    # Wertet Responses in Echtzeit aus\n    # Nutzt Memory f\u00fcr konsistente Bewertungen\n    # Empf\u00e4ngt Evaluierungs-Requests via Message Bus\n
"},{"location":"architecture/multi-agent/#7-code-beispiele","title":"7. Code-Beispiele","text":""},{"location":"architecture/multi-agent/#session-erstellen","title":"Session erstellen","text":"
from agent_core.sessions import SessionManager\n\nmanager = SessionManager(redis_client=redis, db_pool=pool)\nsession = await manager.create_session(\n    agent_type=\"tutor-agent\",\n    user_id=\"user-123\"\n)\n
"},{"location":"architecture/multi-agent/#memory-speichern","title":"Memory speichern","text":"
from agent_core.brain import MemoryStore\n\nstore = MemoryStore(redis_client=redis, db_pool=pool)\nawait store.remember(\n    key=\"student:123:progress\",\n    value={\"level\": 5, \"score\": 85},\n    agent_id=\"tutor-agent\",\n    ttl_days=30\n)\n
"},{"location":"architecture/multi-agent/#nachricht-senden","title":"Nachricht senden","text":"
from agent_core.orchestrator import MessageBus, AgentMessage\n\nbus = MessageBus(redis_client=redis)\nawait bus.publish(AgentMessage(\n    sender=\"orchestrator\",\n    receiver=\"grader-agent\",\n    message_type=\"grade_request\",\n    payload={\"exam_id\": \"exam-1\"}\n))\n
"},{"location":"architecture/multi-agent/#8-tests-ausfuhren","title":"8. Tests ausf\u00fchren","text":"
# Alle Agent-Core Tests\ncd agent-core && pytest -v\n\n# Mit Coverage-Report\npytest --cov=. --cov-report=html\n\n# Einzelne Module\npytest tests/test_session_manager.py -v\npytest tests/test_message_bus.py -v\n
"},{"location":"architecture/multi-agent/#9-deployment-schritte","title":"9. Deployment-Schritte","text":""},{"location":"architecture/multi-agent/#1-migration-ausfuhren","title":"1. Migration ausf\u00fchren","text":"
psql -h localhost -U breakpilot -d breakpilot \\\n  -f backend/migrations/add_agent_core_tables.sql\n
"},{"location":"architecture/multi-agent/#2-voice-service-aktualisieren","title":"2. Voice-Service aktualisieren","text":"
# Sync zu Server\nrsync -avz --exclude 'node_modules' --exclude '.git' \\\n  /path/to/breakpilot-pwa/ server:/path/to/breakpilot-pwa/\n\n# Container neu bauen\ndocker compose build --no-cache voice-service\n\n# Starten\ndocker compose up -d voice-service\n
"},{"location":"architecture/multi-agent/#3-verifizieren","title":"3. Verifizieren","text":"
# Session-Tabelle pr\u00fcfen\npsql -c \"SELECT COUNT(*) FROM agent_sessions;\"\n\n# Memory-Tabelle pr\u00fcfen\npsql -c \"SELECT COUNT(*) FROM agent_memory;\"\n
"},{"location":"architecture/multi-agent/#10-monitoring","title":"10. Monitoring","text":""},{"location":"architecture/multi-agent/#metriken","title":"Metriken","text":"Metrik Beschreibung agent_session_count Anzahl aktiver Sessions agent_heartbeat_delay_ms Zeit seit letztem Heartbeat agent_message_latency_ms Nachrichtenlatenz agent_memory_count Gespeicherte Memories agent_routing_success_rate Erfolgreiche Routings"},{"location":"architecture/multi-agent/#health-check-endpunkte","title":"Health-Check-Endpunkte","text":"
GET /api/v1/agents/health       # Supervisor Status\nGET /api/v1/agents/sessions     # Aktive Sessions\nGET /api/v1/agents/memory/stats # Memory-Statistiken\n
"},{"location":"architecture/multi-agent/#11-troubleshooting","title":"11. Troubleshooting","text":""},{"location":"architecture/multi-agent/#problem-session-nicht-gefunden","title":"Problem: Session nicht gefunden","text":"
  1. Pr\u00fcfen ob Valkey l\u00e4uft: redis-cli ping
  2. Session-Timeout pr\u00fcfen (default 24h)
  3. Heartbeat-Status checken
"},{"location":"architecture/multi-agent/#problem-message-bus-timeout","title":"Problem: Message Bus Timeout","text":"
  1. Redis Pub/Sub Status pr\u00fcfen
  2. Ziel-Agent registriert?
  3. Timeout erh\u00f6hen (default 30s)
"},{"location":"architecture/multi-agent/#problem-memory-nicht-gefunden","title":"Problem: Memory nicht gefunden","text":"
  1. Namespace korrekt?
  2. TTL abgelaufen?
  3. Cleanup-Job gelaufen?
"},{"location":"architecture/multi-agent/#12-erweiterungen","title":"12. Erweiterungen","text":""},{"location":"architecture/multi-agent/#neuen-agent-hinzufugen","title":"Neuen Agent hinzuf\u00fcgen","text":"
  1. SOUL-Datei erstellen in /agent-core/soul/
  2. Routing-Regel in task_router.py hinzuf\u00fcgen
  3. Handler beim Supervisor registrieren
  4. Tests schreiben
"},{"location":"architecture/multi-agent/#neuen-memory-typ-hinzufugen","title":"Neuen Memory-Typ hinzuf\u00fcgen","text":"
  1. Key-Schema definieren (z.B. student:*:progress)
  2. TTL festlegen
  3. Access-Pattern dokumentieren
"},{"location":"architecture/multi-agent/#13-referenzen","title":"13. Referenzen","text":""},{"location":"architecture/sdk-protection/","title":"SDK Protection Middleware","text":""},{"location":"architecture/sdk-protection/#1-worum-geht-es","title":"1. Worum geht es?","text":"

Die SDK Protection Middleware schuetzt die Compliance-SDK-Endpunkte vor einer bestimmten Art von Angriff: der systematischen Enumeration. Was bedeutet das?

Ein Wettbewerber registriert sich als zahlender Kunde und laesst ein Skript langsam und verteilt alle TOM-Controls, alle Pruefaspekte und alle Assessment-Kriterien abfragen. Aus den Ergebnissen rekonstruiert er die gesamte Compliance-Framework-Logik.

Der klassische Rate Limiter (100 Requests/Minute) hilft hier nicht, weil ein cleverer Angreifer langsam vorgeht -- vielleicht nur 20 Anfragen pro Minute, dafuer systematisch und ueber Stunden. Die SDK Protection erkennt solche Muster und reagiert darauf.

Kern-Designprinzip

Normale Nutzer merken nichts. Ein Lehrer, der im TOM-Modul arbeitet, greift typischerweise auf 3-5 Kategorien zu und wiederholt Anfragen an gleiche Endpunkte. Ein Angreifer durchlaeuft dagegen 40+ Kategorien in alphabetischer Reihenfolge. Genau diesen Unterschied erkennt die Middleware.

"},{"location":"architecture/sdk-protection/#2-wie-funktioniert-der-schutz","title":"2. Wie funktioniert der Schutz?","text":"

Die Middleware nutzt ein Anomaly-Score-System. Jeder Benutzer hat einen Score, der bei 0 beginnt. Verschiedene verdaechtige Verhaltensweisen erhoehen den Score. Ueber die Zeit sinkt er wieder ab. Je hoeher der Score, desto staerker wird der Benutzer gebremst.

Man kann es sich wie eine Ampel vorstellen:

Score Ampel Wirkung Beispiel 0-29 Gruen Keine Einschraenkung Normaler Nutzer 30-59 Gelb 1-3 Sekunden Verzoegerung Leicht auffaelliges Muster 60-84 Orange 5-10 Sekunden Verzoegerung, reduzierte Details Deutlich verdaechtiges Verhalten 85+ Rot Zugriff blockiert (HTTP 429) Sehr wahrscheinlich automatisierter Angriff"},{"location":"architecture/sdk-protection/#score-zerfall","title":"Score-Zerfall","text":"

Der Score sinkt automatisch: Alle 5 Minuten wird er mit dem Faktor 0,95 multipliziert. Ein Score von 60 faellt also innerhalb einer Stunde auf etwa 30 -- wenn kein neues verdaechtiges Verhalten hinzukommt.

"},{"location":"architecture/sdk-protection/#3-was-wird-erkannt","title":"3. Was wird erkannt?","text":"

Die Middleware erkennt fuenf verschiedene Anomalie-Muster:

"},{"location":"architecture/sdk-protection/#31-hohe-kategorie-diversitaet","title":"3.1 Hohe Kategorie-Diversitaet","text":"

Was: Ein Benutzer greift innerhalb einer Stunde auf mehr als 40 verschiedene SDK-Kategorien zu.

Warum verdaechtig: Ein normaler Nutzer arbeitet in der Regel mit 3-10 Kategorien. Wer systematisch alle durchlaeuft, sammelt vermutlich Daten.

Score-Erhoehung: +15

Normal:   tom/access-control \u2192 tom/access-control \u2192 tom/encryption \u2192 tom/encryption\n                               (3 verschiedene Kategorien in einer Stunde)\n\nVerdaechtig: tom/access-control \u2192 tom/encryption \u2192 tom/pseudonymization \u2192 tom/integrity\n             \u2192 tom/availability \u2192 tom/resilience \u2192 dsfa/threshold \u2192 dsfa/necessity \u2192 ...\n                               (40+ verschiedene Kategorien in einer Stunde)\n
"},{"location":"architecture/sdk-protection/#32-burst-erkennung","title":"3.2 Burst-Erkennung","text":"

Was: Ein Benutzer sendet mehr als 15 Anfragen an die gleiche Kategorie innerhalb von 2 Minuten.

Warum verdaechtig: Selbst ein eifriger Nutzer klickt nicht 15-mal pro Minute auf denselben Endpunkt. Das deutet auf automatisiertes Scraping hin.

Score-Erhoehung: +20

"},{"location":"architecture/sdk-protection/#33-sequentielle-enumeration","title":"3.3 Sequentielle Enumeration","text":"

Was: Die letzten 10 aufgerufenen Kategorien sind zu mindestens 70% in alphabetischer oder numerischer Reihenfolge.

Warum verdaechtig: Menschen springen zwischen Kategorien -- sie arbeiten thematisch, nicht alphabetisch. Ein Skript dagegen iteriert oft ueber eine sortierte Liste.

Score-Erhoehung: +25

Verdaechtig: assessment_general \u2192 compliance_general \u2192 controls_general\n             \u2192 dsfa_measures \u2192 dsfa_necessity \u2192 dsfa_residual \u2192 dsfa_risks\n             \u2192 dsfa_threshold \u2192 eh_general \u2192 namespace_general\n             (alphabetisch sortiert = Skript-Verhalten)\n
"},{"location":"architecture/sdk-protection/#34-ungewoehnliche-uhrzeiten","title":"3.4 Ungewoehnliche Uhrzeiten","text":"

Was: Anfragen zwischen 0:00 und 5:00 Uhr UTC.

Warum verdaechtig: Lehrer arbeiten tags\u00fcber. Wer um 3 Uhr morgens SDK-Endpunkte abfragt, ist wahrscheinlich ein automatisierter Prozess.

Score-Erhoehung: +10

"},{"location":"architecture/sdk-protection/#35-multi-tenant-zugriff","title":"3.5 Multi-Tenant-Zugriff","text":"

Was: Ein Benutzer greift innerhalb einer Stunde auf mehr als 3 verschiedene Mandanten (Tenants) zu.

Warum verdaechtig: Ein normaler Nutzer gehoert zu einem Mandanten. Wer mehrere durchprobiert, koennte versuchen, mandantenuebergreifend Daten zu sammeln.

Score-Erhoehung: +15

"},{"location":"architecture/sdk-protection/#4-quota-system-mengenbegrenzung","title":"4. Quota-System (Mengenbegrenzung)","text":"

Zusaetzlich zum Anomaly-Score gibt es klassische Mengenbegrenzungen in vier Zeitfenstern:

Tier pro Minute pro Stunde pro Tag pro Monat Free 30 500 3.000 50.000 Standard 60 1.500 10.000 200.000 Enterprise 120 5.000 50.000 1.000.000

Wenn ein Limit in irgendeinem Zeitfenster ueberschritten wird, erhaelt der Nutzer sofort HTTP 429 -- unabhaengig vom Anomaly-Score.

"},{"location":"architecture/sdk-protection/#5-architektur","title":"5. Architektur","text":""},{"location":"architecture/sdk-protection/#datenfluss-eines-sdk-requests","title":"Datenfluss eines SDK-Requests","text":"
Request kommt an\n     \u2502\n     \u25bc\n\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502  Ist der Pfad geschuetzt?                                    \u2502\n\u2502  (/api/sdk/*, /api/v1/tom/*, /api/v1/dsfa/*, ...)           \u2502\n\u2502  Nein \u2192 direkt weiterleiten                                  \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n               \u2502 Ja\n               \u25bc\n\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502  User + Tier + Kategorie extrahieren                         \u2502\n\u2502  (aus Session, API-Key oder X-SDK-Tier Header)               \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n               \u2502\n               \u25bc\n\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502  Multi-Window Quota pruefen                                  \u2502\n\u2502  (Minute / Stunde / Tag / Monat)                             \u2502\n\u2502  Ueberschritten \u2192 HTTP 429 zurueck                          \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n               \u2502 OK\n               \u25bc\n\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502  Anomaly-Score laden (aus Valkey)                            \u2502\n\u2502  Zeitbasierten Zerfall anwenden (\u00d70,95 alle 5 min)           \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n               \u2502\n               \u25bc\n\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502  Anomalie-Detektoren ausfuehren:                             \u2502\n\u2502  \u251c\u2500\u2500 Diversity-Tracking     (+15 wenn >40 Kategorien/h)      \u2502\n\u2502  \u251c\u2500\u2500 Burst-Detection        (+20 wenn >15 gleiche/2min)      \u2502\n\u2502  \u251c\u2500\u2500 Sequential-Enumeration (+25 wenn sortiert)              \u2502\n\u2502  \u251c\u2500\u2500 Unusual-Hours          (+10 wenn 0-5 Uhr UTC)           \u2502\n\u2502  \u2514\u2500\u2500 Multi-Tenant           (+15 wenn >3 Tenants/h)          \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n               \u2502\n               \u25bc\n\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502  Throttle-Level bestimmen                                    \u2502\n\u2502  Level 3 (Score \u226585) \u2192 HTTP 429                              \u2502\n\u2502  Level 2 (Score \u226560) \u2192 5-10s Delay + reduzierte Details      \u2502\n\u2502  Level 1 (Score \u226530) \u2192 1-3s Delay                            \u2502\n\u2502  Level 0             \u2192 keine Einschraenkung                  \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n               \u2502\n               \u25bc\n\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502  Request weiterleiten                                        \u2502\n\u2502  Response-Headers setzen:                                    \u2502\n\u2502  \u251c\u2500\u2500 X-SDK-Quota-Remaining-Minute/Hour                       \u2502\n\u2502  \u251c\u2500\u2500 X-SDK-Throttle-Level                                    \u2502\n\u2502  \u251c\u2500\u2500 X-SDK-Detail-Reduced (bei Level \u22652)                     \u2502\n\u2502  \u2514\u2500\u2500 X-BP-Trace (HMAC-Watermark)                             \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n
"},{"location":"architecture/sdk-protection/#valkey-datenstrukturen","title":"Valkey-Datenstrukturen","text":"

Die Middleware speichert alle Tracking-Daten in Valkey (Redis-Fork). Wenn Valkey nicht erreichbar ist, wird automatisch auf eine In-Memory-Implementierung zurueckgefallen.

Zweck Valkey-Typ Key-Muster TTL Quota pro Zeitfenster Sorted Set sdk_protect:quota:{user}:{window} Fenster + 10s Kategorie-Diversitaet Set sdk_protect:diversity:{user}:{stunde} 3660s Burst-Tracking Sorted Set sdk_protect:burst:{user}:{kategorie} 130s Sequenz-Tracking List sdk_protect:seq:{user} 310s Anomaly-Score Hash sdk_protect:score:{user} 86400s Tenant-Tracking Set sdk_protect:tenants:{user}:{stunde} 3660s"},{"location":"architecture/sdk-protection/#watermarking","title":"Watermarking","text":"

Jede Antwort enthaelt einen X-BP-Trace Header mit einem HMAC-basierten Fingerabdruck. Damit kann nachtraeglich nachgewiesen werden, welcher Benutzer wann welche Daten abgerufen hat -- ohne dass der Benutzer den Trace veraendern kann.

"},{"location":"architecture/sdk-protection/#6-geschuetzte-endpunkte","title":"6. Geschuetzte Endpunkte","text":"

Die Middleware schuetzt alle Pfade, die SDK- und Compliance-relevante Daten liefern:

Pfad-Prefix Bereich /api/sdk/* SDK-Hauptendpunkte /api/compliance/* Compliance-Bewertungen /api/v1/tom/* Technisch-organisatorische Massnahmen /api/v1/dsfa/* Datenschutz-Folgenabschaetzung /api/v1/vvt/* Verarbeitungsverzeichnis /api/v1/controls/* Controls und Massnahmen /api/v1/assessment/* Assessment-Bewertungen /api/v1/eh/* Erwartungshorizonte /api/v1/namespace/* Namespace-Verwaltung

Nicht geschuetzt sind /health, /metrics und /api/health.

"},{"location":"architecture/sdk-protection/#7-admin-verwaltung","title":"7. Admin-Verwaltung","text":"

Ueber das Admin-Dashboard koennen Anomaly-Scores eingesehen und verwaltet werden:

Endpoint Methode Beschreibung /api/admin/middleware/sdk-protection/scores GET Aktuelle Anomaly-Scores aller Benutzer /api/admin/middleware/sdk-protection/stats GET Statistik: Benutzer pro Throttle-Level /api/admin/middleware/sdk-protection/reset-score/{user_id} POST Score eines Benutzers zuruecksetzen /api/admin/middleware/sdk-protection/tiers GET Tier-Konfigurationen anzeigen /api/admin/middleware/sdk-protection/tiers/{name} PUT Tier-Limits aendern"},{"location":"architecture/sdk-protection/#8-dateien-und-quellcode","title":"8. Dateien und Quellcode","text":"Datei Beschreibung backend/middleware/sdk_protection.py Kern-Middleware (~460 Zeilen) backend/middleware/__init__.py Export der Middleware-Klassen backend/main.py Registrierung im FastAPI-Stack backend/middleware_admin_api.py Admin-API-Endpoints backend/migrations/add_sdk_protection_tables.sql Datenbank-Migration backend/tests/test_middleware.py 14 Tests fuer alle Erkennungsmechanismen"},{"location":"architecture/sdk-protection/#9-datenbank-tabellen","title":"9. Datenbank-Tabellen","text":""},{"location":"architecture/sdk-protection/#sdk_anomaly_scores","title":"sdk_anomaly_scores","text":"

Speichert Snapshots der Anomaly-Scores fuer Audit und Analyse.

Spalte Typ Beschreibung id UUID Primaerschluessel user_id VARCHAR(255) Benutzer-Identifikation score DECIMAL(5,2) Aktueller Anomaly-Score throttle_level SMALLINT Aktueller Throttle-Level (0-3) triggered_rules JSONB Welche Regeln ausgeloest wurden endpoint_diversity_count INT Anzahl verschiedener Kategorien request_count_1h INT Anfragen in der letzten Stunde snapshot_at TIMESTAMPTZ Zeitpunkt des Snapshots"},{"location":"architecture/sdk-protection/#sdk_protection_tiers","title":"sdk_protection_tiers","text":"

Konfigurierbare Quota-Tiers, editierbar ueber die Admin-API.

Spalte Typ Beschreibung tier_name VARCHAR(50) Name des Tiers (free, standard, enterprise) quota_per_minute INT Maximale Anfragen pro Minute quota_per_hour INT Maximale Anfragen pro Stunde quota_per_day INT Maximale Anfragen pro Tag quota_per_month INT Maximale Anfragen pro Monat diversity_threshold INT Max verschiedene Kategorien pro Stunde burst_threshold INT Max gleiche Kategorie in 2 Minuten"},{"location":"architecture/sdk-protection/#10-konfiguration","title":"10. Konfiguration","text":"

Die Middleware wird in main.py registriert:

from middleware import SDKProtectionMiddleware\n\napp.add_middleware(SDKProtectionMiddleware)\n

Alle Parameter koennen ueber die SDKProtectionConfig Dataclass angepasst werden. Die wichtigsten Umgebungsvariablen:

Variable Default Beschreibung VALKEY_URL redis://localhost:6379 Verbindung zur Valkey-Instanz SDK_WATERMARK_SECRET (generiert) HMAC-Secret fuer Watermarks"},{"location":"architecture/sdk-protection/#11-tests","title":"11. Tests","text":"

Die Middleware wird durch 14 automatisierte Tests abgedeckt:

# Alle SDK Protection Tests ausfuehren\ndocker compose run --rm --no-deps backend \\\n  python -m pytest tests/test_middleware.py -v -k sdk\n
Test Prueft test_allows_normal_request Normaler Request wird durchgelassen test_blocks_after_quota_exceeded 429 bei Quota-Ueberschreitung test_diversity_tracking_increments_score Viele Kategorien erhoehen den Score test_burst_detection Schnelle gleiche Anfragen erhoehen den Score test_sequential_enumeration_detection Alphabetische Muster werden erkannt test_progressive_throttling_level_1 Delay bei Score >= 30 test_progressive_throttling_level_3_blocks Block bei Score >= 85 test_score_decay_over_time Score sinkt ueber die Zeit test_skips_non_protected_paths Nicht-SDK-Pfade bleiben frei test_watermark_header_present X-BP-Trace Header vorhanden test_fallback_to_inmemory Funktioniert ohne Valkey test_no_user_passes_through Anonyme Requests passieren test_category_extraction Korrekte Kategorie-Zuordnung test_quota_headers_present Response-Headers vorhanden"},{"location":"architecture/secrets-management/","title":"BreakPilot Secrets Management","text":""},{"location":"architecture/secrets-management/#uebersicht","title":"Uebersicht","text":"

BreakPilot verwendet HashiCorp Vault als zentrales Secrets-Management-System.

\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502                        SECRETS MANAGEMENT                                \u2502\n\u2502                                                                          \u2502\n\u2502  \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510 \u2502\n\u2502  \u2502                    HashiCorp Vault                                  \u2502 \u2502\n\u2502  \u2502                       Port 8200                                     \u2502 \u2502\n\u2502  \u2502  \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510  \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510  \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510  \u2502 \u2502\n\u2502  \u2502  \u2502 KV v2 Engine \u2502  \u2502 AppRole Auth \u2502  \u2502 Audit Logging            \u2502  \u2502 \u2502\n\u2502  \u2502  \u2502 secret/      \u2502  \u2502 Token Auth   \u2502  \u2502 Verschluesselung         \u2502  \u2502 \u2502\n\u2502  \u2502  \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518  \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518  \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518  \u2502 \u2502\n\u2502  \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518 \u2502\n\u2502                                    \u2502                                     \u2502\n\u2502              \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510              \u2502\n\u2502              \u25bc                     \u25bc                     \u25bc              \u2502\n\u2502  \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510    \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510    \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510     \u2502\n\u2502  \u2502  Python Backend \u2502    \u2502  Go Services    \u2502    \u2502  Frontend       \u2502     \u2502\n\u2502  \u2502  (hvac client)  \u2502    \u2502  (vault-client) \u2502    \u2502  (via Backend)  \u2502     \u2502\n\u2502  \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518    \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518    \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518     \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n
"},{"location":"architecture/secrets-management/#warum-vault","title":"Warum Vault?","text":"Alternative Nachteil Environment Variables Keine Audit-Logs, keine Verschluesselung, keine Rotation Docker Secrets Nur fuer Docker Swarm, keine zentrale Verwaltung AWS Secrets Manager Cloud Lock-in, Kosten Kubernetes Secrets Keine Verschluesselung by default, nur K8s HashiCorp Vault Open Source (BSL 1.1), Self-Hosted, Enterprise Features"},{"location":"architecture/secrets-management/#architektur","title":"Architektur","text":""},{"location":"architecture/secrets-management/#secret-hierarchie","title":"Secret-Hierarchie","text":"
secret/breakpilot/\n\u251c\u2500\u2500 api_keys/\n\u2502   \u251c\u2500\u2500 anthropic     # Anthropic Claude API Key\n\u2502   \u251c\u2500\u2500 vast          # vast.ai GPU API Key\n\u2502   \u251c\u2500\u2500 stripe        # Stripe Payment Key\n\u2502   \u251c\u2500\u2500 stripe_webhook\n\u2502   \u2514\u2500\u2500 tavily        # Tavily Search API Key\n\u251c\u2500\u2500 database/\n\u2502   \u251c\u2500\u2500 postgres      # username, password, url\n\u2502   \u2514\u2500\u2500 synapse       # Matrix Synapse DB\n\u251c\u2500\u2500 auth/\n\u2502   \u251c\u2500\u2500 jwt           # secret, refresh_secret\n\u2502   \u2514\u2500\u2500 keycloak      # client_secret\n\u251c\u2500\u2500 communication/\n\u2502   \u251c\u2500\u2500 matrix        # access_token, db_password\n\u2502   \u2514\u2500\u2500 jitsi         # app_secret, jicofo, jvb passwords\n\u251c\u2500\u2500 storage/\n\u2502   \u2514\u2500\u2500 minio         # access_key, secret_key\n\u2514\u2500\u2500 infra/\n    \u2514\u2500\u2500 vast          # api_key, instance_id, control_key\n
"},{"location":"architecture/secrets-management/#python-integration","title":"Python Integration","text":"
from secrets import get_secret\n\n# Einzelnes Secret abrufen\napi_key = get_secret(\"ANTHROPIC_API_KEY\")\n\n# Mit Default-Wert\ndebug = get_secret(\"DEBUG\", default=\"false\")\n\n# Als Pflicht-Secret\ndb_url = get_secret(\"DATABASE_URL\", required=True)\n
"},{"location":"architecture/secrets-management/#fallback-reihenfolge","title":"Fallback-Reihenfolge","text":"
1. HashiCorp Vault (wenn VAULT_ADDR gesetzt)\n   \u2193 falls nicht verfuegbar\n2. Environment Variables\n   \u2193 falls nicht gesetzt\n3. Docker Secrets (/run/secrets/)\n   \u2193 falls nicht vorhanden\n4. Default-Wert (wenn angegeben)\n   \u2193 sonst\n5. SecretNotFoundError (wenn required=True)\n
"},{"location":"architecture/secrets-management/#setup","title":"Setup","text":""},{"location":"architecture/secrets-management/#entwicklung-dev-mode","title":"Entwicklung (Dev Mode)","text":"
# Vault starten (Dev Mode - NICHT fuer Produktion!)\ndocker-compose -f docker-compose.vault.yml up -d vault\n\n# Warten bis healthy\ndocker-compose -f docker-compose.vault.yml up vault-init\n\n# Environment setzen\nexport VAULT_ADDR=http://localhost:8200\nexport VAULT_TOKEN=breakpilot-dev-token\n
"},{"location":"architecture/secrets-management/#secrets-setzen","title":"Secrets setzen","text":"
# Anthropic API Key\nvault kv put secret/breakpilot/api_keys/anthropic value='sk-ant-api03-...'\n\n# vast.ai Credentials\nvault kv put secret/breakpilot/infra/vast \\\n    api_key='xxx' \\\n    instance_id='123' \\\n    control_key='yyy'\n\n# Database\nvault kv put secret/breakpilot/database/postgres \\\n    username='breakpilot' \\\n    password='supersecret' \\\n    url='postgres://breakpilot:supersecret@localhost:5432/breakpilot_db'\n
"},{"location":"architecture/secrets-management/#secrets-lesen","title":"Secrets lesen","text":"
# Liste aller Secrets\nvault kv list secret/breakpilot/\n\n# Secret anzeigen\nvault kv get secret/breakpilot/api_keys/anthropic\n\n# Nur den Wert\nvault kv get -field=value secret/breakpilot/api_keys/anthropic\n
"},{"location":"architecture/secrets-management/#produktion","title":"Produktion","text":""},{"location":"architecture/secrets-management/#approle-authentication","title":"AppRole Authentication","text":"

In Produktion verwenden Services AppRole statt Token-Auth:

# 1. AppRole aktivieren (einmalig)\nvault auth enable approle\n\n# 2. Policy erstellen\nvault policy write breakpilot-backend - <<EOF\npath \"secret/data/breakpilot/*\" {\n  capabilities = [\"read\", \"list\"]\n}\nEOF\n\n# 3. Role erstellen\nvault write auth/approle/role/breakpilot-backend \\\n    token_policies=\"breakpilot-backend\" \\\n    token_ttl=1h \\\n    token_max_ttl=4h\n\n# 4. Role-ID holen (fix)\nvault read -field=role_id auth/approle/role/breakpilot-backend/role-id\n\n# 5. Secret-ID generieren (bei jedem Deploy neu)\nvault write -f auth/approle/role/breakpilot-backend/secret-id\n
"},{"location":"architecture/secrets-management/#environment-fuer-services","title":"Environment fuer Services","text":"
# Docker-Compose / Kubernetes\nVAULT_ADDR=https://vault.breakpilot.app:8200\nVAULT_AUTH_METHOD=approle\nVAULT_ROLE_ID=<role-id>\nVAULT_SECRET_ID=<secret-id>\nVAULT_SECRETS_PATH=breakpilot\n
"},{"location":"architecture/secrets-management/#sicherheits-checkliste","title":"Sicherheits-Checkliste","text":""},{"location":"architecture/secrets-management/#muss-erfuellt-sein","title":"Muss erfuellt sein","text":""},{"location":"architecture/secrets-management/#sollte-erfuellt-sein","title":"Sollte erfuellt sein","text":""},{"location":"architecture/secrets-management/#dateien","title":"Dateien","text":"Datei Beschreibung backend/secrets/__init__.py Secrets-Modul Exports backend/secrets/vault_client.py Vault Client Implementation docker-compose.vault.yml Vault Docker Configuration vault/init-secrets.sh Entwicklungs-Secrets Initialisierung vault/policies/ Vault Policy Files"},{"location":"architecture/secrets-management/#fehlerbehebung","title":"Fehlerbehebung","text":""},{"location":"architecture/secrets-management/#vault-nicht-erreichbar","title":"Vault nicht erreichbar","text":"
# Status pruefen\nvault status\n\n# Falls sealed\nvault operator unseal <unseal-key>\n
"},{"location":"architecture/secrets-management/#secret-nicht-gefunden","title":"Secret nicht gefunden","text":"
# Pfad pruefen\nvault kv list secret/breakpilot/\n\n# Cache leeren (Python)\nfrom secrets import get_secrets_manager\nget_secrets_manager().clear_cache()\n
"},{"location":"architecture/secrets-management/#token-abgelaufen","title":"Token abgelaufen","text":"
# Neuen Token holen (AppRole)\nvault write auth/approle/login \\\n    role_id=$VAULT_ROLE_ID \\\n    secret_id=$VAULT_SECRET_ID\n
"},{"location":"architecture/secrets-management/#referenzen","title":"Referenzen","text":""},{"location":"architecture/system-architecture/","title":"BreakPilot PWA - System-Architektur","text":""},{"location":"architecture/system-architecture/#ubersicht","title":"\u00dcbersicht","text":"

BreakPilot ist eine modulare Bildungsplattform f\u00fcr Lehrkr\u00e4fte mit folgenden Hauptkomponenten:

\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502                           Browser                                    \u2502\n\u2502  \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510  \u2502\n\u2502  \u2502                  Frontend (Studio UI)                          \u2502  \u2502\n\u2502  \u2502  \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510 \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510 \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510 \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510  \u2502  \u2502\n\u2502  \u2502  \u2502Dashboard \u2502 \u2502Worksheets\u2502 \u2502Correction\u2502 \u2502Letters/Companion \u2502  \u2502  \u2502\n\u2502  \u2502  \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518 \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518 \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518 \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518  \u2502  \u2502\n\u2502  \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518  \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n                            \u2502 HTTP/REST\n                            \u25bc\n\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502                    Python Backend (FastAPI)                          \u2502\n\u2502                         Port 8000                                    \u2502\n\u2502  \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510 \u2502\n\u2502  \u2502                      API Layer                                  \u2502 \u2502\n\u2502  \u2502  /api/worksheets  /api/corrections  /api/letters  /api/state   \u2502 \u2502\n\u2502  \u2502  /api/school      /api/certificates /api/messenger /api/jitsi  \u2502 \u2502\n\u2502  \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518 \u2502\n\u2502  \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510 \u2502\n\u2502  \u2502                    Service Layer                                \u2502 \u2502\n\u2502  \u2502  FileProcessor \u2502 PDFService \u2502 ContentGenerators \u2502 StateEngine  \u2502 \u2502\n\u2502  \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518 \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n                            \u2502\n              \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n              \u25bc             \u25bc             \u25bc\n\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510 \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510 \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510 \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502  Go Consent     \u2502 \u2502  PostgreSQL   \u2502 \u2502  LLM Gateway \u2502 \u2502  HashiCorp   \u2502\n\u2502  Service        \u2502 \u2502  Database     \u2502 \u2502  (optional)  \u2502 \u2502  Vault       \u2502\n\u2502  Port 8081      \u2502 \u2502  Port 5432    \u2502 \u2502              \u2502 \u2502  Port 8200   \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518 \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518 \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518 \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n
"},{"location":"architecture/system-architecture/#komponenten","title":"Komponenten","text":""},{"location":"architecture/system-architecture/#1-admin-frontend-nextjs-website","title":"1. Admin Frontend (Next.js Website)","text":"

Das Admin Frontend ist eine vollst\u00e4ndige Next.js 15 Anwendung f\u00fcr Developer und Administratoren:

Technologie: Next.js 15, React 18, TypeScript, Tailwind CSS

Container: breakpilot-pwa-website auf Port 3000

Verzeichnis: /website

Modul Route Beschreibung Dashboard /admin \u00dcbersicht & Statistiken GPU Infrastruktur /admin/gpu vast.ai GPU Management Consent Verwaltung /admin/consent Rechtliche Dokumente & Versionen Datenschutzanfragen /admin/dsr DSGVO Art. 15-21 Anfragen DSMS /admin/dsms Datenschutz-Management-System Education Search /admin/edu-search Bildungsquellen & Crawler Personensuche /admin/staff-search Uni-Mitarbeiter & Publikationen Uni-Crawler /admin/uni-crawler Universit\u00e4ts-Crawling Orchestrator LLM Vergleich /admin/llm-compare KI-Provider Vergleich PCA Platform /admin/pca-platform Bot-Erkennung & Monetarisierung Production Backlog /admin/backlog Go-Live Checkliste Developer Docs /admin/docs API & Architektur Dokumentation Kommunikation /admin/communication Matrix & Jitsi Monitoring Security /admin/security DevSecOps Dashboard, Scans, Findings SBOM /admin/sbom Software Bill of Materials"},{"location":"architecture/system-architecture/#2-lehrer-frontend-studio-ui","title":"2. Lehrer Frontend (Studio UI)","text":"

Das Lehrer Frontend ist ein Single-Page-Application-\u00e4hnliches System f\u00fcr Lehrkr\u00e4fte, das in Python-Modulen organisiert ist:

Modul Datei Beschreibung Base frontend/modules/base.py TopBar, Sidebar, Theme, Login Dashboard frontend/modules/dashboard.py \u00dcbersichtsseite Worksheets frontend/modules/worksheets.py Lerneinheiten-Generator Correction frontend/modules/correction.py OCR-Klausurkorrektur Letters frontend/modules/letters.py Elternkommunikation Companion frontend/modules/companion.py Begleiter-Modus mit State Engine School frontend/modules/school.py Schulverwaltung Gradebook frontend/modules/gradebook.py Notenbuch ContentCreator frontend/modules/content_creator.py H5P Content Creator ContentFeed frontend/modules/content_feed.py Content Discovery Messenger frontend/modules/messenger.py Matrix Messenger Jitsi frontend/modules/jitsi.py Videokonferenzen KlausurKorrektur frontend/modules/klausur_korrektur.py Abitur-Klausurkorrektur (15-Punkte-System) AbiturDocsAdmin frontend/modules/abitur_docs_admin.py Admin f\u00fcr Abitur-Dokumente (NiBiS)

Jedes Modul exportiert: - get_css() - CSS-Styles - get_html() - HTML-Template - get_js() - JavaScript-Logik

"},{"location":"architecture/system-architecture/#3-python-backend-fastapi","title":"3. Python Backend (FastAPI)","text":""},{"location":"architecture/system-architecture/#api-router","title":"API-Router","text":"Router Pr\u00e4fix Beschreibung worksheets_api /api/worksheets Content-Generatoren (MC, Cloze, Mindmap, Quiz) correction_api /api/corrections OCR-Pipeline f\u00fcr Klausurkorrektur letters_api /api/letters Elternbriefe mit GFK-Integration state_engine_api /api/state Begleiter-Modus Phasen & Vorschl\u00e4ge school_api /api/school Schulverwaltung (Proxy zu school-service) certificates_api /api/certificates Zeugniserstellung messenger_api /api/messenger Matrix Messenger Integration jitsi_api /api/jitsi Jitsi Meeting-Einladungen consent_api /api/consent DSGVO Consent-Verwaltung gdpr_api /api/gdpr GDPR-Export klausur_korrektur_api /api/klausur-korrektur Abitur-Klausuren (15-Punkte, Gutachten, Fairness) abitur_docs_api /api/abitur-docs NiBiS-Dokumentenverwaltung f\u00fcr RAG"},{"location":"architecture/system-architecture/#services","title":"Services","text":"Service Datei Beschreibung FileProcessor services/file_processor.py OCR mit PaddleOCR PDFService services/pdf_service.py PDF-Generierung ContentGenerators services/content_generators/ MC, Cloze, Mindmap, Quiz StateEngine state_engine/ Phasen-Management & Antizipation"},{"location":"architecture/system-architecture/#4-klausur-korrektur-system-abitur","title":"4. Klausur-Korrektur System (Abitur)","text":"

Das Klausur-Korrektur-System implementiert die vollst\u00e4ndige Abitur-Bewertungspipeline:

\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502                    Klausur-Korrektur Modul                          \u2502\n\u2502                                                                     \u2502\n\u2502  \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510    \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510    \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510    \u2502\n\u2502  \u2502 Modus-Wahl  \u2502\u2500\u2500\u2500\u25ba\u2502 Text-Quellen &   \u2502\u2500\u2500\u2500\u25ba\u2502 Erwartungs-     \u2502    \u2502\n\u2502  \u2502 LandesAbi/  \u2502    \u2502 Rights-Gate      \u2502    \u2502 horizont        \u2502    \u2502\n\u2502  \u2502 Vorabitur   \u2502    \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518    \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518    \u2502\n\u2502  \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518                                      \u2502            \u2502\n\u2502                                                       \u25bc            \u2502\n\u2502  \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510   \u2502\n\u2502  \u2502                   Sch\u00fclerarbeiten-Pipeline                   \u2502   \u2502\n\u2502  \u2502  Upload \u2192 OCR \u2192 KI-Bewertung \u2192 Gutachten \u2192 15-Punkte-Note   \u2502   \u2502\n\u2502  \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518   \u2502\n\u2502                                                       \u2502            \u2502\n\u2502                                                       \u25bc            \u2502\n\u2502  \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510    \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510   \u2502\n\u2502  \u2502 Erst-/Zweitpr\u00fcfer  \u2502\u2500\u2500\u2500\u25ba\u2502 Fairness-Analyse & PDF-Export   \u2502   \u2502\n\u2502  \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518    \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518   \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n
"},{"location":"architecture/system-architecture/#15-punkte-notensystem","title":"15-Punkte-Notensystem","text":"

Das System verwendet den deutschen Abitur-Notenschl\u00fcssel:

Punkte Prozent Note 15-13 95-85% 1+/1/1- 12-10 80-70% 2+/2/2- 9-7 65-55% 3+/3/3- 6-4 50-40% 4+/4/4- 3-1 33-20% 5+/5/5- 0 <20% 6"},{"location":"architecture/system-architecture/#bewertungskriterien","title":"Bewertungskriterien","text":"Kriterium Gewicht Beschreibung Rechtschreibung 15% Orthografie Grammatik 15% Grammatik & Syntax Inhalt 40% Inhaltliche Qualit\u00e4t (h\u00f6chste Gewichtung) Struktur 15% Aufbau & Gliederung Stil 15% Ausdruck & Stil"},{"location":"architecture/system-architecture/#5-go-consent-service","title":"5. Go Consent Service","text":"

Verwaltet DSGVO-Einwilligungen:

consent-service/\n\u251c\u2500\u2500 cmd/server/        # Main entry point\n\u251c\u2500\u2500 internal/\n\u2502   \u251c\u2500\u2500 handlers/      # HTTP Handler\n\u2502   \u251c\u2500\u2500 services/      # Business Logic\n\u2502   \u251c\u2500\u2500 models/        # Data Models\n\u2502   \u2514\u2500\u2500 middleware/    # Auth Middleware\n\u2514\u2500\u2500 migrations/        # SQL Migrations\n
"},{"location":"architecture/system-architecture/#6-llm-gateway-optional","title":"6. LLM Gateway (Optional)","text":"

Wenn LLM_GATEWAY_ENABLED=true:

llm_gateway/\n\u251c\u2500\u2500 routes/\n\u2502   \u251c\u2500\u2500 chat.py            # Chat-Completion API\n\u2502   \u251c\u2500\u2500 communication.py   # GFK-Validierung\n\u2502   \u251c\u2500\u2500 edu_search_seeds.py # Bildungssuche\n\u2502   \u2514\u2500\u2500 legal_crawler.py   # Schulgesetz-Crawler\n\u2514\u2500\u2500 services/\n    \u2514\u2500\u2500 communication_service.py\n
"},{"location":"architecture/system-architecture/#datenfluss","title":"Datenfluss","text":""},{"location":"architecture/system-architecture/#worksheet-generierung","title":"Worksheet-Generierung","text":"
User Input \u2192 Frontend (worksheets.py)\n    \u2193\nPOST /api/worksheets/generate/multiple-choice\n    \u2193\nworksheets_api.py \u2192 MCGenerator (services/content_generators/)\n    \u2193\nOptional: LLM f\u00fcr erweiterte Generierung\n    \u2193\nResponse: WorksheetContent \u2192 Frontend rendert Ergebnis\n
"},{"location":"architecture/system-architecture/#klausurkorrektur","title":"Klausurkorrektur","text":"
File Upload \u2192 Frontend (correction.py)\n    \u2193\nPOST /api/corrections/ (erstellen)\nPOST /api/corrections/{id}/upload (Datei)\n    \u2193\nBackground Task: OCR via FileProcessor\n    \u2193\nPoll GET /api/corrections/{id} bis status=\"ocr_complete\"\n    \u2193\nPOST /api/corrections/{id}/analyze\n    \u2193\nReview Interface \u2192 PUT /api/corrections/{id} (Anpassungen)\n    \u2193\nGET /api/corrections/{id}/export-pdf\n
"},{"location":"architecture/system-architecture/#sicherheit","title":"Sicherheit","text":""},{"location":"architecture/system-architecture/#authentifizierung-autorisierung","title":"Authentifizierung & Autorisierung","text":"

BreakPilot verwendet einen Hybrid-Ansatz:

Schicht Komponente Beschreibung Authentifizierung Keycloak (Prod) / Lokales JWT (Dev) Token-Validierung via JWKS oder HS256 Autorisierung rbac.py (Eigenentwicklung) Domaenenspezifische Berechtigungen

Siehe: Auth-System

"},{"location":"architecture/system-architecture/#basis-rollen","title":"Basis-Rollen","text":"Rolle Beschreibung user Normaler Benutzer teacher / lehrer Lehrkraft admin Administrator data_protection_officer Datenschutzbeauftragter"},{"location":"architecture/system-architecture/#erweiterte-rollen-rbacpy","title":"Erweiterte Rollen (rbac.py)","text":"

15+ domaenenspezifische Rollen fuer Klausurkorrektur und Zeugnisse: - erstkorrektor, zweitkorrektor, drittkorrektor - klassenlehrer, fachlehrer, fachvorsitz - schulleitung, zeugnisbeauftragter, sekretariat

"},{"location":"architecture/system-architecture/#sicherheitsfeatures","title":"Sicherheitsfeatures","text":"

Siehe: - Secrets Management - DevSecOps

"},{"location":"architecture/system-architecture/#deployment","title":"Deployment","text":"
services:\n  backend:\n    build: ./backend\n    ports: [\"8000:8000\"]\n    environment:\n      - DATABASE_URL=postgresql://...\n      - LLM_GATEWAY_ENABLED=false\n\n  consent-service:\n    build: ./consent-service\n    ports: [\"8081:8081\"]\n\n  postgres:\n    image: postgres:15\n    volumes:\n      - pgdata:/var/lib/postgresql/data\n
"},{"location":"architecture/system-architecture/#erweiterung","title":"Erweiterung","text":"

Neues Frontend-Modul hinzuf\u00fcgen:

  1. Modul erstellen: frontend/modules/new_module.py
  2. Klasse mit get_css(), get_html(), get_js() implementieren
  3. In frontend/modules/__init__.py importieren und exportieren
  4. Optional: Zugeh\u00f6rige API in new_module_api.py erstellen
  5. In main.py Router registrieren
"},{"location":"architecture/zeugnis-system/","title":"Zeugnis-System - Architecture Documentation","text":""},{"location":"architecture/zeugnis-system/#overview","title":"Overview","text":"

The Zeugnis (Certificate) System enables schools to generate official school certificates with grades, attendance data, and remarks. It extends the existing School-Service with comprehensive grade management and certificate generation workflows.

"},{"location":"architecture/zeugnis-system/#architecture-diagram","title":"Architecture Diagram","text":"
                                         \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n                                         \u2502      Python Backend (Port 8000)     \u2502\n                                         \u2502   backend/frontend/modules/school.py \u2502\n                                         \u2502                                     \u2502\n                                         \u2502  \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510 \u2502\n                                         \u2502  \u2502   panel-school-certificates     \u2502 \u2502\n                                         \u2502  \u2502   - Klassenauswahl              \u2502 \u2502\n                                         \u2502  \u2502   - Notenspiegel                \u2502 \u2502\n                                         \u2502  \u2502   - Zeugnis-Wizard (5 Steps)    \u2502 \u2502\n                                         \u2502  \u2502   - Workflow-Status             \u2502 \u2502\n                                         \u2502  \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518 \u2502\n                                         \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n                                                            \u2502\n                                                            \u25bc\n\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502                              School-Service (Go, Port 8084)                              \u2502\n\u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n\u2502                                                                                         \u2502\n\u2502  \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510  \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510  \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510  \u2502\n\u2502  \u2502  Grade Handlers     \u2502  \u2502 Statistics Handlers \u2502  \u2502    Certificate Handlers         \u2502  \u2502\n\u2502  \u2502                     \u2502  \u2502                     \u2502  \u2502                                 \u2502  \u2502\n\u2502  \u2502 GetClassGrades      \u2502  \u2502 GetClassStatistics  \u2502  \u2502 GetCertificateTemplates         \u2502  \u2502\n\u2502  \u2502 GetStudentGrades    \u2502  \u2502 GetSubjectStatistics\u2502  \u2502 GetClassCertificates            \u2502  \u2502\n\u2502  \u2502 UpdateOralGrade     \u2502  \u2502 GetStudentStatistics\u2502  \u2502 GenerateCertificate             \u2502  \u2502\n\u2502  \u2502 CalculateFinalGrades\u2502  \u2502 GetNotenspiegel     \u2502  \u2502 BulkGenerateCertificates        \u2502  \u2502\n\u2502  \u2502 LockFinalGrade      \u2502  \u2502                     \u2502  \u2502 FinalizeCertificate             \u2502  \u2502\n\u2502  \u2502 UpdateGradeWeights  \u2502  \u2502                     \u2502  \u2502 GetCertificatePDF               \u2502  \u2502\n\u2502  \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518  \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518  \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518  \u2502\n\u2502                                                                                         \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n                                                            \u2502\n                                                            \u25bc\n                                         \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n                                         \u2502         PostgreSQL Database          \u2502\n                                         \u2502                                     \u2502\n                                         \u2502  Tables:                            \u2502\n                                         \u2502  - grade_overview                   \u2502\n                                         \u2502  - exam_results                     \u2502\n                                         \u2502  - students                         \u2502\n                                         \u2502  - classes                          \u2502\n                                         \u2502  - subjects                         \u2502\n                                         \u2502  - certificates                     \u2502\n                                         \u2502  - attendance                       \u2502\n                                         \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n
"},{"location":"architecture/zeugnis-system/#zeugnis-workflow-role-chain","title":"Zeugnis Workflow (Role Chain)","text":"

The certificate workflow follows a strict approval chain from subject teachers to school principal:

\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510    \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510    \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510    \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510    \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502   FACHLEHRER     \u2502\u2500\u2500\u2500\u25b6\u2502  KLASSENLEHRER   \u2502\u2500\u2500\u2500\u25b6\u2502  ZEUGNISBEAUFTRAGTER   \u2502\u2500\u2500\u2500\u25b6\u2502    SCHULLEITUNG    \u2502\u2500\u2500\u2500\u25b6\u2502   SEKRETARIAT    \u2502\n\u2502   (Subject       \u2502    \u2502  (Class          \u2502    \u2502  (Certificate          \u2502    \u2502    (Principal)     \u2502    \u2502   (Secretary)    \u2502\n\u2502   Teacher)       \u2502    \u2502   Teacher)       \u2502    \u2502   Coordinator)         \u2502    \u2502                    \u2502    \u2502                  \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518    \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518    \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518    \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518    \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n        \u2502                       \u2502                         \u2502                           \u2502                        \u2502\n        \u25bc                       \u25bc                         \u25bc                           \u25bc                        \u25bc\n   Grades Entry            Approve               Quality Check              Sign-off & Lock            Print & Archive\n   (Oral/Written)          Grades                 & Review\n
"},{"location":"architecture/zeugnis-system/#workflow-states","title":"Workflow States","text":"
\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510     \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510     \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510     \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510     \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502   DRAFT     \u2502\u2500\u2500\u2500\u2500\u25b6\u2502  SUBMITTED  \u2502\u2500\u2500\u2500\u2500\u25b6\u2502  REVIEWED   \u2502\u2500\u2500\u2500\u2500\u25b6\u2502   SIGNED    \u2502\u2500\u2500\u2500\u2500\u25b6\u2502   PRINTED   \u2502\n\u2502   (Entwurf) \u2502     \u2502 (Eingereicht)\u2502    \u2502 (Geprueft)  \u2502     \u2502(Unterzeichnet)    \u2502 (Gedruckt)  \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518     \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518     \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518     \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518     \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n      \u2502                   \u2502                   \u2502                   \u2502\n      \u25bc                   \u25bc                   \u25bc                   \u25bc\n  Fachlehrer        Klassenlehrer      Zeugnisbeauftragter   Schulleitung\n
"},{"location":"architecture/zeugnis-system/#rbac-integration","title":"RBAC Integration","text":""},{"location":"architecture/zeugnis-system/#certificate-related-roles","title":"Certificate-Related Roles","text":"Role German Description FACHLEHRER Fachlehrer Subject teacher - enters grades KLASSENLEHRER Klassenlehrer Class teacher - approves class grades ZEUGNISBEAUFTRAGTER Zeugnisbeauftragter Certificate coordinator - quality control SCHULLEITUNG Schulleitung Principal - final sign-off SEKRETARIAT Sekretariat Secretary - printing & archiving"},{"location":"architecture/zeugnis-system/#certificate-resource-types","title":"Certificate Resource Types","text":"ResourceType Description ZEUGNIS Final certificate document ZEUGNIS_VORLAGE Certificate template (per Bundesland) ZEUGNIS_ENTWURF Draft certificate (before approval) FACHNOTE Subject grade KOPFNOTE Head grade (Arbeits-/Sozialverhalten) BEMERKUNG Certificate remarks STATISTIK Class/subject statistics NOTENSPIEGEL Grade distribution chart"},{"location":"architecture/zeugnis-system/#german-grading-system","title":"German Grading System","text":"Grade Meaning Points 1 sehr gut (excellent) 15-13 2 gut (good) 12-10 3 befriedigend (satisfactory) 9-7 4 ausreichend (adequate) 6-4 5 mangelhaft (poor) 3-1 6 ungenuegend (inadequate) 0"},{"location":"architecture/zeugnis-system/#grade-calculation","title":"Grade Calculation","text":"
Final Grade = (Written Weight * Written Avg) + (Oral Weight * Oral Avg)\n\nDefault weights:\n- Written (Klassenarbeiten): 50%\n- Oral (muendliche Note): 50%\n\nCustomizable per subject/student via UpdateGradeWeights endpoint.\n
"},{"location":"architecture/zeugnis-system/#api-routes-school-service","title":"API Routes (School-Service)","text":""},{"location":"architecture/zeugnis-system/#grade-management","title":"Grade Management","text":"Method Endpoint Description GET /api/v1/school/grades/:classId Get class grades GET /api/v1/school/grades/student/:studentId Get student grades PUT /api/v1/school/grades/:studentId/:subjectId/oral Update oral grade POST /api/v1/school/grades/calculate Calculate final grades PUT /api/v1/school/grades/:studentId/:subjectId/lock Lock final grade"},{"location":"architecture/zeugnis-system/#statistics","title":"Statistics","text":"Method Endpoint Description GET /api/v1/school/statistics/:classId Class statistics GET /api/v1/school/statistics/:classId/subject/:subjectId Subject statistics GET /api/v1/school/statistics/student/:studentId Student statistics GET /api/v1/school/statistics/:classId/notenspiegel Grade distribution"},{"location":"architecture/zeugnis-system/#certificates","title":"Certificates","text":"Method Endpoint Description GET /api/v1/school/certificates/templates List templates GET /api/v1/school/certificates/class/:classId Class certificates POST /api/v1/school/certificates/generate Generate single POST /api/v1/school/certificates/generate-bulk Generate bulk GET /api/v1/school/certificates/detail/:id/pdf Download PDF"},{"location":"architecture/zeugnis-system/#security-considerations","title":"Security Considerations","text":"
  1. RBAC Enforcement: All certificate operations check user role permissions
  2. Tenant Isolation: Teachers only see their own classes/students
  3. Audit Trail: All grade changes and approvals logged
  4. Lock Mechanism: Finalized certificates cannot be modified
  5. Workflow Enforcement: Cannot skip approval steps
"},{"location":"backend/venv/lib/python3.9/site-packages/anthropic/lib/foundry/","title":"Anthropic Foundry","text":"

To use this library with Foundry, use the AnthropicFoundry class instead of the Anthropic class.

"},{"location":"backend/venv/lib/python3.9/site-packages/anthropic/lib/foundry/#installation","title":"Installation","text":"
pip install anthropic\n
"},{"location":"backend/venv/lib/python3.9/site-packages/anthropic/lib/foundry/#usage","title":"Usage","text":""},{"location":"backend/venv/lib/python3.9/site-packages/anthropic/lib/foundry/#basic-usage-with-api-key","title":"Basic Usage with API Key","text":"
from anthropic import AnthropicFoundry\n\nclient = AnthropicFoundry(\n    api_key=\"...\",  # defaults to ANTHROPIC_FOUNDRY_API_KEY environment variable\n    resource=\"my-resource\",  # your Foundry resource\n)\n\nmessage = client.messages.create(\n    model=\"claude-3-5-sonnet-20241022\",\n    max_tokens=1024,\n    messages=[{\"role\": \"user\", \"content\": \"Hello!\"}],\n)\n\nprint(message.content[0].text)\n
"},{"location":"backend/venv/lib/python3.9/site-packages/anthropic/lib/foundry/#using-azure-ad-token-provider","title":"Using Azure AD Token Provider","text":"

For enhanced security, you can use Azure AD (Microsoft Entra) authentication instead of an API key:

from anthropic import AnthropicFoundry\nfrom azure.identity import DefaultAzureCredential\nfrom azure.identity import get_bearer_token_provider\n\ncredential = DefaultAzureCredential()\ntoken_provider = get_bearer_token_provider(\n    credential, \n    \"https://ai.azure.com/.default\"\n)\n\nclient = AnthropicFoundry(\n    azure_ad_token_provider=token_provider,\n    resource=\"my-resource\",\n)\n\nmessage = client.messages.create(\n    model=\"claude-3-5-sonnet-20241022\",\n    max_tokens=1024,\n    messages=[{\"role\": \"user\", \"content\": \"Hello!\"}],\n)\n\nprint(message.content[0].text)\n
"},{"location":"backend/venv/lib/python3.9/site-packages/anthropic/lib/foundry/#examples","title":"Examples","text":""},{"location":"backend/venv/lib/python3.9/site-packages/anthropic/lib/foundry/#streaming-messages","title":"Streaming Messages","text":"
from anthropic import AnthropicFoundry\n\nclient = AnthropicFoundry(\n    api_key=\"...\",\n    resource=\"my-resource\",\n)\n\nwith client.messages.stream(\n    model=\"claude-3-5-sonnet-20241022\",\n    max_tokens=1024,\n    messages=[{\"role\": \"user\", \"content\": \"Write a haiku about programming\"}],\n) as stream:\n    for text in stream.text_stream:\n        print(text, end=\"\", flush=True)\n
"},{"location":"backend/venv/lib/python3.9/site-packages/anthropic/lib/foundry/#async-usage","title":"Async Usage","text":"
from anthropic import AsyncAnthropicFoundry\n\nasync def main():\n    client = AsyncAnthropicFoundry(\n        api_key=\"...\",\n        resource=\"my-resource\",\n    )\n\n    message = await client.messages.create(\n        model=\"claude-3-5-sonnet-20241022\",\n        max_tokens=1024,\n        messages=[{\"role\": \"user\", \"content\": \"Hello!\"}],\n    )\n\n    print(message.content[0].text)\n\nimport asyncio\nasyncio.run(main())\n
"},{"location":"backend/venv/lib/python3.9/site-packages/anthropic/lib/foundry/#async-streaming","title":"Async Streaming","text":"
from anthropic import AsyncAnthropicFoundry\n\nasync def main():\n    client = AsyncAnthropicFoundry(\n        api_key=\"...\",\n        resource=\"my-resource\",\n    )\n\n    async with client.messages.stream(\n        model=\"claude-3-5-sonnet-20241022\",\n        max_tokens=1024,\n        messages=[{\"role\": \"user\", \"content\": \"Write a haiku about programming\"}],\n    ) as stream:\n        async for text in stream.text_stream:\n            print(text, end=\"\", flush=True)\n\nimport asyncio\nasyncio.run(main())\n
"},{"location":"backend/venv/lib/python3.9/site-packages/backports_asyncio_runner-1.2.0.dist-info/licenses/LICENSE/","title":"LICENSE","text":"

PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2

  1. This LICENSE AGREEMENT is between the Python Software Foundation (\"PSF\"), and the Individual or Organization (\"Licensee\") accessing and otherwise using this software (\"Python\") in source or binary form and its associated documentation.
  2. Subject to the terms and conditions of this License Agreement, PSF hereby grants Licensee a nonexclusive, royalty-free, world-wide license to reproduce, analyze, test, perform and/or display publicly, prepare derivative works, distribute, and otherwise use Python alone or in any derivative version, provided, however, that PSF's License Agreement and PSF's notice of copyright , i.e., \"Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006 Python Software Foundation All Rights Reserved\" are retained in Python alone or in any derivative version prepared by Licensee.
  3. In the event Licensee prepares a derivative work that is based on or incorporates Python or any part thereof, and wants to make the derivative work available to others as provided herein, then Licensee hereby agrees to include in any such work a brief summary of the changes made to Python.
  4. PSF is making Python available to Licensee on an \"AS IS\" basis. PSF MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, PSF MAKES NO AND DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON WILL NOT INFRINGE ANY THIRD PARTY RIGHTS.
  5. PSF SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON, OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF.
  6. This License Agreement will automatically terminate upon a material breach of its terms and conditions.
  7. Nothing in this License Agreement shall be deemed to create any relationship of agency, partnership, or joint venture between PSF and Licensee. This License Agreement does not grant permission to use PSF trademarks or trade name in a trademark sense to endorse or promote products or services of Licensee, or any third party.
  8. By copying, installing or otherwise using Python, Licensee agrees to be bound by the terms and conditions of this License Agreement.
"},{"location":"backend/venv/lib/python3.9/site-packages/docstring_parser-0.17.0.dist-info/licenses/LICENSE/","title":"LICENSE","text":"

The MIT License (MIT)

Copyright (c) 2018 Marcin Kurczewski

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

"},{"location":"backend/venv/lib/python3.9/site-packages/httpcore-1.0.9.dist-info/licenses/LICENSE/","title":"LICENSE","text":"

Copyright \u00a9 2020, Encode OSS Ltd. All rights reserved.

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

"},{"location":"backend/venv/lib/python3.9/site-packages/httpx-0.28.1.dist-info/licenses/LICENSE/","title":"LICENSE","text":"

Copyright \u00a9 2019, Encode OSS Ltd. All rights reserved.

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

"},{"location":"backend/venv/lib/python3.9/site-packages/idna-3.11.dist-info/licenses/LICENSE/","title":"LICENSE","text":"

BSD 3-Clause License

Copyright (c) 2013-2025, Kim Davies and contributors. All rights reserved.

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

  1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.

  2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.

  3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

"},{"location":"backend/venv/lib/python3.9/site-packages/markdown-3.9.dist-info/licenses/LICENSE/","title":"LICENSE","text":"

BSD 3-Clause License

Copyright 2007, 2008 The Python Markdown Project (v. 1.7 and later) Copyright 2004, 2005, 2006 Yuri Takhteyev (v. 0.2-1.6b) Copyright 2004 Manfred Stienstra (the original version)

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

  1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.

  2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.

  3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

"},{"location":"backend/venv/lib/python3.9/site-packages/numpy/random/LICENSE/","title":"LICENSE","text":"

This software is dual-licensed under the The University of Illinois/NCSA Open Source License (NCSA) and The 3-Clause BSD License

"},{"location":"backend/venv/lib/python3.9/site-packages/numpy/random/LICENSE/#ncsa-open-source-license","title":"NCSA Open Source License","text":"

Copyright (c) 2019 Kevin Sheppard. All rights reserved.

Developed by: Kevin Sheppard (kevin.sheppard@economics.ox.ac.uk, kevin.k.sheppard@gmail.com) http://www.kevinsheppard.com

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal with the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimers.

Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimers in the documentation and/or other materials provided with the distribution.

Neither the names of Kevin Sheppard, nor the names of any contributors may be used to endorse or promote products derived from this Software without specific prior written permission.

THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE SOFTWARE.

"},{"location":"backend/venv/lib/python3.9/site-packages/numpy/random/LICENSE/#3-clause-bsd-license","title":"3-Clause BSD License","text":"

Copyright (c) 2019 Kevin Sheppard. All rights reserved.

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

  1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.

  2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.

  3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

"},{"location":"backend/venv/lib/python3.9/site-packages/numpy/random/LICENSE/#components","title":"Components","text":"

Many parts of this module have been derived from original sources, often the algorithm's designer. Component licenses are located with the component code.

"},{"location":"backend/venv/lib/python3.9/site-packages/pip/_vendor/idna/LICENSE/","title":"LICENSE","text":"

BSD 3-Clause License

Copyright (c) 2013-2024, Kim Davies and contributors. All rights reserved.

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

  1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.

  2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.

  3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

"},{"location":"backend/venv/lib/python3.9/site-packages/pip-25.3.dist-info/licenses/src/pip/_vendor/idna/LICENSE/","title":"LICENSE","text":"

BSD 3-Clause License

Copyright (c) 2013-2024, Kim Davies and contributors. All rights reserved.

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

  1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.

  2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.

  3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

"},{"location":"backend/venv/lib/python3.9/site-packages/soupsieve-2.8.3.dist-info/licenses/LICENSE/","title":"LICENSE","text":"

MIT License

Copyright (c) 2018 - 2026 Isaac Muse isaacmuse@gmail.com

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

"},{"location":"backend/venv/lib/python3.9/site-packages/starlette-0.49.3.dist-info/licenses/LICENSE/","title":"LICENSE","text":"

Copyright \u00a9 2018, Encode OSS Ltd. All rights reserved.

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

"},{"location":"backend/venv/lib/python3.9/site-packages/uvicorn-0.38.0.dist-info/licenses/LICENSE/","title":"LICENSE","text":"

Copyright \u00a9 2017-present, Encode OSS Ltd. All rights reserved.

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

"},{"location":"development/ci-cd-pipeline/","title":"CI/CD Pipeline","text":"

\u00dcbersicht \u00fcber den Deployment-Prozess f\u00fcr Breakpilot.

"},{"location":"development/ci-cd-pipeline/#ubersicht","title":"\u00dcbersicht","text":"Komponente Build-Tool Deployment Frontend (Next.js) Docker Mac Mini Backend (FastAPI) Docker Mac Mini Go Services Docker (Multi-stage) Mac Mini Documentation MkDocs Docker (Nginx)"},{"location":"development/ci-cd-pipeline/#deployment-architektur","title":"Deployment-Architektur","text":"
\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502                      Entwickler-MacBook                          \u2502\n\u2502                                                                   \u2502\n\u2502   breakpilot-pwa/                                                \u2502\n\u2502   \u251c\u2500\u2500 studio-v2/          (Next.js Frontend)                    \u2502\n\u2502   \u251c\u2500\u2500 admin-v2/           (Next.js Admin)                       \u2502\n\u2502   \u251c\u2500\u2500 backend/            (Python FastAPI)                       \u2502\n\u2502   \u251c\u2500\u2500 consent-service/    (Go Service)                          \u2502\n\u2502   \u251c\u2500\u2500 klausur-service/    (Python FastAPI)                      \u2502\n\u2502   \u251c\u2500\u2500 voice-service/      (Python FastAPI)                      \u2502\n\u2502   \u251c\u2500\u2500 ai-compliance-sdk/  (Go Service)                          \u2502\n\u2502   \u2514\u2500\u2500 docs-src/           (MkDocs)                              \u2502\n\u2502                                                                   \u2502\n\u2502   $ ./sync-and-deploy.sh                                         \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n                                \u2502\n                                \u2502 rsync + SSH\n                                \u2502\n                                \u25bc\n\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502                         Mac Mini Server                          \u2502\n\u2502                                                                   \u2502\n\u2502   Docker Compose                                                 \u2502\n\u2502   \u251c\u2500\u2500 website (Port 3000)                                       \u2502\n\u2502   \u251c\u2500\u2500 studio-v2 (Port 3001)                                     \u2502\n\u2502   \u251c\u2500\u2500 admin-v2 (Port 3002)                                      \u2502\n\u2502   \u251c\u2500\u2500 backend (Port 8000)                                       \u2502\n\u2502   \u251c\u2500\u2500 consent-service (Port 8081)                               \u2502\n\u2502   \u251c\u2500\u2500 klausur-service (Port 8086)                               \u2502\n\u2502   \u251c\u2500\u2500 voice-service (Port 8082)                                 \u2502\n\u2502   \u251c\u2500\u2500 ai-compliance-sdk (Port 8090)                             \u2502\n\u2502   \u251c\u2500\u2500 docs (Port 8009)                                          \u2502\n\u2502   \u251c\u2500\u2500 postgres                                                   \u2502\n\u2502   \u251c\u2500\u2500 valkey (Redis)                                            \u2502\n\u2502   \u251c\u2500\u2500 qdrant                                                     \u2502\n\u2502   \u2514\u2500\u2500 minio                                                      \u2502\n\u2502                                                                   \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n
"},{"location":"development/ci-cd-pipeline/#sync-deploy-workflow","title":"Sync & Deploy Workflow","text":""},{"location":"development/ci-cd-pipeline/#1-dateien-synchronisieren","title":"1. Dateien synchronisieren","text":"
# Sync aller relevanten Verzeichnisse zum Mac Mini\nrsync -avz --delete \\\n  --exclude 'node_modules' \\\n  --exclude '.next' \\\n  --exclude '.git' \\\n  --exclude '__pycache__' \\\n  --exclude 'venv' \\\n  --exclude '.pytest_cache' \\\n  /Users/benjaminadmin/Projekte/breakpilot-pwa/ \\\n  macmini:/Users/benjaminadmin/Projekte/breakpilot-pwa/\n
"},{"location":"development/ci-cd-pipeline/#2-container-bauen","title":"2. Container bauen","text":"
# Einzelnen Service bauen\nssh macmini \"/usr/local/bin/docker compose \\\n  -f /Users/benjaminadmin/Projekte/breakpilot-pwa/docker-compose.yml \\\n  build --no-cache <service-name>\"\n\n# Beispiele:\n# studio-v2, admin-v2, website, backend, klausur-service, docs\n
"},{"location":"development/ci-cd-pipeline/#3-container-deployen","title":"3. Container deployen","text":"
# Container neu starten\nssh macmini \"/usr/local/bin/docker compose \\\n  -f /Users/benjaminadmin/Projekte/breakpilot-pwa/docker-compose.yml \\\n  up -d <service-name>\"\n
"},{"location":"development/ci-cd-pipeline/#4-logs-prufen","title":"4. Logs pr\u00fcfen","text":"
# Container-Logs anzeigen\nssh macmini \"/usr/local/bin/docker compose \\\n  -f /Users/benjaminadmin/Projekte/breakpilot-pwa/docker-compose.yml \\\n  logs -f <service-name>\"\n
"},{"location":"development/ci-cd-pipeline/#service-spezifische-deployments","title":"Service-spezifische Deployments","text":""},{"location":"development/ci-cd-pipeline/#nextjs-frontend-studio-v2-admin-v2-website","title":"Next.js Frontend (studio-v2, admin-v2, website)","text":"
# 1. Sync\nrsync -avz --delete \\\n  --exclude 'node_modules' --exclude '.next' --exclude '.git' \\\n  /Users/benjaminadmin/Projekte/breakpilot-pwa/studio-v2/ \\\n  macmini:/Users/benjaminadmin/Projekte/breakpilot-pwa/studio-v2/\n\n# 2. Build & Deploy\nssh macmini \"/usr/local/bin/docker compose \\\n  -f /Users/benjaminadmin/Projekte/breakpilot-pwa/docker-compose.yml \\\n  build --no-cache studio-v2 && \\\n  /usr/local/bin/docker compose \\\n  -f /Users/benjaminadmin/Projekte/breakpilot-pwa/docker-compose.yml \\\n  up -d studio-v2\"\n
"},{"location":"development/ci-cd-pipeline/#python-services-backend-klausur-service-voice-service","title":"Python Services (backend, klausur-service, voice-service)","text":"
# Build mit requirements.txt\nssh macmini \"/usr/local/bin/docker compose \\\n  -f /Users/benjaminadmin/Projekte/breakpilot-pwa/docker-compose.yml \\\n  build klausur-service && \\\n  /usr/local/bin/docker compose \\\n  -f /Users/benjaminadmin/Projekte/breakpilot-pwa/docker-compose.yml \\\n  up -d klausur-service\"\n
"},{"location":"development/ci-cd-pipeline/#go-services-consent-service-ai-compliance-sdk","title":"Go Services (consent-service, ai-compliance-sdk)","text":"
# Multi-stage Build (Go \u2192 Alpine)\nssh macmini \"/usr/local/bin/docker compose \\\n  -f /Users/benjaminadmin/Projekte/breakpilot-pwa/docker-compose.yml \\\n  build --no-cache consent-service && \\\n  /usr/local/bin/docker compose \\\n  -f /Users/benjaminadmin/Projekte/breakpilot-pwa/docker-compose.yml \\\n  up -d consent-service\"\n
"},{"location":"development/ci-cd-pipeline/#mkdocs-dokumentation","title":"MkDocs Dokumentation","text":"
# Build & Deploy\nssh macmini \"/usr/local/bin/docker compose \\\n  -f /Users/benjaminadmin/Projekte/breakpilot-pwa/docker-compose.yml \\\n  build --no-cache docs && \\\n  /usr/local/bin/docker compose \\\n  -f /Users/benjaminadmin/Projekte/breakpilot-pwa/docker-compose.yml \\\n  up -d docs\"\n\n# Verf\u00fcgbar unter: http://macmini:8009\n
"},{"location":"development/ci-cd-pipeline/#health-checks","title":"Health Checks","text":""},{"location":"development/ci-cd-pipeline/#service-status-prufen","title":"Service-Status pr\u00fcfen","text":"
# Alle Container-Status\nssh macmini \"docker ps --format 'table {{.Names}}\\t{{.Status}}\\t{{.Ports}}'\"\n\n# Health-Endpoints pr\u00fcfen\ncurl -s http://macmini:8000/health\ncurl -s http://macmini:8081/health\ncurl -s http://macmini:8086/health\ncurl -s http://macmini:8090/health\n
"},{"location":"development/ci-cd-pipeline/#logs-analysieren","title":"Logs analysieren","text":"
# Letzte 100 Zeilen\nssh macmini \"docker logs --tail 100 breakpilot-pwa-backend-1\"\n\n# Live-Logs folgen\nssh macmini \"docker logs -f breakpilot-pwa-backend-1\"\n
"},{"location":"development/ci-cd-pipeline/#rollback","title":"Rollback","text":""},{"location":"development/ci-cd-pipeline/#container-auf-vorherige-version-zurucksetzen","title":"Container auf vorherige Version zur\u00fccksetzen","text":"
# 1. Aktuelles Image taggen\nssh macmini \"docker tag breakpilot-pwa-backend:latest breakpilot-pwa-backend:backup\"\n\n# 2. Altes Image deployen\nssh macmini \"/usr/local/bin/docker compose \\\n  -f /Users/benjaminadmin/Projekte/breakpilot-pwa/docker-compose.yml \\\n  up -d backend\"\n\n# 3. Bei Problemen: Backup wiederherstellen\nssh macmini \"docker tag breakpilot-pwa-backend:backup breakpilot-pwa-backend:latest\"\n
"},{"location":"development/ci-cd-pipeline/#troubleshooting","title":"Troubleshooting","text":""},{"location":"development/ci-cd-pipeline/#container-startet-nicht","title":"Container startet nicht","text":"
# 1. Logs pr\u00fcfen\nssh macmini \"docker logs breakpilot-pwa-<service>-1\"\n\n# 2. Container manuell starten f\u00fcr Debug-Output\nssh macmini \"docker compose -f .../docker-compose.yml run --rm <service>\"\n\n# 3. In Container einloggen\nssh macmini \"docker exec -it breakpilot-pwa-<service>-1 /bin/sh\"\n
"},{"location":"development/ci-cd-pipeline/#port-bereits-belegt","title":"Port bereits belegt","text":"
# Port-Belegung pr\u00fcfen\nssh macmini \"lsof -i :8000\"\n\n# Container mit dem Port finden\nssh macmini \"docker ps --filter publish=8000\"\n
"},{"location":"development/ci-cd-pipeline/#build-fehler","title":"Build-Fehler","text":"
# Cache komplett leeren\nssh macmini \"docker builder prune -a\"\n\n# Ohne Cache bauen\nssh macmini \"docker compose build --no-cache <service>\"\n
"},{"location":"development/ci-cd-pipeline/#monitoring","title":"Monitoring","text":""},{"location":"development/ci-cd-pipeline/#resource-nutzung","title":"Resource-Nutzung","text":"
# CPU/Memory aller Container\nssh macmini \"docker stats --no-stream\"\n\n# Disk-Nutzung\nssh macmini \"docker system df\"\n
"},{"location":"development/ci-cd-pipeline/#cleanup","title":"Cleanup","text":"
# Ungenutzte Images/Container entfernen\nssh macmini \"docker system prune -a --volumes\"\n\n# Nur dangling Images\nssh macmini \"docker image prune\"\n
"},{"location":"development/ci-cd-pipeline/#umgebungsvariablen","title":"Umgebungsvariablen","text":"

Umgebungsvariablen werden \u00fcber .env Dateien und docker-compose.yml verwaltet:

# docker-compose.yml\nservices:\n  backend:\n    environment:\n      - DATABASE_URL=postgresql://...\n      - REDIS_URL=redis://valkey:6379\n      - SECRET_KEY=${SECRET_KEY}\n

Wichtig: Sensible Werte niemals in Git committen. Stattdessen: - .env Datei auf dem Server pflegen - Secrets \u00fcber HashiCorp Vault (siehe unten)

"},{"location":"development/ci-cd-pipeline/#woodpecker-ci-automatisierte-oauth-integration","title":"Woodpecker CI - Automatisierte OAuth Integration","text":""},{"location":"development/ci-cd-pipeline/#uberblick","title":"\u00dcberblick","text":"

Die OAuth-Integration zwischen Woodpecker CI und Gitea ist vollst\u00e4ndig automatisiert. Credentials werden in HashiCorp Vault gespeichert und bei Bedarf automatisch regeneriert.

Warum automatisiert?

Diese Automatisierung ist eine DevSecOps Best Practice:

"},{"location":"development/ci-cd-pipeline/#architektur","title":"Architektur","text":"
\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502                        Mac Mini Server                           \u2502\n\u2502                                                                   \u2502\n\u2502   \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510         OAuth 2.0         \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510 \u2502\n\u2502   \u2502    Gitea      \u2502 \u2190\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2192\u2502  Woodpecker   \u2502 \u2502\n\u2502   \u2502  (Port 3003)  \u2502    Client ID + Secret     \u2502  (Port 8090)  \u2502 \u2502\n\u2502   \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518                           \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518 \u2502\n\u2502          \u2502                                            \u2502         \u2502\n\u2502          \u2502 OAuth App                                  \u2502 Env Vars\u2502\n\u2502          \u2502 (DB: oauth2_application)                   \u2502         \u2502\n\u2502          \u2502                                            \u2502         \u2502\n\u2502          \u25bc                                            \u25bc         \u2502\n\u2502   \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510 \u2502\n\u2502   \u2502                 HashiCorp Vault (Port 8200)                \u2502 \u2502\n\u2502   \u2502                                                             \u2502 \u2502\n\u2502   \u2502   secret/cicd/woodpecker:                                  \u2502 \u2502\n\u2502   \u2502     - gitea_client_id                                      \u2502 \u2502\n\u2502   \u2502     - gitea_client_secret                                  \u2502 \u2502\n\u2502   \u2502                                                             \u2502 \u2502\n\u2502   \u2502   secret/cicd/api-tokens:                                  \u2502 \u2502\n\u2502   \u2502     - gitea_token (f\u00fcr API-Zugriff)                       \u2502 \u2502\n\u2502   \u2502     - woodpecker_token (f\u00fcr Pipeline-Trigger)             \u2502 \u2502\n\u2502   \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518 \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n
"},{"location":"development/ci-cd-pipeline/#credentials-speicherorte","title":"Credentials-Speicherorte","text":"Ort Pfad Inhalt HashiCorp Vault secret/cicd/woodpecker Client ID + Secret (Quelle der Wahrheit) .env Datei WOODPECKER_GITEA_CLIENT/SECRET F\u00fcr Docker Compose (aus Vault geladen) Gitea PostgreSQL oauth2_application Tabelle OAuth App Registration (gehashtes Secret)"},{"location":"development/ci-cd-pipeline/#troubleshooting-oauth-fehler","title":"Troubleshooting: OAuth Fehler","text":"

Falls der Fehler \"Client ID not registered\" oder \"user does not exist [uid: 0]\" auftritt:

# Option 1: Automatisches Regenerieren (empfohlen)\n./scripts/sync-woodpecker-credentials.sh --regenerate\n\n# Option 2: Manuelles Vorgehen\n# 1. Credentials aus Vault laden\nvault kv get secret/cicd/woodpecker\n\n# 2. .env aktualisieren\nWOODPECKER_GITEA_CLIENT=<client_id>\nWOODPECKER_GITEA_SECRET=<client_secret>\n\n# 3. Zu Mac Mini synchronisieren\nrsync .env macmini:~/Projekte/breakpilot-pwa/\n\n# 4. Woodpecker neu starten\nssh macmini \"cd ~/Projekte/breakpilot-pwa && \\\n  docker compose up -d --force-recreate woodpecker-server\"\n
"},{"location":"development/ci-cd-pipeline/#das-sync-script","title":"Das Sync-Script","text":"

Das Script scripts/sync-woodpecker-credentials.sh automatisiert den gesamten Prozess:

# Credentials aus Vault laden und .env aktualisieren\n./scripts/sync-woodpecker-credentials.sh\n\n# Neue Credentials generieren (OAuth App in Gitea + Vault + .env)\n./scripts/sync-woodpecker-credentials.sh --regenerate\n

Was das Script macht:

  1. Liest die aktuellen Credentials aus Vault
  2. Aktualisiert die .env Datei automatisch
  3. Bei --regenerate:
  4. L\u00f6scht alte OAuth Apps in Gitea
  5. Erstellt neue OAuth App mit neuem Client ID/Secret
  6. Speichert Credentials in Vault
  7. Aktualisiert .env
"},{"location":"development/ci-cd-pipeline/#vault-zugriff","title":"Vault-Zugriff","text":"
# Vault Token (Development)\nexport VAULT_TOKEN=breakpilot-dev-token\n\n# Credentials lesen\ndocker exec -e VAULT_TOKEN=$VAULT_TOKEN breakpilot-pwa-vault \\\n  vault kv get secret/cicd/woodpecker\n\n# Credentials setzen\ndocker exec -e VAULT_TOKEN=$VAULT_TOKEN breakpilot-pwa-vault \\\n  vault kv put secret/cicd/woodpecker \\\n  gitea_client_id=\"...\" \\\n  gitea_client_secret=\"...\"\n
"},{"location":"development/ci-cd-pipeline/#services-neustarten-nach-credentials-anderung","title":"Services neustarten nach Credentials-\u00c4nderung","text":"
# Wichtig: --force-recreate um neue Env Vars zu laden\ncd /Users/benjaminadmin/Projekte/breakpilot-pwa\ndocker compose up -d --force-recreate woodpecker-server\n\n# Logs pr\u00fcfen\ndocker logs breakpilot-pwa-woodpecker-server --tail 50\n
"},{"location":"development/documentation/","title":"Dokumentations-Regeln","text":""},{"location":"development/documentation/#automatische-dokumentations-aktualisierung","title":"Automatische Dokumentations-Aktualisierung","text":"

WICHTIG: Bei JEDER Code-Aenderung muss die entsprechende Dokumentation aktualisiert werden!

"},{"location":"development/documentation/#wann-dokumentation-aktualisieren","title":"Wann Dokumentation aktualisieren?","text":""},{"location":"development/documentation/#api-aenderungen","title":"API-Aenderungen","text":"

Wenn du einen Endpoint aenderst, hinzufuegst oder entfernst:

"},{"location":"development/documentation/#neue-funktionenklassen","title":"Neue Funktionen/Klassen","text":"

Wenn du neue Funktionen, Klassen oder Module erstellst:

"},{"location":"development/documentation/#architektur-aenderungen","title":"Architektur-Aenderungen","text":"

Wenn du die Systemarchitektur aenderst:

"},{"location":"development/documentation/#neue-konfigurationsoptionen","title":"Neue Konfigurationsoptionen","text":"

Wenn du neue Umgebungsvariablen oder Konfigurationen hinzufuegst:

"},{"location":"development/documentation/#dokumentations-format","title":"Dokumentations-Format","text":""},{"location":"development/documentation/#api-endpoints-dokumentieren","title":"API-Endpoints dokumentieren","text":"
### METHOD /path/to/endpoint\n\nKurze Beschreibung.\n\n**Request Body:**\n```json\n{\n  \"field\": \"value\"\n}\n

Response (200):

{\n  \"result\": \"value\"\n}\n

Errors: - 400: Beschreibung - 401: Beschreibung

### Funktionen dokumentieren\n\n```markdown\n### FunctionName (file.go:123)\n\n```go\nfunc FunctionName(param Type) ReturnType\n

Beschreibung: Was macht die Funktion?

Parameter: - param: Beschreibung

Rueckgabe: Beschreibung

## Checkliste nach Code-Aenderungen\n\nVor dem Abschluss einer Aufgabe pruefen:\n\n- [ ] Wurden neue API-Endpoints hinzugefuegt? \u2192 API-Docs aktualisieren\n- [ ] Wurden Datenmodelle geaendert? \u2192 Architektur-Docs aktualisieren\n- [ ] Wurden neue Konfigurationen hinzugefuegt? \u2192 README aktualisieren\n- [ ] Wurden neue Abhaengigkeiten hinzugefuegt? \u2192 requirements.txt/go.mod UND Docs\n- [ ] Wurde die Architektur geaendert? \u2192 architecture/ aktualisieren\n\n## Beispiel: Vollstaendige Dokumentation einer neuen Funktion\n\nWenn du z.B. `GetUserStats()` im Go Service hinzufuegst:\n\n1. **Code schreiben** in `internal/services/stats_service.go`\n2. **API-Doc aktualisieren** in der API-Dokumentation\n3. **Service-Doc aktualisieren** in der Service-README\n4. **Test schreiben** (siehe [Testing](./testing.md))\n\n## Dokumentations-Struktur\n\nDie zentrale Dokumentation befindet sich unter `docs-src/`:\n
docs-src/ \u251c\u2500\u2500 index.md # Startseite \u251c\u2500\u2500 getting-started/ # Erste Schritte \u2502 \u251c\u2500\u2500 environment-setup.md \u2502 \u2514\u2500\u2500 mac-mini-setup.md \u251c\u2500\u2500 architecture/ # Architektur-Dokumentation \u2502 \u251c\u2500\u2500 system-architecture.md \u2502 \u251c\u2500\u2500 auth-system.md \u2502 \u2514\u2500\u2500 ... \u251c\u2500\u2500 api/ # API-Dokumentation \u2502 \u2514\u2500\u2500 backend-api.md \u251c\u2500\u2500 services/ # Service-Dokumentation \u2502 \u251c\u2500\u2500 klausur-service/ \u2502 \u251c\u2500\u2500 agent-core/ \u2502 \u2514\u2500\u2500 ... \u251c\u2500\u2500 development/ # Entwickler-Guides \u2502 \u251c\u2500\u2500 testing.md \u2502 \u2514\u2500\u2500 documentation.md \u2514\u2500\u2500 guides/ # Weitere Anleitungen ```

"},{"location":"development/documentation/#mkdocs-konventionen","title":"MkDocs Konventionen","text":"

Diese Dokumentation wird mit MkDocs + Material Theme generiert:

!!! warning \"Warnung\" Vorsicht bei dieser Aktion. ```

=== \"Go\" go fmt.Println(\"Hello\") ```

"},{"location":"development/testing/","title":"Test-Regeln","text":""},{"location":"development/testing/#automatische-test-erweiterung","title":"Automatische Test-Erweiterung","text":"

WICHTIG: Bei JEDER Code-Aenderung muessen entsprechende Tests erstellt oder aktualisiert werden!

"},{"location":"development/testing/#wann-tests-schreiben","title":"Wann Tests schreiben?","text":""},{"location":"development/testing/#immer-wenn-du","title":"IMMER wenn du:","text":"
  1. Neue Funktionen erstellst \u2192 Unit Test
  2. Neue API-Endpoints hinzufuegst \u2192 Handler Test
  3. Bugs fixst \u2192 Regression Test (der Bug sollte nie wieder auftreten)
  4. Bestehenden Code aenderst \u2192 Bestehende Tests anpassen
"},{"location":"development/testing/#test-struktur","title":"Test-Struktur","text":""},{"location":"development/testing/#go-tests-consent-service","title":"Go Tests (Consent Service)","text":"

Speicherort: Im gleichen Verzeichnis wie der Code

internal/\n\u251c\u2500\u2500 services/\n\u2502   \u251c\u2500\u2500 auth_service.go\n\u2502   \u2514\u2500\u2500 auth_service_test.go    \u2190 Test hier\n\u251c\u2500\u2500 handlers/\n\u2502   \u251c\u2500\u2500 handlers.go\n\u2502   \u2514\u2500\u2500 handlers_test.go        \u2190 Test hier\n\u2514\u2500\u2500 middleware/\n    \u251c\u2500\u2500 auth.go\n    \u2514\u2500\u2500 middleware_test.go      \u2190 Test hier\n

Test-Namenskonvention:

func TestFunctionName_Scenario_ExpectedResult(t *testing.T)\n\n// Beispiele:\nfunc TestHashPassword_ValidPassword_ReturnsHash(t *testing.T)\nfunc TestLogin_InvalidCredentials_Returns401(t *testing.T)\nfunc TestCreateDocument_MissingTitle_ReturnsError(t *testing.T)\n

Test-Template:

func TestFunctionName(t *testing.T) {\n    // Arrange\n    service := &MyService{}\n    input := \"test-input\"\n\n    // Act\n    result, err := service.DoSomething(input)\n\n    // Assert\n    if err != nil {\n        t.Fatalf(\"Expected no error, got %v\", err)\n    }\n    if result != expected {\n        t.Errorf(\"Expected %v, got %v\", expected, result)\n    }\n}\n

Table-Driven Tests bevorzugen:

func TestValidateEmail(t *testing.T) {\n    tests := []struct {\n        name     string\n        email    string\n        expected bool\n    }{\n        {\"valid email\", \"test@example.com\", true},\n        {\"missing @\", \"testexample.com\", false},\n        {\"empty\", \"\", false},\n    }\n\n    for _, tt := range tests {\n        t.Run(tt.name, func(t *testing.T) {\n            result := ValidateEmail(tt.email)\n            if result != tt.expected {\n                t.Errorf(\"Expected %v, got %v\", tt.expected, result)\n            }\n        })\n    }\n}\n
"},{"location":"development/testing/#python-tests-backend","title":"Python Tests (Backend)","text":"

Speicherort: /backend/tests/

backend/\n\u251c\u2500\u2500 consent_client.py\n\u251c\u2500\u2500 gdpr_api.py\n\u2514\u2500\u2500 tests/\n    \u251c\u2500\u2500 __init__.py\n    \u251c\u2500\u2500 test_consent_client.py  \u2190 Tests fuer consent_client.py\n    \u2514\u2500\u2500 test_gdpr_api.py        \u2190 Tests fuer gdpr_api.py\n

Test-Namenskonvention:

class TestClassName:\n    def test_method_scenario_expected_result(self):\n        pass\n\n# Beispiele:\nclass TestConsentClient:\n    def test_check_consent_valid_token_returns_status(self):\n        pass\n\n    def test_check_consent_expired_token_raises_error(self):\n        pass\n

Test-Template:

import pytest\nfrom unittest.mock import AsyncMock, patch, MagicMock\n\nclass TestMyFeature:\n    def test_sync_function(self):\n        # Arrange\n        input_data = \"test\"\n\n        # Act\n        result = my_function(input_data)\n\n        # Assert\n        assert result == expected\n\n    @pytest.mark.asyncio\n    async def test_async_function(self):\n        # Arrange\n        client = MyClient()\n\n        # Act\n        with patch(\"httpx.AsyncClient\") as mock:\n            mock_instance = AsyncMock()\n            mock.return_value = mock_instance\n            result = await client.fetch_data()\n\n        # Assert\n        assert result is not None\n
"},{"location":"development/testing/#test-kategorien","title":"Test-Kategorien","text":""},{"location":"development/testing/#1-unit-tests-hoechste-prioritaet","title":"1. Unit Tests (Hoechste Prioritaet)","text":""},{"location":"development/testing/#2-integration-tests","title":"2. Integration Tests","text":""},{"location":"development/testing/#3-security-tests","title":"3. Security Tests","text":""},{"location":"development/testing/#checkliste-vor-abschluss","title":"Checkliste vor Abschluss","text":"

Vor dem Abschluss einer Aufgabe:

"},{"location":"development/testing/#tests-ausfuehren","title":"Tests ausfuehren","text":"
# Go - Alle Tests\ncd consent-service && go test -v ./...\n\n# Go - Mit Coverage\ncd consent-service && go test -cover ./...\n\n# Python - Alle Tests\ncd backend && source venv/bin/activate && pytest -v\n\n# Python - Mit Coverage\ncd backend && pytest --cov=. --cov-report=html\n
"},{"location":"development/testing/#beispiel-vollstaendiger-test-workflow","title":"Beispiel: Vollstaendiger Test-Workflow","text":"

Wenn du z.B. eine neue GetUserStats() Funktion im Go Service hinzufuegst:

  1. Funktion schreiben in internal/services/stats_service.go
  2. Test erstellen in internal/services/stats_service_test.go:
    func TestGetUserStats_ValidUser_ReturnsStats(t *testing.T) {...}\nfunc TestGetUserStats_InvalidUser_ReturnsError(t *testing.T) {...}\nfunc TestGetUserStats_NoConsents_ReturnsEmptyStats(t *testing.T) {...}\n
  3. Tests ausfuehren: go test -v ./internal/services/...
  4. Dokumentation aktualisieren (siehe Dokumentation)
"},{"location":"getting-started/environment-setup/","title":"Entwickler-Guide: Umgebungs-Setup","text":"

Dieser Guide erkl\u00e4rt das t\u00e4gliche Arbeiten mit den Dev/Staging/Prod-Umgebungen.

"},{"location":"getting-started/environment-setup/#schnellstart","title":"Schnellstart","text":"
# 1. Wechsle in das Projektverzeichnis\ncd /Users/benjaminadmin/Projekte/breakpilot-pwa\n\n# 2. Starte die Entwicklungsumgebung\n./scripts/start.sh dev\n\n# 3. Pr\u00fcfe den Status\n./scripts/status.sh\n
"},{"location":"getting-started/environment-setup/#taglicher-workflow","title":"T\u00e4glicher Workflow","text":""},{"location":"getting-started/environment-setup/#morgens-entwicklung-starten","title":"Morgens: Entwicklung starten","text":"
# Auf develop-Branch wechseln\ngit checkout develop\n\n# Neueste \u00c4nderungen holen (falls Remote konfiguriert)\ngit pull origin develop\n\n# Umgebung starten\n./scripts/start.sh dev\n
"},{"location":"getting-started/environment-setup/#wahrend-der-arbeit","title":"W\u00e4hrend der Arbeit","text":"
# Logs eines Services anzeigen\ndocker compose logs -f backend\n\n# Service neustarten\ndocker compose restart backend\n\n# Status pr\u00fcfen\n./scripts/status.sh\n
"},{"location":"getting-started/environment-setup/#anderungen-committen","title":"\u00c4nderungen committen","text":"
# \u00c4nderungen anzeigen\ngit status\n\n# Dateien hinzuf\u00fcgen\ngit add .\n\n# Commit erstellen\ngit commit -m \"Feature: Beschreibung der \u00c4nderung\"\n
"},{"location":"getting-started/environment-setup/#abends-umgebung-stoppen","title":"Abends: Umgebung stoppen","text":"
./scripts/stop.sh dev\n
"},{"location":"getting-started/environment-setup/#umgebung-wechseln","title":"Umgebung wechseln","text":""},{"location":"getting-started/environment-setup/#von-dev-zu-staging","title":"Von Dev zu Staging","text":"
# Stoppe Dev\n./scripts/stop.sh dev\n\n# Starte Staging\n./scripts/start.sh staging\n
"},{"location":"getting-started/environment-setup/#zuruck-zu-dev","title":"Zur\u00fcck zu Dev","text":"
./scripts/stop.sh staging\n./scripts/start.sh dev\n
"},{"location":"getting-started/environment-setup/#code-promoten","title":"Code promoten","text":""},{"location":"getting-started/environment-setup/#dev-staging-nach-erfolgreichem-test","title":"Dev \u2192 Staging (nach erfolgreichem Test)","text":"
# Stelle sicher, dass alle \u00c4nderungen committet sind\ngit status\n\n# Promote zu Staging\n./scripts/promote.sh dev-to-staging\n\n# Push zu Remote (falls konfiguriert)\ngit push origin staging\n
"},{"location":"getting-started/environment-setup/#staging-production-release","title":"Staging \u2192 Production (Release)","text":"
# Nur nach vollst\u00e4ndigem Test auf Staging!\n./scripts/promote.sh staging-to-prod\n\n# Push zu Remote\ngit push origin main\n
"},{"location":"getting-started/environment-setup/#nutzliche-befehle","title":"N\u00fctzliche Befehle","text":""},{"location":"getting-started/environment-setup/#docker","title":"Docker","text":"
# Alle Container anzeigen\ndocker compose ps\n\n# Logs folgen\ndocker compose logs -f [service]\n\n# In Container einsteigen\ndocker compose exec backend bash\ndocker compose exec postgres psql -U breakpilot -d breakpilot_dev\n\n# Container neustarten\ndocker compose restart [service]\n\n# Alle Container stoppen und entfernen\ndocker compose down\n\n# Mit Volumes l\u00f6schen (VORSICHT!)\ndocker compose down -v\n
"},{"location":"getting-started/environment-setup/#git","title":"Git","text":"
# Aktuellen Branch anzeigen\ngit branch --show-current\n\n# Alle Branches anzeigen\ngit branch -v\n\n# \u00c4nderungen zwischen Branches anzeigen\ngit diff develop..staging\n
"},{"location":"getting-started/environment-setup/#datenbank","title":"Datenbank","text":"
# Direkt mit PostgreSQL verbinden (Dev)\ndocker compose exec postgres psql -U breakpilot -d breakpilot_dev\n\n# Backup erstellen\n./scripts/backup.sh\n\n# Backup wiederherstellen\n./scripts/restore.sh backup-file.sql.gz\n
"},{"location":"getting-started/environment-setup/#haufige-probleme","title":"H\u00e4ufige Probleme","text":""},{"location":"getting-started/environment-setup/#port-already-in-use","title":"\"Port already in use\"","text":"

Ein anderer Prozess oder Container verwendet den Port.

# Laufende Container pr\u00fcfen\ndocker ps\n\n# Alte Container stoppen\ndocker compose down\n\n# Prozess auf Port finden (z.B. 8000)\nlsof -i :8000\n
"},{"location":"getting-started/environment-setup/#container-startet-nicht","title":"Container startet nicht","text":"
# Logs pr\u00fcfen\ndocker compose logs backend\n\n# Container neu bauen\ndocker compose build backend\ndocker compose up -d backend\n
"},{"location":"getting-started/environment-setup/#datenbank-verbindungsfehler","title":"Datenbank-Verbindungsfehler","text":"
# Pr\u00fcfen ob PostgreSQL l\u00e4uft\ndocker compose ps postgres\n\n# PostgreSQL-Logs pr\u00fcfen\ndocker compose logs postgres\n\n# Neustart\ndocker compose restart postgres\n
"},{"location":"getting-started/environment-setup/#falsche-umgebung-aktiv","title":"Falsche Umgebung aktiv","text":"
# Status pr\u00fcfen\n./scripts/status.sh\n\n# Auf richtige Umgebung wechseln\n./scripts/env-switch.sh dev\n
"},{"location":"getting-started/environment-setup/#umgebungs-dateien","title":"Umgebungs-Dateien","text":"Datei Beschreibung Im Git? .env Aktive Umgebung Nein .env.dev Development Werte Ja .env.staging Staging Werte Ja .env.prod Production Werte NEIN .env.example Template Ja"},{"location":"getting-started/environment-setup/#ports-ubersicht","title":"Ports \u00dcbersicht","text":""},{"location":"getting-started/environment-setup/#development","title":"Development","text":"Service Port URL Backend 8000 http://localhost:8000 Website 3000 http://localhost:3000 Consent Service 8081 http://localhost:8081 PostgreSQL 5432 localhost:5432 Mailpit UI 8025 http://localhost:8025 MinIO Console 9001 http://localhost:9001"},{"location":"getting-started/environment-setup/#staging","title":"Staging","text":"Service Port URL Backend 8001 http://localhost:8001 PostgreSQL 5433 localhost:5433 Mailpit UI 8026 http://localhost:8026 MinIO Console 9003 http://localhost:9003"},{"location":"getting-started/environment-setup/#hilfe","title":"Hilfe","text":"
# Status und \u00dcbersicht\n./scripts/status.sh\n\n# Script-Hilfe\n./scripts/env-switch.sh --help\n./scripts/promote.sh --help\n
"},{"location":"getting-started/environment-setup/#verwandte-dokumentation","title":"Verwandte Dokumentation","text":""},{"location":"getting-started/mac-mini-setup/","title":"Mac Mini Headless Setup - Vollst\u00e4ndig Automatisch","text":""},{"location":"getting-started/mac-mini-setup/#verbindungsdaten","title":"Verbindungsdaten","text":""},{"location":"getting-started/mac-mini-setup/#nach-neustart-alles-startet-automatisch","title":"Nach Neustart - Alles startet automatisch!","text":"Service Auto-Start Port SSH Ja 22 Docker Desktop Ja - Docker Container Ja (nach ~2 Min) 8000, 8081, etc. Ollama Server Ja 11434 Unity Hub Ja - VS Code Ja -

Keine Aktion n\u00f6tig nach Neustart! Einfach 2-3 Minuten warten.

"},{"location":"getting-started/mac-mini-setup/#status-prufen","title":"Status pr\u00fcfen","text":"
./scripts/mac-mini/status.sh\n
"},{"location":"getting-started/mac-mini-setup/#services-ports","title":"Services & Ports","text":"Service Port URL Backend API 8000 http://192.168.178.100:8000/admin Consent Service 8081 - PostgreSQL 5432 - Valkey/Redis 6379 - MinIO 9000/9001 http://192.168.178.100:9001 Mailpit 8025 http://192.168.178.100:8025 Ollama 11434 http://192.168.178.100:11434/api/tags Dokumentation 8008 http://192.168.178.100:8008"},{"location":"getting-started/mac-mini-setup/#llm-modelle","title":"LLM Modelle","text":""},{"location":"getting-started/mac-mini-setup/#scripts-auf-macbook","title":"Scripts (auf MacBook)","text":"
./scripts/mac-mini/status.sh   # Status pr\u00fcfen\n./scripts/mac-mini/sync.sh     # Code synchronisieren\n./scripts/mac-mini/docker.sh   # Docker-Befehle\n./scripts/mac-mini/backup.sh   # Backup erstellen\n
"},{"location":"getting-started/mac-mini-setup/#docker-befehle","title":"Docker-Befehle","text":"
./scripts/mac-mini/docker.sh ps           # Container anzeigen\n./scripts/mac-mini/docker.sh logs backend # Logs\n./scripts/mac-mini/docker.sh restart      # Neustart\n./scripts/mac-mini/docker.sh build        # Image bauen\n
"},{"location":"getting-started/mac-mini-setup/#launchagents-auto-start","title":"LaunchAgents (Auto-Start)","text":"

Pfad auf Mac Mini: ~/Library/LaunchAgents/

Agent Funktion com.docker.desktop.plist Docker Desktop com.breakpilot.docker-containers.plist Container Auto-Start com.ollama.serve.plist Ollama Server com.unity.hub.plist Unity Hub com.microsoft.vscode.plist VS Code"},{"location":"getting-started/mac-mini-setup/#projekt-pfade","title":"Projekt-Pfade","text":""},{"location":"getting-started/mac-mini-setup/#troubleshooting","title":"Troubleshooting","text":""},{"location":"getting-started/mac-mini-setup/#docker-onboarding-erscheint-wieder","title":"Docker Onboarding erscheint wieder","text":"

Docker-Einstellungen sind gesichert in ~/docker-settings-backup/

# Wiederherstellen:\ncp -r ~/docker-settings-backup/* ~/Library/Group\\ Containers/group.com.docker/\n
"},{"location":"getting-started/mac-mini-setup/#container-starten-nicht-automatisch","title":"Container starten nicht automatisch","text":"

Log pr\u00fcfen:

ssh benjaminadmin@192.168.178.100 \"cat /tmp/docker-autostart.log\"\n

Manuell starten:

./scripts/mac-mini/docker.sh up\n
"},{"location":"getting-started/mac-mini-setup/#ssh-nicht-erreichbar","title":"SSH nicht erreichbar","text":""},{"location":"services/agent-core/","title":"Breakpilot Agent Core","text":"

Multi-Agent Architecture Infrastructure fuer Breakpilot.

"},{"location":"services/agent-core/#uebersicht","title":"Uebersicht","text":"

Das agent-core Modul stellt die gemeinsame Infrastruktur fuer Breakpilots Multi-Agent-System bereit:

"},{"location":"services/agent-core/#architektur","title":"Architektur","text":"
\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502                     Breakpilot Services                          \u2502\n\u2502  \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510  \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510  \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510  \u2502\n\u2502  \u2502Voice Service\u2502  \u2502Klausur Svc  \u2502  \u2502  Admin-v2 / AlertAgent  \u2502  \u2502\n\u2502  \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2518  \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2518  \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518  \u2502\n\u2502         \u2502                \u2502                      \u2502                \u2502\n\u2502         \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518                \u2502\n\u2502                          \u2502                                       \u2502\n\u2502  \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u25bc\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510  \u2502\n\u2502  \u2502                    Agent Core                              \u2502  \u2502\n\u2502  \u2502  \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510  \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510  \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510  \u2502  \u2502\n\u2502  \u2502  \u2502   Sessions  \u2502  \u2502Shared Brain \u2502  \u2502   Orchestrator    \u2502  \u2502  \u2502\n\u2502  \u2502  \u2502 - Manager   \u2502  \u2502 - Memory    \u2502  \u2502 - Message Bus     \u2502  \u2502  \u2502\n\u2502  \u2502  \u2502 - Heartbeat \u2502  \u2502 - Context   \u2502  \u2502 - Supervisor      \u2502  \u2502  \u2502\n\u2502  \u2502  \u2502 - Checkpoint\u2502  \u2502 - Knowledge \u2502  \u2502 - Task Router     \u2502  \u2502  \u2502\n\u2502  \u2502  \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518  \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518  \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518  \u2502  \u2502\n\u2502  \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518  \u2502\n\u2502                          \u2502                                       \u2502\n\u2502  \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u25bc\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510  \u2502\n\u2502  \u2502                   Infrastructure                           \u2502  \u2502\n\u2502  \u2502     Valkey (Redis)          PostgreSQL          Qdrant     \u2502  \u2502\n\u2502  \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518  \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n
"},{"location":"services/agent-core/#verzeichnisstruktur","title":"Verzeichnisstruktur","text":"
agent-core/\n\u251c\u2500\u2500 __init__.py              # Modul-Exports\n\u251c\u2500\u2500 README.md                # Diese Datei\n\u251c\u2500\u2500 requirements.txt         # Python-Abhaengigkeiten\n\u251c\u2500\u2500 pytest.ini               # Test-Konfiguration\n\u2502\n\u251c\u2500\u2500 soul/                    # Agent SOUL Files (Persoenlichkeiten)\n\u2502   \u251c\u2500\u2500 tutor-agent.soul.md\n\u2502   \u251c\u2500\u2500 grader-agent.soul.md\n\u2502   \u251c\u2500\u2500 quality-judge.soul.md\n\u2502   \u251c\u2500\u2500 alert-agent.soul.md\n\u2502   \u2514\u2500\u2500 orchestrator.soul.md\n\u2502\n\u251c\u2500\u2500 brain/                   # Shared Brain Implementation\n\u2502   \u251c\u2500\u2500 __init__.py\n\u2502   \u251c\u2500\u2500 memory_store.py      # Langzeit-Gedaechtnis\n\u2502   \u251c\u2500\u2500 context_manager.py   # Konversations-Kontext\n\u2502   \u2514\u2500\u2500 knowledge_graph.py   # Entity-Beziehungen\n\u2502\n\u251c\u2500\u2500 sessions/                # Session Management\n\u2502   \u251c\u2500\u2500 __init__.py\n\u2502   \u251c\u2500\u2500 session_manager.py   # Session-Lifecycle\n\u2502   \u251c\u2500\u2500 heartbeat.py         # Liveness-Monitoring\n\u2502   \u2514\u2500\u2500 checkpoint.py        # Recovery-Checkpoints\n\u2502\n\u251c\u2500\u2500 orchestrator/            # Multi-Agent Orchestration\n\u2502   \u251c\u2500\u2500 __init__.py\n\u2502   \u251c\u2500\u2500 message_bus.py       # Inter-Agent Kommunikation\n\u2502   \u251c\u2500\u2500 supervisor.py        # Agent-Ueberwachung\n\u2502   \u2514\u2500\u2500 task_router.py       # Intent-basiertes Routing\n\u2502\n\u2514\u2500\u2500 tests/                   # Unit Tests\n    \u251c\u2500\u2500 conftest.py\n    \u251c\u2500\u2500 test_session_manager.py\n    \u251c\u2500\u2500 test_heartbeat.py\n    \u251c\u2500\u2500 test_message_bus.py\n    \u251c\u2500\u2500 test_memory_store.py\n    \u2514\u2500\u2500 test_task_router.py\n
"},{"location":"services/agent-core/#komponenten","title":"Komponenten","text":""},{"location":"services/agent-core/#1-session-management","title":"1. Session Management","text":"

Verwaltet Agent-Sessions mit State-Machine und Recovery-Faehigkeiten.

from agent_core.sessions import SessionManager, AgentSession\n\n# Session Manager erstellen\nmanager = SessionManager(\n    redis_client=redis,\n    db_pool=pg_pool,\n    namespace=\"breakpilot\"\n)\n\n# Session erstellen\nsession = await manager.create_session(\n    agent_type=\"tutor-agent\",\n    user_id=\"user-123\",\n    context={\"subject\": \"math\"}\n)\n\n# Checkpoint setzen\nsession.checkpoint(\"task_started\", {\"task_id\": \"abc\"})\n\n# Session beenden\nsession.complete({\"result\": \"success\"})\n

Session States:

"},{"location":"services/agent-core/#2-heartbeat-monitoring","title":"2. Heartbeat Monitoring","text":"

Ueberwacht Agent-Liveness und triggert Recovery bei Timeout.

from agent_core.sessions import HeartbeatMonitor, HeartbeatClient\n\n# Monitor starten\nmonitor = HeartbeatMonitor(\n    timeout_seconds=30,\n    check_interval_seconds=5,\n    max_missed_beats=3\n)\nawait monitor.start_monitoring()\n\n# Agent registrieren\nmonitor.register(\"agent-1\", \"tutor-agent\")\n\n# Heartbeat senden\nasync with HeartbeatClient(\"agent-1\", monitor) as client:\n    # Agent-Arbeit...\n    pass\n
"},{"location":"services/agent-core/#3-memory-store","title":"3. Memory Store","text":"

Langzeit-Gedaechtnis fuer Agents mit TTL und Access-Tracking.

from agent_core.brain import MemoryStore\n\nstore = MemoryStore(redis_client=redis, db_pool=pg_pool)\n\n# Erinnerung speichern\nawait store.remember(\n    key=\"evaluation:math:student-1\",\n    value={\"score\": 85, \"feedback\": \"Gut gemacht!\"},\n    agent_id=\"grader-agent\",\n    ttl_days=30\n)\n\n# Erinnerung abrufen\nresult = await store.recall(\"evaluation:math:student-1\")\n\n# Nach Pattern suchen\nsimilar = await store.search(\"evaluation:math:*\")\n
"},{"location":"services/agent-core/#4-context-manager","title":"4. Context Manager","text":"

Verwaltet Konversationskontext mit automatischer Komprimierung.

from agent_core.brain import ContextManager, MessageRole\n\nctx_manager = ContextManager(redis_client=redis)\n\n# Kontext erstellen\ncontext = ctx_manager.create_context(\n    session_id=\"session-123\",\n    system_prompt=\"Du bist ein hilfreicher Tutor...\",\n    max_messages=50\n)\n\n# Nachrichten hinzufuegen\ncontext.add_message(MessageRole.USER, \"Was ist Photosynthese?\")\ncontext.add_message(MessageRole.ASSISTANT, \"Photosynthese ist...\")\n\n# Fuer LLM API formatieren\nmessages = context.get_messages_for_llm()\n
"},{"location":"services/agent-core/#5-message-bus","title":"5. Message Bus","text":"

Inter-Agent Kommunikation via Redis Pub/Sub.

from agent_core.orchestrator import MessageBus, AgentMessage, MessagePriority\n\nbus = MessageBus(redis_client=redis)\nawait bus.start()\n\n# Handler registrieren\nasync def handle_message(msg):\n    return {\"status\": \"processed\"}\n\nawait bus.subscribe(\"grader-agent\", handle_message)\n\n# Nachricht senden\nawait bus.publish(AgentMessage(\n    sender=\"orchestrator\",\n    receiver=\"grader-agent\",\n    message_type=\"grade_request\",\n    payload={\"exam_id\": \"exam-1\"},\n    priority=MessagePriority.HIGH\n))\n\n# Request-Response Pattern\nresponse = await bus.request(message, timeout=30.0)\n
"},{"location":"services/agent-core/#6-agent-supervisor","title":"6. Agent Supervisor","text":"

Ueberwacht und koordiniert alle Agents.

from agent_core.orchestrator import AgentSupervisor, RestartPolicy\n\nsupervisor = AgentSupervisor(message_bus=bus, heartbeat_monitor=monitor)\n\n# Agent registrieren\nawait supervisor.register_agent(\n    agent_id=\"tutor-1\",\n    agent_type=\"tutor-agent\",\n    restart_policy=RestartPolicy.ON_FAILURE,\n    max_restarts=3,\n    capacity=10\n)\n\n# Agent starten\nawait supervisor.start_agent(\"tutor-1\")\n\n# Load Balancing\navailable = supervisor.get_available_agent(\"tutor-agent\")\n
"},{"location":"services/agent-core/#7-task-router","title":"7. Task Router","text":"

Intent-basiertes Routing mit Fallback-Ketten.

from agent_core.orchestrator import TaskRouter, RoutingRule, RoutingStrategy\n\nrouter = TaskRouter(supervisor=supervisor)\n\n# Eigene Regel hinzufuegen\nrouter.add_rule(RoutingRule(\n    intent_pattern=\"learning_*\",\n    agent_type=\"tutor-agent\",\n    priority=10,\n    fallback_agent=\"orchestrator\"\n))\n\n# Task routen\nresult = await router.route(\n    intent=\"learning_math\",\n    context={\"grade\": 10},\n    strategy=RoutingStrategy.LEAST_LOADED\n)\n\nif result.success:\n    print(f\"Routed to {result.agent_id}\")\n
"},{"location":"services/agent-core/#soul-files","title":"SOUL Files","text":"

SOUL-Dateien definieren die Persoenlichkeit und Verhaltensregeln jedes Agents.

Agent SOUL File Verantwortlichkeit TutorAgent tutor-agent.soul.md Lernbegleitung, Fragen beantworten GraderAgent grader-agent.soul.md Klausur-Korrektur, Bewertung QualityJudge quality-judge.soul.md BQAS Qualitaetspruefung AlertAgent alert-agent.soul.md Monitoring, Benachrichtigungen Orchestrator orchestrator.soul.md Task-Koordination"},{"location":"services/agent-core/#datenbank-schema","title":"Datenbank-Schema","text":""},{"location":"services/agent-core/#agent_sessions","title":"agent_sessions","text":"
CREATE TABLE agent_sessions (\n    id UUID PRIMARY KEY,\n    agent_type VARCHAR(50) NOT NULL,\n    user_id UUID REFERENCES users(id),\n    state VARCHAR(20) NOT NULL DEFAULT 'active',\n    context JSONB DEFAULT '{}',\n    checkpoints JSONB DEFAULT '[]',\n    created_at TIMESTAMPTZ DEFAULT NOW(),\n    updated_at TIMESTAMPTZ DEFAULT NOW(),\n    last_heartbeat TIMESTAMPTZ DEFAULT NOW()\n);\n
"},{"location":"services/agent-core/#agent_memory","title":"agent_memory","text":"
CREATE TABLE agent_memory (\n    id UUID PRIMARY KEY,\n    namespace VARCHAR(100) NOT NULL,\n    key VARCHAR(500) NOT NULL,\n    value JSONB NOT NULL,\n    agent_id VARCHAR(50) NOT NULL,\n    access_count INTEGER DEFAULT 0,\n    created_at TIMESTAMPTZ DEFAULT NOW(),\n    expires_at TIMESTAMPTZ,\n    UNIQUE(namespace, key)\n);\n
"},{"location":"services/agent-core/#agent_messages","title":"agent_messages","text":"
CREATE TABLE agent_messages (\n    id UUID PRIMARY KEY,\n    sender VARCHAR(50) NOT NULL,\n    receiver VARCHAR(50) NOT NULL,\n    message_type VARCHAR(50) NOT NULL,\n    payload JSONB NOT NULL,\n    priority INTEGER DEFAULT 1,\n    correlation_id UUID,\n    created_at TIMESTAMPTZ DEFAULT NOW()\n);\n
"},{"location":"services/agent-core/#integration","title":"Integration","text":""},{"location":"services/agent-core/#mit-voice-service","title":"Mit Voice-Service","text":"
from services.enhanced_task_orchestrator import EnhancedTaskOrchestrator\n\norchestrator = EnhancedTaskOrchestrator(\n    redis_client=redis,\n    db_pool=pg_pool\n)\n\nawait orchestrator.start()\n\n# Session fuer Voice-Interaktion\nsession = await orchestrator.create_session(\n    voice_session_id=\"voice-123\",\n    user_id=\"teacher-1\"\n)\n\n# Task verarbeiten (nutzt Multi-Agent wenn noetig)\nawait orchestrator.process_task(task)\n
"},{"location":"services/agent-core/#mit-bqas","title":"Mit BQAS","text":"
from bqas.quality_judge_agent import QualityJudgeAgent\n\njudge = QualityJudgeAgent(\n    message_bus=bus,\n    memory_store=memory\n)\n\nawait judge.start()\n\n# Direkte Evaluation\nresult = await judge.evaluate(\n    response=\"Der Satz des Pythagoras...\",\n    task_type=\"learning_math\",\n    context={\"user_input\": \"Was ist Pythagoras?\"}\n)\n\nif result[\"verdict\"] == \"production_ready\":\n    # Response ist OK\n    pass\n
"},{"location":"services/agent-core/#tests","title":"Tests","text":"
# In agent-core Verzeichnis\ncd agent-core\n\n# Alle Tests ausfuehren\npytest -v\n\n# Mit Coverage\npytest --cov=. --cov-report=html\n\n# Einzelnes Test-Modul\npytest tests/test_session_manager.py -v\n\n# Async-Tests\npytest tests/test_message_bus.py -v\n
"},{"location":"services/agent-core/#metriken","title":"Metriken","text":"

Das Agent-Core exportiert folgende Metriken:

Metrik Beschreibung agent_session_duration_seconds Dauer von Agent-Sessions agent_heartbeat_delay_seconds Zeit seit letztem Heartbeat agent_message_latency_ms Latenz der Inter-Agent Kommunikation agent_memory_access_total Memory-Zugriffe pro Agent agent_error_total Fehler pro Agent-Typ"},{"location":"services/agent-core/#naechste-schritte","title":"Naechste Schritte","text":"
  1. Migration ausfuehren: psql -f backend/migrations/add_agent_core_tables.sql
  2. Voice-Service erweitern: Enhanced Orchestrator aktivieren
  3. BQAS integrieren: Quality Judge Agent starten
  4. Monitoring aufsetzen: Metriken in Grafana integrieren
"},{"location":"services/ai-compliance-sdk/","title":"AI Compliance SDK","text":"

Das AI Compliance SDK ist ein Go-basierter Service zur Compliance-Bewertung von KI-Anwendungsf\u00e4llen.

"},{"location":"services/ai-compliance-sdk/#ubersicht","title":"\u00dcbersicht","text":"Eigenschaft Wert Port 8090 Framework Go (Gin) Datenbank PostgreSQL Vector DB Qdrant (Legal RAG)"},{"location":"services/ai-compliance-sdk/#kernkomponenten","title":"Kernkomponenten","text":"
\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502                              UCCA System                                      \u2502\n\u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n\u2502                                                                               \u2502\n\u2502   \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510    \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510    \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510                  \u2502\n\u2502   \u2502   Frontend   \u2502\u2500\u2500\u2500>\u2502   SDK API    \u2502\u2500\u2500\u2500>\u2502  PostgreSQL  \u2502                  \u2502\n\u2502   \u2502  (Next.js)   \u2502    \u2502    (Go)      \u2502    \u2502   Database   \u2502                  \u2502\n\u2502   \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518    \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518    \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518                  \u2502\n\u2502                              \u2502                                               \u2502\n\u2502         \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510                         \u2502\n\u2502         \u2502                    \u2502                    \u2502                         \u2502\n\u2502         \u25bc                    \u25bc                    \u25bc                         \u2502\n\u2502   \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510    \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510    \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510                  \u2502\n\u2502   \u2502 Policy       \u2502    \u2502 Escalation   \u2502    \u2502  Legal RAG   \u2502                  \u2502\n\u2502   \u2502 Engine       \u2502    \u2502 Workflow     \u2502    \u2502  (Qdrant)    \u2502                  \u2502\n\u2502   \u2502 (45 Regeln)  \u2502    \u2502 (E0-E3)      \u2502    \u2502 2,274 Chunks \u2502                  \u2502\n\u2502   \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518    \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518    \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518                  \u2502\n\u2502                                                                               \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n
"},{"location":"services/ai-compliance-sdk/#features","title":"Features","text":""},{"location":"services/ai-compliance-sdk/#kernprinzip","title":"Kernprinzip","text":"

\"LLM ist NICHT die Quelle der Wahrheit. Wahrheit = Regeln + Evidenz. LLM = \u00dcbersetzer + Subsumptionshelfer\"

Das System folgt einem strikten Human-in-the-Loop Ansatz:

  1. Deterministische Regeln treffen alle Compliance-Entscheidungen
  2. LLM erkl\u00e4rt nur Ergebnisse, \u00fcberschreibt nie BLOCK-Entscheidungen
  3. Menschen (DSB, Legal) treffen finale Entscheidungen bei kritischen F\u00e4llen
"},{"location":"services/ai-compliance-sdk/#api-endpunkte","title":"API-Endpunkte","text":""},{"location":"services/ai-compliance-sdk/#assessment","title":"Assessment","text":"Method Endpoint Beschreibung POST /sdk/v1/ucca/assess Assessment erstellen GET /sdk/v1/ucca/assessments Assessments auflisten GET /sdk/v1/ucca/assessments/:id Assessment abrufen POST /sdk/v1/ucca/assessments/:id/explain LLM-Erkl\u00e4rung generieren"},{"location":"services/ai-compliance-sdk/#eskalation","title":"Eskalation","text":"Method Endpoint Beschreibung GET /sdk/v1/ucca/escalations Eskalationen auflisten POST /sdk/v1/ucca/escalations/:id/decide Entscheidung treffen"},{"location":"services/ai-compliance-sdk/#obligations-framework","title":"Obligations Framework","text":"Method Endpoint Beschreibung POST /sdk/v1/ucca/obligations/assess Pflichten-Assessment POST /sdk/v1/ucca/obligations/export/memo PDF-Export"},{"location":"services/ai-compliance-sdk/#weiterfuhrende-dokumentation","title":"Weiterf\u00fchrende Dokumentation","text":""},{"location":"services/ai-compliance-sdk/#tests","title":"Tests","text":"
cd ai-compliance-sdk\ngo test -v ./...\n\n# Mit Coverage\ngo test -cover ./...\n
"},{"location":"services/ai-compliance-sdk/ARCHITECTURE/","title":"UCCA - Use-Case Compliance & Feasibility Advisor","text":""},{"location":"services/ai-compliance-sdk/ARCHITECTURE/#systemarchitektur","title":"Systemarchitektur","text":""},{"location":"services/ai-compliance-sdk/ARCHITECTURE/#1-ubersicht","title":"1. \u00dcbersicht","text":"

Das UCCA-System ist ein deterministisches Compliance-Bewertungssystem f\u00fcr KI-Anwendungsf\u00e4lle. Es kombiniert regelbasierte Evaluation mit optionaler LLM-Erkl\u00e4rung und semantischer Rechtstextsuche.

\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502                              UCCA System                                      \u2502\n\u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n\u2502                                                                               \u2502\n\u2502   \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510    \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510    \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510                  \u2502\n\u2502   \u2502   Frontend   \u2502\u2500\u2500\u2500>\u2502   SDK API    \u2502\u2500\u2500\u2500>\u2502  PostgreSQL  \u2502                  \u2502\n\u2502   \u2502  (Next.js)   \u2502    \u2502    (Go)      \u2502    \u2502   Database   \u2502                  \u2502\n\u2502   \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518    \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518    \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518                  \u2502\n\u2502                              \u2502                                               \u2502\n\u2502         \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510                         \u2502\n\u2502         \u2502                    \u2502                    \u2502                         \u2502\n\u2502         \u25bc                    \u25bc                    \u25bc                         \u2502\n\u2502   \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510    \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510    \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510                  \u2502\n\u2502   \u2502 Policy       \u2502    \u2502 Escalation   \u2502    \u2502  Legal RAG   \u2502                  \u2502\n\u2502   \u2502 Engine       \u2502    \u2502 Workflow     \u2502    \u2502  (Qdrant)    \u2502                  \u2502\n\u2502   \u2502 (45 Regeln)  \u2502    \u2502 (E0-E3)      \u2502    \u2502 2,274 Chunks \u2502                  \u2502\n\u2502   \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518    \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518    \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518                  \u2502\n\u2502         \u2502                    \u2502                    \u2502                         \u2502\n\u2502         \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518                         \u2502\n\u2502                              \u2502                                               \u2502\n\u2502                              \u25bc                                               \u2502\n\u2502                       \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510                                       \u2502\n\u2502                       \u2502 LLM Provider \u2502                                       \u2502\n\u2502                       \u2502 (Ollama/API) \u2502                                       \u2502\n\u2502                       \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518                                       \u2502\n\u2502                                                                               \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n
"},{"location":"services/ai-compliance-sdk/ARCHITECTURE/#2-kernprinzip","title":"2. Kernprinzip","text":"

\"LLM ist NICHT die Quelle der Wahrheit. Wahrheit = Regeln + Evidenz. LLM = \u00dcbersetzer + Subsumptionshelfer\"

Das System folgt einem strikten Human-in-the-Loop Ansatz:

  1. Deterministische Regeln treffen alle Compliance-Entscheidungen
  2. LLM erkl\u00e4rt nur Ergebnisse, \u00fcberschreibt nie BLOCK-Entscheidungen
  3. Menschen (DSB, Legal) treffen finale Entscheidungen bei kritischen F\u00e4llen
"},{"location":"services/ai-compliance-sdk/ARCHITECTURE/#3-komponenten","title":"3. Komponenten","text":""},{"location":"services/ai-compliance-sdk/ARCHITECTURE/#31-policy-engine-internaluccarulesgo","title":"3.1 Policy Engine (internal/ucca/rules.go)","text":"

Die Policy Engine evaluiert Use-Cases gegen ~45 deterministische Regeln.

\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502                        Policy Engine                             \u2502\n\u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n\u2502                                                                   \u2502\n\u2502  UseCaseIntake \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500>  \u2502\n\u2502       \u2502                                                           \u2502\n\u2502       \u25bc                                                           \u2502\n\u2502  \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510 \u2502\n\u2502  \u2502 Regelkategorien (A-J)                                       \u2502 \u2502\n\u2502  \u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524 \u2502\n\u2502  \u2502 A. Datenklassifikation    \u2502 R-001 bis R-006 \u2502 6 Regeln    \u2502 \u2502\n\u2502  \u2502 B. Zweck & Kontext        \u2502 R-010 bis R-013 \u2502 4 Regeln    \u2502 \u2502\n\u2502  \u2502 C. Automatisierung        \u2502 R-020 bis R-025 \u2502 6 Regeln    \u2502 \u2502\n\u2502  \u2502 D. Training vs Nutzung    \u2502 R-030 bis R-035 \u2502 6 Regeln    \u2502 \u2502\n\u2502  \u2502 E. Speicherung            \u2502 R-040 bis R-042 \u2502 3 Regeln    \u2502 \u2502\n\u2502  \u2502 F. Hosting                \u2502 R-050 bis R-052 \u2502 3 Regeln    \u2502 \u2502\n\u2502  \u2502 G. Transparenz            \u2502 R-060 bis R-062 \u2502 3 Regeln    \u2502 \u2502\n\u2502  \u2502 H. Domain-spezifisch      \u2502 R-070 bis R-074 \u2502 5 Regeln    \u2502 \u2502\n\u2502  \u2502 I. Aggregation            \u2502 R-090 bis R-092 \u2502 3 Regeln    \u2502 \u2502\n\u2502  \u2502 J. Erkl\u00e4rung              \u2502 R-100          \u2502 1 Regel     \u2502 \u2502\n\u2502  \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518 \u2502\n\u2502       \u2502                                                           \u2502\n\u2502       \u25bc                                                           \u2502\n\u2502  AssessmentResult                                                 \u2502\n\u2502    \u251c\u2500\u2500 feasibility: YES | CONDITIONAL | NO                        \u2502\n\u2502    \u251c\u2500\u2500 risk_score: 0-100                                          \u2502\n\u2502    \u251c\u2500\u2500 risk_level: MINIMAL | LOW | MEDIUM | HIGH | CRITICAL       \u2502\n\u2502    \u251c\u2500\u2500 triggered_rules: []TriggeredRule                           \u2502\n\u2502    \u251c\u2500\u2500 required_controls: []RequiredControl                       \u2502\n\u2502    \u251c\u2500\u2500 recommended_architecture: []PatternRecommendation          \u2502\n\u2502    \u2514\u2500\u2500 forbidden_patterns: []ForbiddenPattern                     \u2502\n\u2502                                                                   \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n

Regel-Severities: - INFO: Informativ, kein Risiko-Impact - WARN: Warnung, erh\u00f6ht Risk Score - BLOCK: Kritisch, f\u00fchrt zu feasibility=NO

"},{"location":"services/ai-compliance-sdk/ARCHITECTURE/#32-escalation-workflow-internaluccaescalation_go","title":"3.2 Escalation Workflow (internal/ucca/escalation_*.go)","text":"

Das Eskalationssystem routet kritische Assessments zur menschlichen Pr\u00fcfung.

\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502                    Escalation Workflow                           \u2502\n\u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n\u2502                                                                   \u2502\n\u2502  AssessmentResult \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500> \u2502\n\u2502       \u2502                                                           \u2502\n\u2502       \u25bc                                                           \u2502\n\u2502  \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510 \u2502\n\u2502  \u2502              Escalation Level Determination                  \u2502 \u2502\n\u2502  \u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524 \u2502\n\u2502  \u2502                                                               \u2502 \u2502\n\u2502  \u2502  E0: Nur INFO-Regeln, Risk < 20                              \u2502 \u2502\n\u2502  \u2502      \u2192 Auto-Approve, keine menschliche Pr\u00fcfung               \u2502 \u2502\n\u2502  \u2502                                                               \u2502 \u2502\n\u2502  \u2502  E1: WARN-Regeln, Risk 20-39                                 \u2502 \u2502\n\u2502  \u2502      \u2192 Team-Lead Review (SLA: 24h)                           \u2502 \u2502\n\u2502  \u2502                                                               \u2502 \u2502\n\u2502  \u2502  E2: Art.9 Daten ODER Risk 40-59 ODER DSFA empfohlen         \u2502 \u2502\n\u2502  \u2502      \u2192 DSB Consultation (SLA: 8h)                            \u2502 \u2502\n\u2502  \u2502                                                               \u2502 \u2502\n\u2502  \u2502  E3: BLOCK-Regel ODER Risk \u226560 ODER Art.22 Risiko            \u2502 \u2502\n\u2502  \u2502      \u2192 DSB + Legal Review (SLA: 4h)                          \u2502 \u2502\n\u2502  \u2502                                                               \u2502 \u2502\n\u2502  \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518 \u2502\n\u2502       \u2502                                                           \u2502\n\u2502       \u25bc                                                           \u2502\n\u2502  \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510 \u2502\n\u2502  \u2502                    DSB Pool Assignment                        \u2502 \u2502\n\u2502  \u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524 \u2502\n\u2502  \u2502  Role          \u2502 Level \u2502 Max Concurrent \u2502 Auto-Assign        \u2502 \u2502\n\u2502  \u2502  \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 \u2502 \u2502\n\u2502  \u2502  team_lead     \u2502 E1    \u2502 10             \u2502 Round-Robin        \u2502 \u2502\n\u2502  \u2502  dsb           \u2502 E2,E3 \u2502 5              \u2502 Workload-Based     \u2502 \u2502\n\u2502  \u2502  legal         \u2502 E3    \u2502 3              \u2502 Workload-Based     \u2502 \u2502\n\u2502  \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518 \u2502\n\u2502       \u2502                                                           \u2502\n\u2502       \u25bc                                                           \u2502\n\u2502  Escalation Status Flow:                                          \u2502\n\u2502                                                                   \u2502\n\u2502  pending \u2192 assigned \u2192 in_review \u2192 approved/rejected/returned     \u2502\n\u2502                                                                   \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n
"},{"location":"services/ai-compliance-sdk/ARCHITECTURE/#33-legal-rag-internalllmlegal_raggo","title":"3.3 Legal RAG (internal/llm/legal_rag.go)","text":"

Semantische Suche in 19 EU-Regulierungen f\u00fcr kontextbasierte Erkl\u00e4rungen.

\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502                       Legal RAG System                           \u2502\n\u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n\u2502                                                                   \u2502\n\u2502  Explain Request \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500> \u2502\n\u2502       \u2502                                                           \u2502\n\u2502       \u25bc                                                           \u2502\n\u2502  \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510 \u2502\n\u2502  \u2502                   Qdrant Vector DB                            \u2502 \u2502\n\u2502  \u2502                   Collection: bp_legal_corpus                 \u2502 \u2502\n\u2502  \u2502                   2,274 Chunks, 1024-dim BGE-M3               \u2502 \u2502\n\u2502  \u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524 \u2502\n\u2502  \u2502                                                               \u2502 \u2502\n\u2502  \u2502  EU-Verordnungen:                                             \u2502 \u2502\n\u2502  \u2502  \u251c\u2500\u2500 DSGVO (128)       \u251c\u2500\u2500 AI Act (96)      \u251c\u2500\u2500 NIS2 (128)  \u2502 \u2502\n\u2502  \u2502  \u251c\u2500\u2500 CRA (256)         \u251c\u2500\u2500 Data Act (256)   \u251c\u2500\u2500 DSA (256)   \u2502 \u2502\n\u2502  \u2502  \u251c\u2500\u2500 DGA (32)          \u251c\u2500\u2500 EUCSA (32)       \u251c\u2500\u2500 DPF (714)   \u2502 \u2502\n\u2502  \u2502  \u2514\u2500\u2500 ...                                                      \u2502 \u2502\n\u2502  \u2502                                                               \u2502 \u2502\n\u2502  \u2502  Deutsche Gesetze:                                            \u2502 \u2502\n\u2502  \u2502  \u251c\u2500\u2500 TDDDG (1)         \u251c\u2500\u2500 SCC (32)         \u251c\u2500\u2500 ...         \u2502 \u2502\n\u2502  \u2502                                                               \u2502 \u2502\n\u2502  \u2502  BSI-Standards:                                               \u2502 \u2502\n\u2502  \u2502  \u251c\u2500\u2500 TR-03161-1 (6)    \u251c\u2500\u2500 TR-03161-2 (6)   \u251c\u2500\u2500 TR-03161-3  \u2502 \u2502\n\u2502  \u2502                                                               \u2502 \u2502\n\u2502  \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518 \u2502\n\u2502       \u2502                                                           \u2502\n\u2502       \u2502 Hybrid Search (Dense + Sparse)                           \u2502\n\u2502       \u2502 Re-Ranking (Cross-Encoder)                               \u2502\n\u2502       \u25bc                                                           \u2502\n\u2502  Top-K Relevant Passages \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500>  \u2502\n\u2502       \u2502                                                           \u2502\n\u2502       \u25bc                                                           \u2502\n\u2502  \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510 \u2502\n\u2502  \u2502                    LLM Explanation                            \u2502 \u2502\n\u2502  \u2502  Provider: Ollama (local) / Anthropic (fallback)             \u2502 \u2502\n\u2502  \u2502  Prompt: Assessment + Legal Context \u2192 Erkl\u00e4rung              \u2502 \u2502\n\u2502  \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518 \u2502\n\u2502                                                                   \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n
"},{"location":"services/ai-compliance-sdk/ARCHITECTURE/#4-datenfluss","title":"4. Datenfluss","text":""},{"location":"services/ai-compliance-sdk/ARCHITECTURE/#41-assessment-erstellung","title":"4.1 Assessment-Erstellung","text":"
User Input (Frontend)\n       \u2502\n       \u25bc\nPOST /sdk/v1/ucca/assess\n       \u2502\n       \u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n       \u2502                                          \u2502\n       \u25bc                                          \u25bc\n\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510                          \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502 Policy       \u2502                          \u2502 Escalation   \u2502\n\u2502 Engine       \u2502                          \u2502 Trigger      \u2502\n\u2502 Evaluation   \u2502                          \u2502 Check        \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518                          \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n       \u2502                                          \u2502\n       \u2502 AssessmentResult                         \u2502 EscalationLevel\n       \u2502                                          \u2502\n       \u25bc                                          \u25bc\n\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502                   PostgreSQL                          \u2502\n\u2502  \u251c\u2500\u2500 ucca_assessments (Assessment + Result)           \u2502\n\u2502  \u2514\u2500\u2500 ucca_escalations (wenn Level > E0)              \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n       \u2502\n       \u2502 If Level > E0\n       \u25bc\n\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502 DSB Pool     \u2502\n\u2502 Auto-Assign  \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n       \u2502\n       \u25bc\nNotification (E-Mail/Webhook)\n
"},{"location":"services/ai-compliance-sdk/ARCHITECTURE/#42-erklarung-mit-legal-rag","title":"4.2 Erkl\u00e4rung mit Legal RAG","text":"
POST /sdk/v1/ucca/assessments/:id/explain\n       \u2502\n       \u25bc\n\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502 Load         \u2502\n\u2502 Assessment   \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n       \u2502\n       \u25bc\n\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510    Query Vector    \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502 Extract      \u2502 \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500>\u2502 Qdrant       \u2502\n\u2502 Keywords     \u2502                    \u2502 bp_legal_    \u2502\n\u2502 from Rules   \u2502<\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2502 corpus       \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518    Top-K Docs      \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n       \u2502\n       \u2502 Assessment + Legal Context\n       \u25bc\n\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502 LLM          \u2502\n\u2502 Provider     \u2502\n\u2502 Registry     \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n       \u2502\n       \u25bc\nExplanation (DE) + Legal References\n
"},{"location":"services/ai-compliance-sdk/ARCHITECTURE/#5-entscheidungsdiagramm","title":"5. Entscheidungsdiagramm","text":""},{"location":"services/ai-compliance-sdk/ARCHITECTURE/#51-feasibility-entscheidung","title":"5.1 Feasibility-Entscheidung","text":"
                    UseCaseIntake\n                         \u2502\n                         \u25bc\n              \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n              \u2502 Hat BLOCK-Regeln?   \u2502\n              \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n                    \u2502         \u2502\n                   Ja        Nein\n                    \u2502         \u2502\n                    \u25bc         \u25bc\n            \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510  \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n            \u2502 NO        \u2502  \u2502 Hat WARN-Regeln?    \u2502\n            \u2502 (blocked) \u2502  \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n            \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518        \u2502         \u2502\n                                Ja        Nein\n                                 \u2502         \u2502\n                                 \u25bc         \u25bc\n                         \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510  \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n                         \u2502CONDITIONAL\u2502  \u2502 YES       \u2502\n                         \u2502(mit       \u2502  \u2502(gr\u00fcnes    \u2502\n                         \u2502Auflagen)  \u2502  \u2502Licht)     \u2502\n                         \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518  \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n
"},{"location":"services/ai-compliance-sdk/ARCHITECTURE/#52-escalation-level-entscheidung","title":"5.2 Escalation-Level-Entscheidung","text":"
                   AssessmentResult\n                         \u2502\n                         \u25bc\n              \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n              \u2502 BLOCK-Regel oder    \u2502\n              \u2502 Art.22 Risiko?      \u2502\n              \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n                    \u2502         \u2502\n                   Ja        Nein\n                    \u2502         \u2502\n                    \u25bc         \u2502\n              \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510   \u2502\n              \u2502 E3        \u2502   \u2502\n              \u2502 DSB+Legal \u2502   \u2502\n              \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518   \u25bc\n                    \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n                    \u2502 Risk \u226540 oder       \u2502\n                    \u2502 Art.9 Daten oder    \u2502\n                    \u2502 DSFA empfohlen?     \u2502\n                    \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n                          \u2502         \u2502\n                         Ja        Nein\n                          \u2502         \u2502\n                          \u25bc         \u2502\n                    \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510   \u2502\n                    \u2502 E2        \u2502   \u2502\n                    \u2502 DSB       \u2502   \u2502\n                    \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518   \u25bc\n                          \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n                          \u2502 Risk \u226520 oder       \u2502\n                          \u2502 WARN-Regeln?        \u2502\n                          \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n                                \u2502         \u2502\n                               Ja        Nein\n                                \u2502         \u2502\n                                \u25bc         \u25bc\n                          \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510  \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n                          \u2502 E1        \u2502  \u2502 E0        \u2502\n                          \u2502 Team-Lead \u2502  \u2502 Auto-OK   \u2502\n                          \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518  \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n
"},{"location":"services/ai-compliance-sdk/ARCHITECTURE/#6-datenbank-schema","title":"6. Datenbank-Schema","text":""},{"location":"services/ai-compliance-sdk/ARCHITECTURE/#61-ucca_assessments","title":"6.1 ucca_assessments","text":"
CREATE TABLE ucca_assessments (\n    id UUID PRIMARY KEY,\n    tenant_id UUID NOT NULL,\n    namespace_id UUID,\n    title VARCHAR(500),\n    policy_version VARCHAR(50) NOT NULL,\n    status VARCHAR(50) DEFAULT 'completed',\n\n    -- Input\n    intake JSONB NOT NULL,\n    use_case_text_stored BOOLEAN DEFAULT FALSE,\n    use_case_text_hash VARCHAR(64),\n    domain VARCHAR(50),\n\n    -- Result\n    feasibility VARCHAR(20) NOT NULL,\n    risk_level VARCHAR(20) NOT NULL,\n    risk_score INT NOT NULL DEFAULT 0,\n    triggered_rules JSONB DEFAULT '[]',\n    required_controls JSONB DEFAULT '[]',\n    recommended_architecture JSONB DEFAULT '[]',\n    forbidden_patterns JSONB DEFAULT '[]',\n    example_matches JSONB DEFAULT '[]',\n\n    -- Flags\n    dsfa_recommended BOOLEAN DEFAULT FALSE,\n    art22_risk BOOLEAN DEFAULT FALSE,\n    training_allowed VARCHAR(50),\n\n    -- Explanation\n    explanation_text TEXT,\n    explanation_generated_at TIMESTAMPTZ,\n    explanation_model VARCHAR(100),\n\n    -- Audit\n    created_at TIMESTAMPTZ DEFAULT NOW(),\n    updated_at TIMESTAMPTZ DEFAULT NOW(),\n    created_by UUID NOT NULL\n);\n
"},{"location":"services/ai-compliance-sdk/ARCHITECTURE/#62-ucca_escalations","title":"6.2 ucca_escalations","text":"
CREATE TABLE ucca_escalations (\n    id UUID PRIMARY KEY,\n    tenant_id UUID NOT NULL,\n    assessment_id UUID NOT NULL REFERENCES ucca_assessments(id),\n\n    -- Level & Status\n    escalation_level VARCHAR(10) NOT NULL,\n    escalation_reason TEXT,\n    status VARCHAR(50) NOT NULL DEFAULT 'pending',\n\n    -- Assignment\n    assigned_to UUID,\n    assigned_role VARCHAR(50),\n    assigned_at TIMESTAMPTZ,\n\n    -- Review\n    reviewer_id UUID,\n    reviewer_notes TEXT,\n    reviewed_at TIMESTAMPTZ,\n\n    -- Decision\n    decision VARCHAR(50),\n    decision_notes TEXT,\n    decision_at TIMESTAMPTZ,\n    conditions JSONB DEFAULT '[]',\n\n    -- SLA\n    due_date TIMESTAMPTZ,\n    notification_sent BOOLEAN DEFAULT FALSE,\n    notification_sent_at TIMESTAMPTZ,\n\n    -- Audit\n    created_at TIMESTAMPTZ DEFAULT NOW(),\n    updated_at TIMESTAMPTZ DEFAULT NOW()\n);\n
"},{"location":"services/ai-compliance-sdk/ARCHITECTURE/#63-ucca_dsb_pool","title":"6.3 ucca_dsb_pool","text":"
CREATE TABLE ucca_dsb_pool (\n    id UUID PRIMARY KEY,\n    tenant_id UUID NOT NULL,\n    user_id UUID NOT NULL,\n    user_name VARCHAR(255) NOT NULL,\n    user_email VARCHAR(255) NOT NULL,\n    role VARCHAR(50) NOT NULL,\n    is_active BOOLEAN DEFAULT TRUE,\n    max_concurrent_reviews INT DEFAULT 10,\n    current_reviews INT DEFAULT 0,\n    created_at TIMESTAMPTZ DEFAULT NOW(),\n    updated_at TIMESTAMPTZ DEFAULT NOW()\n);\n
"},{"location":"services/ai-compliance-sdk/ARCHITECTURE/#7-api-endpunkte","title":"7. API-Endpunkte","text":""},{"location":"services/ai-compliance-sdk/ARCHITECTURE/#71-assessment","title":"7.1 Assessment","text":"Method Endpoint Beschreibung POST /sdk/v1/ucca/assess Assessment erstellen GET /sdk/v1/ucca/assessments Assessments auflisten GET /sdk/v1/ucca/assessments/:id Assessment abrufen DELETE /sdk/v1/ucca/assessments/:id Assessment l\u00f6schen POST /sdk/v1/ucca/assessments/:id/explain LLM-Erkl\u00e4rung generieren GET /sdk/v1/ucca/export/:id Assessment exportieren"},{"location":"services/ai-compliance-sdk/ARCHITECTURE/#72-kataloge","title":"7.2 Kataloge","text":"Method Endpoint Beschreibung GET /sdk/v1/ucca/patterns Architektur-Patterns GET /sdk/v1/ucca/examples Didaktische Beispiele GET /sdk/v1/ucca/rules Alle Regeln GET /sdk/v1/ucca/controls Required Controls GET /sdk/v1/ucca/problem-solutions Problem-L\u00f6sungen"},{"location":"services/ai-compliance-sdk/ARCHITECTURE/#73-eskalation","title":"7.3 Eskalation","text":"Method Endpoint Beschreibung GET /sdk/v1/ucca/escalations Eskalationen auflisten GET /sdk/v1/ucca/escalations/:id Eskalation abrufen POST /sdk/v1/ucca/escalations Manuelle Eskalation POST /sdk/v1/ucca/escalations/:id/assign Zuweisen POST /sdk/v1/ucca/escalations/:id/review Review starten POST /sdk/v1/ucca/escalations/:id/decide Entscheidung treffen GET /sdk/v1/ucca/escalations/stats Statistiken"},{"location":"services/ai-compliance-sdk/ARCHITECTURE/#74-dsb-pool","title":"7.4 DSB Pool","text":"Method Endpoint Beschreibung GET /sdk/v1/ucca/dsb-pool Pool-Mitglieder auflisten POST /sdk/v1/ucca/dsb-pool Mitglied hinzuf\u00fcgen"},{"location":"services/ai-compliance-sdk/ARCHITECTURE/#8-sicherheit","title":"8. Sicherheit","text":""},{"location":"services/ai-compliance-sdk/ARCHITECTURE/#81-authentifizierung","title":"8.1 Authentifizierung","text":""},{"location":"services/ai-compliance-sdk/ARCHITECTURE/#82-autorisierung","title":"8.2 Autorisierung","text":""},{"location":"services/ai-compliance-sdk/ARCHITECTURE/#83-datenschutz","title":"8.3 Datenschutz","text":""},{"location":"services/ai-compliance-sdk/ARCHITECTURE/#9-deployment","title":"9. Deployment","text":""},{"location":"services/ai-compliance-sdk/ARCHITECTURE/#91-container","title":"9.1 Container","text":"
ai-compliance-sdk:\n  build: ./ai-compliance-sdk\n  ports:\n    - \"8090:8090\"\n  environment:\n    - DATABASE_URL=postgres://...\n    - OLLAMA_URL=http://ollama:11434\n    - QDRANT_URL=http://qdrant:6333\n  depends_on:\n    - postgres\n    - qdrant\n
"},{"location":"services/ai-compliance-sdk/ARCHITECTURE/#92-abhangigkeiten","title":"9.2 Abh\u00e4ngigkeiten","text":""},{"location":"services/ai-compliance-sdk/ARCHITECTURE/#10-monitoring","title":"10. Monitoring","text":""},{"location":"services/ai-compliance-sdk/ARCHITECTURE/#101-health-check","title":"10.1 Health Check","text":"
GET /sdk/v1/health\n\u2192 {\"status\": \"ok\"}\n
"},{"location":"services/ai-compliance-sdk/ARCHITECTURE/#102-metriken","title":"10.2 Metriken","text":""},{"location":"services/ai-compliance-sdk/ARCHITECTURE/#11-wizard-legal-assistant","title":"11. Wizard & Legal Assistant","text":""},{"location":"services/ai-compliance-sdk/ARCHITECTURE/#111-wizard-architektur","title":"11.1 Wizard-Architektur","text":"

Der UCCA-Wizard f\u00fchrt Benutzer durch 9 Schritte zur Erfassung aller relevanten Compliance-Fakten.

\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502                        UCCA Wizard v1.1                          \u2502\n\u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n\u2502                                                                   \u2502\n\u2502  Step 1: Grundlegende Informationen                              \u2502\n\u2502  Step 2: Datenarten (Personal Data, Art. 9, etc.)                \u2502\n\u2502  Step 3: Verarbeitungszweck (Profiling, Scoring)                 \u2502\n\u2502  Step 4: Hosting & Provider                                      \u2502\n\u2502  Step 5: Internationaler Datentransfer (SCC, TIA)                \u2502\n\u2502  Step 6: KI-Modell und Training                                  \u2502\n\u2502  Step 7: Vertr\u00e4ge & Compliance (AVV, DSFA)                       \u2502\n\u2502  Step 8: Automatisierung & Human Oversight                       \u2502\n\u2502  Step 9: Standards & Normen (f\u00fcr Maschinenbauer) \u2190 NEU           \u2502\n\u2502                                                                   \u2502\n\u2502  Features:                                                        \u2502\n\u2502  \u251c\u2500\u2500 Adaptive Subflows (visible_if Conditions)                   \u2502\n\u2502  \u251c\u2500\u2500 Simple/Expert Mode Toggle                                   \u2502\n\u2502  \u251c\u2500\u2500 Legal Assistant Chat pro Step                               \u2502\n\u2502  \u2514\u2500\u2500 simple_explanation f\u00fcr Nicht-Juristen                       \u2502\n\u2502                                                                   \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n
"},{"location":"services/ai-compliance-sdk/ARCHITECTURE/#112-legal-assistant-wizard-chat","title":"11.2 Legal Assistant (Wizard Chat)","text":"

Integrierter Rechtsassistent f\u00fcr Echtzeit-Hilfe bei Wizard-Fragen.

\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502                     Legal Assistant Flow                          \u2502\n\u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n\u2502                                                                   \u2502\n\u2502  User Question \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500>\u2502\n\u2502       \u2502                                                           \u2502\n\u2502       \u25bc                                                           \u2502\n\u2502  \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510                                            \u2502\n\u2502  \u2502 Build RAG Query  \u2502                                            \u2502\n\u2502  \u2502 + Step Context   \u2502                                            \u2502\n\u2502  \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518                                            \u2502\n\u2502           \u2502                                                       \u2502\n\u2502           \u25bc                                                       \u2502\n\u2502  \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510    Search    \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510         \u2502\n\u2502  \u2502 Legal RAG        \u2502 \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500>\u2502 Qdrant           \u2502         \u2502\n\u2502  \u2502 Client           \u2502              \u2502 bp_legal_corpus  \u2502         \u2502\n\u2502  \u2502                  \u2502<\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2502 + SCC Corpus     \u2502         \u2502\n\u2502  \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518    Top-5     \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518         \u2502\n\u2502           \u2502                                                       \u2502\n\u2502           \u2502 Question + Legal Context                             \u2502\n\u2502           \u25bc                                                       \u2502\n\u2502  \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510                                            \u2502\n\u2502  \u2502 Internal 32B LLM \u2502                                            \u2502\n\u2502  \u2502 (Ollama)         \u2502                                            \u2502\n\u2502  \u2502 temp=0.3         \u2502                                            \u2502\n\u2502  \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518                                            \u2502\n\u2502           \u2502                                                       \u2502\n\u2502           \u25bc                                                       \u2502\n\u2502  Answer + Sources + Related Fields                               \u2502\n\u2502                                                                   \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n

API-Endpunkte:

Method Endpoint Beschreibung GET /sdk/v1/ucca/wizard/schema Wizard-Schema abrufen POST /sdk/v1/ucca/wizard/ask Frage an Legal Assistant"},{"location":"services/ai-compliance-sdk/ARCHITECTURE/#12-license-policy-engine-standards-compliance","title":"12. License Policy Engine (Standards Compliance)","text":""},{"location":"services/ai-compliance-sdk/ARCHITECTURE/#121-ubersicht","title":"12.1 \u00dcbersicht","text":"

Die License Policy Engine verwaltet die Lizenz-/Urheberrechts-Compliance f\u00fcr Standards und Normen (DIN, ISO, VDI, etc.).

\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502                    License Policy Engine                          \u2502\n\u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n\u2502                                                                   \u2502\n\u2502  LicensedContentFacts \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500>\u2502\n\u2502       \u2502                                                           \u2502\n\u2502       \u2502  \u251c\u2500\u2500 present: bool                                       \u2502\n\u2502       \u2502  \u251c\u2500\u2500 publisher: DIN_MEDIA | VDI | ISO | ...              \u2502\n\u2502       \u2502  \u251c\u2500\u2500 license_type: SINGLE | NETWORK | ENTERPRISE | AI    \u2502\n\u2502       \u2502  \u251c\u2500\u2500 ai_use_permitted: YES | NO | UNKNOWN                \u2502\n\u2502       \u2502  \u251c\u2500\u2500 operation_mode: LINK | NOTES | FULLTEXT | TRAINING  \u2502\n\u2502       \u2502  \u2514\u2500\u2500 proof_uploaded: bool                                \u2502\n\u2502       \u2502                                                           \u2502\n\u2502       \u25bc                                                           \u2502\n\u2502  \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\u2502\n\u2502  \u2502                 Operation Mode Evaluation                    \u2502\u2502\n\u2502  \u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\u2502\n\u2502  \u2502                                                               \u2502\u2502\n\u2502  \u2502  LINK_ONLY \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 Always Allowed \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500> OK      \u2502\u2502\n\u2502  \u2502  NOTES_ONLY \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 Usually Allowed \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500> OK      \u2502\u2502\n\u2502  \u2502  FULLTEXT_RAG \u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500 ai_use=YES + proof \u2500\u2500\u2500\u2500\u2500\u2500\u2500> OK      \u2502\u2502\n\u2502  \u2502                   \u2514\u2500\u2500\u2500\u2500 else \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500> BLOCK   \u2502\u2502\n\u2502  \u2502  TRAINING \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500 AI_LICENSE + proof \u2500\u2500\u2500\u2500\u2500\u2500\u2500> OK      \u2502\u2502\n\u2502  \u2502                   \u2514\u2500\u2500\u2500\u2500 else \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500> BLOCK   \u2502\u2502\n\u2502  \u2502                                                               \u2502\u2502\n\u2502  \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\u2502\n\u2502       \u2502                                                           \u2502\n\u2502       \u25bc                                                           \u2502\n\u2502  LicensePolicyResult                                              \u2502\n\u2502    \u251c\u2500\u2500 allowed: bool                                             \u2502\n\u2502    \u251c\u2500\u2500 effective_mode: string (may be downgraded)                \u2502\n\u2502    \u251c\u2500\u2500 gaps: []LicenseGap                                        \u2502\n\u2502    \u251c\u2500\u2500 required_controls: []LicenseControl                       \u2502\n\u2502    \u251c\u2500\u2500 stop_line: *StopLine (if hard blocked)                    \u2502\n\u2502    \u2514\u2500\u2500 output_restrictions: *OutputRestrictions                  \u2502\n\u2502                                                                   \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n
"},{"location":"services/ai-compliance-sdk/ARCHITECTURE/#122-betriebs-modi-operation-modes","title":"12.2 Betriebs-Modi (Operation Modes)","text":"Modus Beschreibung Lizenz-Anforderung Ingest Output LINK_ONLY Nur Verweise & Checklisten Keine Metadata only Keine Zitate NOTES_ONLY Kundeneigene Zusammenfassungen Standard Notes only Paraphrasen EXCERPT_ONLY Kurze Zitate (Zitatrecht) Standard + Zitatrecht Notes Max 150 Zeichen FULLTEXT_RAG Volltext indexiert AI-Lizenz + Proof Fulltext Max 500 Zeichen TRAINING Modell-Training AI-Training-Lizenz Fulltext N/A"},{"location":"services/ai-compliance-sdk/ARCHITECTURE/#123-publisher-spezifische-regeln","title":"12.3 Publisher-spezifische Regeln","text":"

DIN Media (ehem. Beuth): - AI-Nutzung aktuell verboten (ohne explizite Genehmigung) - AI-Lizenzmodell geplant ab Q4/2025 - Crawler/Scraper verboten (AGB) - TDM-Vorbehalt nach \u00a744b UrhG

"},{"location":"services/ai-compliance-sdk/ARCHITECTURE/#124-stop-lines-hard-deny","title":"12.4 Stop-Lines (Hard Deny)","text":"
STOP_DIN_FULLTEXT_AI_NOT_ALLOWED\n  WENN: publisher=DIN_MEDIA AND operation_mode in [FULLTEXT_RAG, TRAINING]\n        AND ai_use_permitted in [NO, UNKNOWN]\n  DANN: BLOCKIERT\n  FALLBACK: LINK_ONLY\n\nSTOP_TRAINING_WITHOUT_PROOF\n  WENN: operation_mode=TRAINING AND proof_uploaded=false\n  DANN: BLOCKIERT\n
"},{"location":"services/ai-compliance-sdk/ARCHITECTURE/#13-scc-transfer-impact-assessment","title":"13. SCC & Transfer Impact Assessment","text":""},{"location":"services/ai-compliance-sdk/ARCHITECTURE/#131-drittlandtransfer-bewertung","title":"13.1 Drittlandtransfer-Bewertung","text":"

Das System unterst\u00fctzt die vollst\u00e4ndige Bewertung internationaler Datentransfers.

\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502              SCC/Transfer Assessment Flow                         \u2502\n\u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n\u2502                                                                   \u2502\n\u2502  hosting.region \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 \u2502\n\u2502       \u2502                                                           \u2502\n\u2502       \u251c\u2500\u2500 EU/EWR \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500> OK (no SCC)  \u2502\n\u2502       \u2502                                                           \u2502\n\u2502       \u251c\u2500\u2500 Adequacy Country (UK, CH, JP) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500> OK (no SCC)  \u2502\n\u2502       \u2502                                                           \u2502\n\u2502       \u2514\u2500\u2500 Third Country (US, etc.) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 \u2502\n\u2502                \u2502                                                  \u2502\n\u2502                \u25bc                                                  \u2502\n\u2502       \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\u2502\n\u2502       \u2502 USA: DPF-Zertifizierung pr\u00fcfen                          \u2502\u2502\n\u2502       \u2502   \u251c\u2500\u2500 Zertifiziert \u2500\u2500\u2500> OK (SCC empfohlen als Backup)  \u2502\u2502\n\u2502       \u2502   \u2514\u2500\u2500 Nicht zertifiziert \u2500\u2500\u2500> SCC + TIA erforderlich   \u2502\u2502\n\u2502       \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\u2502\n\u2502                \u2502                                                  \u2502\n\u2502                \u25bc                                                  \u2502\n\u2502       \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\u2502\n\u2502       \u2502 Transfer Impact Assessment (TIA)                         \u2502\u2502\n\u2502       \u2502   \u251c\u2500\u2500 Adequate \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500> Transfer OK               \u2502\u2502\n\u2502       \u2502   \u251c\u2500\u2500 Adequate + Measures \u2500\u2500> + Technical Supplementary \u2502\u2502\n\u2502       \u2502   \u251c\u2500\u2500 Inadequate \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500> Fix required              \u2502\u2502\n\u2502       \u2502   \u2514\u2500\u2500 Not Feasible \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500> Transfer NOT allowed      \u2502\u2502\n\u2502       \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\u2502\n\u2502                                                                   \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n
"},{"location":"services/ai-compliance-sdk/ARCHITECTURE/#132-scc-versionen","title":"13.2 SCC-Versionen","text":""},{"location":"services/ai-compliance-sdk/ARCHITECTURE/#14-controls-catalog","title":"14. Controls Catalog","text":""},{"location":"services/ai-compliance-sdk/ARCHITECTURE/#141-ubersicht","title":"14.1 \u00dcbersicht","text":"

Der Controls Catalog enth\u00e4lt ~30 Ma\u00dfnahmenbausteine mit detaillierten Handlungsanweisungen.

\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502                      Controls Catalog v1.0                        \u2502\n\u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n\u2502                                                                   \u2502\n\u2502  Kategorien:                                                      \u2502\n\u2502  \u251c\u2500\u2500 DSGVO (Rechtsgrundlagen, Betroffenenrechte, Dokumentation) \u2502\n\u2502  \u251c\u2500\u2500 AI_Act (Transparenz, HITL, Risikoeinstufung)               \u2502\n\u2502  \u251c\u2500\u2500 Technical (Verschl\u00fcsselung, Anonymisierung, PII-Gateway)   \u2502\n\u2502  \u2514\u2500\u2500 Contractual (AVV, SCC, TIA)                                \u2502\n\u2502                                                                   \u2502\n\u2502  Struktur pro Control:                                           \u2502\n\u2502  \u251c\u2500\u2500 id: CTRL-xxx                                                \u2502\n\u2502  \u251c\u2500\u2500 title: Kurztitel                                            \u2502\n\u2502  \u251c\u2500\u2500 when_applicable: Wann erforderlich?                         \u2502\n\u2502  \u251c\u2500\u2500 what_to_do: Konkrete Handlungsschritte                      \u2502\n\u2502  \u251c\u2500\u2500 evidence_needed: Erforderliche Nachweise                    \u2502\n\u2502  \u251c\u2500\u2500 effort: low | medium | high                                 \u2502\n\u2502  \u2514\u2500\u2500 gdpr_ref: Rechtsgrundlage                                   \u2502\n\u2502                                                                   \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n
"},{"location":"services/ai-compliance-sdk/ARCHITECTURE/#142-beispiel-controls","title":"14.2 Beispiel-Controls","text":"ID Titel Kategorie CTRL-CONSENT-EXPLICIT Ausdr\u00fcckliche Einwilligung DSGVO CTRL-AI-TRANSPARENCY KI-Transparenz-Hinweis AI_Act CTRL-DSFA Datenschutz-Folgenabsch\u00e4tzung DSGVO CTRL-SCC Standardvertragsklauseln Contractual CTRL-TIA Transfer Impact Assessment Contractual CTRL-LICENSE-PROOF Lizenz-/Rechte-Nachweis License CTRL-LINK-ONLY-MODE Evidence Navigator License CTRL-PII-GATEWAY PII-Redaction Gateway Technical"},{"location":"services/ai-compliance-sdk/ARCHITECTURE/#15-policy-dateien","title":"15. Policy-Dateien","text":""},{"location":"services/ai-compliance-sdk/ARCHITECTURE/#151-dateistruktur","title":"15.1 Dateistruktur","text":"
policies/\n\u251c\u2500\u2500 ucca_policy_v1.yaml          # Haupt-Policy (Regeln, Controls)\n\u251c\u2500\u2500 controls_catalog.yaml        # Detaillierter Ma\u00dfnahmenkatalog\n\u251c\u2500\u2500 gap_mapping.yaml             # Facts \u2192 Gaps \u2192 Controls\n\u251c\u2500\u2500 wizard_schema_v1.yaml        # Wizard-Fragen (9 Steps)\n\u251c\u2500\u2500 scc_legal_corpus.yaml        # SCC/Transfer Rechtstexte\n\u2514\u2500\u2500 licensed_content_policy.yaml # Normen-Lizenz-Compliance (NEU)\n
"},{"location":"services/ai-compliance-sdk/ARCHITECTURE/#152-versions-management","title":"15.2 Versions-Management","text":""},{"location":"services/ai-compliance-sdk/ARCHITECTURE/#16-generic-obligations-framework","title":"16. Generic Obligations Framework","text":""},{"location":"services/ai-compliance-sdk/ARCHITECTURE/#161-ubersicht","title":"16.1 \u00dcbersicht","text":"

Das Generic Obligations Framework erm\u00f6glicht die automatische Ableitung regulatorischer Pflichten aus mehreren Verordnungen basierend auf Unternehmensfakten.

\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502                Generic Obligations Framework                      \u2502\n\u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n\u2502                                                                   \u2502\n\u2502  UnifiedFacts \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 \u2502\n\u2502       \u2502                                                           \u2502\n\u2502       \u2502  \u251c\u2500\u2500 organization: EmployeeCount, Revenue, Country       \u2502\n\u2502       \u2502  \u251c\u2500\u2500 sector: PrimarySector, IsKRITIS, SpecialServices   \u2502\n\u2502       \u2502  \u251c\u2500\u2500 data_protection: ProcessesPersonalData              \u2502\n\u2502       \u2502  \u2514\u2500\u2500 ai_usage: UsesAI, HighRiskCategories, IsGPAI       \u2502\n\u2502       \u2502                                                           \u2502\n\u2502       \u25bc                                                           \u2502\n\u2502  \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\u2502\n\u2502  \u2502                 Obligations Registry                         \u2502\u2502\n\u2502  \u2502        (Module Registration & Evaluation)                    \u2502\u2502\n\u2502  \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\u2502\n\u2502                             \u2502                                     \u2502\n\u2502         \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510                \u2502\n\u2502         \u2502                   \u2502                   \u2502                \u2502\n\u2502         \u25bc                   \u25bc                   \u25bc                \u2502\n\u2502   \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510      \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510      \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510           \u2502\n\u2502   \u2502   NIS2    \u2502      \u2502   DSGVO   \u2502      \u2502   AI Act  \u2502           \u2502\n\u2502   \u2502  Module   \u2502      \u2502  Module   \u2502      \u2502  Module   \u2502           \u2502\n\u2502   \u2514\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2518      \u2514\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2518      \u2514\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2518           \u2502\n\u2502         \u2502                   \u2502                   \u2502                \u2502\n\u2502         \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518                \u2502\n\u2502                             \u2502                                     \u2502\n\u2502                             \u25bc                                     \u2502\n\u2502  \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\u2502\n\u2502  \u2502           ManagementObligationsOverview                      \u2502\u2502\n\u2502  \u2502  \u251c\u2500\u2500 ApplicableRegulations[]                                 \u2502\u2502\n\u2502  \u2502  \u251c\u2500\u2500 Obligations[] (sortiert nach Priorit\u00e4t)                 \u2502\u2502\n\u2502  \u2502  \u251c\u2500\u2500 RequiredControls[]                                      \u2502\u2502\n\u2502  \u2502  \u251c\u2500\u2500 IncidentDeadlines[]                                     \u2502\u2502\n\u2502  \u2502  \u251c\u2500\u2500 SanctionsSummary                                        \u2502\u2502\n\u2502  \u2502  \u2514\u2500\u2500 ExecutiveSummary                                        \u2502\u2502\n\u2502  \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\u2502\n\u2502                                                                   \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n
"},{"location":"services/ai-compliance-sdk/ARCHITECTURE/#162-regulation-modules","title":"16.2 Regulation Modules","text":"

Jede Regulierung wird als eigenst\u00e4ndiges Modul implementiert:

Implementierte Module:

Modul ID Datei Pflichten Kontrollen NIS2 nis2 nis2_module.go ~15 ~8 DSGVO dsgvo dsgvo_module.go ~12 ~6 AI Act ai_act ai_act_module.go ~15 ~6"},{"location":"services/ai-compliance-sdk/ARCHITECTURE/#17-obligations-api-endpunkte","title":"17. Obligations API-Endpunkte","text":""},{"location":"services/ai-compliance-sdk/ARCHITECTURE/#171-assessment","title":"17.1 Assessment","text":"Method Endpoint Beschreibung POST /sdk/v1/ucca/obligations/assess Pflichten-Assessment erstellen GET /sdk/v1/ucca/obligations/:id Assessment abrufen GET /sdk/v1/ucca/obligations Assessments auflisten"},{"location":"services/ai-compliance-sdk/ARCHITECTURE/#172-export","title":"17.2 Export","text":"Method Endpoint Beschreibung POST /sdk/v1/ucca/obligations/export/memo Memo exportieren (gespeichert) POST /sdk/v1/ucca/obligations/export/direct Direkt-Export ohne Speicherung"},{"location":"services/ai-compliance-sdk/ARCHITECTURE/#173-regulations","title":"17.3 Regulations","text":"Method Endpoint Beschreibung GET /sdk/v1/ucca/regulations Liste aller Regulierungsmodule GET /sdk/v1/ucca/regulations/:id/decision-tree Decision Tree f\u00fcr Regulierung"},{"location":"services/ai-compliance-sdk/ARCHITECTURE/#18-dateien-des-obligations-framework","title":"18. Dateien des Obligations Framework","text":""},{"location":"services/ai-compliance-sdk/ARCHITECTURE/#181-backend-go","title":"18.1 Backend (Go)","text":"
internal/ucca/\n\u251c\u2500\u2500 obligations_framework.go    # Interfaces, Typen, Konstanten\n\u251c\u2500\u2500 obligations_registry.go     # Modul-Registry, EvaluateAll()\n\u251c\u2500\u2500 nis2_module.go              # NIS2 Decision Tree + Pflichten\n\u251c\u2500\u2500 nis2_module_test.go         # NIS2 Tests\n\u251c\u2500\u2500 dsgvo_module.go             # DSGVO Pflichten\n\u251c\u2500\u2500 dsgvo_module_test.go        # DSGVO Tests\n\u251c\u2500\u2500 ai_act_module.go            # AI Act Risk Classification\n\u251c\u2500\u2500 ai_act_module_test.go       # AI Act Tests\n\u251c\u2500\u2500 pdf_export.go               # PDF/Markdown Export\n\u2514\u2500\u2500 pdf_export_test.go          # Export Tests\n
"},{"location":"services/ai-compliance-sdk/ARCHITECTURE/#182-policy-dateien-yaml","title":"18.2 Policy-Dateien (YAML)","text":"
policies/obligations/\n\u251c\u2500\u2500 nis2_obligations.yaml       # ~15 NIS2-Pflichten\n\u251c\u2500\u2500 dsgvo_obligations.yaml      # ~12 DSGVO-Pflichten\n\u2514\u2500\u2500 ai_act_obligations.yaml     # ~15 AI Act-Pflichten\n

Dokumentation erstellt: 2026-01-29 Version: 2.1.0

"},{"location":"services/ai-compliance-sdk/AUDITOR_DOCUMENTATION/","title":"UCCA - Dokumentation f\u00fcr externe Auditoren","text":""},{"location":"services/ai-compliance-sdk/AUDITOR_DOCUMENTATION/#systemdokumentation-nach-art-30-dsgvo","title":"Systemdokumentation nach Art. 30 DSGVO","text":"

Verantwortlicher: [Name des Unternehmens] Datenschutzbeauftragter: [Kontakt] Dokumentationsstand: 2026-01-29 Version: 1.0.0

"},{"location":"services/ai-compliance-sdk/AUDITOR_DOCUMENTATION/#1-zweck-und-funktionsweise-des-systems","title":"1. Zweck und Funktionsweise des Systems","text":""},{"location":"services/ai-compliance-sdk/AUDITOR_DOCUMENTATION/#11-systembezeichnung","title":"1.1 Systembezeichnung","text":"

UCCA - Use-Case Compliance & Feasibility Advisor

"},{"location":"services/ai-compliance-sdk/AUDITOR_DOCUMENTATION/#12-zweckbeschreibung","title":"1.2 Zweckbeschreibung","text":"

Das UCCA-System ist ein Compliance-Pr\u00fcfwerkzeug, das Organisationen bei der Bewertung geplanter KI-Anwendungsf\u00e4lle hinsichtlich ihrer datenschutzrechtlichen Zul\u00e4ssigkeit unterst\u00fctzt.

Kernfunktionen: - Automatisierte Vorpr\u00fcfung von KI-Anwendungsf\u00e4llen gegen EU-Regulierungen - Identifikation erforderlicher technischer und organisatorischer Ma\u00dfnahmen - Eskalation kritischer F\u00e4lle zur menschlichen Pr\u00fcfung - Dokumentation und Nachvollziehbarkeit aller Pr\u00fcfentscheidungen

"},{"location":"services/ai-compliance-sdk/AUDITOR_DOCUMENTATION/#13-rechtsgrundlage","title":"1.3 Rechtsgrundlage","text":"

Die Verarbeitung erfolgt auf Basis von: - Art. 6 Abs. 1 lit. c DSGVO - Erf\u00fcllung rechtlicher Verpflichtungen - Art. 6 Abs. 1 lit. f DSGVO - Berechtigte Interessen (Compliance-Management)

"},{"location":"services/ai-compliance-sdk/AUDITOR_DOCUMENTATION/#2-verarbeitete-datenkategorien","title":"2. Verarbeitete Datenkategorien","text":""},{"location":"services/ai-compliance-sdk/AUDITOR_DOCUMENTATION/#21-eingabedaten-use-case-beschreibungen","title":"2.1 Eingabedaten (Use-Case-Beschreibungen)","text":"Datenkategorie Beschreibung Speicherung Use-Case-Text Freitextbeschreibung des geplanten Anwendungsfalls Optional (Opt-in), ansonsten nur Hash Domain Branchenkategorie (z.B. \"education\", \"healthcare\") Ja Datentyp-Flags Angaben zu verarbeiteten Datenarten Ja Automatisierungsgrad assistiv/teil-/vollautomatisch Ja Hosting-Informationen Region, Provider Ja

Wichtig: Der System speichert standardm\u00e4\u00dfig keine Freitexte, sondern nur: - SHA-256 Hash des Textes (zur Deduplizierung) - Strukturierte Metadaten (Checkboxen, Dropdowns)

"},{"location":"services/ai-compliance-sdk/AUDITOR_DOCUMENTATION/#22-bewertungsergebnisse","title":"2.2 Bewertungsergebnisse","text":"Datenkategorie Beschreibung Aufbewahrung Risk Score Numerischer Wert 0-100 Dauerhaft Triggered Rules Ausgel\u00f6ste Compliance-Regeln Dauerhaft Required Controls Empfohlene Ma\u00dfnahmen Dauerhaft Explanation KI-generierte Erkl\u00e4rung Dauerhaft"},{"location":"services/ai-compliance-sdk/AUDITOR_DOCUMENTATION/#23-audit-trail-daten","title":"2.3 Audit-Trail-Daten","text":"Datenkategorie Beschreibung Aufbewahrung Benutzer-ID UUID des ausf\u00fchrenden Benutzers 10 Jahre Timestamp Zeitpunkt der Aktion 10 Jahre Aktionstyp created/reviewed/decided 10 Jahre Entscheidungsnotizen Begr\u00fcndungen bei Eskalationen 10 Jahre"},{"location":"services/ai-compliance-sdk/AUDITOR_DOCUMENTATION/#3-entscheidungslogik-und-automatisierung","title":"3. Entscheidungslogik und Automatisierung","text":""},{"location":"services/ai-compliance-sdk/AUDITOR_DOCUMENTATION/#31-regelbasierte-bewertung-deterministische-logik","title":"3.1 Regelbasierte Bewertung (Deterministische Logik)","text":"

Das System verwendet ausschlie\u00dflich deterministische Regeln f\u00fcr Compliance-Entscheidungen. Diese Regeln sind:

  1. Transparent - Alle Regeln sind im Quellcode einsehbar
  2. Nachvollziehbar - Jede ausgel\u00f6ste Regel wird dokumentiert
  3. \u00dcberpr\u00fcfbar - Regellogik basiert auf konkreten DSGVO-Artikeln

Beispiel-Regel R-F001:

WENN:\n  - Domain = \"education\" UND\n  - Automation = \"fully_automated\" UND\n  - Output enth\u00e4lt \"rankings_or_scores\"\nDANN:\n  - Severity = BLOCK\n  - DSGVO-Referenz = Art. 22 Abs. 1\n  - Begr\u00fcndung = \"Vollautomatisierte Bewertung von Sch\u00fclern ohne menschliche \u00dcberpr\u00fcfung\"\n

"},{"location":"services/ai-compliance-sdk/AUDITOR_DOCUMENTATION/#32-keine-autonomen-ki-entscheidungen","title":"3.2 Keine autonomen KI-Entscheidungen","text":"

Das System trifft KEINE autonomen KI-Entscheidungen bez\u00fcglich: - Zul\u00e4ssigkeit eines Anwendungsfalls (immer regelbasiert) - Freigabe oder Ablehnung (immer durch Mensch) - Rechtliche Bewertungen (immer durch DSB/Legal)

KI wird ausschlie\u00dflich verwendet f\u00fcr: - Erkl\u00e4rung bereits getroffener Regelentscheidungen - Zusammenfassung von Rechtstexten - Sprachliche Formulierung von Hinweisen

"},{"location":"services/ai-compliance-sdk/AUDITOR_DOCUMENTATION/#33-human-in-the-loop","title":"3.3 Human-in-the-Loop","text":"

Bei allen kritischen Entscheidungen ist ein menschlicher Pr\u00fcfer eingebunden:

Eskalationsstufe Ausl\u00f6ser Pr\u00fcfer SLA E0 Nur informative Regeln Automatisch - E1 Warnungen, geringes Risiko Team-Lead 24h E2 Art. 9-Daten, DSFA empfohlen DSB 8h E3 BLOCK-Regeln, hohes Risiko DSB + Legal 4h

BLOCK-Entscheidungen k\u00f6nnen NICHT durch KI \u00fcberschrieben werden.

"},{"location":"services/ai-compliance-sdk/AUDITOR_DOCUMENTATION/#4-technische-und-organisatorische-manahmen-art-32-dsgvo","title":"4. Technische und organisatorische Ma\u00dfnahmen (Art. 32 DSGVO)","text":""},{"location":"services/ai-compliance-sdk/AUDITOR_DOCUMENTATION/#41-vertraulichkeit","title":"4.1 Vertraulichkeit","text":"Ma\u00dfnahme Umsetzung Zugriffskontrolle RBAC mit Tenant-Isolation Verschl\u00fcsselung in Transit TLS 1.3 Verschl\u00fcsselung at Rest AES-256 (PostgreSQL, Qdrant) Authentifizierung JWT-basiert, Token-Expiry"},{"location":"services/ai-compliance-sdk/AUDITOR_DOCUMENTATION/#42-integritat","title":"4.2 Integrit\u00e4t","text":"Ma\u00dfnahme Umsetzung Audit-Trail Unver\u00e4nderlicher Verlauf aller Aktionen Versionierung Policy-Version in jedem Assessment Input-Validierung Schema-Validierung aller API-Eingaben"},{"location":"services/ai-compliance-sdk/AUDITOR_DOCUMENTATION/#43-verfugbarkeit","title":"4.3 Verf\u00fcgbarkeit","text":"Ma\u00dfnahme Umsetzung Backup T\u00e4gliche PostgreSQL-Backups Redundanz Container-Orchestrierung mit Auto-Restart Monitoring Health-Checks, SLA-\u00dcberwachung"},{"location":"services/ai-compliance-sdk/AUDITOR_DOCUMENTATION/#44-belastbarkeit","title":"4.4 Belastbarkeit","text":"Ma\u00dfnahme Umsetzung Rate Limiting API-Anfragenbegrenzung Graceful Degradation LLM-Fallback bei Ausfall Ressourcenlimits Container-Memory-Limits"},{"location":"services/ai-compliance-sdk/AUDITOR_DOCUMENTATION/#5-datenschutz-folgenabschatzung-art-35-dsgvo","title":"5. Datenschutz-Folgenabsch\u00e4tzung (Art. 35 DSGVO)","text":""},{"location":"services/ai-compliance-sdk/AUDITOR_DOCUMENTATION/#51-risikobewertung","title":"5.1 Risikobewertung","text":"Risiko Bewertung Mitigierung Fehleinsch\u00e4tzung durch KI Mittel Deterministische Regeln, Human Review Datenverlust Niedrig Backup, Verschl\u00fcsselung Unbefugter Zugriff Niedrig RBAC, Audit-Trail Bias in Regellogik Niedrig Transparente Regeln, Review-Prozess"},{"location":"services/ai-compliance-sdk/AUDITOR_DOCUMENTATION/#52-dsfa-trigger-im-system","title":"5.2 DSFA-Trigger im System","text":"

Das System erkennt automatisch, wann eine DSFA erforderlich ist: - Verarbeitung besonderer Kategorien (Art. 9 DSGVO) - Systematische Bewertung nat\u00fcrlicher Personen - Neue Technologien mit hohem Risiko

"},{"location":"services/ai-compliance-sdk/AUDITOR_DOCUMENTATION/#6-betroffenenrechte-art-15-22-dsgvo","title":"6. Betroffenenrechte (Art. 15-22 DSGVO)","text":""},{"location":"services/ai-compliance-sdk/AUDITOR_DOCUMENTATION/#61-auskunftsrecht-art-15","title":"6.1 Auskunftsrecht (Art. 15)","text":"

Betroffene k\u00f6nnen Auskunft erhalten \u00fcber: - Gespeicherte Assessments mit ihren Daten - Audit-Trail ihrer Interaktionen - Regelbasierte Entscheidungsbegr\u00fcndungen

"},{"location":"services/ai-compliance-sdk/AUDITOR_DOCUMENTATION/#62-recht-auf-berichtigung-art-16","title":"6.2 Recht auf Berichtigung (Art. 16)","text":"

Betroffene k\u00f6nnen die Korrektur fehlerhafter Eingabedaten verlangen.

"},{"location":"services/ai-compliance-sdk/AUDITOR_DOCUMENTATION/#63-recht-auf-loschung-art-17","title":"6.3 Recht auf L\u00f6schung (Art. 17)","text":"

Assessments k\u00f6nnen gel\u00f6scht werden, sofern: - Keine gesetzlichen Aufbewahrungspflichten bestehen - Keine laufenden Eskalationsverfahren existieren

"},{"location":"services/ai-compliance-sdk/AUDITOR_DOCUMENTATION/#64-recht-auf-einschrankung-art-18","title":"6.4 Recht auf Einschr\u00e4nkung (Art. 18)","text":"

Die Verarbeitung kann eingeschr\u00e4nkt werden durch: - Archivierung statt L\u00f6schung - Sperrung des Datensatzes

"},{"location":"services/ai-compliance-sdk/AUDITOR_DOCUMENTATION/#65-automatisierte-entscheidungen-art-22","title":"6.5 Automatisierte Entscheidungen (Art. 22)","text":"

Das System trifft keine automatisierten Einzelentscheidungen im Sinne von Art. 22 DSGVO, da:

  1. Regelauswertung ist keine rechtlich bindende Entscheidung
  2. Alle kritischen F\u00e4lle werden menschlich gepr\u00fcft (E1-E3)
  3. BLOCK-Entscheidungen erfordern immer menschliche Freigabe
  4. Betroffene haben Anfechtungsm\u00f6glichkeit \u00fcber Eskalation
"},{"location":"services/ai-compliance-sdk/AUDITOR_DOCUMENTATION/#7-auftragsverarbeitung","title":"7. Auftragsverarbeitung","text":""},{"location":"services/ai-compliance-sdk/AUDITOR_DOCUMENTATION/#71-unterauftragnehmer","title":"7.1 Unterauftragnehmer","text":"Dienst Anbieter Standort Zweck Embedding-Service Lokal (Self-Hosted) EU Vektorisierung Vector-DB (Qdrant) Lokal (Self-Hosted) EU \u00c4hnlichkeitssuche LLM (Ollama) Lokal (Self-Hosted) EU Erkl\u00e4rungsgenerierung

Hinweis: Das System kann vollst\u00e4ndig on-premise betrieben werden ohne externe Dienste.

"},{"location":"services/ai-compliance-sdk/AUDITOR_DOCUMENTATION/#72-internationale-transfers","title":"7.2 Internationale Transfers","text":"

Bei Nutzung von Cloud-LLM-Anbietern: - Anthropic Claude: US (DPF-zertifiziert) - OpenAI: US (DPF-zertifiziert)

Empfehlung: Nutzung des lokalen Ollama-Providers f\u00fcr sensible Daten.

"},{"location":"services/ai-compliance-sdk/AUDITOR_DOCUMENTATION/#8-audit-trail-und-nachvollziehbarkeit","title":"8. Audit-Trail und Nachvollziehbarkeit","text":""},{"location":"services/ai-compliance-sdk/AUDITOR_DOCUMENTATION/#81-protokollierte-ereignisse","title":"8.1 Protokollierte Ereignisse","text":"Ereignis Protokollierte Daten Assessment erstellt Benutzer, Timestamp, Intake-Hash, Ergebnis Eskalation erstellt Level, Grund, SLA Zuweisung Benutzer, Rolle Review gestartet Benutzer, Timestamp Entscheidung Benutzer, Entscheidung, Begr\u00fcndung"},{"location":"services/ai-compliance-sdk/AUDITOR_DOCUMENTATION/#82-aufbewahrungsfristen","title":"8.2 Aufbewahrungsfristen","text":"Datenart Aufbewahrung Rechtsgrundlage Assessments 10 Jahre \u00a7 147 AO Audit-Trail 10 Jahre \u00a7 147 AO Eskalationen 10 Jahre \u00a7 147 AO L\u00f6schprotokolle 3 Jahre Art. 17 DSGVO"},{"location":"services/ai-compliance-sdk/AUDITOR_DOCUMENTATION/#9-lizenzierte-inhalte-normen-compliance-44b-urhg","title":"9. Lizenzierte Inhalte & Normen-Compliance (\u00a744b UrhG)","text":""},{"location":"services/ai-compliance-sdk/AUDITOR_DOCUMENTATION/#91-zweck","title":"9.1 Zweck","text":"

Das System enth\u00e4lt einen spezialisierten License Policy Engine zur Compliance-Pr\u00fcfung bei der Verarbeitung urheberrechtlich gesch\u00fctzter Inhalte, insbesondere:

"},{"location":"services/ai-compliance-sdk/AUDITOR_DOCUMENTATION/#92-rechtlicher-hintergrund","title":"9.2 Rechtlicher Hintergrund","text":"

\u00a744b UrhG - Text und Data Mining:

\"Die Vervielf\u00e4ltigung von rechtm\u00e4\u00dfig zug\u00e4nglichen Werken f\u00fcr das Text und Data Mining ist zul\u00e4ssig.\"

ABER: Rechteinhaber k\u00f6nnen TDM gem. \u00a744b Abs. 3 UrhG vorbehalten: - DIN Media: Expliziter Vorbehalt in AGB \u2013 keine KI/TDM-Nutzung ohne Sonderlizenz - Geplante KI-Lizenzmodelle: Ab Q4/2025 (DIN Media)

"},{"location":"services/ai-compliance-sdk/AUDITOR_DOCUMENTATION/#93-operationsmodi-im-system","title":"9.3 Operationsmodi im System","text":"Modus Beschreibung Lizenzanforderung LINK_ONLY Nur Verlinkung zum Original Keine NOTES_ONLY Eigene Notizen/Zusammenfassungen Keine (\u00a751 UrhG) EXCERPT_ONLY Kurze Zitate (<100 W\u00f6rter) Standard-Lizenz FULLTEXT_RAG Volltextsuche mit Embedding Explizite KI-Lizenz TRAINING Modell-Training Enterprise-Lizenz + Vertrag"},{"location":"services/ai-compliance-sdk/AUDITOR_DOCUMENTATION/#94-stop-lines-automatische-sperren","title":"9.4 Stop-Lines (Automatische Sperren)","text":"

Das System blockiert automatisch folgende Kombinationen:

Stop-Line ID Bedingung Aktion STOP_DIN_FULLTEXT_AI_NOT_ALLOWED DIN Media + FULLTEXT_RAG + keine KI-Lizenz Ablehnung STOP_LICENSE_UNKNOWN_FULLTEXT Lizenz unbekannt + FULLTEXT_RAG Warnung + Eskalation STOP_TRAINING_WITHOUT_ENTERPRISE Beliebig + TRAINING + keine Enterprise-Lizenz Ablehnung"},{"location":"services/ai-compliance-sdk/AUDITOR_DOCUMENTATION/#95-license-policy-engine-entscheidungslogik","title":"9.5 License Policy Engine - Entscheidungslogik","text":"
INPUT:\n\u251c\u2500\u2500 licensed_content.present = true\n\u251c\u2500\u2500 licensed_content.publisher = \"DIN_MEDIA\"\n\u251c\u2500\u2500 licensed_content.license_type = \"SINGLE_WORKSTATION\"\n\u251c\u2500\u2500 licensed_content.ai_use_permitted = \"NO\"\n\u2514\u2500\u2500 licensed_content.operation_mode = \"FULLTEXT_RAG\"\n\nREGEL-EVALUATION:\n\u251c\u2500\u2500 Pr\u00fcfe Publisher-spezifische Regeln\n\u251c\u2500\u2500 Pr\u00fcfe Lizenztyp vs. gew\u00fcnschter Modus\n\u251c\u2500\u2500 Pr\u00fcfe AI-Use-Flag\n\u2514\u2500\u2500 Bestimme maximal zul\u00e4ssigen Modus\n\nOUTPUT:\n\u251c\u2500\u2500 allowed: false\n\u251c\u2500\u2500 max_allowed_mode: \"NOTES_ONLY\"\n\u251c\u2500\u2500 required_controls: [\"CTRL-LICENSE-PROOF\", \"CTRL-NO-CRAWLING-DIN\"]\n\u251c\u2500\u2500 gaps: [\"GAP_DIN_MEDIA_WITHOUT_AI_LICENSE\"]\n\u251c\u2500\u2500 stop_lines: [\"STOP_DIN_FULLTEXT_AI_NOT_ALLOWED\"]\n\u2514\u2500\u2500 explanation: \"DIN Media verbietet KI-Nutzung ohne explizite Lizenz...\"\n
"},{"location":"services/ai-compliance-sdk/AUDITOR_DOCUMENTATION/#96-erforderliche-controls-bei-lizenzierten-inhalten","title":"9.6 Erforderliche Controls bei lizenzierten Inhalten","text":"Control ID Beschreibung Evidence CTRL-LICENSE-PROOF Lizenznachweis dokumentieren Lizenzvertrag, Rechnung CTRL-LICENSE-GATED-INGEST Technische Sperre vor Ingest Konfiguration, Logs CTRL-NO-CRAWLING-DIN Kein automatisches Crawling System-Konfiguration CTRL-OUTPUT-GUARD Ausgabe-Beschr\u00e4nkung (Zitatlimit) API-Logs"},{"location":"services/ai-compliance-sdk/AUDITOR_DOCUMENTATION/#97-audit-relevante-protokollierung","title":"9.7 Audit-relevante Protokollierung","text":"

Bei jeder Verarbeitung lizenzierter Inhalte wird dokumentiert:

Feld Beschreibung Aufbewahrung license_check_timestamp Zeitpunkt der Pr\u00fcfung 10 Jahre license_decision Ergebnis (allowed/denied) 10 Jahre license_proof_hash Hash des Lizenznachweises 10 Jahre operation_mode_requested Angefragter Modus 10 Jahre operation_mode_granted Erlaubter Modus 10 Jahre publisher Rechteinhaber 10 Jahre"},{"location":"services/ai-compliance-sdk/AUDITOR_DOCUMENTATION/#98-on-premise-deployment-fur-sensible-normen","title":"9.8 On-Premise-Deployment f\u00fcr sensible Normen","text":"

F\u00fcr Unternehmen mit strengen Compliance-Anforderungen:

Komponente Deployment Isolation Normen-Datenbank Lokaler Mac Studio Air-gapped Embedding-Service Lokal (bge-m3) Keine Cloud Vector-DB (Qdrant) Lokaler Container Tenant-Isolation LLM (Ollama) Lokal (Qwen2.5-Coder) Keine API-Calls"},{"location":"services/ai-compliance-sdk/AUDITOR_DOCUMENTATION/#10-kontakt-und-verantwortlichkeiten","title":"10. Kontakt und Verantwortlichkeiten","text":""},{"location":"services/ai-compliance-sdk/AUDITOR_DOCUMENTATION/#101-verantwortlicher","title":"10.1 Verantwortlicher","text":"

[Name und Adresse des Unternehmens]

"},{"location":"services/ai-compliance-sdk/AUDITOR_DOCUMENTATION/#102-datenschutzbeauftragter","title":"10.2 Datenschutzbeauftragter","text":"

Name: [Name] E-Mail: [E-Mail] Telefon: [Telefon]

"},{"location":"services/ai-compliance-sdk/AUDITOR_DOCUMENTATION/#103-technischer-ansprechpartner","title":"10.3 Technischer Ansprechpartner","text":"

Name: [Name] E-Mail: [E-Mail]

"},{"location":"services/ai-compliance-sdk/AUDITOR_DOCUMENTATION/#11-anderungshistorie","title":"11. \u00c4nderungshistorie","text":"Version Datum \u00c4nderung Autor 1.1.0 2026-01-29 License Policy Engine & Standards-Compliance (\u00a744b UrhG) [Autor] 1.0.0 2026-01-29 Erstversion [Autor]

Diese Dokumentation erf\u00fcllt die Anforderungen nach Art. 30 DSGVO (Verzeichnis von Verarbeitungst\u00e4tigkeiten) und dient als Grundlage f\u00fcr Audits nach Art. 32 DSGVO (Sicherheit der Verarbeitung).

"},{"location":"services/ai-compliance-sdk/DEVELOPER/","title":"AI Compliance SDK - Entwickler-Dokumentation","text":""},{"location":"services/ai-compliance-sdk/DEVELOPER/#inhaltsverzeichnis","title":"Inhaltsverzeichnis","text":"
  1. Schnellstart
  2. Architektur-\u00dcbersicht
  3. Policy Engine
  4. License Policy Engine
  5. Legal RAG Integration
  6. Wizard & Legal Assistant
  7. Eskalations-System
  8. API-Endpoints
  9. Policy-Dateien
  10. Tests ausf\u00fchren
"},{"location":"services/ai-compliance-sdk/DEVELOPER/#1-schnellstart","title":"1. Schnellstart","text":""},{"location":"services/ai-compliance-sdk/DEVELOPER/#voraussetzungen","title":"Voraussetzungen","text":""},{"location":"services/ai-compliance-sdk/DEVELOPER/#build-run","title":"Build & Run","text":"
# Build\ncd ai-compliance-sdk\ngo build -o server ./cmd/server\n\n# Run\n./server --config config.yaml\n\n# Alternativ: mit Docker\ndocker compose up -d\n
"},{"location":"services/ai-compliance-sdk/DEVELOPER/#erste-anfrage","title":"Erste Anfrage","text":"
# UCCA Assessment erstellen\ncurl -X POST http://localhost:8080/sdk/v1/ucca/assess \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n    \"use_case_text\": \"Chatbot f\u00fcr Kundenservice mit FAQ-Suche\",\n    \"domain\": \"utilities\",\n    \"data_types\": {\n      \"personal_data\": false,\n      \"public_data\": true\n    },\n    \"automation\": \"assistive\",\n    \"model_usage\": {\n      \"rag\": true\n    },\n    \"hosting\": {\n      \"region\": \"eu\"\n    }\n  }'\n
"},{"location":"services/ai-compliance-sdk/DEVELOPER/#2-architektur-ubersicht","title":"2. Architektur-\u00dcbersicht","text":"
\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502                        API Layer (Gin)                           \u2502\n\u2502                    internal/api/handlers/                        \u2502\n\u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n\u2502                                                                   \u2502\n\u2502  \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510  \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510  \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510  \u2502\n\u2502  \u2502   UCCA      \u2502  \u2502   License   \u2502  \u2502      Eskalation         \u2502  \u2502\n\u2502  \u2502   Handler   \u2502  \u2502   Handler   \u2502  \u2502      Handler            \u2502  \u2502\n\u2502  \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2518  \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2518  \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518  \u2502\n\u2502         \u2502                \u2502                      \u2502                \u2502\n\u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n\u2502         \u25bc                \u25bc                      \u25bc                \u2502\n\u2502  \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510  \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510  \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510  \u2502\n\u2502  \u2502   Policy    \u2502  \u2502   License   \u2502  \u2502   Escalation            \u2502  \u2502\n\u2502  \u2502   Engine    \u2502  \u2502   Policy    \u2502  \u2502   Store                 \u2502  \u2502\n\u2502  \u2502             \u2502  \u2502   Engine    \u2502  \u2502                         \u2502  \u2502\n\u2502  \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2518  \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2518  \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518  \u2502\n\u2502         \u2502                \u2502                      \u2502                \u2502\n\u2502         \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518                \u2502\n\u2502                  \u25bc                                               \u2502\n\u2502         \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510     \u2502\n\u2502         \u2502              Legal RAG System                    \u2502     \u2502\n\u2502         \u2502         (Qdrant + LLM Integration)              \u2502     \u2502\n\u2502         \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518     \u2502\n\u2502                                                                   \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n
"},{"location":"services/ai-compliance-sdk/DEVELOPER/#kernprinzip","title":"Kernprinzip","text":"

LLM ist NICHT die Quelle der Wahrheit!

Komponente Entscheidet LLM-Nutzung Policy Engine Feasibility, Risk Level Nein License Engine Operation Mode, Stop-Lines Nein Gap Mapping Facts \u2192 Gaps \u2192 Controls Nein Legal RAG Erkl\u00e4rung generieren Ja (nur Output)"},{"location":"services/ai-compliance-sdk/DEVELOPER/#3-policy-engine","title":"3. Policy Engine","text":""},{"location":"services/ai-compliance-sdk/DEVELOPER/#ubersicht","title":"\u00dcbersicht","text":"

Die Policy Engine (internal/ucca/policy_engine.go) evaluiert Use Cases gegen deterministische Regeln.

"},{"location":"services/ai-compliance-sdk/DEVELOPER/#verwendung","title":"Verwendung","text":"
import \"ai-compliance-sdk/internal/ucca\"\n\n// Engine erstellen\nengine, err := ucca.NewPolicyEngineFromPath(\"policies/ucca_policy_v1.yaml\")\nif err != nil {\n    log.Fatal(err)\n}\n\n// Intake erstellen\nintake := &ucca.UseCaseIntake{\n    UseCaseText: \"Chatbot f\u00fcr Kundenservice\",\n    Domain:      ucca.DomainUtilities,\n    DataTypes: ucca.DataTypes{\n        PersonalData: false,\n        PublicData:   true,\n    },\n    Automation: ucca.AutomationAssistive,\n    ModelUsage: ucca.ModelUsage{\n        RAG: true,\n    },\n    Hosting: ucca.Hosting{\n        Region: \"eu\",\n    },\n}\n\n// Evaluieren\nresult := engine.Evaluate(intake)\n\n// Ergebnis auswerten\nfmt.Println(\"Feasibility:\", result.Feasibility)   // YES, NO, CONDITIONAL\nfmt.Println(\"Risk Level:\", result.RiskLevel)      // MINIMAL, LOW, MEDIUM, HIGH\nfmt.Println(\"Risk Score:\", result.RiskScore)      // 0-100\n
"},{"location":"services/ai-compliance-sdk/DEVELOPER/#ergebnis-struktur","title":"Ergebnis-Struktur","text":"
type EvaluationResult struct {\n    Feasibility           Feasibility            // YES, NO, CONDITIONAL\n    RiskLevel             RiskLevel              // MINIMAL, LOW, MEDIUM, HIGH\n    RiskScore             int                    // 0-100\n    TriggeredRules        []TriggeredRule        // Ausgel\u00f6ste Regeln\n    RequiredControls      []Control              // Erforderliche Ma\u00dfnahmen\n    RecommendedArchitecture []Pattern            // Empfohlene Patterns\n    DSFARecommended       bool                   // DSFA erforderlich?\n    Art22Risk             bool                   // Art. 22 Risiko?\n    TrainingAllowed       TrainingAllowed        // YES, NO, CONDITIONAL\n    PolicyVersion         string                 // Version der Policy\n}\n
"},{"location":"services/ai-compliance-sdk/DEVELOPER/#regeln-hinzufugen","title":"Regeln hinzuf\u00fcgen","text":"

Neue Regeln werden in policies/ucca_policy_v1.yaml definiert:

rules:\n  - id: R-CUSTOM-001\n    code: R-CUSTOM-001\n    category: custom\n    title: Custom Rule\n    title_de: Benutzerdefinierte Regel\n    description: Custom rule description\n    severity: WARN  # INFO, WARN, BLOCK\n    gdpr_ref: \"Art. 6 DSGVO\"\n    condition:\n      all_of:\n        - field: domain\n          equals: custom_domain\n        - field: data_types.personal_data\n          equals: true\n    controls:\n      - C_CUSTOM_CONTROL\n
"},{"location":"services/ai-compliance-sdk/DEVELOPER/#4-license-policy-engine","title":"4. License Policy Engine","text":""},{"location":"services/ai-compliance-sdk/DEVELOPER/#ubersicht_1","title":"\u00dcbersicht","text":"

Die License Policy Engine (internal/ucca/license_policy.go) pr\u00fcft die Lizenz-Compliance f\u00fcr Standards und Normen.

"},{"location":"services/ai-compliance-sdk/DEVELOPER/#operationsmodi","title":"Operationsmodi","text":"Modus Beschreibung Lizenzanforderung LINK_ONLY Nur Verweise Keine NOTES_ONLY Eigene Notizen Keine EXCERPT_ONLY Kurzzitate (<150 Zeichen) Standard-Lizenz FULLTEXT_RAG Volltext-Embedding Explizite KI-Lizenz TRAINING Modell-Training Enterprise + Vertrag"},{"location":"services/ai-compliance-sdk/DEVELOPER/#verwendung_1","title":"Verwendung","text":"
import \"ai-compliance-sdk/internal/ucca\"\n\nengine := ucca.NewLicensePolicyEngine()\n\nfacts := &ucca.LicensedContentFacts{\n    Present:       true,\n    Publisher:     \"DIN_MEDIA\",\n    LicenseType:   \"SINGLE_WORKSTATION\",\n    AIUsePermitted: \"NO\",\n    ProofUploaded: false,\n    OperationMode: \"FULLTEXT_RAG\",\n}\n\nresult := engine.Evaluate(facts)\n\nif !result.Allowed {\n    fmt.Println(\"Blockiert:\", result.StopLine.Message)\n    fmt.Println(\"Effektiver Modus:\", result.EffectiveMode)\n}\n
"},{"location":"services/ai-compliance-sdk/DEVELOPER/#ingest-entscheidung","title":"Ingest-Entscheidung","text":"
// Pr\u00fcfen ob Volltext-Ingest erlaubt ist\ncanIngest := engine.CanIngestFulltext(facts)\n\n// Oder detaillierte Entscheidung\ndecision := engine.DecideIngest(facts)\nfmt.Println(\"Fulltext:\", decision.AllowFulltext)\nfmt.Println(\"Notes:\", decision.AllowNotes)\nfmt.Println(\"Metadata:\", decision.AllowMetadata)\n
"},{"location":"services/ai-compliance-sdk/DEVELOPER/#audit-logging","title":"Audit-Logging","text":"
// Audit-Entry erstellen\nentry := engine.FormatAuditEntry(\"tenant-123\", \"doc-456\", facts, result)\n\n// Human-readable Summary\nsummary := engine.FormatHumanReadableSummary(result)\nfmt.Println(summary)\n
"},{"location":"services/ai-compliance-sdk/DEVELOPER/#publisher-spezifische-regeln","title":"Publisher-spezifische Regeln","text":"

DIN Media hat explizite Restriktionen:

// DIN Media blockiert FULLTEXT_RAG ohne AI-Lizenz\nif facts.Publisher == \"DIN_MEDIA\" && facts.AIUsePermitted != \"YES\" {\n    // \u2192 STOP_DIN_FULLTEXT_AI_NOT_ALLOWED\n    // \u2192 Downgrade auf LINK_ONLY\n}\n
"},{"location":"services/ai-compliance-sdk/DEVELOPER/#5-legal-rag-integration","title":"5. Legal RAG Integration","text":""},{"location":"services/ai-compliance-sdk/DEVELOPER/#ubersicht_2","title":"\u00dcbersicht","text":"

Das Legal RAG System (internal/ucca/legal_rag.go) generiert Erkl\u00e4rungen mit rechtlichem Kontext.

"},{"location":"services/ai-compliance-sdk/DEVELOPER/#verwendung_2","title":"Verwendung","text":"
import \"ai-compliance-sdk/internal/ucca\"\n\nrag := ucca.NewLegalRAGService(qdrantClient, llmClient, \"bp_legal_corpus\")\n\n// Erkl\u00e4rung generieren\nexplanation, err := rag.Explain(ctx, result, intake)\nif err != nil {\n    log.Error(err)\n}\n\nfmt.Println(\"Erkl\u00e4rung:\", explanation.Text)\nfmt.Println(\"Rechtsquellen:\", explanation.Sources)\n
"},{"location":"services/ai-compliance-sdk/DEVELOPER/#rechtsquellen-im-rag","title":"Rechtsquellen im RAG","text":"Quelle Chunks Beschreibung DSGVO 128 EU Datenschutz-Grundverordnung AI Act 96 EU AI-Verordnung NIS2 128 Netzwerk-Informationssicherheit SCC 32 Standardvertragsklauseln DPF 714 Data Privacy Framework"},{"location":"services/ai-compliance-sdk/DEVELOPER/#6-wizard-legal-assistant","title":"6. Wizard & Legal Assistant","text":""},{"location":"services/ai-compliance-sdk/DEVELOPER/#wizard-schema","title":"Wizard-Schema","text":"

Das Wizard-Schema (policies/wizard_schema_v1.yaml) definiert die Fragen f\u00fcr das Frontend.

"},{"location":"services/ai-compliance-sdk/DEVELOPER/#legal-assistant-verwenden","title":"Legal Assistant verwenden","text":"
// Wizard-Frage an Legal Assistant stellen\ntype WizardAskRequest struct {\n    Question    string                 `json:\"question\"`\n    StepNumber  int                    `json:\"step_number\"`\n    FieldID     string                 `json:\"field_id,omitempty\"`\n    CurrentData map[string]interface{} `json:\"current_data,omitempty\"`\n}\n\n// POST /sdk/v1/ucca/wizard/ask\n
"},{"location":"services/ai-compliance-sdk/DEVELOPER/#beispiel-api-call","title":"Beispiel API-Call","text":"
curl -X POST http://localhost:8080/sdk/v1/ucca/wizard/ask \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n    \"question\": \"Was sind personenbezogene Daten?\",\n    \"step_number\": 2,\n    \"field_id\": \"data_types.personal_data\"\n  }'\n
"},{"location":"services/ai-compliance-sdk/DEVELOPER/#7-eskalations-system","title":"7. Eskalations-System","text":""},{"location":"services/ai-compliance-sdk/DEVELOPER/#eskalationsstufen","title":"Eskalationsstufen","text":"Level Ausl\u00f6ser Pr\u00fcfer SLA E0 Nur INFO Automatisch - E1 WARN, geringes Risiko Team-Lead 24h E2 Art. 9, DSFA empfohlen DSB 8h E3 BLOCK, hohes Risiko DSB + Legal 4h"},{"location":"services/ai-compliance-sdk/DEVELOPER/#eskalation-erstellen","title":"Eskalation erstellen","text":"
import \"ai-compliance-sdk/internal/ucca\"\n\nstore := ucca.NewEscalationStore(db)\n\nescalation := &ucca.Escalation{\n    AssessmentID:    \"assess-123\",\n    Level:           ucca.EscalationE2,\n    TriggerReason:   \"Art. 9 Daten betroffen\",\n    RequiredReviews: 1,\n}\n\nerr := store.CreateEscalation(ctx, escalation)\n
"},{"location":"services/ai-compliance-sdk/DEVELOPER/#sla-monitor","title":"SLA-Monitor","text":"
monitor := ucca.NewSLAMonitor(store, notificationService)\n\n// Im Hintergrund starten\ngo monitor.Start(ctx)\n
"},{"location":"services/ai-compliance-sdk/DEVELOPER/#8-api-endpoints","title":"8. API-Endpoints","text":""},{"location":"services/ai-compliance-sdk/DEVELOPER/#ucca-endpoints","title":"UCCA Endpoints","text":"Method Endpoint Beschreibung POST /sdk/v1/ucca/assess Assessment erstellen GET /sdk/v1/ucca/assess/:id Assessment abrufen POST /sdk/v1/ucca/explain Erkl\u00e4rung generieren GET /sdk/v1/ucca/wizard/schema Wizard-Schema abrufen POST /sdk/v1/ucca/wizard/ask Legal Assistant fragen"},{"location":"services/ai-compliance-sdk/DEVELOPER/#license-endpoints","title":"License Endpoints","text":"Method Endpoint Beschreibung POST /sdk/v1/license/evaluate Lizenz-Pr\u00fcfung POST /sdk/v1/license/decide-ingest Ingest-Entscheidung"},{"location":"services/ai-compliance-sdk/DEVELOPER/#eskalations-endpoints","title":"Eskalations-Endpoints","text":"Method Endpoint Beschreibung GET /sdk/v1/escalations Offene Eskalationen GET /sdk/v1/escalations/:id Eskalation abrufen POST /sdk/v1/escalations/:id/decide Entscheidung treffen"},{"location":"services/ai-compliance-sdk/DEVELOPER/#9-policy-dateien","title":"9. Policy-Dateien","text":""},{"location":"services/ai-compliance-sdk/DEVELOPER/#dateistruktur","title":"Dateistruktur","text":"
policies/\n\u251c\u2500\u2500 ucca_policy_v1.yaml        # Haupt-Policy (Regeln, Controls, Patterns)\n\u251c\u2500\u2500 wizard_schema_v1.yaml      # Wizard-Fragen und Legal Assistant\n\u251c\u2500\u2500 controls_catalog.yaml      # Detaillierte Control-Beschreibungen\n\u251c\u2500\u2500 gap_mapping.yaml           # Facts \u2192 Gaps \u2192 Controls\n\u251c\u2500\u2500 licensed_content_policy.yaml # Standards/Normen Compliance\n\u2514\u2500\u2500 scc_legal_corpus.yaml      # SCC Rechtsquellen\n
"},{"location":"services/ai-compliance-sdk/DEVELOPER/#policy-version","title":"Policy-Version","text":"

Jede Policy hat eine Version:

metadata:\n  version: \"1.0.0\"\n  effective_date: \"2025-01-01\"\n  author: \"Compliance Team\"\n
"},{"location":"services/ai-compliance-sdk/DEVELOPER/#10-tests-ausfuhren","title":"10. Tests ausf\u00fchren","text":""},{"location":"services/ai-compliance-sdk/DEVELOPER/#alle-tests","title":"Alle Tests","text":"
cd ai-compliance-sdk\ngo test -v ./...\n
"},{"location":"services/ai-compliance-sdk/DEVELOPER/#spezifische-tests","title":"Spezifische Tests","text":"
# Policy Engine Tests\ngo test -v ./internal/ucca/policy_engine_test.go\n\n# License Policy Tests\ngo test -v ./internal/ucca/license_policy_test.go\n\n# Eskalation Tests\ngo test -v ./internal/ucca/escalation_test.go\n
"},{"location":"services/ai-compliance-sdk/DEVELOPER/#test-coverage","title":"Test-Coverage","text":"
go test -cover ./...\n\n# HTML-Report\ngo test -coverprofile=coverage.out ./...\ngo tool cover -html=coverage.out\n
"},{"location":"services/ai-compliance-sdk/DEVELOPER/#beispiel-neuen-test-hinzufugen","title":"Beispiel: Neuen Test hinzuf\u00fcgen","text":"
func TestMyNewFeature(t *testing.T) {\n    engine := NewLicensePolicyEngine()\n\n    facts := &LicensedContentFacts{\n        Present:       true,\n        Publisher:     \"DIN_MEDIA\",\n        OperationMode: \"FULLTEXT_RAG\",\n    }\n\n    result := engine.Evaluate(facts)\n\n    if result.Allowed {\n        t.Error(\"Expected blocked for DIN_MEDIA FULLTEXT_RAG\")\n    }\n}\n
"},{"location":"services/ai-compliance-sdk/DEVELOPER/#11-generic-obligations-framework","title":"11. Generic Obligations Framework","text":""},{"location":"services/ai-compliance-sdk/DEVELOPER/#ubersicht_3","title":"\u00dcbersicht","text":"

Das Obligations Framework erm\u00f6glicht die automatische Ableitung regulatorischer Pflichten aus NIS2, DSGVO und AI Act.

"},{"location":"services/ai-compliance-sdk/DEVELOPER/#verwendung_3","title":"Verwendung","text":"
import \"ai-compliance-sdk/internal/ucca\"\n\n// Registry erstellen (l\u00e4dt alle Module)\nregistry := ucca.NewObligationsRegistry()\n\n// UnifiedFacts aufbauen\nfacts := &ucca.UnifiedFacts{\n    Organization: ucca.OrganizationFacts{\n        EmployeeCount:  150,\n        AnnualRevenue:  30000000,\n        Country:        \"DE\",\n        EUMember:       true,\n    },\n    Sector: ucca.SectorFacts{\n        PrimarySector:    \"digital_infrastructure\",\n        SpecialServices:  []string{\"cloud\", \"msp\"},\n        IsKRITIS:         false,\n    },\n    DataProtection: ucca.DataProtectionFacts{\n        ProcessesPersonalData: true,\n    },\n    AIUsage: ucca.AIUsageFacts{\n        UsesAI:             true,\n        HighRiskCategories: []string{\"employment\"},\n        IsGPAIProvider:     false,\n    },\n}\n\n// Alle anwendbaren Pflichten evaluieren\noverview := registry.EvaluateAll(facts, \"Muster GmbH\")\n\n// Ergebnis auswerten\nfmt.Println(\"Anwendbare Regulierungen:\", len(overview.ApplicableRegulations))\nfmt.Println(\"Gesamtzahl Pflichten:\", len(overview.Obligations))\nfmt.Println(\"Kritische Pflichten:\", overview.ExecutiveSummary.CriticalObligations)\n
"},{"location":"services/ai-compliance-sdk/DEVELOPER/#neues-regulierungsmodul-erstellen","title":"Neues Regulierungsmodul erstellen","text":"
// 1. Module-Interface implementieren\ntype MyRegulationModule struct {\n    obligations       []ucca.Obligation\n    controls          []ucca.ObligationControl\n    incidentDeadlines []ucca.IncidentDeadline\n}\n\nfunc (m *MyRegulationModule) ID() string { return \"my_regulation\" }\nfunc (m *MyRegulationModule) Name() string { return \"My Regulation\" }\n\nfunc (m *MyRegulationModule) IsApplicable(facts *ucca.UnifiedFacts) bool {\n    // Pr\u00fcflogik implementieren\n    return facts.Organization.Country == \"DE\"\n}\n\nfunc (m *MyRegulationModule) DeriveObligations(facts *ucca.UnifiedFacts) []ucca.Obligation {\n    // Pflichten basierend auf Facts ableiten\n    return m.obligations\n}\n\n// 2. In Registry registrieren\nfunc NewMyRegulationModule() (*MyRegulationModule, error) {\n    m := &MyRegulationModule{}\n    // YAML laden oder hardcoded Pflichten definieren\n    return m, nil\n}\n\n// In obligations_registry.go:\n// r.Register(NewMyRegulationModule())\n
"},{"location":"services/ai-compliance-sdk/DEVELOPER/#yaml-basierte-pflichten","title":"YAML-basierte Pflichten","text":"
# policies/obligations/my_regulation_obligations.yaml\nregulation: my_regulation\nname: \"My Regulation\"\n\nobligations:\n  - id: \"MYREG-OBL-001\"\n    title: \"Compliance-Pflicht\"\n    description: \"Beschreibung der Pflicht\"\n    applies_when: \"classification != 'nicht_betroffen'\"\n    legal_basis:\n      - norm: \"\u00a7 1 MyReg\"\n    category: \"Governance\"\n    responsible: \"Gesch\u00e4ftsf\u00fchrung\"\n    deadline:\n      type: \"relative\"\n      duration: \"12 Monate\"\n    sanctions:\n      max_fine: \"1 Mio. EUR\"\n    priority: \"high\"\n\ncontrols:\n  - id: \"MYREG-CTRL-001\"\n    name: \"Kontrollma\u00dfnahme\"\n    category: \"Technical\"\n    when_applicable: \"immer\"\n    what_to_do: \"Ma\u00dfnahme implementieren\"\n    evidence_needed:\n      - \"Dokumentation\"\n
"},{"location":"services/ai-compliance-sdk/DEVELOPER/#pdf-export","title":"PDF Export","text":"
import \"ai-compliance-sdk/internal/ucca\"\n\n// Exporter erstellen\nexporter := ucca.NewPDFExporter(\"de\")\n\n// PDF generieren\nresponse, err := exporter.ExportManagementMemo(overview)\nif err != nil {\n    log.Fatal(err)\n}\n\n// base64-kodierter PDF-Inhalt\nfmt.Println(\"Content-Type:\", response.ContentType)  // application/pdf\nfmt.Println(\"Filename:\", response.Filename)\n\n// PDF speichern\ndecoded, _ := base64.StdEncoding.DecodeString(response.Content)\nos.WriteFile(\"memo.pdf\", decoded, 0644)\n\n// Alternativ: Markdown\nmdResponse, err := exporter.ExportMarkdown(overview)\nfmt.Println(mdResponse.Content)  // Markdown-Text\n
"},{"location":"services/ai-compliance-sdk/DEVELOPER/#api-endpoints","title":"API-Endpoints","text":"
# Assessment erstellen\ncurl -X POST http://localhost:8090/sdk/v1/ucca/obligations/assess \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n    \"facts\": {\n      \"organization\": {\"employee_count\": 150, \"country\": \"DE\"},\n      \"sector\": {\"primary_sector\": \"healthcare\"},\n      \"data_protection\": {\"processes_personal_data\": true},\n      \"ai_usage\": {\"uses_ai\": false}\n    },\n    \"organization_name\": \"Test GmbH\"\n  }'\n\n# PDF Export (direkt)\ncurl -X POST http://localhost:8090/sdk/v1/ucca/obligations/export/direct \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n    \"overview\": { ... },\n    \"format\": \"pdf\",\n    \"language\": \"de\"\n  }'\n
"},{"location":"services/ai-compliance-sdk/DEVELOPER/#12-tests-fur-obligations-framework","title":"12. Tests f\u00fcr Obligations Framework","text":"
# Alle Obligations-Tests\ngo test -v ./internal/ucca/..._module_test.go\n\n# NIS2 Module Tests\ngo test -v ./internal/ucca/nis2_module_test.go\n\n# DSGVO Module Tests\ngo test -v ./internal/ucca/dsgvo_module_test.go\n\n# AI Act Module Tests\ngo test -v ./internal/ucca/ai_act_module_test.go\n\n# PDF Export Tests\ngo test -v ./internal/ucca/pdf_export_test.go\n
"},{"location":"services/ai-compliance-sdk/DEVELOPER/#beispiel-tests","title":"Beispiel-Tests","text":"
func TestNIS2Module_LargeCompanyInAnnexISector(t *testing.T) {\n    module, _ := ucca.NewNIS2Module()\n\n    facts := &ucca.UnifiedFacts{\n        Organization: ucca.OrganizationFacts{\n            EmployeeCount: 500,\n            AnnualRevenue: 100000000,\n            Country:       \"DE\",\n        },\n        Sector: ucca.SectorFacts{\n            PrimarySector: \"energy\",\n        },\n    }\n\n    if !module.IsApplicable(facts) {\n        t.Error(\"Expected NIS2 to apply to large energy company\")\n    }\n\n    classification := module.Classify(facts)\n    if classification != \"besonders_wichtige_einrichtung\" {\n        t.Errorf(\"Expected 'besonders_wichtige_einrichtung', got '%s'\", classification)\n    }\n}\n\nfunc TestAIActModule_HighRiskEmploymentAI(t *testing.T) {\n    module, _ := ucca.NewAIActModule()\n\n    facts := &ucca.UnifiedFacts{\n        AIUsage: ucca.AIUsageFacts{\n            UsesAI:             true,\n            HighRiskCategories: []string{\"employment\"},\n        },\n    }\n\n    if !module.IsApplicable(facts) {\n        t.Error(\"Expected AI Act to apply\")\n    }\n\n    riskLevel := module.ClassifyRisk(facts)\n    if riskLevel != ucca.AIActHighRisk {\n        t.Errorf(\"Expected 'high_risk', got '%s'\", riskLevel)\n    }\n}\n
"},{"location":"services/ai-compliance-sdk/DEVELOPER/#anhang-wichtige-dateien","title":"Anhang: Wichtige Dateien","text":"Datei Beschreibung internal/ucca/policy_engine.go Haupt-Policy-Engine internal/ucca/license_policy.go License Policy Engine internal/ucca/obligations_framework.go Obligations Interfaces & Typen internal/ucca/obligations_registry.go Modul-Registry internal/ucca/nis2_module.go NIS2 Decision Tree internal/ucca/dsgvo_module.go DSGVO Pflichten internal/ucca/ai_act_module.go AI Act Risk Classification internal/ucca/pdf_export.go PDF/Markdown Export internal/api/handlers/obligations_handlers.go Obligations API policies/obligations/*.yaml Pflichten-Kataloge

Dokumentationsstand: 2026-01-29

"},{"location":"services/ai-compliance-sdk/SBOM/","title":"AI Compliance SDK - Software Bill of Materials (SBOM)","text":"

Erstellt: 2026-01-29 Go-Version: 1.24.0

"},{"location":"services/ai-compliance-sdk/SBOM/#zusammenfassung","title":"Zusammenfassung","text":"Kategorie Anzahl Status Direkte Abh\u00e4ngigkeiten 7 \u2705 Alle kommerziell nutzbar Indirekte Abh\u00e4ngigkeiten ~45 \u2705 Alle kommerziell nutzbar Gesamt ~52 \u2705 Alle Open Source, kommerziell nutzbar"},{"location":"services/ai-compliance-sdk/SBOM/#direkte-abhangigkeiten","title":"Direkte Abh\u00e4ngigkeiten","text":"Package Version Lizenz Kommerziell nutzbar github.com/gin-gonic/gin v1.10.1 MIT \u2705 Ja github.com/gin-contrib/cors v1.7.6 MIT \u2705 Ja github.com/google/uuid v1.6.0 BSD-3-Clause \u2705 Ja github.com/jackc/pgx/v5 v5.5.3 MIT \u2705 Ja github.com/joho/godotenv v1.5.1 MIT \u2705 Ja github.com/xuri/excelize/v2 v2.9.1 BSD-3-Clause \u2705 Ja gopkg.in/yaml.v3 v3.0.1 MIT / Apache-2.0 \u2705 Ja"},{"location":"services/ai-compliance-sdk/SBOM/#indirekte-abhangigkeiten-transitive","title":"Indirekte Abh\u00e4ngigkeiten (Transitive)","text":""},{"location":"services/ai-compliance-sdk/SBOM/#json-serialisierung","title":"JSON / Serialisierung","text":"Package Version Lizenz Kommerziell nutzbar github.com/bytedance/sonic v1.13.3 Apache-2.0 \u2705 Ja github.com/goccy/go-json v0.10.5 MIT \u2705 Ja github.com/json-iterator/go v1.1.12 MIT \u2705 Ja github.com/pelletier/go-toml/v2 v2.2.4 MIT \u2705 Ja gopkg.in/yaml.v3 v3.0.1 MIT / Apache-2.0 \u2705 Ja github.com/ugorji/go/codec v1.3.0 MIT \u2705 Ja"},{"location":"services/ai-compliance-sdk/SBOM/#web-framework-gin-okosystem","title":"Web Framework (Gin-\u00d6kosystem)","text":"Package Version Lizenz Kommerziell nutzbar github.com/gin-contrib/sse v1.1.0 MIT \u2705 Ja github.com/go-playground/validator/v10 v10.26.0 MIT \u2705 Ja github.com/go-playground/locales v0.14.1 MIT \u2705 Ja github.com/go-playground/universal-translator v0.18.1 MIT \u2705 Ja github.com/leodido/go-urn v1.4.0 MIT \u2705 Ja"},{"location":"services/ai-compliance-sdk/SBOM/#datenbank-postgresql","title":"Datenbank (PostgreSQL)","text":"Package Version Lizenz Kommerziell nutzbar github.com/jackc/pgpassfile v1.0.0 MIT \u2705 Ja github.com/jackc/pgservicefile v0.0.0-... MIT \u2705 Ja github.com/jackc/puddle/v2 v2.2.1 MIT \u2705 Ja"},{"location":"services/ai-compliance-sdk/SBOM/#excel-verarbeitung","title":"Excel-Verarbeitung","text":"Package Version Lizenz Kommerziell nutzbar github.com/xuri/excelize/v2 v2.9.1 BSD-3-Clause \u2705 Ja github.com/xuri/efp v0.0.1 BSD-3-Clause \u2705 Ja github.com/xuri/nfp v0.0.2-... BSD-3-Clause \u2705 Ja github.com/richardlehane/mscfb v1.0.4 Apache-2.0 \u2705 Ja github.com/richardlehane/msoleps v1.0.4 Apache-2.0 \u2705 Ja"},{"location":"services/ai-compliance-sdk/SBOM/#pdf-generierung","title":"PDF-Generierung","text":"Package Version Lizenz Kommerziell nutzbar github.com/jung-kurt/gofpdf v1.16.2 MIT \u2705 Ja"},{"location":"services/ai-compliance-sdk/SBOM/#utilities","title":"Utilities","text":"Package Version Lizenz Kommerziell nutzbar github.com/gabriel-vasile/mimetype v1.4.9 MIT \u2705 Ja github.com/mattn/go-isatty v0.0.20 MIT \u2705 Ja github.com/modern-go/concurrent v0.0.0-... Apache-2.0 \u2705 Ja github.com/modern-go/reflect2 v1.0.2 Apache-2.0 \u2705 Ja github.com/klauspost/cpuid/v2 v2.2.10 MIT \u2705 Ja github.com/tiendc/go-deepcopy v1.7.1 MIT \u2705 Ja github.com/twitchyliquid64/golang-asm v0.15.1 MIT \u2705 Ja github.com/cloudwego/base64x v0.1.5 Apache-2.0 \u2705 Ja"},{"location":"services/ai-compliance-sdk/SBOM/#go-standardbibliothek-erweiterungen","title":"Go Standardbibliothek Erweiterungen","text":"Package Version Lizenz Kommerziell nutzbar golang.org/x/arch v0.18.0 BSD-3-Clause \u2705 Ja golang.org/x/crypto v0.43.0 BSD-3-Clause \u2705 Ja golang.org/x/net v0.46.0 BSD-3-Clause \u2705 Ja golang.org/x/sync v0.17.0 BSD-3-Clause \u2705 Ja golang.org/x/sys v0.37.0 BSD-3-Clause \u2705 Ja golang.org/x/text v0.30.0 BSD-3-Clause \u2705 Ja"},{"location":"services/ai-compliance-sdk/SBOM/#protokoll-bibliotheken","title":"Protokoll-Bibliotheken","text":"Package Version Lizenz Kommerziell nutzbar google.golang.org/protobuf v1.36.6 BSD-3-Clause \u2705 Ja"},{"location":"services/ai-compliance-sdk/SBOM/#lizenz-ubersicht","title":"Lizenz-\u00dcbersicht","text":"Lizenz Anzahl Packages Kommerziell nutzbar Copyleft MIT ~25 \u2705 Ja \u274c Nein Apache-2.0 ~8 \u2705 Ja \u274c Nein (schwach) BSD-3-Clause ~12 \u2705 Ja \u274c Nein BSD-2-Clause 0 \u2705 Ja \u274c Nein"},{"location":"services/ai-compliance-sdk/SBOM/#keine-problematischen-lizenzen","title":"Keine problematischen Lizenzen!","text":"Lizenz Status GPL-2.0 \u274c Nicht verwendet GPL-3.0 \u274c Nicht verwendet AGPL \u274c Nicht verwendet LGPL \u274c Nicht verwendet SSPL \u274c Nicht verwendet Commons Clause \u274c Nicht verwendet"},{"location":"services/ai-compliance-sdk/SBOM/#eigene-komponenten-keine-externen-abhangigkeiten","title":"Eigene Komponenten (Keine externen Abh\u00e4ngigkeiten)","text":"

Die folgenden Komponenten wurden im Rahmen des AI Compliance SDK entwickelt und haben keine zus\u00e4tzlichen Abh\u00e4ngigkeiten:

Komponente Dateien Externe Deps Policy Engine internal/ucca/policy_engine.go Keine License Policy Engine internal/ucca/license_policy.go Keine Legal RAG internal/ucca/legal_rag.go Keine Escalation System internal/ucca/escalation_*.go Keine SLA Monitor internal/ucca/sla_monitor.go Keine UCCA Handlers internal/api/handlers/ucca_handlers.go Gin (MIT) Obligations Framework internal/ucca/obligations_framework.go Keine Obligations Registry internal/ucca/obligations_registry.go Keine NIS2 Module internal/ucca/nis2_module.go Keine DSGVO Module internal/ucca/dsgvo_module.go Keine AI Act Module internal/ucca/ai_act_module.go Keine PDF Export internal/ucca/pdf_export.go gofpdf (MIT) Obligations Handlers internal/api/handlers/obligations_handlers.go Gin (MIT) Funding Models internal/funding/models.go Keine Funding Store internal/funding/store.go, postgres_store.go pgx (MIT) Funding Export internal/funding/export.go gofpdf (MIT), excelize (BSD-3) Funding Handlers internal/api/handlers/funding_handlers.go Gin (MIT)"},{"location":"services/ai-compliance-sdk/SBOM/#policy-dateien-reine-yamljson","title":"Policy-Dateien (Reine YAML/JSON)","text":"Datei Format Abh\u00e4ngigkeiten ucca_policy_v1.yaml YAML Keine wizard_schema_v1.yaml YAML Keine controls_catalog.yaml YAML Keine gap_mapping.yaml YAML Keine licensed_content_policy.yaml YAML Keine financial_regulations_policy.yaml YAML Keine financial_regulations_corpus.yaml YAML Keine scc_legal_corpus.yaml YAML Keine obligations/nis2_obligations.yaml YAML Keine obligations/dsgvo_obligations.yaml YAML Keine obligations/ai_act_obligations.yaml YAML Keine funding/foerderantrag_wizard_v1.yaml YAML Keine funding/bundesland_profiles.yaml YAML Keine"},{"location":"services/ai-compliance-sdk/SBOM/#compliance-erklarung","title":"Compliance-Erkl\u00e4rung","text":""},{"location":"services/ai-compliance-sdk/SBOM/#fur-kommerzielle-nutzung-geeignet-ja","title":"F\u00fcr kommerzielle Nutzung geeignet: \u2705 JA","text":"

Alle verwendeten Abh\u00e4ngigkeiten verwenden permissive Open-Source-Lizenzen:

  1. MIT-Lizenz: Erlaubt kommerzielle Nutzung, Modifikation, Distribution. Nur Lizenzhinweis erforderlich.

  2. Apache-2.0-Lizenz: Erlaubt kommerzielle Nutzung, Modifikation, Distribution. Patentgew\u00e4hrung enthalten.

  3. BSD-3-Clause: Erlaubt kommerzielle Nutzung, Modifikation, Distribution. Nur Lizenzhinweis erforderlich.

"},{"location":"services/ai-compliance-sdk/SBOM/#keine-copyleft-lizenzen","title":"Keine Copyleft-Lizenzen","text":"

Es werden keine Copyleft-Lizenzen (GPL, AGPL, LGPL) verwendet, die eine Offenlegung des eigenen Quellcodes erfordern w\u00fcrden.

"},{"location":"services/ai-compliance-sdk/SBOM/#empfohlene-manahmen","title":"Empfohlene Ma\u00dfnahmen","text":"
  1. NOTICE-Datei pflegen: Alle Lizenztexte in einer NOTICE-Datei zusammenfassen
  2. Regelm\u00e4\u00dfige Updates: Abh\u00e4ngigkeiten auf bekannte Schwachstellen pr\u00fcfen
  3. License-Scanner: Tool wie go-licenses oder fossa f\u00fcr automatisierte Pr\u00fcfung
"},{"location":"services/ai-compliance-sdk/SBOM/#generierung-des-sbom","title":"Generierung des SBOM","text":"
# SBOM im SPDX-Format generieren\ngo install github.com/spdx/tools-golang/cmd/spdx-tvwriter@latest\ngo mod download\n# Manuell: SPDX-Dokument erstellen\n\n# Alternativ: CycloneDX Format\ngo install github.com/CycloneDX/cyclonedx-gomod/cmd/cyclonedx-gomod@latest\ncyclonedx-gomod mod -output sbom.json\n\n# Lizenz-Pr\u00fcfung\ngo install github.com/google/go-licenses@latest\ngo-licenses csv github.com/breakpilot/ai-compliance-sdk/...\n

Dokumentationsstand: 2026-01-29

"},{"location":"services/ki-daten-pipeline/","title":"KI-Daten-Pipeline","text":"

Die KI-Daten-Pipeline ist ein zusammenhaengendes System aus drei Modulen, das den Datenfluss von der Erfassung bis zur semantischen Suche abbildet.

"},{"location":"services/ki-daten-pipeline/#uebersicht","title":"Uebersicht","text":"
flowchart LR\n    subgraph OCR[\"OCR-Labeling\"]\n        A[Klausur-Scans] --> B[OCR Erkennung]\n        B --> C[Ground Truth Labels]\n    end\n\n    subgraph RAG[\"RAG Pipeline\"]\n        D[PDF Dokumente] --> E[Text-Extraktion]\n        E --> F[Chunking]\n        F --> G[Embedding]\n    end\n\n    subgraph SEARCH[\"Daten & RAG\"]\n        H[Qdrant Collections]\n        I[Semantische Suche]\n    end\n\n    C -->|Export| D\n    G -->|Indexierung| H\n    H --> I\n    I -->|Ergebnisse| J[Klausur-Korrektur]
"},{"location":"services/ki-daten-pipeline/#module","title":"Module","text":"Modul Pfad Funktion Backend OCR-Labeling /ai/ocr-labeling Ground Truth fuer Handschrift-OCR klausur-service:8086 RAG Pipeline /ai/rag-pipeline Dokument-Indexierung klausur-service:8086 Daten & RAG /ai/rag Vektor-Suche & Collection-Mapping klausur-service:8086"},{"location":"services/ki-daten-pipeline/#datenfluss","title":"Datenfluss","text":""},{"location":"services/ki-daten-pipeline/#1-ocr-labeling-eingabe","title":"1. OCR-Labeling (Eingabe)","text":"

Das OCR-Labeling-Modul erfasst Ground Truth Daten fuer das Training von Handschrift-Erkennungsmodellen:

"},{"location":"services/ki-daten-pipeline/#2-rag-pipeline-verarbeitung","title":"2. RAG Pipeline (Verarbeitung)","text":"

Die RAG Pipeline verarbeitet Dokumente und macht sie suchbar:

flowchart TD\n    A[Datenquellen] --> B[OCR/Text-Extraktion]\n    B --> C[Chunking]\n    C --> D[Embedding]\n    D --> E[Qdrant Indexierung]\n\n    subgraph sources[\"Datenquellen\"]\n        S1[NiBiS PDFs]\n        S2[Eigene EH]\n        S3[Rechtskorpus]\n        S4[Schulordnungen]\n    end

Verarbeitungsschritte:

  1. Dokumentenextraktion: PDFs und Bilder werden per OCR in Text umgewandelt
  2. Chunking: Lange Texte werden in Abschnitte aufgeteilt
  3. Chunk-Groesse: 1000 Zeichen
  4. Ueberlappung: 200 Zeichen
  5. Embedding: Jeder Chunk wird in einen Vektor umgewandelt
  6. Modell: text-embedding-3-small
  7. Dimensionen: 1536
  8. Indexierung: Vektoren werden in Qdrant gespeichert
"},{"location":"services/ki-daten-pipeline/#3-daten-rag-ausgabe","title":"3. Daten & RAG (Ausgabe)","text":"

Das Daten & RAG Modul ermoeglicht die Verwaltung und Suche:

"},{"location":"services/ki-daten-pipeline/#qdrant-collections","title":"Qdrant Collections","text":"Collection Inhalt Status bp_nibis_eh Offizielle NiBiS Erwartungshorizonte Aktiv bp_eh Benutzerdefinierte Erwartungshorizonte Aktiv bp_schulordnungen Schulordnungen aller Bundeslaender In Arbeit bp_legal_corpus Rechtskorpus (DSGVO, AI Act, BSI, etc.) Aktiv"},{"location":"services/ki-daten-pipeline/#technische-architektur","title":"Technische Architektur","text":""},{"location":"services/ki-daten-pipeline/#services","title":"Services","text":"
graph TB\n    subgraph Frontend[\"Admin-v2 (Next.js)\"]\n        F1[\"/ai/ocr-labeling\"]\n        F2[\"/ai/rag-pipeline\"]\n        F3[\"/ai/rag\"]\n    end\n\n    subgraph Backend[\"klausur-service (Python)\"]\n        B1[OCR Endpoints]\n        B2[Indexierungs-Jobs]\n        B3[Such-API]\n    end\n\n    subgraph Storage[\"Datenbanken\"]\n        D1[(PostgreSQL)]\n        D2[(Qdrant)]\n        D3[(MinIO)]\n    end\n\n    F1 --> B1\n    F2 --> B2\n    F3 --> B3\n\n    B1 --> D1\n    B1 --> D3\n    B2 --> D2\n    B3 --> D2
"},{"location":"services/ki-daten-pipeline/#backend-endpunkte","title":"Backend-Endpunkte","text":""},{"location":"services/ki-daten-pipeline/#ocr-labeling-apiv1ocr-label","title":"OCR-Labeling (/api/v1/ocr-label/)","text":"Endpoint Methode Beschreibung /sessions GET/POST Session-Verwaltung /sessions/{id}/upload POST Bilder hochladen /queue GET Labeling-Queue /confirm POST OCR bestaetigen /correct POST OCR korrigieren /skip POST Item ueberspringen /stats GET Statistiken /export POST Trainingsdaten exportieren"},{"location":"services/ki-daten-pipeline/#rag-pipeline-apiairag-pipeline","title":"RAG Pipeline (/api/ai/rag-pipeline)","text":"Action Beschreibung jobs Indexierungs-Jobs auflisten dataset-stats Datensatz-Statistiken create-job Neue Indexierung starten pause Job pausieren resume Job fortsetzen cancel Job abbrechen"},{"location":"services/ki-daten-pipeline/#legal-corpus-apilegal-corpus","title":"Legal Corpus (/api/legal-corpus/)","text":"Endpoint Beschreibung /status Collection-Status /search Semantische Suche /ingest Dokumente indexieren"},{"location":"services/ki-daten-pipeline/#integration-mit-klausur-korrektur","title":"Integration mit Klausur-Korrektur","text":"

Die KI-Daten-Pipeline liefert Erwartungshorizont-Vorschlaege fuer die Klausur-Korrektur:

sequenceDiagram\n    participant L as Lehrer\n    participant K as Klausur-Korrektur\n    participant R as RAG-Suche\n    participant Q as Qdrant\n\n    L->>K: Schueler-Antwort pruefen\n    K->>R: EH-Vorschlaege laden\n    R->>Q: Semantische Suche\n    Q->>R: Top-k Chunks\n    R->>K: Relevante EH-Passagen\n    K->>L: Bewertungsvorschlaege
"},{"location":"services/ki-daten-pipeline/#deployment","title":"Deployment","text":"

Die Module werden als Teil des admin-v2 Containers deployed:

# 1. Sync\nrsync -avz --delete --exclude 'node_modules' --exclude '.next' --exclude '.git' \\\n  /Users/benjaminadmin/Projekte/breakpilot-pwa/admin-v2/ \\\n  macmini:/Users/benjaminadmin/Projekte/breakpilot-pwa/admin-v2/\n\n# 2. Build & Deploy\nssh macmini \"/usr/local/bin/docker compose \\\n  -f /Users/benjaminadmin/Projekte/breakpilot-pwa/docker-compose.yml \\\n  build --no-cache admin-v2 && \\\n  /usr/local/bin/docker compose \\\n  -f /Users/benjaminadmin/Projekte/breakpilot-pwa/docker-compose.yml \\\n  up -d admin-v2\"\n
"},{"location":"services/ki-daten-pipeline/#verwandte-dokumentation","title":"Verwandte Dokumentation","text":""},{"location":"services/ki-daten-pipeline/architecture/","title":"KI-Daten-Pipeline Architektur","text":"

Diese Seite dokumentiert die technische Architektur der KI-Daten-Pipeline im Detail.

"},{"location":"services/ki-daten-pipeline/architecture/#systemuebersicht","title":"Systemuebersicht","text":"
graph TB\n    subgraph Users[\"Benutzer\"]\n        U1[Entwickler]\n        U2[Data Scientists]\n        U3[Lehrer]\n    end\n\n    subgraph Frontend[\"Frontend (admin-v2)\"]\n        direction TB\n        F1[\"OCR-Labeling<br/>/ai/ocr-labeling\"]\n        F2[\"RAG Pipeline<br/>/ai/rag-pipeline\"]\n        F3[\"Daten & RAG<br/>/ai/rag\"]\n        F4[\"Klausur-Korrektur<br/>/ai/klausur-korrektur\"]\n    end\n\n    subgraph Backend[\"Backend Services\"]\n        direction TB\n        B1[\"klausur-service<br/>Port 8086\"]\n        B2[\"embedding-service<br/>Port 8087\"]\n    end\n\n    subgraph Storage[\"Persistenz\"]\n        direction TB\n        D1[(PostgreSQL<br/>Metadaten)]\n        D2[(Qdrant<br/>Vektoren)]\n        D3[(MinIO<br/>Bilder/PDFs)]\n    end\n\n    subgraph External[\"Externe APIs\"]\n        E1[OpenAI API]\n        E2[Ollama]\n    end\n\n    U1 --> F1\n    U2 --> F2\n    U3 --> F4\n\n    F1 --> B1\n    F2 --> B1\n    F3 --> B1\n    F4 --> B1\n\n    B1 --> D1\n    B1 --> D2\n    B1 --> D3\n    B1 --> B2\n\n    B2 --> E1\n    B1 --> E2
"},{"location":"services/ki-daten-pipeline/architecture/#komponenten-details","title":"Komponenten-Details","text":""},{"location":"services/ki-daten-pipeline/architecture/#ocr-labeling-modul","title":"OCR-Labeling Modul","text":"
flowchart TB\n    subgraph Upload[\"Upload-Prozess\"]\n        U1[Bilder hochladen] --> U2[MinIO speichern]\n        U2 --> U3[Session erstellen]\n    end\n\n    subgraph OCR[\"OCR-Verarbeitung\"]\n        O1[Bild laden] --> O2{Modell w\u00e4hlen}\n        O2 -->|llama3.2-vision| O3a[Vision LLM]\n        O2 -->|trocr| O3b[Transformer]\n        O2 -->|paddleocr| O3c[PaddleOCR]\n        O2 -->|donut| O3d[Document AI]\n        O3a --> O4[OCR-Text]\n        O3b --> O4\n        O3c --> O4\n        O3d --> O4\n    end\n\n    subgraph Labeling[\"Labeling-Prozess\"]\n        L1[Queue laden] --> L2[Item anzeigen]\n        L2 --> L3{Entscheidung}\n        L3 -->|korrekt| L4[Bestaetigen]\n        L3 -->|falsch| L5[Korrigieren]\n        L3 -->|unklar| L6[Ueberspringen]\n        L4 --> L7[PostgreSQL]\n        L5 --> L7\n        L6 --> L7\n    end\n\n    subgraph Export[\"Export\"]\n        E1[Gelabelte Items] --> E2{Format}\n        E2 -->|TrOCR| E3a[Transformer Format]\n        E2 -->|Llama| E3b[Vision Format]\n        E2 -->|Generic| E3c[JSON]\n    end\n\n    Upload --> OCR\n    OCR --> Labeling\n    Labeling --> Export
"},{"location":"services/ki-daten-pipeline/architecture/#rag-pipeline-modul","title":"RAG Pipeline Modul","text":"
flowchart TB\n    subgraph Sources[\"Datenquellen\"]\n        S1[NiBiS PDFs]\n        S2[Uploads]\n        S3[Rechtskorpus]\n        S4[Schulordnungen]\n    end\n\n    subgraph Processing[\"Verarbeitung\"]\n        direction TB\n        P1[PDF Parser] --> P2[OCR falls noetig]\n        P2 --> P3[Text Cleaning]\n        P3 --> P4[Chunking<br/>1000 chars, 200 overlap]\n        P4 --> P5[Metadata Extraction]\n    end\n\n    subgraph Embedding[\"Embedding\"]\n        E1[embedding-service] --> E2[OpenAI API]\n        E2 --> E3[1536-dim Vektor]\n    end\n\n    subgraph Indexing[\"Indexierung\"]\n        I1{Collection waehlen}\n        I1 -->|EH| I2a[bp_nibis_eh]\n        I1 -->|Custom| I2b[bp_eh]\n        I1 -->|Legal| I2c[bp_legal_corpus]\n        I1 -->|Schul| I2d[bp_schulordnungen]\n        I2a --> I3[Qdrant upsert]\n        I2b --> I3\n        I2c --> I3\n        I2d --> I3\n    end\n\n    Sources --> Processing\n    Processing --> Embedding\n    Embedding --> Indexing
"},{"location":"services/ki-daten-pipeline/architecture/#daten-rag-modul","title":"Daten & RAG Modul","text":"
flowchart TB\n    subgraph Query[\"Suchanfrage\"]\n        Q1[User Query] --> Q2[Query Embedding]\n        Q2 --> Q3[1536-dim Vektor]\n    end\n\n    subgraph Search[\"Qdrant Suche\"]\n        S1[Collection waehlen] --> S2[Vector Search]\n        S2 --> S3[Top-k Results]\n        S3 --> S4[Score Filtering]\n    end\n\n    subgraph Results[\"Ergebnisse\"]\n        R1[Chunks] --> R2[Metadata anreichern]\n        R2 --> R3[Source URLs]\n        R3 --> R4[Response]\n    end\n\n    Query --> Search\n    Search --> Results
"},{"location":"services/ki-daten-pipeline/architecture/#datenmodelle","title":"Datenmodelle","text":""},{"location":"services/ki-daten-pipeline/architecture/#ocr-labeling","title":"OCR-Labeling","text":"
interface OCRSession {\n  id: string\n  name: string\n  source_type: 'klausur' | 'handwriting_sample' | 'scan'\n  ocr_model: 'llama3.2-vision:11b' | 'trocr' | 'paddleocr' | 'donut'\n  total_items: number\n  labeled_items: number\n  status: 'active' | 'completed' | 'archived'\n  created_at: string\n}\n\ninterface OCRItem {\n  id: string\n  session_id: string\n  image_path: string\n  ocr_text: string | null\n  ocr_confidence: number | null\n  ground_truth: string | null\n  status: 'pending' | 'confirmed' | 'corrected' | 'skipped'\n  label_time_seconds: number | null\n}\n
"},{"location":"services/ki-daten-pipeline/architecture/#rag-pipeline","title":"RAG Pipeline","text":"
interface TrainingJob {\n  id: string\n  name: string\n  status: 'queued' | 'preparing' | 'training' | 'validating' | 'completed' | 'failed' | 'paused'\n  progress: number\n  current_epoch: number\n  total_epochs: number\n  documents_processed: number\n  total_documents: number\n  config: {\n    batch_size: number\n    bundeslaender: string[]\n    mixed_precision: boolean\n  }\n}\n\ninterface DataSource {\n  id: string\n  name: string\n  collection: string\n  document_count: number\n  chunk_count: number\n  status: 'active' | 'pending' | 'error'\n  last_updated: string | null\n}\n
"},{"location":"services/ki-daten-pipeline/architecture/#legal-corpus","title":"Legal Corpus","text":"
interface RegulationStatus {\n  code: string\n  name: string\n  fullName: string\n  type: 'eu_regulation' | 'eu_directive' | 'de_law' | 'bsi_standard'\n  chunkCount: number\n  status: 'ready' | 'empty' | 'error'\n}\n\ninterface SearchResult {\n  text: string\n  regulation_code: string\n  regulation_name: string\n  article: string | null\n  paragraph: string | null\n  source_url: string\n  score: number\n}\n
"},{"location":"services/ki-daten-pipeline/architecture/#qdrant-collections","title":"Qdrant Collections","text":""},{"location":"services/ki-daten-pipeline/architecture/#konfiguration","title":"Konfiguration","text":"Collection Vektor-Dimension Distanz-Metrik Payload bp_nibis_eh 1536 COSINE bundesland, fach, aufgabe bp_eh 1536 COSINE user_id, klausur_id bp_legal_corpus 1536 COSINE regulation, article, source_url bp_schulordnungen 1536 COSINE bundesland, typ, datum"},{"location":"services/ki-daten-pipeline/architecture/#chunk-strategie","title":"Chunk-Strategie","text":"
\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502                      Originaldokument                        \u2502\n\u2502  Lorem ipsum dolor sit amet, consectetur adipiscing elit...  \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n                              \u2502\n                              \u25bc\n\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510  \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510  \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502      Chunk 1         \u2502  \u2502      Chunk 2         \u2502  \u2502      Chunk 3         \u2502\n\u2502  0-1000 chars        \u2502  \u2502  800-1800 chars      \u2502  \u2502  1600-2600 chars     \u2502\n\u2502                      \u2502  \u2502  (200 overlap)       \u2502  \u2502  (200 overlap)       \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518  \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518  \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n
"},{"location":"services/ki-daten-pipeline/architecture/#api-authentifizierung","title":"API-Authentifizierung","text":"

Alle Endpunkte nutzen die zentrale Auth-Middleware:

sequenceDiagram\n    participant C as Client\n    participant A as API Gateway\n    participant S as klausur-service\n    participant D as Datenbank\n\n    C->>A: Request + JWT Token\n    A->>A: Token validieren\n    A->>S: Forwarded Request\n    S->>D: Daten abfragen\n    D->>S: Response\n    S->>C: JSON Response
"},{"location":"services/ki-daten-pipeline/architecture/#monitoring-metriken","title":"Monitoring & Metriken","text":""},{"location":"services/ki-daten-pipeline/architecture/#verfuegbare-metriken","title":"Verfuegbare Metriken","text":"Metrik Beschreibung Endpoint ocr_items_total Gesamtzahl OCR-Items /api/v1/ocr-label/stats ocr_accuracy_rate OCR-Genauigkeit /api/v1/ocr-label/stats rag_chunk_count Anzahl indexierter Chunks /api/legal-corpus/status rag_collection_status Collection-Status /api/legal-corpus/status"},{"location":"services/ki-daten-pipeline/architecture/#logging","title":"Logging","text":"
# Strukturiertes Logging im klausur-service\nlogger.info(\"OCR processing started\", extra={\n    \"session_id\": session_id,\n    \"item_count\": item_count,\n    \"model\": ocr_model\n})\n
"},{"location":"services/ki-daten-pipeline/architecture/#fehlerbehandlung","title":"Fehlerbehandlung","text":""},{"location":"services/ki-daten-pipeline/architecture/#retry-strategien","title":"Retry-Strategien","text":"Operation Max Retries Backoff OCR-Verarbeitung 3 Exponentiell (1s, 2s, 4s) Embedding-API 5 Exponentiell mit Jitter Qdrant-Upsert 3 Linear (1s)"},{"location":"services/ki-daten-pipeline/architecture/#fallback-verhalten","title":"Fallback-Verhalten","text":"
flowchart TD\n    A[Embedding Request] --> B{OpenAI verfuegbar?}\n    B -->|Ja| C[OpenAI API]\n    B -->|Nein| D{Lokales Modell?}\n    D -->|Ja| E[Ollama Embedding]\n    D -->|Nein| F[Error + Queue]
"},{"location":"services/ki-daten-pipeline/architecture/#skalierung","title":"Skalierung","text":""},{"location":"services/ki-daten-pipeline/architecture/#aktueller-stand","title":"Aktueller Stand","text":""},{"location":"services/ki-daten-pipeline/architecture/#geplante-erweiterungen","title":"Geplante Erweiterungen","text":"
  1. Qdrant Cluster: Bei > 1M Chunks
  2. Worker Queue: Redis-basiert fuer Batch-Jobs
  3. GPU-Offloading: OCR auf vast.ai GPU-Instanzen
"},{"location":"services/klausur-service/","title":"Klausur-Service","text":"

Der Klausur-Service ist ein FastAPI-basierter Microservice fuer KI-gestuetzte Abitur-Klausurkorrektur.

"},{"location":"services/klausur-service/#uebersicht","title":"Uebersicht","text":"Eigenschaft Wert Port 8086 Framework FastAPI (Python) Datenbank PostgreSQL + Qdrant (Vektor-DB) Speicher MinIO (Datei-Storage)"},{"location":"services/klausur-service/#features","title":"Features","text":""},{"location":"services/klausur-service/#architektur","title":"Architektur","text":"
\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502                    Frontend (Next.js)                        \u2502\n\u2502  /website/app/admin/klausur-korrektur/                      \u2502\n\u2502  - Klausur-Liste                                            \u2502\n\u2502  - Studenten-Liste                                          \u2502\n\u2502  - Korrektur-Workspace (2/3-1/3 Layout)                     \u2502\n\u2502  - Fairness-Dashboard                                       \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n                              \u2502\n                              \u25bc\n\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502                 klausur-service (FastAPI)                    \u2502\n\u2502  Port 8086 - /klausur-service/backend/main.py               \u2502\n\u2502  - Klausur CRUD (/api/v1/klausuren)                         \u2502\n\u2502  - Student Work (/api/v1/students)                          \u2502\n\u2502  - Annotations (/api/v1/annotations)                        \u2502\n\u2502  - BYOEH (/api/v1/eh)                                       \u2502\n\u2502  - PDF Export                                               \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n                              \u2502\n                              \u25bc\n\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502                    Infrastruktur                             \u2502\n\u2502  - Qdrant (Vektor-DB fuer RAG)                              \u2502\n\u2502  - MinIO (Datei-Storage)                                    \u2502\n\u2502  - PostgreSQL (Metadaten)                                   \u2502\n\u2502  - Embedding-Service (Port 8087)                            \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n
"},{"location":"services/klausur-service/#api-endpoints","title":"API Endpoints","text":""},{"location":"services/klausur-service/#klausur-verwaltung","title":"Klausur-Verwaltung","text":"Method Endpoint Beschreibung GET /api/v1/klausuren Liste aller Klausuren POST /api/v1/klausuren Neue Klausur erstellen GET /api/v1/klausuren/{id} Klausur-Details DELETE /api/v1/klausuren/{id} Klausur loeschen"},{"location":"services/klausur-service/#studenten-arbeiten","title":"Studenten-Arbeiten","text":"Method Endpoint Beschreibung POST /api/v1/klausuren/{id}/students Arbeit hochladen GET /api/v1/klausuren/{id}/students Studenten-Liste GET /api/v1/students/{id} Einzelne Arbeit PUT /api/v1/students/{id}/criteria Kriterien bewerten PUT /api/v1/students/{id}/gutachten Gutachten speichern"},{"location":"services/klausur-service/#ki-funktionen","title":"KI-Funktionen","text":"Method Endpoint Beschreibung POST /api/v1/students/{id}/gutachten/generate Gutachten generieren GET /api/v1/klausuren/{id}/fairness Fairness-Analyse POST /api/v1/students/{id}/eh-suggestions EH-Vorschlaege via RAG"},{"location":"services/klausur-service/#pdf-export","title":"PDF-Export","text":"Method Endpoint Beschreibung GET /api/v1/students/{id}/export/gutachten Einzelgutachten PDF GET /api/v1/students/{id}/export/annotations Anmerkungen PDF GET /api/v1/klausuren/{id}/export/overview Notenuebersicht PDF GET /api/v1/klausuren/{id}/export/all-gutachten Alle Gutachten PDF"},{"location":"services/klausur-service/#notensystem","title":"Notensystem","text":"

Das System verwendet das deutsche 15-Punkte-System fuer Abiturklausuren:

Punkte Prozent Note 15 >= 95% 1+ 14 >= 90% 1 13 >= 85% 1- 12 >= 80% 2+ 11 >= 75% 2 10 >= 70% 2- 9 >= 65% 3+ 8 >= 60% 3 7 >= 55% 3- 6 >= 50% 4+ 5 >= 45% 4 4 >= 40% 4- 3 >= 33% 5+ 2 >= 27% 5 1 >= 20% 5- 0 < 20% 6"},{"location":"services/klausur-service/#bewertungskriterien","title":"Bewertungskriterien","text":"Kriterium Gewicht Beschreibung Rechtschreibung 15% Orthografie Grammatik 15% Grammatik & Syntax Inhalt 40% Inhaltliche Qualitaet Struktur 15% Aufbau & Gliederung Stil 15% Ausdruck & Stil"},{"location":"services/klausur-service/#verzeichnisstruktur","title":"Verzeichnisstruktur","text":"
klausur-service/\n\u251c\u2500\u2500 backend/\n\u2502   \u251c\u2500\u2500 main.py              # API Endpoints + Datenmodelle\n\u2502   \u251c\u2500\u2500 qdrant_service.py    # Vektor-Datenbank Operationen\n\u2502   \u251c\u2500\u2500 eh_pipeline.py       # BYOEH Verarbeitung\n\u2502   \u251c\u2500\u2500 hybrid_search.py     # Hybrid Search (BM25 + Semantic)\n\u2502   \u2514\u2500\u2500 requirements.txt     # Python Dependencies\n\u251c\u2500\u2500 frontend/\n\u2502   \u2514\u2500\u2500 src/\n\u2502       \u251c\u2500\u2500 components/      # React Komponenten\n\u2502       \u251c\u2500\u2500 pages/           # Seiten\n\u2502       \u2514\u2500\u2500 services/        # API Client\n\u2514\u2500\u2500 docs/\n    \u251c\u2500\u2500 BYOEH-Architecture.md\n    \u2514\u2500\u2500 BYOEH-Developer-Guide.md\n
"},{"location":"services/klausur-service/#konfiguration","title":"Konfiguration","text":""},{"location":"services/klausur-service/#umgebungsvariablen","title":"Umgebungsvariablen","text":"
# Klausur-Service\nKLAUSUR_SERVICE_PORT=8086\nQDRANT_URL=http://qdrant:6333\nMINIO_ENDPOINT=minio:9000\nMINIO_ACCESS_KEY=...\nMINIO_SECRET_KEY=...\n\n# Embedding-Service\nEMBEDDING_SERVICE_URL=http://embedding:8087\nOPENAI_API_KEY=sk-...\n\n# BYOEH\nBYOEH_ENCRYPTION_ENABLED=true\nEH_UPLOAD_DIR=/app/eh-uploads\n
"},{"location":"services/klausur-service/#weiterfuhrende-dokumentation","title":"Weiterf\u00fchrende Dokumentation","text":""},{"location":"services/klausur-service/BYOEH-Architecture/","title":"BYOEH (Bring-Your-Own-Expectation-Horizon) - Architecture Documentation","text":""},{"location":"services/klausur-service/BYOEH-Architecture/#overview","title":"Overview","text":"

The BYOEH module enables teachers to upload their own Erwartungshorizonte (expectation horizons/grading rubrics) and use them for RAG-assisted grading suggestions. Key design principles:

"},{"location":"services/klausur-service/BYOEH-Architecture/#architecture-diagram","title":"Architecture Diagram","text":"
\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502                         klausur-service (Port 8086)                      \u2502\n\u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n\u2502  \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510    \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510  \u2502\n\u2502  \u2502   BYOEH REST API   \u2502    \u2502           BYOEH Service Layer           \u2502  \u2502\n\u2502  \u2502                    \u2502    \u2502                                         \u2502  \u2502\n\u2502  \u2502 POST /api/v1/eh    \u2502\u2500\u2500\u2500\u25b6\u2502 - Upload Wizard Logic                   \u2502  \u2502\n\u2502  \u2502 GET /api/v1/eh     \u2502    \u2502 - Rights Confirmation                   \u2502  \u2502\n\u2502  \u2502 DELETE /api/v1/eh  \u2502    \u2502 - Chunking Pipeline                     \u2502  \u2502\n\u2502  \u2502 POST /rag-query    \u2502    \u2502 - Encryption Service                    \u2502  \u2502\n\u2502  \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518    \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518  \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n                                                  \u2502\n          \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n          \u2502                                       \u2502                       \u2502\n          \u25bc                                       \u25bc                       \u25bc\n\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510   \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510   \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502     PostgreSQL       \u2502   \u2502        Qdrant            \u2502   \u2502  Encrypted Storage   \u2502\n\u2502   (Metadata + Audit) \u2502   \u2502   (Vector Search)        \u2502   \u2502   /app/eh-uploads/   \u2502\n\u2502                      \u2502   \u2502                          \u2502   \u2502                      \u2502\n\u2502 In-Memory Storage:   \u2502   \u2502 Collection: bp_eh        \u2502   \u2502 {tenant}/{eh_id}/    \u2502\n\u2502 - erwartungshorizonte\u2502   \u2502 - tenant_id (filter)     \u2502   \u2502   encrypted.bin      \u2502\n\u2502 - eh_chunks          \u2502   \u2502 - eh_id                  \u2502   \u2502   salt.txt           \u2502\n\u2502 - eh_key_shares      \u2502   \u2502 - embedding[1536]        \u2502   \u2502                      \u2502\n\u2502 - eh_klausur_links   \u2502   \u2502 - encrypted_content      \u2502   \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n\u2502 - eh_audit_log       \u2502   \u2502                          \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518   \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n
"},{"location":"services/klausur-service/BYOEH-Architecture/#data-flow","title":"Data Flow","text":""},{"location":"services/klausur-service/BYOEH-Architecture/#1-upload-flow","title":"1. Upload Flow","text":"
Browser                          Backend                        Storage\n   \u2502                               \u2502                               \u2502\n   \u2502 1. User selects PDF          \u2502                               \u2502\n   \u2502 2. User enters passphrase    \u2502                               \u2502\n   \u2502 3. PBKDF2 key derivation     \u2502                               \u2502\n   \u2502 4. AES-256-GCM encryption    \u2502                               \u2502\n   \u2502 5. SHA-256 key hash          \u2502                               \u2502\n   \u2502                               \u2502                               \u2502\n   \u2502\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u25b6\u2502                               \u2502\n   \u2502 POST /api/v1/eh/upload        \u2502                               \u2502\n   \u2502 (encrypted blob + key_hash)   \u2502                               \u2502\n   \u2502                               \u2502\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u25b6\u2502\n   \u2502                               \u2502 Store encrypted.bin + salt    \u2502\n   \u2502                               \u2502\u25c0\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2502\n   \u2502                               \u2502                               \u2502\n   \u2502                               \u2502 Save metadata to DB           \u2502\n   \u2502\u25c0\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2502                               \u2502\n   \u2502 Return EH record              \u2502                               \u2502\n
"},{"location":"services/klausur-service/BYOEH-Architecture/#2-indexing-flow-rag-preparation","title":"2. Indexing Flow (RAG Preparation)","text":"
Browser                          Backend                        Qdrant\n   \u2502                               \u2502                               \u2502\n   \u2502\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u25b6\u2502                               \u2502\n   \u2502 POST /api/v1/eh/{id}/index    \u2502                               \u2502\n   \u2502 (passphrase for decryption)   \u2502                               \u2502\n   \u2502                               \u2502                               \u2502\n   \u2502                               \u2502 1. Verify key hash            \u2502\n   \u2502                               \u2502 2. Decrypt content            \u2502\n   \u2502                               \u2502 3. Extract text (PDF)         \u2502\n   \u2502                               \u2502 4. Chunk text                 \u2502\n   \u2502                               \u2502 5. Generate embeddings        \u2502\n   \u2502                               \u2502 6. Re-encrypt each chunk      \u2502\n   \u2502                               \u2502\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u25b6\u2502\n   \u2502                               \u2502 Index vectors + encrypted     \u2502\n   \u2502                               \u2502 chunks with tenant filter     \u2502\n   \u2502\u25c0\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2502                               \u2502\n   \u2502 Return chunk count            \u2502                               \u2502\n
"},{"location":"services/klausur-service/BYOEH-Architecture/#3-rag-query-flow","title":"3. RAG Query Flow","text":"
Browser                          Backend                        Qdrant\n   \u2502                               \u2502                               \u2502\n   \u2502\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u25b6\u2502                               \u2502\n   \u2502 POST /api/v1/eh/rag-query     \u2502                               \u2502\n   \u2502 (query + passphrase)          \u2502                               \u2502\n   \u2502                               \u2502                               \u2502\n   \u2502                               \u2502 1. Generate query embedding   \u2502\n   \u2502                               \u2502\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u25b6\u2502\n   \u2502                               \u2502 2. Semantic search            \u2502\n   \u2502                               \u2502    (tenant-filtered)          \u2502\n   \u2502                               \u2502\u25c0\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2502\n   \u2502                               \u2502 3. Decrypt matched chunks     \u2502\n   \u2502\u25c0\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2502                               \u2502\n   \u2502 Return decrypted context      \u2502                               \u2502\n
"},{"location":"services/klausur-service/BYOEH-Architecture/#security-architecture","title":"Security Architecture","text":""},{"location":"services/klausur-service/BYOEH-Architecture/#client-side-encryption","title":"Client-Side Encryption","text":"
\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502                    Browser (Client-Side)                         \u2502\n\u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n\u2502                                                                 \u2502\n\u2502  1. User enters passphrase (NEVER sent to server)               \u2502\n\u2502     \u2502                                                           \u2502\n\u2502     \u25bc                                                           \u2502\n\u2502  2. Key Derivation: PBKDF2-SHA256(passphrase, salt, 100k iter)  \u2502\n\u2502     \u2502                                                           \u2502\n\u2502     \u25bc                                                           \u2502\n\u2502  3. Encryption: AES-256-GCM(key, iv, file_content)              \u2502\n\u2502     \u2502                                                           \u2502\n\u2502     \u25bc                                                           \u2502\n\u2502  4. Key-Hash: SHA-256(derived_key) \u2192 server verification only   \u2502\n\u2502     \u2502                                                           \u2502\n\u2502     \u25bc                                                           \u2502\n\u2502  5. Upload: encrypted_blob + key_hash + salt (NOT key!)         \u2502\n\u2502                                                                 \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n
"},{"location":"services/klausur-service/BYOEH-Architecture/#security-guarantees","title":"Security Guarantees","text":"Guarantee Implementation No Training training_allowed: false on all Qdrant points Operator Blindness Passphrase never leaves browser; server only sees key hash Tenant Isolation Every query filtered by tenant_id Audit Trail All actions logged with timestamps"},{"location":"services/klausur-service/BYOEH-Architecture/#key-sharing-system","title":"Key Sharing System","text":"

The key sharing system enables first examiners to grant access to their EH to second examiners and supervisors.

"},{"location":"services/klausur-service/BYOEH-Architecture/#share-flow","title":"Share Flow","text":"
First Examiner                   Backend                    Second Examiner\n      \u2502                             \u2502                             \u2502\n      \u2502 1. Encrypt passphrase for   \u2502                             \u2502\n      \u2502    recipient (client-side)  \u2502                             \u2502\n      \u2502                             \u2502                             \u2502\n      \u2502\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u25b6                             \u2502\n      \u2502 POST /eh/{id}/share         \u2502                             \u2502\n      \u2502 (encrypted_passphrase, role)\u2502                             \u2502\n      \u2502                             \u2502                             \u2502\n      \u2502                             \u2502 Store EHKeyShare            \u2502\n      \u2502\u25c0\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500                             \u2502\n      \u2502                             \u2502                             \u2502\n      \u2502                             \u2502                             \u2502\n      \u2502                             \u2502\u25c0\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2502\n      \u2502                             \u2502 GET /eh/shared-with-me      \u2502\n      \u2502                             \u2502                             \u2502\n      \u2502                             \u2502\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u25b6\n      \u2502                             \u2502 Return shared EH list       \u2502\n      \u2502                             \u2502                             \u2502\n      \u2502                             \u2502\u25c0\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2502\n      \u2502                             \u2502 RAG query with decrypted    \u2502\n      \u2502                             \u2502 passphrase                  \u2502\n
"},{"location":"services/klausur-service/BYOEH-Architecture/#data-structures","title":"Data Structures","text":"
@dataclass\nclass EHKeyShare:\n    id: str\n    eh_id: str\n    user_id: str                    # Recipient\n    encrypted_passphrase: str       # Client-encrypted for recipient\n    passphrase_hint: str            # Optional hint\n    granted_by: str                 # Grantor user ID\n    granted_at: datetime\n    role: str                       # second_examiner, third_examiner, supervisor\n    klausur_id: Optional[str]       # Link to specific Klausur\n    active: bool\n\n@dataclass\nclass EHKlausurLink:\n    id: str\n    eh_id: str\n    klausur_id: str\n    linked_by: str\n    linked_at: datetime\n
"},{"location":"services/klausur-service/BYOEH-Architecture/#api-endpoints","title":"API Endpoints","text":""},{"location":"services/klausur-service/BYOEH-Architecture/#core-eh-endpoints","title":"Core EH Endpoints","text":"Method Endpoint Description POST /api/v1/eh/upload Upload encrypted EH GET /api/v1/eh List user's EH GET /api/v1/eh/{id} Get single EH DELETE /api/v1/eh/{id} Soft delete EH POST /api/v1/eh/{id}/index Index EH for RAG POST /api/v1/eh/rag-query Query EH content"},{"location":"services/klausur-service/BYOEH-Architecture/#key-sharing-endpoints","title":"Key Sharing Endpoints","text":"Method Endpoint Description POST /api/v1/eh/{id}/share Share EH with examiner GET /api/v1/eh/{id}/shares List shares (owner) DELETE /api/v1/eh/{id}/shares/{shareId} Revoke share GET /api/v1/eh/shared-with-me List EH shared with user"},{"location":"services/klausur-service/BYOEH-Architecture/#klausur-integration-endpoints","title":"Klausur Integration Endpoints","text":"Method Endpoint Description POST /api/v1/eh/{id}/link-klausur Link EH to Klausur DELETE /api/v1/eh/{id}/link-klausur/{klausurId} Unlink EH GET /api/v1/klausuren/{id}/linked-eh Get linked EH for Klausur"},{"location":"services/klausur-service/BYOEH-Architecture/#audit-admin-endpoints","title":"Audit & Admin Endpoints","text":"Method Endpoint Description GET /api/v1/eh/audit-log Get audit log GET /api/v1/eh/rights-text Get rights confirmation text GET /api/v1/eh/qdrant-status Get Qdrant status (admin)"},{"location":"services/klausur-service/BYOEH-Architecture/#frontend-components","title":"Frontend Components","text":""},{"location":"services/klausur-service/BYOEH-Architecture/#ehuploadwizard","title":"EHUploadWizard","text":"

5-step wizard for uploading Erwartungshorizonte:

  1. File Selection - Choose PDF file
  2. Metadata - Title, Subject, Niveau, Year
  3. Rights Confirmation - Legal acknowledgment
  4. Encryption - Set passphrase (2x confirmation)
  5. Summary - Review and upload
"},{"location":"services/klausur-service/BYOEH-Architecture/#integration-points","title":"Integration Points","text":""},{"location":"services/klausur-service/BYOEH-Architecture/#file-structure","title":"File Structure","text":"
klausur-service/\n\u251c\u2500\u2500 backend/\n\u2502   \u251c\u2500\u2500 main.py              # API endpoints + data structures\n\u2502   \u251c\u2500\u2500 qdrant_service.py    # Vector database operations\n\u2502   \u251c\u2500\u2500 eh_pipeline.py       # Chunking, embedding, encryption\n\u2502   \u2514\u2500\u2500 requirements.txt     # Python dependencies\n\u251c\u2500\u2500 frontend/\n\u2502   \u2514\u2500\u2500 src/\n\u2502       \u251c\u2500\u2500 components/\n\u2502       \u2502   \u2514\u2500\u2500 EHUploadWizard.tsx\n\u2502       \u251c\u2500\u2500 services/\n\u2502       \u2502   \u251c\u2500\u2500 api.ts       # API client\n\u2502       \u2502   \u2514\u2500\u2500 encryption.ts # Client-side crypto\n\u2502       \u251c\u2500\u2500 pages/\n\u2502       \u2502   \u2514\u2500\u2500 KorrekturPage.tsx # EH integration\n\u2502       \u2514\u2500\u2500 styles/\n\u2502           \u2514\u2500\u2500 eh-wizard.css\n\u2514\u2500\u2500 docs/\n    \u251c\u2500\u2500 BYOEH-Architecture.md\n    \u2514\u2500\u2500 BYOEH-Developer-Guide.md\n
"},{"location":"services/klausur-service/BYOEH-Architecture/#configuration","title":"Configuration","text":""},{"location":"services/klausur-service/BYOEH-Architecture/#environment-variables","title":"Environment Variables","text":"
QDRANT_URL=http://qdrant:6333\nOPENAI_API_KEY=sk-...              # For embeddings\nBYOEH_ENCRYPTION_ENABLED=true\nEH_UPLOAD_DIR=/app/eh-uploads\n
"},{"location":"services/klausur-service/BYOEH-Architecture/#docker-services","title":"Docker Services","text":"
# docker-compose.yml\nservices:\n  qdrant:\n    image: qdrant/qdrant:v1.7.4\n    ports:\n      - \"6333:6333\"\n    volumes:\n      - qdrant_data:/qdrant/storage\n
"},{"location":"services/klausur-service/BYOEH-Architecture/#audit-events","title":"Audit Events","text":"Action Description upload EH uploaded index EH indexed for RAG rag_query RAG query executed delete EH soft deleted share EH shared with examiner revoke_share Share revoked link_klausur EH linked to Klausur unlink_klausur EH unlinked from Klausur"},{"location":"services/klausur-service/BYOEH-Architecture/#see-also","title":"See Also","text":""},{"location":"services/klausur-service/BYOEH-Developer-Guide/","title":"BYOEH Developer Guide","text":""},{"location":"services/klausur-service/BYOEH-Developer-Guide/#quick-start","title":"Quick Start","text":""},{"location":"services/klausur-service/BYOEH-Developer-Guide/#prerequisites","title":"Prerequisites","text":""},{"location":"services/klausur-service/BYOEH-Developer-Guide/#setup","title":"Setup","text":"
  1. Start services:

    docker-compose up -d qdrant\n

  2. Configure environment:

    QDRANT_URL=http://localhost:6333\nOPENAI_API_KEY=sk-your-key\nBYOEH_ENCRYPTION_ENABLED=true\n

  3. Run klausur-service:

    cd klausur-service/backend\npip install -r requirements.txt\nuvicorn main:app --reload --port 8086\n

  4. Run frontend:

    cd klausur-service/frontend\nnpm install\nnpm run dev\n

"},{"location":"services/klausur-service/BYOEH-Developer-Guide/#client-side-encryption","title":"Client-Side Encryption","text":"

The encryption service (encryption.ts) handles all cryptographic operations in the browser:

"},{"location":"services/klausur-service/BYOEH-Developer-Guide/#encrypting-a-file","title":"Encrypting a File","text":"
import { encryptFile, generateSalt } from '../services/encryption'\n\nconst file = document.getElementById('fileInput').files[0]\nconst passphrase = 'user-secret-password'\n\nconst encrypted = await encryptFile(file, passphrase)\n// Result:\n// {\n//   encryptedData: ArrayBuffer,\n//   keyHash: string,      // SHA-256 hash for verification\n//   salt: string,         // Hex-encoded salt\n//   iv: string            // Hex-encoded initialization vector\n// }\n
"},{"location":"services/klausur-service/BYOEH-Developer-Guide/#decrypting-content","title":"Decrypting Content","text":"
import { decryptText, verifyPassphrase } from '../services/encryption'\n\n// First verify the passphrase\nconst isValid = await verifyPassphrase(passphrase, salt, expectedKeyHash)\n\nif (isValid) {\n  const decrypted = await decryptText(encryptedBase64, passphrase, salt)\n}\n
"},{"location":"services/klausur-service/BYOEH-Developer-Guide/#backend-api-usage","title":"Backend API Usage","text":""},{"location":"services/klausur-service/BYOEH-Developer-Guide/#upload-an-erwartungshorizont","title":"Upload an Erwartungshorizont","text":"
# The upload endpoint accepts FormData with:\n# - file: encrypted binary blob\n# - metadata_json: JSON string with metadata\n\nPOST /api/v1/eh/upload\nContent-Type: multipart/form-data\n\n{\n  \"file\": <encrypted_blob>,\n  \"metadata_json\": {\n    \"metadata\": {\n      \"title\": \"Deutsch LK 2025\",\n      \"subject\": \"deutsch\",\n      \"niveau\": \"eA\",\n      \"year\": 2025,\n      \"aufgaben_nummer\": \"Aufgabe 1\"\n    },\n    \"encryption_key_hash\": \"abc123...\",\n    \"salt\": \"def456...\",\n    \"rights_confirmed\": true,\n    \"original_filename\": \"erwartungshorizont.pdf\"\n  }\n}\n
"},{"location":"services/klausur-service/BYOEH-Developer-Guide/#index-for-rag","title":"Index for RAG","text":"
POST /api/v1/eh/{eh_id}/index\nContent-Type: application/json\n\n{\n  \"passphrase\": \"user-secret-password\"\n}\n

The backend will: 1. Verify the passphrase against stored key hash 2. Decrypt the file 3. Extract text from PDF 4. Chunk the text (1000 chars, 200 overlap) 5. Generate OpenAI embeddings 6. Re-encrypt each chunk 7. Index in Qdrant with tenant filter

"},{"location":"services/klausur-service/BYOEH-Developer-Guide/#rag-query","title":"RAG Query","text":"
POST /api/v1/eh/rag-query\nContent-Type: application/json\n\n{\n  \"query_text\": \"Wie sollte die Einleitung strukturiert sein?\",\n  \"passphrase\": \"user-secret-password\",\n  \"subject\": \"deutsch\",      # Optional filter\n  \"limit\": 5                 # Max results\n}\n

Response:

{\n  \"context\": \"Die Einleitung sollte...\",\n  \"sources\": [\n    {\n      \"text\": \"Die Einleitung sollte...\",\n      \"eh_id\": \"uuid\",\n      \"eh_title\": \"Deutsch LK 2025\",\n      \"chunk_index\": 2,\n      \"score\": 0.89\n    }\n  ],\n  \"query\": \"Wie sollte die Einleitung strukturiert sein?\"\n}\n

"},{"location":"services/klausur-service/BYOEH-Developer-Guide/#key-sharing-implementation","title":"Key Sharing Implementation","text":""},{"location":"services/klausur-service/BYOEH-Developer-Guide/#invitation-flow-recommended","title":"Invitation Flow (Recommended)","text":"

The invitation flow provides a two-phase sharing process: Invite -> Accept

import { ehApi } from '../services/api'\n\n// 1. First examiner sends invitation to second examiner\nconst invitation = await ehApi.inviteToEH(ehId, {\n  invitee_email: 'zweitkorrektor@school.de',\n  role: 'second_examiner',\n  klausur_id: 'klausur-uuid',  // Optional: link to specific Klausur\n  message: 'Bitte fuer Zweitkorrektur nutzen',\n  expires_in_days: 14  // Default: 14 days\n})\n// Returns: { invitation_id, eh_id, invitee_email, role, expires_at, eh_title }\n\n// 2. Second examiner sees pending invitation\nconst pending = await ehApi.getPendingInvitations()\n// [{ invitation: {...}, eh: { id, title, subject, niveau, year } }]\n\n// 3. Second examiner accepts invitation\nconst accepted = await ehApi.acceptInvitation(\n  invitationId,\n  encryptedPassphrase  // Passphrase encrypted for recipient\n)\n// Returns: { status: 'accepted', share_id, eh_id, role, klausur_id }\n
"},{"location":"services/klausur-service/BYOEH-Developer-Guide/#invitation-management","title":"Invitation Management","text":"
// Get invitations sent by current user\nconst sent = await ehApi.getSentInvitations()\n\n// Decline an invitation (as invitee)\nawait ehApi.declineInvitation(invitationId)\n\n// Revoke a pending invitation (as inviter)\nawait ehApi.revokeInvitation(invitationId)\n\n// Get complete access chain for an EH\nconst chain = await ehApi.getAccessChain(ehId)\n// Returns: { eh_id, eh_title, owner, active_shares, pending_invitations, revoked_shares }\n
"},{"location":"services/klausur-service/BYOEH-Developer-Guide/#direct-sharing-legacy","title":"Direct Sharing (Legacy)","text":"

For immediate sharing without invitation:

// First examiner shares directly with second examiner\nawait ehApi.shareEH(ehId, {\n  user_id: 'second-examiner-uuid',\n  role: 'second_examiner',\n  encrypted_passphrase: encryptedPassphrase, // Encrypted for recipient\n  passphrase_hint: 'Das uebliche Passwort',\n  klausur_id: 'klausur-uuid'  // Optional\n})\n
"},{"location":"services/klausur-service/BYOEH-Developer-Guide/#accessing-shared-eh","title":"Accessing Shared EH","text":"
// Second examiner gets shared EH\nconst shared = await ehApi.getSharedWithMe()\n// [{ eh: {...}, share: {...} }]\n\n// Query using provided passphrase\nconst result = await ehApi.ragQuery({\n  query_text: 'search query',\n  passphrase: decryptedPassphrase,\n  subject: 'deutsch'\n})\n
"},{"location":"services/klausur-service/BYOEH-Developer-Guide/#revoking-access","title":"Revoking Access","text":"
// List all shares for an EH\nconst shares = await ehApi.listShares(ehId)\n\n// Revoke a share\nawait ehApi.revokeShare(ehId, shareId)\n
"},{"location":"services/klausur-service/BYOEH-Developer-Guide/#klausur-integration","title":"Klausur Integration","text":""},{"location":"services/klausur-service/BYOEH-Developer-Guide/#automatic-eh-prompt","title":"Automatic EH Prompt","text":"

The KorrekturPage shows an EH upload prompt after the first student work is uploaded:

// In KorrekturPage.tsx\nuseEffect(() => {\n  if (\n    currentKlausur?.students.length === 1 &&\n    linkedEHs.length === 0 &&\n    !ehPromptDismissed\n  ) {\n    setShowEHPrompt(true)\n  }\n}, [currentKlausur?.students.length])\n
"},{"location":"services/klausur-service/BYOEH-Developer-Guide/#linking-eh-to-klausur","title":"Linking EH to Klausur","text":"
// After EH upload, auto-link to Klausur\nawait ehApi.linkToKlausur(ehId, klausurId)\n\n// Get linked EH for a Klausur\nconst linked = await klausurEHApi.getLinkedEH(klausurId)\n
"},{"location":"services/klausur-service/BYOEH-Developer-Guide/#frontend-components","title":"Frontend Components","text":""},{"location":"services/klausur-service/BYOEH-Developer-Guide/#ehuploadwizard-props","title":"EHUploadWizard Props","text":"
interface EHUploadWizardProps {\n  onClose: () => void\n  onComplete?: (ehId: string) => void\n  defaultSubject?: string     // Pre-fill subject\n  defaultYear?: number        // Pre-fill year\n  klausurId?: string          // Auto-link after upload\n}\n\n// Usage\n<EHUploadWizard\n  onClose={() => setShowWizard(false)}\n  onComplete={(ehId) => console.log('Uploaded:', ehId)}\n  defaultSubject={klausur.subject}\n  defaultYear={klausur.year}\n  klausurId={klausur.id}\n/>\n
"},{"location":"services/klausur-service/BYOEH-Developer-Guide/#wizard-steps","title":"Wizard Steps","text":"
  1. file - PDF file selection with drag & drop
  2. metadata - Form for title, subject, niveau, year
  3. rights - Rights confirmation checkbox
  4. encryption - Passphrase input with strength meter
  5. summary - Review and confirm upload
"},{"location":"services/klausur-service/BYOEH-Developer-Guide/#qdrant-operations","title":"Qdrant Operations","text":""},{"location":"services/klausur-service/BYOEH-Developer-Guide/#collection-schema","title":"Collection Schema","text":"
# Collection: bp_eh\n{\n  \"vectors\": {\n    \"size\": 1536,           # OpenAI text-embedding-3-small\n    \"distance\": \"Cosine\"\n  }\n}\n\n# Point payload\n{\n  \"tenant_id\": \"school-uuid\",\n  \"eh_id\": \"eh-uuid\",\n  \"chunk_index\": 0,\n  \"encrypted_content\": \"base64...\",\n  \"training_allowed\": false  # ALWAYS false\n}\n
"},{"location":"services/klausur-service/BYOEH-Developer-Guide/#tenant-isolated-search","title":"Tenant-Isolated Search","text":"
from qdrant_service import search_eh\n\nresults = await search_eh(\n    query_embedding=embedding,\n    tenant_id=\"school-uuid\",\n    subject=\"deutsch\",\n    limit=5\n)\n
"},{"location":"services/klausur-service/BYOEH-Developer-Guide/#testing","title":"Testing","text":""},{"location":"services/klausur-service/BYOEH-Developer-Guide/#unit-tests","title":"Unit Tests","text":"
cd klausur-service/backend\npytest tests/test_byoeh.py -v\n
"},{"location":"services/klausur-service/BYOEH-Developer-Guide/#test-structure","title":"Test Structure","text":"
# tests/test_byoeh.py\nclass TestBYOEH:\n    def test_upload_eh(self, client, auth_headers):\n        \"\"\"Test EH upload with encryption\"\"\"\n        pass\n\n    def test_index_eh(self, client, auth_headers, uploaded_eh):\n        \"\"\"Test EH indexing for RAG\"\"\"\n        pass\n\n    def test_rag_query(self, client, auth_headers, indexed_eh):\n        \"\"\"Test RAG query returns relevant chunks\"\"\"\n        pass\n\n    def test_share_eh(self, client, auth_headers, uploaded_eh):\n        \"\"\"Test sharing EH with another user\"\"\"\n        pass\n
"},{"location":"services/klausur-service/BYOEH-Developer-Guide/#frontend-tests","title":"Frontend Tests","text":"
// EHUploadWizard.test.tsx\ndescribe('EHUploadWizard', () => {\n  it('completes all steps successfully', async () => {\n    // ...\n  })\n\n  it('validates passphrase strength', async () => {\n    // ...\n  })\n\n  it('auto-links to klausur when klausurId provided', async () => {\n    // ...\n  })\n})\n
"},{"location":"services/klausur-service/BYOEH-Developer-Guide/#error-handling","title":"Error Handling","text":""},{"location":"services/klausur-service/BYOEH-Developer-Guide/#common-errors","title":"Common Errors","text":"Error Cause Solution Passphrase verification failed Wrong passphrase Ask user to re-enter EH not found Invalid ID or deleted Check ID, reload list Access denied User not owner/shared Check permissions Qdrant connection failed Service unavailable Check Qdrant container"},{"location":"services/klausur-service/BYOEH-Developer-Guide/#error-response-format","title":"Error Response Format","text":"
{\n  \"detail\": \"Passphrase verification failed\"\n}\n
"},{"location":"services/klausur-service/BYOEH-Developer-Guide/#security-considerations","title":"Security Considerations","text":""},{"location":"services/klausur-service/BYOEH-Developer-Guide/#dos","title":"Do's","text":""},{"location":"services/klausur-service/BYOEH-Developer-Guide/#donts","title":"Don'ts","text":""},{"location":"services/klausur-service/BYOEH-Developer-Guide/#performance-tips","title":"Performance Tips","text":""},{"location":"services/klausur-service/BYOEH-Developer-Guide/#chunking-configuration","title":"Chunking Configuration","text":"
CHUNK_SIZE = 1000    # Characters per chunk\nCHUNK_OVERLAP = 200  # Overlap for context continuity\n
"},{"location":"services/klausur-service/BYOEH-Developer-Guide/#embedding-batching","title":"Embedding Batching","text":"
# Generate embeddings in batches of 20\nEMBEDDING_BATCH_SIZE = 20\n
"},{"location":"services/klausur-service/BYOEH-Developer-Guide/#qdrant-optimization","title":"Qdrant Optimization","text":"
# Use HNSW index for fast approximate search\n# Collection is automatically optimized on creation\n
"},{"location":"services/klausur-service/BYOEH-Developer-Guide/#debugging","title":"Debugging","text":""},{"location":"services/klausur-service/BYOEH-Developer-Guide/#enable-debug-logging","title":"Enable Debug Logging","text":"
import logging\nlogging.getLogger('byoeh').setLevel(logging.DEBUG)\n
"},{"location":"services/klausur-service/BYOEH-Developer-Guide/#check-qdrant-status","title":"Check Qdrant Status","text":"
curl http://localhost:6333/collections/bp_eh\n
"},{"location":"services/klausur-service/BYOEH-Developer-Guide/#verify-encryption","title":"Verify Encryption","text":"
import { isEncryptionSupported } from '../services/encryption'\n\nif (!isEncryptionSupported()) {\n  console.error('Web Crypto API not available')\n}\n
"},{"location":"services/klausur-service/BYOEH-Developer-Guide/#migration-notes","title":"Migration Notes","text":""},{"location":"services/klausur-service/BYOEH-Developer-Guide/#from-v10-to-v11","title":"From v1.0 to v1.1","text":"
  1. Added key sharing system
  2. Added Klausur linking
  3. EH prompt after student upload

No database migrations required - all data structures are additive.

"},{"location":"services/klausur-service/NiBiS-Ingestion-Pipeline/","title":"NiBiS Ingestion Pipeline","text":""},{"location":"services/klausur-service/NiBiS-Ingestion-Pipeline/#overview","title":"Overview","text":"

Die NiBiS Ingestion Pipeline verarbeitet Abitur-Erwartungshorizonte aus Niedersachsen und indexiert sie in Qdrant f\u00fcr RAG-basierte Klausurkorrektur.

"},{"location":"services/klausur-service/NiBiS-Ingestion-Pipeline/#unterstutzte-daten","title":"Unterst\u00fctzte Daten","text":""},{"location":"services/klausur-service/NiBiS-Ingestion-Pipeline/#verzeichnisse","title":"Verzeichnisse","text":"Verzeichnis Jahre Namenskonvention docs/za-download 2024, 2025 {Jahr}_{Fach}_{niveau}_{Nr}_EWH.pdf docs/za-download-2 2016 {Jahr}{Fach}{Niveau}Lehrer/{Jahr}{Fach}{Niveau}A{Nr}L.pdf docs/za-download-3 2017 {Jahr}{Fach}{Niveau}Lehrer/{Jahr}{Fach}{Niveau}A{Nr}L.pdf"},{"location":"services/klausur-service/NiBiS-Ingestion-Pipeline/#dokumenttypen","title":"Dokumenttypen","text":""},{"location":"services/klausur-service/NiBiS-Ingestion-Pipeline/#facher","title":"F\u00e4cher","text":"

Deutsch, Englisch, Mathematik, Informatik, Biologie, Chemie, Physik, Geschichte, Erdkunde, Kunst, Musik, Sport, Latein, Griechisch, Franz\u00f6sisch, Spanisch, Katholische Religion, Evangelische Religion, Werte und Normen, BRC, BVW, Gesundheit-Pflege

"},{"location":"services/klausur-service/NiBiS-Ingestion-Pipeline/#architektur","title":"Architektur","text":"
\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502                     NiBiS Ingestion Pipeline                     \u2502\n\u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n\u2502                                                                 \u2502\n\u2502  1. ZIP Extraction                                              \u2502\n\u2502     \u2514\u2500\u2500 Entpackt 2024.zip, 2025.zip, etc.                       \u2502\n\u2502                                                                 \u2502\n\u2502  2. Document Discovery                                          \u2502\n\u2502     \u251c\u2500\u2500 Parst alte Namenskonvention (2016/2017)                 \u2502\n\u2502     \u2514\u2500\u2500 Parst neue Namenskonvention (2024/2025)                 \u2502\n\u2502                                                                 \u2502\n\u2502  3. PDF Processing                                              \u2502\n\u2502     \u251c\u2500\u2500 Text-Extraktion (PyPDF2)                                \u2502\n\u2502     \u2514\u2500\u2500 Chunking (1000 chars, 200 overlap)                      \u2502\n\u2502                                                                 \u2502\n\u2502  4. Embedding Generation                                        \u2502\n\u2502     \u2514\u2500\u2500 OpenAI text-embedding-3-small (1536 dim)                \u2502\n\u2502                                                                 \u2502\n\u2502  5. Qdrant Indexing                                             \u2502\n\u2502     \u2514\u2500\u2500 Collection: bp_nibis_eh                                 \u2502\n\u2502                                                                 \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n
"},{"location":"services/klausur-service/NiBiS-Ingestion-Pipeline/#verwendung","title":"Verwendung","text":""},{"location":"services/klausur-service/NiBiS-Ingestion-Pipeline/#via-api-empfohlen","title":"Via API (empfohlen)","text":"
# 1. Vorschau der verf\u00fcgbaren Dokumente\ncurl http://localhost:8086/api/v1/admin/nibis/discover\n\n# 2. ZIP-Dateien entpacken\ncurl -X POST http://localhost:8086/api/v1/admin/nibis/extract-zips\n\n# 3. Ingestion starten\ncurl -X POST http://localhost:8086/api/v1/admin/nibis/ingest \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"ewh_only\": true}'\n\n# 4. Status pr\u00fcfen\ncurl http://localhost:8086/api/v1/admin/nibis/status\n\n# 5. Semantische Suche testen\ncurl -X POST http://localhost:8086/api/v1/admin/nibis/search \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"query\": \"Analyse literarischer Texte\", \"subject\": \"Deutsch\", \"limit\": 5}'\n
"},{"location":"services/klausur-service/NiBiS-Ingestion-Pipeline/#via-cli","title":"Via CLI","text":"
# Dry-Run (nur analysieren)\ncd klausur-service/backend\npython nibis_ingestion.py --dry-run\n\n# Vollst\u00e4ndige Ingestion\npython nibis_ingestion.py\n\n# Nur bestimmtes Jahr\npython nibis_ingestion.py --year 2024\n\n# Nur bestimmtes Fach\npython nibis_ingestion.py --subject Deutsch\n\n# Manifest erstellen\npython nibis_ingestion.py --manifest /tmp/nibis_manifest.json\n
"},{"location":"services/klausur-service/NiBiS-Ingestion-Pipeline/#via-shell-script","title":"Via Shell Script","text":"
./klausur-service/scripts/run_nibis_ingestion.sh --dry-run\n./klausur-service/scripts/run_nibis_ingestion.sh --year 2024 --subject Deutsch\n
"},{"location":"services/klausur-service/NiBiS-Ingestion-Pipeline/#qdrant-schema","title":"Qdrant Schema","text":""},{"location":"services/klausur-service/NiBiS-Ingestion-Pipeline/#collection-bp_nibis_eh","title":"Collection: bp_nibis_eh","text":"
{\n  \"id\": \"nibis_2024_deutsch_ea_1_abc123_chunk_0\",\n  \"vector\": [1536 dimensions],\n  \"payload\": {\n    \"doc_id\": \"nibis_2024_deutsch_ea_1_abc123\",\n    \"chunk_index\": 0,\n    \"text\": \"Der Erwartungshorizont...\",\n    \"year\": 2024,\n    \"subject\": \"Deutsch\",\n    \"niveau\": \"eA\",\n    \"task_number\": 1,\n    \"doc_type\": \"EWH\",\n    \"bundesland\": \"NI\",\n    \"variant\": null,\n    \"source\": \"nibis\",\n    \"training_allowed\": true\n  }\n}\n
"},{"location":"services/klausur-service/NiBiS-Ingestion-Pipeline/#api-endpoints","title":"API Endpoints","text":"Methode Endpoint Beschreibung GET /api/v1/admin/nibis/status Ingestion-Status POST /api/v1/admin/nibis/extract-zips ZIP-Dateien entpacken GET /api/v1/admin/nibis/discover Dokumente finden POST /api/v1/admin/nibis/ingest Ingestion starten POST /api/v1/admin/nibis/search Semantische Suche GET /api/v1/admin/nibis/stats Statistiken GET /api/v1/admin/nibis/collections Qdrant Collections DELETE /api/v1/admin/nibis/collection Collection l\u00f6schen"},{"location":"services/klausur-service/NiBiS-Ingestion-Pipeline/#erweiterung-fur-andere-bundeslander","title":"Erweiterung f\u00fcr andere Bundesl\u00e4nder","text":"

Die Pipeline ist so designed, dass sie leicht erweitert werden kann:

"},{"location":"services/klausur-service/NiBiS-Ingestion-Pipeline/#1-neues-bundesland-hinzufugen","title":"1. Neues Bundesland hinzuf\u00fcgen","text":"
# In nibis_ingestion.py\n\n# Bundesland-Code (ISO 3166-2:DE)\nBUNDESLAND_CODES = {\n    \"NI\": \"Niedersachsen\",\n    \"BE\": \"Berlin\",\n    \"BY\": \"Bayern\",\n    # ...\n}\n\n# Parsing-Funktion f\u00fcr neues Format\ndef parse_filename_berlin(filename: str, file_path: Path) -> Optional[Dict]:\n    # Berlin-spezifische Namenskonvention\n    pass\n
"},{"location":"services/klausur-service/NiBiS-Ingestion-Pipeline/#2-neues-verzeichnis-registrieren","title":"2. Neues Verzeichnis registrieren","text":"
# docs/za-download-berlin/ hinzuf\u00fcgen\nZA_DOWNLOAD_DIRS = [\n    \"za-download\",\n    \"za-download-2\",\n    \"za-download-3\",\n    \"za-download-berlin\",  # NEU\n]\n
"},{"location":"services/klausur-service/NiBiS-Ingestion-Pipeline/#3-dokumenttyp-erweiterung","title":"3. Dokumenttyp-Erweiterung","text":"

F\u00fcr Zeugnisgeneration oder andere Dokumenttypen:

DOC_TYPES = {\n    \"EWH\": \"Erwartungshorizont\",\n    \"ZEUGNIS_VORLAGE\": \"Zeugnisvorlage\",\n    \"NOTENSPIEGEL\": \"Notenspiegel\",\n    \"BEMERKUNG\": \"Bemerkungstexte\",\n}\n
"},{"location":"services/klausur-service/NiBiS-Ingestion-Pipeline/#rechtliche-hinweise","title":"Rechtliche Hinweise","text":""},{"location":"services/klausur-service/NiBiS-Ingestion-Pipeline/#troubleshooting","title":"Troubleshooting","text":""},{"location":"services/klausur-service/NiBiS-Ingestion-Pipeline/#qdrant-nicht-erreichbar","title":"Qdrant nicht erreichbar","text":"
# Pr\u00fcfen ob Qdrant l\u00e4uft\ncurl http://localhost:6333/health\n\n# Docker starten\ndocker-compose up -d qdrant\n
"},{"location":"services/klausur-service/NiBiS-Ingestion-Pipeline/#openai-api-fehler","title":"OpenAI API Fehler","text":"
# API Key setzen\nexport OPENAI_API_KEY=sk-...\n
"},{"location":"services/klausur-service/NiBiS-Ingestion-Pipeline/#pdf-extraktion-fehlgeschlagen","title":"PDF-Extraktion fehlgeschlagen","text":"

Einige PDFs k\u00f6nnen problematisch sein (gescannte Dokumente ohne OCR). Diese werden \u00fcbersprungen und im Error-Log protokolliert.

"},{"location":"services/klausur-service/NiBiS-Ingestion-Pipeline/#performance","title":"Performance","text":""},{"location":"services/klausur-service/OCR-Compare/","title":"OCR Compare - Block Review Feature","text":"

Status: Produktiv Letzte Aktualisierung: 2026-02-08 URL: https://macmini:3002/ai/ocr-compare

"},{"location":"services/klausur-service/OCR-Compare/#uebersicht","title":"Uebersicht","text":"

Das OCR Compare Tool ermoeglicht den Vergleich verschiedener OCR-Methoden zur Texterkennung aus gescannten Dokumenten. Die Block Review Funktion erlaubt eine zellenweise Ueberpruefung und Korrektur der OCR-Ergebnisse.

"},{"location":"services/klausur-service/OCR-Compare/#hauptfunktionen","title":"Hauptfunktionen","text":"Feature Beschreibung Multi-Method OCR Vergleich von Vision LLM, Tesseract, PaddleOCR und Claude Vision Grid Detection Automatische Erkennung von Tabellenstrukturen Block Review Zellenweise Ueberpruefung und Korrektur Session Persistence Sessions bleiben bei Seitenwechsel erhalten High-Resolution Display Hochaufloesende Bildanzeige (zoom=2.0)"},{"location":"services/klausur-service/OCR-Compare/#architektur","title":"Architektur","text":"
\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502                    admin-v2 (Next.js)                        \u2502\n\u2502  /app/(admin)/ai/ocr-compare/page.tsx                       \u2502\n\u2502  - PDF Upload & Session Management                          \u2502\n\u2502  - Grid Visualization mit SVG Overlay                       \u2502\n\u2502  - Block Review Panel                                       \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n                              \u2502\n                              \u25bc\n\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502                 klausur-service (FastAPI)                    \u2502\n\u2502  Port 8086                                                   \u2502\n\u2502  - /api/v1/vocab/sessions (Session CRUD)                    \u2502\n\u2502  - /api/v1/vocab/sessions/{id}/pdf-thumbnail (Bild-Export)  \u2502\n\u2502  - /api/v1/vocab/sessions/{id}/detect-grid (Grid-Erkennung) \u2502\n\u2502  - /api/v1/vocab/sessions/{id}/run-ocr (OCR-Ausfuehrung)    \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n
"},{"location":"services/klausur-service/OCR-Compare/#komponenten","title":"Komponenten","text":""},{"location":"services/klausur-service/OCR-Compare/#gridoverlay","title":"GridOverlay","text":"

SVG-Overlay zur Visualisierung der erkannten Grid-Struktur.

Datei: /admin-v2/components/ocr/GridOverlay.tsx

interface GridOverlayProps {\n  grid: GridData\n  imageUrl?: string\n  onCellClick?: (cell: GridCell) => void\n  selectedCell?: GridCell | null\n  showEmpty?: boolean        // Leere Zellen anzeigen\n  showLabels?: boolean       // Spaltenlabels (EN, DE, Ex)\n  showNumbers?: boolean      // Block-Nummern anzeigen\n  highlightedBlockNumber?: number | null  // Hervorgehobener Block\n  className?: string\n}\n

Zellenstatus-Farben:

Status Farbe Bedeutung recognized Gruen Text erfolgreich erkannt problematic Orange Niedriger Confidence-Wert manual Blau Manuell korrigiert empty Transparent Keine Erkennung"},{"location":"services/klausur-service/OCR-Compare/#blockreviewpanel","title":"BlockReviewPanel","text":"

Panel zur Block-fuer-Block Ueberpruefung der OCR-Ergebnisse.

Datei: /admin-v2/components/ocr/BlockReviewPanel.tsx

interface BlockReviewPanelProps {\n  grid: GridData\n  methodResults: Record<string, { vocabulary: Array<...> }>\n  currentBlockNumber: number\n  onBlockChange: (blockNumber: number) => void\n  onApprove: (blockNumber: number, methodId: string, text: string) => void\n  onCorrect: (blockNumber: number, correctedText: string) => void\n  onSkip: (blockNumber: number) => void\n  reviewData: Record<number, BlockReviewData>\n  className?: string\n}\n

Review-Status:

Status Beschreibung pending Noch nicht ueberprueft approved OCR-Ergebnis akzeptiert corrected Manuell korrigiert skipped Uebersprungen"},{"location":"services/klausur-service/OCR-Compare/#blockreviewsummary","title":"BlockReviewSummary","text":"

Zusammenfassung aller ueberprueften Bloecke.

interface BlockReviewSummaryProps {\n  reviewData: Record<number, BlockReviewData>\n  totalBlocks: number\n  onBlockClick: (blockNumber: number) => void\n  className?: string\n}\n
"},{"location":"services/klausur-service/OCR-Compare/#ocr-methoden","title":"OCR-Methoden","text":"ID Name Beschreibung vision_llm Vision LLM Qwen VL 32B ueber Ollama tesseract Tesseract Klassisches OCR (lokal) paddleocr PaddleOCR PaddleOCR Engine claude_vision Claude Vision Anthropic Claude Vision API"},{"location":"services/klausur-service/OCR-Compare/#api-endpoints","title":"API Endpoints","text":""},{"location":"services/klausur-service/OCR-Compare/#session-management","title":"Session Management","text":"Method Endpoint Beschreibung POST /api/v1/vocab/upload-pdf-info PDF hochladen GET /api/v1/vocab/sessions/{id} Session-Details DELETE /api/v1/vocab/sessions/{id} Session loeschen"},{"location":"services/klausur-service/OCR-Compare/#bildexport","title":"Bildexport","text":"Method Endpoint Beschreibung GET /api/v1/vocab/sessions/{id}/pdf-thumbnail/{page} Thumbnail (zoom=0.5) GET /api/v1/vocab/sessions/{id}/pdf-thumbnail/{page}?hires=true High-Res (zoom=2.0)"},{"location":"services/klausur-service/OCR-Compare/#grid-erkennung","title":"Grid-Erkennung","text":"Method Endpoint Beschreibung POST /api/v1/vocab/sessions/{id}/detect-grid Grid-Struktur erkennen POST /api/v1/vocab/sessions/{id}/run-ocr OCR auf Grid ausfuehren"},{"location":"services/klausur-service/OCR-Compare/#session-persistence","title":"Session Persistence","text":"

Die aktive Session wird im localStorage gespeichert:

// Speichern\nlocalStorage.setItem('ocr-compare-active-session', sessionId)\n\n// Wiederherstellen beim Seitenladen\nconst lastSessionId = localStorage.getItem('ocr-compare-active-session')\nif (lastSessionId) {\n  // Session-Daten laden\n}\n
"},{"location":"services/klausur-service/OCR-Compare/#block-review-workflow","title":"Block Review Workflow","text":"
  1. PDF hochladen - Dokument in das System laden
  2. Grid erkennen - Automatische Tabellenerkennung
  3. OCR ausfuehren - Alle Methoden parallel ausfuehren
  4. Block Review starten - \"Block Review\" Button klicken
  5. Bloecke pruefen - Fuer jeden Block:
  6. Ergebnisse aller Methoden vergleichen
  7. Bestes Ergebnis waehlen oder manuell korrigieren
  8. Zusammenfassung - Uebersicht der Korrekturen
"},{"location":"services/klausur-service/OCR-Compare/#high-resolution-bilder","title":"High-Resolution Bilder","text":"

Fuer die Anzeige werden hochaufloesende Bilder verwendet:

// Thumbnail URL mit High-Resolution Parameter\nconst imageUrl = `${KLAUSUR_API}/api/v1/vocab/sessions/${sessionId}/pdf-thumbnail/${pageNumber}?hires=true`\n
Parameter Zoom Verwendung Ohne hires 0.5 Vorschau/Thumbnails Mit hires=true 2.0 Anzeige/OCR"},{"location":"services/klausur-service/OCR-Compare/#dateien","title":"Dateien","text":""},{"location":"services/klausur-service/OCR-Compare/#frontend-admin-v2","title":"Frontend (admin-v2)","text":"Datei Beschreibung app/(admin)/ai/ocr-compare/page.tsx Haupt-UI components/ocr/GridOverlay.tsx SVG Grid-Overlay components/ocr/BlockReviewPanel.tsx Review-Panel components/ocr/CellCorrectionDialog.tsx Korrektur-Dialog components/ocr/index.ts Exports"},{"location":"services/klausur-service/OCR-Compare/#backend-klausur-service","title":"Backend (klausur-service)","text":"Datei Beschreibung vocab_worksheet_api.py API-Router hybrid_vocab_extractor.py OCR-Extraktion"},{"location":"services/klausur-service/OCR-Compare/#aenderungshistorie","title":"Aenderungshistorie","text":"Datum Aenderung 2026-02-08 Block Review Feature hinzugefuegt 2026-02-08 High-Resolution Bilder aktiviert 2026-02-08 Session Persistence implementiert 2026-02-07 Grid Detection und Multi-Method OCR"},{"location":"services/klausur-service/OCR-Labeling-Spec/","title":"OCR-Labeling System Spezifikation","text":"

Version: 1.1.0 Status: In Produktion (Mac Mini)

"},{"location":"services/klausur-service/OCR-Labeling-Spec/#ubersicht","title":"\u00dcbersicht","text":"

Das OCR-Labeling System erm\u00f6glicht das Erstellen von Trainingsdaten f\u00fcr Handschrift-OCR-Modelle aus eingescannten Klausuren. Es unterst\u00fctzt folgende OCR-Modelle:

Modell Beschreibung Geschwindigkeit Empfohlen f\u00fcr llama3.2-vision:11b Vision-LLM (Standard) Langsam Handschrift, beste Qualit\u00e4t TrOCR Microsoft Transformer Schnell Gedruckter Text PaddleOCR + LLM Hybrid-Ansatz (NEU) Sehr schnell (4x) Gemischte Dokumente Donut Document Understanding (NEU) Mittel Tabellen, Formulare qwen2.5:14b Korrektur-LLM - Klausurbewertung"},{"location":"services/klausur-service/OCR-Labeling-Spec/#neue-ocr-optionen-v110","title":"Neue OCR-Optionen (v1.1.0)","text":""},{"location":"services/klausur-service/OCR-Labeling-Spec/#paddleocr-llm-empfohlen-fur-geschwindigkeit","title":"PaddleOCR + LLM (Empfohlen f\u00fcr Geschwindigkeit)","text":"

PaddleOCR ist ein zweistufiger Ansatz: 1. PaddleOCR - Schnelle, pr\u00e4zise Texterkennung mit Bounding-Boxes 2. qwen2.5:14b - Semantische Strukturierung des erkannten Texts

Vorteile: - 4x schneller als Vision-LLM (~7-15 Sek vs 30-60 Sek pro Seite) - H\u00f6here Genauigkeit bei gedrucktem Text (95-99%) - Weniger Halluzinationen (LLM korrigiert nur, erfindet nicht) - Position-basierte Spaltenerkennung m\u00f6glich

Dateien: - /klausur-service/backend/hybrid_vocab_extractor.py - PaddleOCR Integration

"},{"location":"services/klausur-service/OCR-Labeling-Spec/#donut-document-understanding-transformer","title":"Donut (Document Understanding Transformer)","text":"

Donut ist speziell f\u00fcr strukturierte Dokumente optimiert: - Tabellen und Formulare - Rechnungen und Quittungen - Multi-Spalten-Layouts

Dateien: - /klausur-service/backend/services/donut_ocr_service.py - Donut Service

"},{"location":"services/klausur-service/OCR-Labeling-Spec/#architektur","title":"Architektur","text":"
\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502                           OCR-Labeling System                             \u2502\n\u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n\u2502                                                                          \u2502\n\u2502   \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510    \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510    \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510  \u2502\n\u2502   \u2502   Frontend  \u2502\u25c4\u2500\u2500\u25ba\u2502  Klausur-Service \u2502\u25c4\u2500\u2500\u25ba\u2502    PostgreSQL          \u2502  \u2502\n\u2502   \u2502  (Next.js)  \u2502    \u2502   (FastAPI)      \u2502    \u2502  - ocr_labeling_sessions\u2502  \u2502\n\u2502   \u2502  Port 3000  \u2502    \u2502   Port 8086      \u2502    \u2502  - ocr_labeling_items   \u2502  \u2502\n\u2502   \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518    \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518    \u2502  - ocr_training_samples \u2502  \u2502\n\u2502                               \u2502              \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518  \u2502\n\u2502                               \u2502                                          \u2502\n\u2502                    \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510                              \u2502\n\u2502                    \u25bc          \u25bc          \u25bc                              \u2502\n\u2502            \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510 \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510 \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510                  \u2502\n\u2502            \u2502   MinIO   \u2502 \u2502 Ollama  \u2502 \u2502 Export Service \u2502                  \u2502\n\u2502            \u2502  (Images) \u2502 \u2502 (OCR)   \u2502 \u2502 (Training)     \u2502                  \u2502\n\u2502            \u2502 Port 9000 \u2502 \u2502 :11434  \u2502 \u2502                \u2502                  \u2502\n\u2502            \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518 \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518 \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518                  \u2502\n\u2502                                                                          \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n
"},{"location":"services/klausur-service/OCR-Labeling-Spec/#datenmodell","title":"Datenmodell","text":""},{"location":"services/klausur-service/OCR-Labeling-Spec/#postgresql-tabellen","title":"PostgreSQL Tabellen","text":"
-- Labeling Sessions (gruppiert zusammengeh\u00f6rige Bilder)\nCREATE TABLE ocr_labeling_sessions (\n    id VARCHAR(36) PRIMARY KEY,\n    name VARCHAR(255) NOT NULL,\n    source_type VARCHAR(50) NOT NULL,  -- 'klausur', 'handwriting_sample', 'scan'\n    description TEXT,\n    ocr_model VARCHAR(100),             -- z.B. 'llama3.2-vision:11b'\n    total_items INTEGER DEFAULT 0,\n    labeled_items INTEGER DEFAULT 0,\n    confirmed_items INTEGER DEFAULT 0,\n    corrected_items INTEGER DEFAULT 0,\n    skipped_items INTEGER DEFAULT 0,\n    teacher_id VARCHAR(100),\n    created_at TIMESTAMP DEFAULT NOW()\n);\n\n-- Einzelne Labeling Items (Bild + OCR + Ground Truth)\nCREATE TABLE ocr_labeling_items (\n    id VARCHAR(36) PRIMARY KEY,\n    session_id VARCHAR(36) REFERENCES ocr_labeling_sessions(id),\n    image_path TEXT NOT NULL,           -- MinIO Pfad oder lokaler Pfad\n    image_hash VARCHAR(64),             -- SHA256 f\u00fcr Deduplizierung\n    ocr_text TEXT,                      -- Von LLM erkannter Text\n    ocr_confidence FLOAT,               -- Konfidenz (0-1)\n    ocr_model VARCHAR(100),\n    ground_truth TEXT,                  -- Korrigierter/best\u00e4tigter Text\n    status VARCHAR(20) DEFAULT 'pending', -- pending/confirmed/corrected/skipped\n    labeled_by VARCHAR(100),\n    labeled_at TIMESTAMP,\n    label_time_seconds INTEGER,\n    metadata JSONB,\n    created_at TIMESTAMP DEFAULT NOW()\n);\n\n-- Exportierte Training Samples\nCREATE TABLE ocr_training_samples (\n    id VARCHAR(36) PRIMARY KEY,\n    item_id VARCHAR(36) REFERENCES ocr_labeling_items(id),\n    image_path TEXT NOT NULL,\n    ground_truth TEXT NOT NULL,\n    export_format VARCHAR(50) NOT NULL,  -- 'generic', 'trocr', 'llama_vision'\n    exported_at TIMESTAMP DEFAULT NOW(),\n    training_batch VARCHAR(100),\n    used_in_training BOOLEAN DEFAULT FALSE\n);\n
"},{"location":"services/klausur-service/OCR-Labeling-Spec/#api-referenz","title":"API Referenz","text":"

Base URL: http://macmini:8086/api/v1/ocr-label

"},{"location":"services/klausur-service/OCR-Labeling-Spec/#sessions","title":"Sessions","text":""},{"location":"services/klausur-service/OCR-Labeling-Spec/#post-sessions","title":"POST /sessions","text":"

Neue Labeling-Session erstellen.

Request:

{\n  \"name\": \"Klausur Deutsch 12a Q1\",\n  \"source_type\": \"klausur\",\n  \"description\": \"Gedichtanalyse Expressionismus\",\n  \"ocr_model\": \"llama3.2-vision:11b\"\n}\n

Response:

{\n  \"id\": \"abc-123-def\",\n  \"name\": \"Klausur Deutsch 12a Q1\",\n  \"source_type\": \"klausur\",\n  \"total_items\": 0,\n  \"labeled_items\": 0,\n  \"created_at\": \"2026-01-21T10:30:00Z\"\n}\n

"},{"location":"services/klausur-service/OCR-Labeling-Spec/#get-sessions","title":"GET /sessions","text":"

Sessions auflisten.

Query Parameter: - limit (int, default: 50) - Maximale Anzahl

"},{"location":"services/klausur-service/OCR-Labeling-Spec/#get-sessionssession_id","title":"GET /sessions/{session_id}","text":"

Einzelne Session abrufen.

"},{"location":"services/klausur-service/OCR-Labeling-Spec/#upload","title":"Upload","text":""},{"location":"services/klausur-service/OCR-Labeling-Spec/#post-sessionssession_idupload","title":"POST /sessions/{session_id}/upload","text":"

Bilder zu einer Session hochladen.

Request: Multipart Form Data - files (File[]) - PNG/JPG/PDF Dateien - run_ocr (bool, default: true) - OCR direkt ausf\u00fchren - metadata (JSON string) - Optional: Metadaten

Response:

{\n  \"session_id\": \"abc-123-def\",\n  \"uploaded_count\": 5,\n  \"items\": [\n    {\n      \"id\": \"item-1\",\n      \"filename\": \"scan_001.png\",\n      \"image_path\": \"ocr-labeling/abc-123/item-1.png\",\n      \"ocr_text\": \"Die L\u00f6sung der Aufgabe...\",\n      \"ocr_confidence\": 0.87,\n      \"status\": \"pending\"\n    }\n  ]\n}\n

"},{"location":"services/klausur-service/OCR-Labeling-Spec/#labeling-queue","title":"Labeling Queue","text":""},{"location":"services/klausur-service/OCR-Labeling-Spec/#get-queue","title":"GET /queue","text":"

N\u00e4chste zu labelnde Items abrufen.

Query Parameter: - session_id (str, optional) - Nach Session filtern - status (str, default: \"pending\") - Status-Filter - limit (int, default: 10) - Maximale Anzahl

Response:

[\n  {\n    \"id\": \"item-456\",\n    \"session_id\": \"abc-123\",\n    \"session_name\": \"Klausur Deutsch\",\n    \"image_path\": \"/app/ocr-labeling/abc-123/item-456.png\",\n    \"image_url\": \"/api/v1/ocr-label/images/abc-123/item-456.png\",\n    \"ocr_text\": \"Erkannter Text...\",\n    \"ocr_confidence\": 0.87,\n    \"ground_truth\": null,\n    \"status\": \"pending\",\n    \"metadata\": {\"page\": 1}\n  }\n]\n

"},{"location":"services/klausur-service/OCR-Labeling-Spec/#labeling-actions","title":"Labeling Actions","text":""},{"location":"services/klausur-service/OCR-Labeling-Spec/#post-confirm","title":"POST /confirm","text":"

OCR-Text als korrekt best\u00e4tigen.

Request:

{\n  \"item_id\": \"item-456\",\n  \"label_time_seconds\": 5\n}\n

Effect: ground_truth = ocr_text, status = 'confirmed'

"},{"location":"services/klausur-service/OCR-Labeling-Spec/#post-correct","title":"POST /correct","text":"

Ground Truth korrigieren.

Request:

{\n  \"item_id\": \"item-456\",\n  \"ground_truth\": \"Korrigierter Text hier\",\n  \"label_time_seconds\": 15\n}\n

Effect: ground_truth = <input>, status = 'corrected'

"},{"location":"services/klausur-service/OCR-Labeling-Spec/#post-skip","title":"POST /skip","text":"

Item \u00fcberspringen (unbrauchbar).

Request:

{\n  \"item_id\": \"item-456\"\n}\n

Effect: status = 'skipped' (wird nicht exportiert)

"},{"location":"services/klausur-service/OCR-Labeling-Spec/#statistiken","title":"Statistiken","text":""},{"location":"services/klausur-service/OCR-Labeling-Spec/#get-stats","title":"GET /stats","text":"

Labeling-Statistiken abrufen.

Query Parameter: - session_id (str, optional) - F\u00fcr Session-spezifische Stats

Response:

{\n  \"total_items\": 100,\n  \"labeled_items\": 75,\n  \"confirmed_items\": 60,\n  \"corrected_items\": 15,\n  \"pending_items\": 25,\n  \"accuracy_rate\": 0.80,\n  \"avg_label_time_seconds\": 8.5\n}\n

"},{"location":"services/klausur-service/OCR-Labeling-Spec/#training-export","title":"Training Export","text":""},{"location":"services/klausur-service/OCR-Labeling-Spec/#post-export","title":"POST /export","text":"

Trainingsdaten exportieren.

Request:

{\n  \"export_format\": \"trocr\",\n  \"session_id\": \"abc-123\",\n  \"batch_id\": \"batch_20260121\"\n}\n

Export Formate:

Format Beschreibung Output generic Allgemeines JSONL {\"id\", \"image_path\", \"ground_truth\", ...} trocr Microsoft TrOCR {\"file_name\", \"text\", \"id\"} llama_vision Llama 3.2 Vision OpenAI-style Messages mit image_url

Response:

{\n  \"export_format\": \"trocr\",\n  \"batch_id\": \"batch_20260121\",\n  \"exported_count\": 75,\n  \"export_path\": \"/app/ocr-exports/trocr/batch_20260121\",\n  \"manifest_path\": \"/app/ocr-exports/trocr/batch_20260121/manifest.json\",\n  \"samples\": [...]\n}\n

"},{"location":"services/klausur-service/OCR-Labeling-Spec/#get-exports","title":"GET /exports","text":"

Verf\u00fcgbare Exports auflisten.

Query Parameter: - export_format (str, optional) - Nach Format filtern

"},{"location":"services/klausur-service/OCR-Labeling-Spec/#export-formate-im-detail","title":"Export Formate im Detail","text":""},{"location":"services/klausur-service/OCR-Labeling-Spec/#trocr-format","title":"TrOCR Format","text":"
batch_20260121/\n\u251c\u2500\u2500 manifest.json\n\u251c\u2500\u2500 train.jsonl\n\u2514\u2500\u2500 images/\n    \u251c\u2500\u2500 item-1.png\n    \u2514\u2500\u2500 item-2.png\n

train.jsonl:

{\"file_name\": \"images/item-1.png\", \"text\": \"Ground truth text\", \"id\": \"item-1\"}\n{\"file_name\": \"images/item-2.png\", \"text\": \"Another text\", \"id\": \"item-2\"}\n

"},{"location":"services/klausur-service/OCR-Labeling-Spec/#llama-vision-format","title":"Llama Vision Format","text":"
{\n  \"id\": \"item-1\",\n  \"messages\": [\n    {\"role\": \"system\", \"content\": \"Du bist ein OCR-Experte f\u00fcr deutsche Handschrift...\"},\n    {\"role\": \"user\", \"content\": [\n      {\"type\": \"image_url\", \"image_url\": {\"url\": \"images/item-1.png\"}},\n      {\"type\": \"text\", \"text\": \"Lies den handgeschriebenen Text in diesem Bild.\"}\n    ]},\n    {\"role\": \"assistant\", \"content\": \"Ground truth text\"}\n  ]\n}\n
"},{"location":"services/klausur-service/OCR-Labeling-Spec/#generic-format","title":"Generic Format","text":"
{\n  \"id\": \"item-1\",\n  \"image_path\": \"images/item-1.png\",\n  \"ground_truth\": \"Ground truth text\",\n  \"ocr_text\": \"OCR recognized text\",\n  \"ocr_confidence\": 0.87,\n  \"metadata\": {\"page\": 1, \"session\": \"Deutsch 12a\"}\n}\n
"},{"location":"services/klausur-service/OCR-Labeling-Spec/#frontend-integration","title":"Frontend Integration","text":"

Die OCR-Labeling UI ist unter /admin/ocr-labeling verf\u00fcgbar.

"},{"location":"services/klausur-service/OCR-Labeling-Spec/#keyboard-shortcuts","title":"Keyboard Shortcuts","text":"Taste Aktion Enter Best\u00e4tigen (OCR korrekt) Tab Ins Korrekturfeld springen Escape \u00dcberspringen \u2190 / \u2192 Navigation (Prev/Next)"},{"location":"services/klausur-service/OCR-Labeling-Spec/#workflow","title":"Workflow","text":"
  1. Session erstellen - Name, Typ, OCR-Modell w\u00e4hlen
  2. Bilder hochladen - Drag & Drop oder File-Browser
  3. Labeling durchf\u00fchren - Bild + OCR-Text vergleichen
  4. Korrekt \u2192 Best\u00e4tigen (Enter)
  5. Falsch \u2192 Korrigieren + Speichern
  6. Unbrauchbar \u2192 \u00dcberspringen
  7. Export - Format w\u00e4hlen (TrOCR, Llama Vision, Generic)
  8. Training starten - Export-Ordner f\u00fcr Fine-Tuning nutzen
"},{"location":"services/klausur-service/OCR-Labeling-Spec/#umgebungsvariablen","title":"Umgebungsvariablen","text":"
# PostgreSQL\nDATABASE_URL=postgres://user:pass@postgres:5432/breakpilot_db\n\n# MinIO (S3-kompatibel)\nMINIO_ENDPOINT=minio:9000\nMINIO_ACCESS_KEY=breakpilot\nMINIO_SECRET_KEY=breakpilot123\nMINIO_BUCKET=breakpilot-rag\nMINIO_SECURE=false\n\n# Ollama (Vision-LLM)\nOLLAMA_BASE_URL=http://host.docker.internal:11434\nOLLAMA_VISION_MODEL=llama3.2-vision:11b\nOLLAMA_CORRECTION_MODEL=qwen2.5:14b\n\n# Export\nOCR_EXPORT_PATH=/app/ocr-exports\nOCR_STORAGE_PATH=/app/ocr-labeling\n
"},{"location":"services/klausur-service/OCR-Labeling-Spec/#sicherheit-datenschutz","title":"Sicherheit & Datenschutz","text":""},{"location":"services/klausur-service/OCR-Labeling-Spec/#dateien","title":"Dateien","text":"Datei Beschreibung klausur-service/backend/ocr_labeling_api.py FastAPI Router mit OCR Model Dispatcher klausur-service/backend/training_export_service.py Export-Service f\u00fcr TrOCR/Llama klausur-service/backend/metrics_db.py PostgreSQL CRUD Funktionen klausur-service/backend/minio_storage.py MinIO OCR-Image Storage klausur-service/backend/hybrid_vocab_extractor.py PaddleOCR Integration klausur-service/backend/services/donut_ocr_service.py Donut OCR Service (NEU) klausur-service/backend/services/trocr_service.py TrOCR Service (NEU) website/app/admin/ocr-labeling/page.tsx Frontend UI mit Model-Auswahl website/app/admin/ocr-labeling/types.ts TypeScript Interfaces inkl. OCRModel Type"},{"location":"services/klausur-service/OCR-Labeling-Spec/#tests","title":"Tests","text":"
# Backend-Tests ausf\u00fchren\ncd klausur-service/backend\npytest tests/test_ocr_labeling.py -v\n\n# Mit Coverage\npytest tests/test_ocr_labeling.py --cov=. --cov-report=html\n
"},{"location":"services/klausur-service/RAG-Admin-Spec/","title":"RAG & Daten-Management Spezifikation","text":""},{"location":"services/klausur-service/RAG-Admin-Spec/#ubersicht","title":"\u00dcbersicht","text":"

Admin-Frontend f\u00fcr die Verwaltung von Trainingsdaten und RAG-Systemen in BreakPilot.

Location: /admin/docs \u2192 Tab \"Daten & RAG\" Backend: klausur-service (Port 8086) Storage: MinIO (persistentes Docker Volume minio_data) Vector DB: Qdrant (Port 6333)

"},{"location":"services/klausur-service/RAG-Admin-Spec/#datenmodell","title":"Datenmodell","text":""},{"location":"services/klausur-service/RAG-Admin-Spec/#zwei-datentypen-mit-unterschiedlichen-regeln","title":"Zwei Datentypen mit unterschiedlichen Regeln","text":"Typ Quelle Training erlaubt Isolation Collection Landes-Daten NiBiS, andere Bundesl\u00e4nder \u2705 Ja Pro Bundesland bp_{bundesland}_{usecase} Lehrer-Daten Lehrer-Upload (BYOEH) \u274c Nein Pro Tenant (Schule/Lehrer) bp_eh (verschl\u00fcsselt)"},{"location":"services/klausur-service/RAG-Admin-Spec/#bundesland-codes-iso-3166-2de","title":"Bundesland-Codes (ISO 3166-2:DE)","text":"
NI = Niedersachsen    BY = Bayern         BW = Baden-W\u00fcrttemberg\nNW = Nordrhein-Westf. HE = Hessen         SN = Sachsen\nBE = Berlin           HH = Hamburg        SH = Schleswig-Holstein\nBB = Brandenburg      MV = Meckl.-Vorp.   ST = Sachsen-Anhalt\nTH = Th\u00fcringen        RP = Rheinland-Pfalz SL = Saarland\nHB = Bremen\n
"},{"location":"services/klausur-service/RAG-Admin-Spec/#use-cases-rag-sammlungen","title":"Use Cases (RAG-Sammlungen)","text":"Use Case Collection Pattern Beschreibung Klausurkorrektur bp_{bl}_klausur Erwartungshorizonte f\u00fcr Abitur Zeugnisgenerator bp_{bl}_zeugnis Textbausteine f\u00fcr Zeugnisse Lehrplan bp_{bl}_lehrplan Kerncurricula, Rahmenrichtlinien

Beispiel: bp_ni_klausur = Niedersachsen Klausurkorrektur

"},{"location":"services/klausur-service/RAG-Admin-Spec/#minio-bucket-struktur","title":"MinIO Bucket-Struktur","text":"
breakpilot-rag/\n\u251c\u2500\u2500 landes-daten/\n\u2502   \u251c\u2500\u2500 ni/                          # Niedersachsen\n\u2502   \u2502   \u251c\u2500\u2500 klausur/\n\u2502   \u2502   \u2502   \u251c\u2500\u2500 2016/\n\u2502   \u2502   \u2502   \u2502   \u251c\u2500\u2500 manifest.json\n\u2502   \u2502   \u2502   \u2502   \u2514\u2500\u2500 *.pdf\n\u2502   \u2502   \u2502   \u251c\u2500\u2500 2017/\n\u2502   \u2502   \u2502   \u251c\u2500\u2500 ...\n\u2502   \u2502   \u2502   \u2514\u2500\u2500 2025/\n\u2502   \u2502   \u2514\u2500\u2500 zeugnis/\n\u2502   \u251c\u2500\u2500 by/                          # Bayern\n\u2502   \u2514\u2500\u2500 .../\n\u2502\n\u2514\u2500\u2500 lehrer-daten/                    # BYOEH - verschl\u00fcsselt\n    \u2514\u2500\u2500 {tenant_id}/\n        \u2514\u2500\u2500 {lehrer_id}/\n            \u2514\u2500\u2500 *.pdf.enc\n
"},{"location":"services/klausur-service/RAG-Admin-Spec/#qdrant-schema","title":"Qdrant Schema","text":""},{"location":"services/klausur-service/RAG-Admin-Spec/#landes-daten-collection-zb-bp_ni_klausur","title":"Landes-Daten Collection (z.B. bp_ni_klausur)","text":"
{\n  \"id\": \"uuid-v5-from-string\",\n  \"vector\": [384 dimensions],\n  \"payload\": {\n    \"original_id\": \"nibis_2024_deutsch_ea_1_abc123_chunk_0\",\n    \"doc_id\": \"nibis_2024_deutsch_ea_1_abc123\",\n    \"chunk_index\": 0,\n    \"text\": \"Der Erwartungshorizont...\",\n    \"year\": 2024,\n    \"subject\": \"Deutsch\",\n    \"niveau\": \"eA\",\n    \"task_number\": 1,\n    \"doc_type\": \"EWH\",\n    \"bundesland\": \"NI\",\n    \"source\": \"nibis\",\n    \"training_allowed\": true,\n    \"minio_path\": \"landes-daten/ni/klausur/2024/2024_Deutsch_eA_I_EWH.pdf\"\n  }\n}\n
"},{"location":"services/klausur-service/RAG-Admin-Spec/#lehrer-daten-collection-bp_eh","title":"Lehrer-Daten Collection (bp_eh)","text":"
{\n  \"id\": \"uuid\",\n  \"vector\": [384 dimensions],\n  \"payload\": {\n    \"tenant_id\": \"schule_123\",\n    \"eh_id\": \"eh_abc\",\n    \"chunk_index\": 0,\n    \"subject\": \"deutsch\",\n    \"encrypted_content\": \"base64...\",\n    \"training_allowed\": false\n  }\n}\n
"},{"location":"services/klausur-service/RAG-Admin-Spec/#frontend-komponenten","title":"Frontend-Komponenten","text":""},{"location":"services/klausur-service/RAG-Admin-Spec/#1-sammlungen-ubersicht-adminragcollections","title":"1. Sammlungen-\u00dcbersicht (/admin/rag/collections)","text":"
\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502 Daten & RAG                                                      \u2502\n\u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n\u2502                                                                  \u2502\n\u2502  Sammlungen                                          [+ Neu]     \u2502\n\u2502  \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500  \u2502\n\u2502                                                                  \u2502\n\u2502  \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510    \u2502\n\u2502  \u2502 \ud83d\udcda Niedersachsen - Klausurkorrektur                     \u2502    \u2502\n\u2502  \u2502    bp_ni_klausur | 630 Docs | 4.521 Chunks | 2016-2025  \u2502    \u2502\n\u2502  \u2502    [Suchen] [Indexieren] [Details]                      \u2502    \u2502\n\u2502  \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518    \u2502\n\u2502                                                                  \u2502\n\u2502  \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510    \u2502\n\u2502  \u2502 \ud83d\udcda Niedersachsen - Zeugnisgenerator                     \u2502    \u2502\n\u2502  \u2502    bp_ni_zeugnis | 0 Docs | Leer                        \u2502    \u2502\n\u2502  \u2502    [Suchen] [Indexieren] [Details]                      \u2502    \u2502\n\u2502  \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518    \u2502\n\u2502                                                                  \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n
"},{"location":"services/klausur-service/RAG-Admin-Spec/#2-upload-bereich-adminragupload","title":"2. Upload-Bereich (/admin/rag/upload)","text":"
\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502 Dokumente hochladen                                              \u2502\n\u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n\u2502                                                                  \u2502\n\u2502  Ziel-Sammlung:  [Niedersachsen - Klausurkorrektur \u25bc]           \u2502\n\u2502                                                                  \u2502\n\u2502  \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510    \u2502\n\u2502  \u2502                                                         \u2502    \u2502\n\u2502  \u2502     \ud83d\udcc1 ZIP-Datei oder Ordner hierher ziehen            \u2502    \u2502\n\u2502  \u2502                                                         \u2502    \u2502\n\u2502  \u2502              oder [Dateien ausw\u00e4hlen]                   \u2502    \u2502\n\u2502  \u2502                                                         \u2502    \u2502\n\u2502  \u2502     Unterst\u00fctzt: .zip, .pdf, Ordner                    \u2502    \u2502\n\u2502  \u2502                                                         \u2502    \u2502\n\u2502  \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518    \u2502\n\u2502                                                                  \u2502\n\u2502  Upload-Queue:                                                   \u2502\n\u2502  \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510    \u2502\n\u2502  \u2502 \u2705 2018.zip - 45 PDFs erkannt                          \u2502    \u2502\n\u2502  \u2502 \u23f3 2019.zip - Wird analysiert...                       \u2502    \u2502\n\u2502  \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518    \u2502\n\u2502                                                                  \u2502\n\u2502  [Hochladen & Indexieren]                                        \u2502\n\u2502                                                                  \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n
"},{"location":"services/klausur-service/RAG-Admin-Spec/#3-ingestion-status-adminragingestion","title":"3. Ingestion-Status (/admin/rag/ingestion)","text":"
\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502 Ingestion Status                                                 \u2502\n\u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n\u2502                                                                  \u2502\n\u2502  Aktueller Job: Niedersachsen Klausur 2024                      \u2502\n\u2502  \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591  65% (412/630 Docs)             \u2502\n\u2502  Chunks: 2.891 | Fehler: 3 | ETA: 4:32                          \u2502\n\u2502  [Pausieren] [Abbrechen]                                         \u2502\n\u2502                                                                  \u2502\n\u2502  \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500  \u2502\n\u2502                                                                  \u2502\n\u2502  Letzte Jobs:                                                    \u2502\n\u2502  \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510    \u2502\n\u2502  \u2502 \u2705 09.01.2025 15:30 - NI Klausur 2024 - 128 Chunks     \u2502    \u2502\n\u2502  \u2502 \u2705 09.01.2025 14:00 - NI Klausur 2017 - 890 Chunks     \u2502    \u2502\n\u2502  \u2502 \u274c 08.01.2025 10:15 - BY Klausur - Fehler: Timeout     \u2502    \u2502\n\u2502  \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518    \u2502\n\u2502                                                                  \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n
"},{"location":"services/klausur-service/RAG-Admin-Spec/#4-suche-qualitatstest-adminragsearch","title":"4. Suche & Qualit\u00e4tstest (/admin/rag/search)","text":"
\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502 RAG Suche & Qualit\u00e4tstest                                        \u2502\n\u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n\u2502                                                                  \u2502\n\u2502  Sammlung: [Niedersachsen - Klausurkorrektur \u25bc]                 \u2502\n\u2502                                                                  \u2502\n\u2502  Query: [Analyse eines Gedichts von Rilke                    ]  \u2502\n\u2502                                                                  \u2502\n\u2502  Filter:                                                         \u2502\n\u2502  Jahr: [Alle \u25bc]  Fach: [Deutsch \u25bc]  Niveau: [eA \u25bc]             \u2502\n\u2502                                                                  \u2502\n\u2502  [\ud83d\udd0d Suchen]                                                     \u2502\n\u2502                                                                  \u2502\n\u2502  \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500  \u2502\n\u2502                                                                  \u2502\n\u2502  Ergebnisse (3):                                    Latenz: 45ms \u2502\n\u2502                                                                  \u2502\n\u2502  \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510    \u2502\n\u2502  \u2502 #1 | Score: 0.847 | 2024 Deutsch eA Aufgabe 2          \u2502    \u2502\n\u2502  \u2502                                                         \u2502    \u2502\n\u2502  \u2502 \"...Die Analyse des Rilke-Gedichts soll folgende       \u2502    \u2502\n\u2502  \u2502 Aspekte ber\u00fccksichtigen: Aufbau, Bildsprache...\"       \u2502    \u2502\n\u2502  \u2502                                                         \u2502    \u2502\n\u2502  \u2502 Relevanz: [\u2b50\u2b50\u2b50\u2b50\u2b50] [\u2b50\u2b50\u2b50\u2b50] [\u2b50\u2b50\u2b50] [\u2b50\u2b50] [\u2b50]       \u2502    \u2502\n\u2502  \u2502 Notizen: [Optional: Warum relevant/nicht relevant?   ] \u2502    \u2502\n\u2502  \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518    \u2502\n\u2502                                                                  \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n
"},{"location":"services/klausur-service/RAG-Admin-Spec/#5-metriken-dashboard-adminragmetrics","title":"5. Metriken-Dashboard (/admin/rag/metrics)","text":"
\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502 RAG Qualit\u00e4tsmetriken                                            \u2502\n\u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n\u2502                                                                  \u2502\n\u2502  Zeitraum: [Letzte 7 Tage \u25bc]  Sammlung: [Alle \u25bc]               \u2502\n\u2502                                                                  \u2502\n\u2502  \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510  \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510  \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510          \u2502\n\u2502  \u2502 Precision@5  \u2502  \u2502 Recall@10    \u2502  \u2502 MRR          \u2502          \u2502\n\u2502  \u2502    0.78      \u2502  \u2502    0.85      \u2502  \u2502   0.72       \u2502          \u2502\n\u2502  \u2502   \u2191 +5%      \u2502  \u2502   \u2191 +3%      \u2502  \u2502   \u2193 -2%      \u2502          \u2502\n\u2502  \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518  \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518  \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518          \u2502\n\u2502                                                                  \u2502\n\u2502  \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510  \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510  \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510          \u2502\n\u2502  \u2502 Avg Latency  \u2502  \u2502 Bewertungen  \u2502  \u2502 Fehlerrate   \u2502          \u2502\n\u2502  \u2502    52ms      \u2502  \u2502    127       \u2502  \u2502   0.3%       \u2502          \u2502\n\u2502  \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518  \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518  \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518          \u2502\n\u2502                                                                  \u2502\n\u2502  \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500  \u2502\n\u2502                                                                  \u2502\n\u2502  Score-Verteilung:                                               \u2502\n\u2502  0.9+ \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588 23%                                      \u2502\n\u2502  0.7+ \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588 41%                          \u2502\n\u2502  0.5+ \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588 28%                                  \u2502\n\u2502  <0.5 \u2588\u2588\u2588\u2588\u2588\u2588 8%                                                 \u2502\n\u2502                                                                  \u2502\n\u2502  [Export CSV] [Detailbericht]                                    \u2502\n\u2502                                                                  \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n
"},{"location":"services/klausur-service/RAG-Admin-Spec/#api-endpoints","title":"API Endpoints","text":""},{"location":"services/klausur-service/RAG-Admin-Spec/#collections-api","title":"Collections API","text":"
GET    /api/v1/admin/rag/collections\nPOST   /api/v1/admin/rag/collections\nGET    /api/v1/admin/rag/collections/{id}\nDELETE /api/v1/admin/rag/collections/{id}\nGET    /api/v1/admin/rag/collections/{id}/stats\n
"},{"location":"services/klausur-service/RAG-Admin-Spec/#upload-api","title":"Upload API","text":"
POST   /api/v1/admin/rag/upload\n       Content-Type: multipart/form-data\n       - file: ZIP oder PDF\n       - collection_id: string\n       - metadata: JSON (optional)\n\nPOST   /api/v1/admin/rag/upload/folder\n       - F\u00fcr Ordner-Upload (WebKitDirectory)\n
"},{"location":"services/klausur-service/RAG-Admin-Spec/#ingestion-api","title":"Ingestion API","text":"
POST   /api/v1/admin/rag/ingest\n       - collection_id: string\n       - filters: {year?, subject?, doc_type?}\n\nGET    /api/v1/admin/rag/ingest/status\nGET    /api/v1/admin/rag/ingest/history\nPOST   /api/v1/admin/rag/ingest/cancel\n
"},{"location":"services/klausur-service/RAG-Admin-Spec/#search-api","title":"Search API","text":"
POST   /api/v1/admin/rag/search\n       - query: string\n       - collection_id: string\n       - filters: {year?, subject?, niveau?}\n       - limit: int\n\nPOST   /api/v1/admin/rag/search/feedback\n       - result_id: string\n       - rating: 1-5\n       - notes: string (optional)\n
"},{"location":"services/klausur-service/RAG-Admin-Spec/#metrics-api","title":"Metrics API","text":"
GET    /api/v1/admin/rag/metrics\n       - collection_id?: string\n       - from_date?: date\n       - to_date?: date\n\nGET    /api/v1/admin/rag/metrics/export\n       - format: csv|json\n
"},{"location":"services/klausur-service/RAG-Admin-Spec/#embedding-konfiguration","title":"Embedding-Konfiguration","text":"
# Default: Lokale Embeddings (kein API-Key n\u00f6tig)\nEMBEDDING_BACKEND = \"local\"\nLOCAL_EMBEDDING_MODEL = \"all-MiniLM-L6-v2\"\nVECTOR_DIMENSIONS = 384\n\n# Optional: OpenAI (f\u00fcr Produktion)\nEMBEDDING_BACKEND = \"openai\"\nEMBEDDING_MODEL = \"text-embedding-3-small\"\nVECTOR_DIMENSIONS = 1536\n
"},{"location":"services/klausur-service/RAG-Admin-Spec/#datenpersistenz","title":"Datenpersistenz","text":""},{"location":"services/klausur-service/RAG-Admin-Spec/#docker-volumes-wichtig-nicht-loschen","title":"Docker Volumes (WICHTIG - nicht l\u00f6schen!)","text":"
volumes:\n  minio_data:        # Alle hochgeladenen Dokumente\n  qdrant_data:       # Alle Vektoren und Embeddings\n  postgres_data:     # Metadaten, Bewertungen, History\n
"},{"location":"services/klausur-service/RAG-Admin-Spec/#backup-strategie","title":"Backup-Strategie","text":"
# MinIO Backup\ndocker exec breakpilot-pwa-minio mc mirror /data /backup\n\n# Qdrant Backup\ncurl -X POST http://localhost:6333/collections/bp_ni_klausur/snapshots\n\n# Postgres Backup (bereits implementiert)\n# L\u00e4uft automatisch t\u00e4glich um 2 Uhr\n
"},{"location":"services/klausur-service/RAG-Admin-Spec/#implementierungsreihenfolge","title":"Implementierungsreihenfolge","text":"
  1. \u2705 Backend: Basis-Ingestion (nibis_ingestion.py)
  2. \u2705 Backend: Lokale Embeddings (sentence-transformers)
  3. \u2705 Backend: MinIO-Integration (minio_storage.py)
  4. \u2705 Backend: Collections API (admin_api.py)
  5. \u2705 Backend: Upload API mit ZIP-Support
  6. \u2705 Backend: Metrics API mit PostgreSQL (metrics_db.py)
  7. \u2705 Frontend: Sammlungen-\u00dcbersicht
  8. \u2705 Frontend: Upload-Bereich (Drag & Drop)
  9. \u2705 Frontend: Ingestion-Status
  10. \u2705 Frontend: Suche & Qualit\u00e4tstest (mit Stern-Bewertungen)
  11. \u2705 Frontend: Metriken-Dashboard
"},{"location":"services/klausur-service/RAG-Admin-Spec/#technologie-stack","title":"Technologie-Stack","text":""},{"location":"services/klausur-service/RAG-Admin-Spec/#entwickler-dokumentation","title":"Entwickler-Dokumentation","text":""},{"location":"services/klausur-service/RAG-Admin-Spec/#projektstruktur","title":"Projektstruktur","text":"
klausur-service/\n\u251c\u2500\u2500 backend/\n\u2502   \u251c\u2500\u2500 main.py              # FastAPI App + BYOEH Endpoints\n\u2502   \u251c\u2500\u2500 admin_api.py         # RAG Admin API (Upload, Search, Metrics)\n\u2502   \u251c\u2500\u2500 nibis_ingestion.py   # NiBiS Dokument-Ingestion Pipeline\n\u2502   \u251c\u2500\u2500 eh_pipeline.py       # Chunking, Embeddings, Encryption\n\u2502   \u251c\u2500\u2500 qdrant_service.py    # Qdrant Client + Search\n\u2502   \u251c\u2500\u2500 minio_storage.py     # MinIO S3 Storage\n\u2502   \u251c\u2500\u2500 metrics_db.py        # PostgreSQL Metrics\n\u2502   \u251c\u2500\u2500 requirements.txt     # Python Dependencies\n\u2502   \u2514\u2500\u2500 tests/\n\u2502       \u2514\u2500\u2500 test_rag_admin.py\n\u2514\u2500\u2500 docs/\n    \u2514\u2500\u2500 RAG-Admin-Spec.md    # Diese Datei\n
"},{"location":"services/klausur-service/RAG-Admin-Spec/#schnellstart-fur-entwickler","title":"Schnellstart f\u00fcr Entwickler","text":"
# 1. Services starten\ncd /path/to/breakpilot-pwa\ndocker-compose up -d qdrant minio postgres\n\n# 2. Dependencies installieren\ncd klausur-service/backend\npip install -r requirements.txt\n\n# 3. Service starten\npython -m uvicorn main:app --port 8086 --reload\n\n# 4. RAG-Services initialisieren (erstellt Bucket + Tabellen)\ncurl -X POST http://localhost:8086/api/v1/admin/rag/init\n
"},{"location":"services/klausur-service/RAG-Admin-Spec/#api-referenz-implementiert","title":"API-Referenz (Implementiert)","text":""},{"location":"services/klausur-service/RAG-Admin-Spec/#nibis-ingestion","title":"NiBiS Ingestion","text":"
GET  /api/v1/admin/nibis/discover       # Dokumente finden\nPOST /api/v1/admin/nibis/ingest         # Indexierung starten\nGET  /api/v1/admin/nibis/status         # Status abfragen\nGET  /api/v1/admin/nibis/stats          # Statistiken\nPOST /api/v1/admin/nibis/search         # Semantische Suche\nGET  /api/v1/admin/nibis/collections    # Qdrant Collections\n
"},{"location":"services/klausur-service/RAG-Admin-Spec/#rag-upload-storage","title":"RAG Upload & Storage","text":"
POST /api/v1/admin/rag/upload           # ZIP/PDF hochladen\nGET  /api/v1/admin/rag/upload/history   # Upload-Verlauf\nGET  /api/v1/admin/rag/storage/stats    # MinIO Statistiken\n
"},{"location":"services/klausur-service/RAG-Admin-Spec/#metrics-feedback","title":"Metrics & Feedback","text":"
GET  /api/v1/admin/rag/metrics          # Qualit\u00e4tsmetriken\nPOST /api/v1/admin/rag/search/feedback  # Bewertung abgeben\nPOST /api/v1/admin/rag/init             # Services initialisieren\n
"},{"location":"services/klausur-service/RAG-Admin-Spec/#umgebungsvariablen","title":"Umgebungsvariablen","text":"
# Qdrant\nQDRANT_URL=http://localhost:6333\n\n# MinIO\nMINIO_ENDPOINT=localhost:9000\nMINIO_ACCESS_KEY=breakpilot\nMINIO_SECRET_KEY=breakpilot123\nMINIO_BUCKET=breakpilot-rag\n\n# PostgreSQL\nDATABASE_URL=postgres://breakpilot:breakpilot123@localhost:5432/breakpilot_db\n\n# Embeddings\nEMBEDDING_BACKEND=local\nLOCAL_EMBEDDING_MODEL=all-MiniLM-L6-v2\n
"},{"location":"services/klausur-service/RAG-Admin-Spec/#aktuelle-indexierungs-statistik","title":"Aktuelle Indexierungs-Statistik","text":""},{"location":"services/klausur-service/Worksheet-Editor-Architecture/","title":"Visual Worksheet Editor - Architecture Documentation","text":"

Version: 1.0 Status: Implementiert

"},{"location":"services/klausur-service/Worksheet-Editor-Architecture/#1-ubersicht","title":"1. \u00dcbersicht","text":"

Der Visual Worksheet Editor ist ein Canvas-basierter Editor f\u00fcr die Erstellung und Bearbeitung von Arbeitsbl\u00e4ttern. Er erm\u00f6glicht Lehrern, eingescannte Arbeitsbl\u00e4tter originalgetreu zu rekonstruieren oder neue Arbeitsbl\u00e4tter visuell zu gestalten.

"},{"location":"services/klausur-service/Worksheet-Editor-Architecture/#11-hauptfunktionen","title":"1.1 Hauptfunktionen","text":""},{"location":"services/klausur-service/Worksheet-Editor-Architecture/#12-technologie-stack","title":"1.2 Technologie-Stack","text":"Komponente Technologie Lizenz Canvas-Bibliothek Fabric.js 6.x MIT PDF-Export pdf-lib 1.17.x MIT Frontend Next.js / React MIT Backend API FastAPI MIT KI-Bilder Ollama + Stable Diffusion Apache 2.0 / MIT"},{"location":"services/klausur-service/Worksheet-Editor-Architecture/#2-architektur","title":"2. Architektur","text":"
\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502                    Frontend (studio-v2 / Next.js)                     \u2502\n\u2502  /studio-v2/app/worksheet-editor/page.tsx                            \u2502\n\u2502                                                                        \u2502\n\u2502  \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510  \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510  \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510 \u2502\n\u2502  \u2502  Toolbar    \u2502  \u2502     Fabric.js Canvas       \u2502  \u2502  Properties    \u2502 \u2502\n\u2502  \u2502  (Links)    \u2502  \u2502     (Mitte - 60%)          \u2502  \u2502  Panel         \u2502 \u2502\n\u2502  \u2502             \u2502  \u2502                            \u2502  \u2502  (Rechts)      \u2502 \u2502\n\u2502  \u2502 - Select    \u2502  \u2502  \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510  \u2502  \u2502                \u2502 \u2502\n\u2502  \u2502 - Text      \u2502  \u2502  \u2502                      \u2502  \u2502  \u2502 - Schriftart   \u2502 \u2502\n\u2502  \u2502 - Formen    \u2502  \u2502  \u2502    A4 Arbeitsfl\u00e4che  \u2502  \u2502  \u2502 - Gr\u00f6\u00dfe        \u2502 \u2502\n\u2502  \u2502 - Bilder    \u2502  \u2502  \u2502    mit Grid          \u2502  \u2502  \u2502 - Farbe        \u2502 \u2502\n\u2502  \u2502 - KI-Bild   \u2502  \u2502  \u2502                      \u2502  \u2502  \u2502 - Position     \u2502 \u2502\n\u2502  \u2502 - Tabelle   \u2502  \u2502  \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518  \u2502  \u2502 - Ebene        \u2502 \u2502\n\u2502  \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518  \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518  \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518 \u2502\n\u2502                                                                        \u2502\n\u2502  \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510   \u2502\n\u2502  \u2502  Seiten-Navigation | Zoom | Grid | Export PDF                   \u2502   \u2502\n\u2502  \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518   \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n                              \u2502\n                              \u25bc\n\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502                 klausur-service (FastAPI - Port 8086)                 \u2502\n\u2502  POST /api/v1/worksheet/ai-image     \u2192 Bild via Ollama generieren    \u2502\n\u2502  POST /api/v1/worksheet/save         \u2192 Worksheet speichern           \u2502\n\u2502  GET  /api/v1/worksheet/{id}         \u2192 Worksheet laden               \u2502\n\u2502  POST /api/v1/worksheet/export-pdf   \u2192 PDF generieren                \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n                              \u2502\n                              \u25bc\n\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502                    Ollama (Port 11434)                                \u2502\n\u2502  Model: stable-diffusion oder kompatibles Text-to-Image Modell       \u2502\n\u2502  Text-to-Image f\u00fcr KI-generierte Grafiken                            \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n
"},{"location":"services/klausur-service/Worksheet-Editor-Architecture/#3-dateistruktur","title":"3. Dateistruktur","text":""},{"location":"services/klausur-service/Worksheet-Editor-Architecture/#31-frontend-studio-v2","title":"3.1 Frontend (studio-v2)","text":"
/studio-v2/\n\u251c\u2500\u2500 app/\n\u2502   \u2514\u2500\u2500 worksheet-editor/\n\u2502       \u251c\u2500\u2500 page.tsx                    # Haupt-Editor-Seite\n\u2502       \u2514\u2500\u2500 types.ts                    # TypeScript Interfaces\n\u2502\n\u251c\u2500\u2500 components/\n\u2502   \u2514\u2500\u2500 worksheet-editor/\n\u2502       \u251c\u2500\u2500 index.ts                    # Exports\n\u2502       \u251c\u2500\u2500 FabricCanvas.tsx            # Fabric.js Canvas Wrapper\n\u2502       \u251c\u2500\u2500 EditorToolbar.tsx           # Werkzeugleiste (links)\n\u2502       \u251c\u2500\u2500 PropertiesPanel.tsx         # Eigenschaften-Panel (rechts)\n\u2502       \u251c\u2500\u2500 AIImageGenerator.tsx        # KI-Bild Generator Modal\n\u2502       \u251c\u2500\u2500 CanvasControls.tsx          # Zoom, Grid, Seiten\n\u2502       \u251c\u2500\u2500 ExportPanel.tsx             # PDF/Bild Export\n\u2502       \u2514\u2500\u2500 PageNavigator.tsx           # Mehrseitige Dokumente\n\u2502\n\u251c\u2500\u2500 lib/\n\u2502   \u2514\u2500\u2500 worksheet-editor/\n\u2502       \u251c\u2500\u2500 index.ts                    # Exports\n\u2502       \u2514\u2500\u2500 WorksheetContext.tsx        # State Management\n
"},{"location":"services/klausur-service/Worksheet-Editor-Architecture/#32-backend-klausur-service","title":"3.2 Backend (klausur-service)","text":"
/klausur-service/backend/\n\u251c\u2500\u2500 worksheet_editor_api.py             # API Endpoints\n\u2514\u2500\u2500 main.py                             # Router-Registrierung\n
"},{"location":"services/klausur-service/Worksheet-Editor-Architecture/#4-api-endpoints","title":"4. API Endpoints","text":""},{"location":"services/klausur-service/Worksheet-Editor-Architecture/#41-ki-bild-generieren","title":"4.1 KI-Bild generieren","text":"
POST /api/v1/worksheet/ai-image\nContent-Type: application/json\n\n{\n  \"prompt\": \"Ein freundlicher Cartoon-Hund der ein Buch liest\",\n  \"style\": \"cartoon\",\n  \"width\": 512,\n  \"height\": 512\n}\n

Response:

{\n  \"image_base64\": \"data:image/png;base64,...\",\n  \"prompt_used\": \"...\",\n  \"error\": null\n}\n

Styles: - realistic - Fotorealistisch - cartoon - Cartoon/Comic - sketch - Handgezeichnete Skizze - clipart - Einfache Clipart-Grafiken - educational - Bildungs-Illustrationen

"},{"location":"services/klausur-service/Worksheet-Editor-Architecture/#42-worksheet-speichern","title":"4.2 Worksheet speichern","text":"
POST /api/v1/worksheet/save\nContent-Type: application/json\n\n{\n  \"id\": \"optional-existing-id\",\n  \"title\": \"Englisch Vokabeln Unit 3\",\n  \"pages\": [\n    { \"id\": \"page_1\", \"index\": 0, \"canvasJSON\": \"{...}\" }\n  ],\n  \"pageFormat\": {\n    \"width\": 210,\n    \"height\": 297,\n    \"orientation\": \"portrait\"\n  }\n}\n
"},{"location":"services/klausur-service/Worksheet-Editor-Architecture/#43-worksheet-laden","title":"4.3 Worksheet laden","text":"
GET /api/v1/worksheet/{id}\n
"},{"location":"services/klausur-service/Worksheet-Editor-Architecture/#44-pdf-exportieren","title":"4.4 PDF exportieren","text":"
POST /api/v1/worksheet/{id}/export-pdf\n

Response: PDF-Datei als Download

"},{"location":"services/klausur-service/Worksheet-Editor-Architecture/#45-worksheets-auflisten","title":"4.5 Worksheets auflisten","text":"
GET /api/v1/worksheet/list/all\n
"},{"location":"services/klausur-service/Worksheet-Editor-Architecture/#5-komponenten","title":"5. Komponenten","text":""},{"location":"services/klausur-service/Worksheet-Editor-Architecture/#51-fabriccanvas","title":"5.1 FabricCanvas","text":"

Die Kernkomponente f\u00fcr den Canvas-Bereich:

"},{"location":"services/klausur-service/Worksheet-Editor-Architecture/#52-editortoolbar","title":"5.2 EditorToolbar","text":"

Werkzeuge f\u00fcr die Bearbeitung:

Icon Tool Beschreibung \ud83d\uddb1\ufe0f Select Elemente ausw\u00e4hlen/verschieben T Text Text hinzuf\u00fcgen (IText) \u25ad Rechteck Rechteck zeichnen \u25cb Kreis Kreis/Ellipse zeichnen \u2015 Linie Linie zeichnen \u2192 Pfeil Pfeil zeichnen \ud83d\uddbc\ufe0f Bild Bild hochladen \u2728 KI-Bild Bild mit KI generieren \u229e Tabelle Tabelle einf\u00fcgen"},{"location":"services/klausur-service/Worksheet-Editor-Architecture/#53-propertiespanel","title":"5.3 PropertiesPanel","text":"

Eigenschaften-Editor f\u00fcr ausgew\u00e4hlte Objekte:

Text-Eigenschaften: - Schriftart (Arial, Times, Georgia, OpenDyslexic, Schulschrift) - Schriftgr\u00f6\u00dfe (8-120pt) - Schriftstil (Normal, Fett, Kursiv) - Zeilenh\u00f6he, Zeichenabstand - Textausrichtung - Textfarbe

Form-Eigenschaften: - F\u00fcllfarbe - Rahmenfarbe und -st\u00e4rke - Eckenradius

Allgemein: - Deckkraft - L\u00f6schen-Button

"},{"location":"services/klausur-service/Worksheet-Editor-Architecture/#54-worksheetcontext","title":"5.4 WorksheetContext","text":"

React Context f\u00fcr globalen State:

interface WorksheetContextType {\n  canvas: Canvas | null\n  document: WorksheetDocument | null\n  activeTool: EditorTool\n  selectedObjects: FabricObject[]\n  zoom: number\n  showGrid: boolean\n  snapToGrid: boolean\n  currentPageIndex: number\n  canUndo: boolean\n  canRedo: boolean\n  isDirty: boolean\n  // ... Methoden\n}\n
"},{"location":"services/klausur-service/Worksheet-Editor-Architecture/#6-datenmodelle","title":"6. Datenmodelle","text":""},{"location":"services/klausur-service/Worksheet-Editor-Architecture/#61-worksheetdocument","title":"6.1 WorksheetDocument","text":"
interface WorksheetDocument {\n  id: string\n  title: string\n  description?: string\n  pages: WorksheetPage[]\n  pageFormat: PageFormat\n  createdAt: string\n  updatedAt: string\n}\n
"},{"location":"services/klausur-service/Worksheet-Editor-Architecture/#62-worksheetpage","title":"6.2 WorksheetPage","text":"
interface WorksheetPage {\n  id: string\n  index: number\n  canvasJSON: string  // Serialisierter Fabric.js Canvas\n  thumbnail?: string\n}\n
"},{"location":"services/klausur-service/Worksheet-Editor-Architecture/#63-pageformat","title":"6.3 PageFormat","text":"
interface PageFormat {\n  width: number   // in mm (Standard: 210)\n  height: number  // in mm (Standard: 297)\n  orientation: 'portrait' | 'landscape'\n  margins: { top, right, bottom, left: number }\n}\n
"},{"location":"services/klausur-service/Worksheet-Editor-Architecture/#7-features","title":"7. Features","text":""},{"location":"services/klausur-service/Worksheet-Editor-Architecture/#71-undoredo","title":"7.1 Undo/Redo","text":""},{"location":"services/klausur-service/Worksheet-Editor-Architecture/#72-grid-snap","title":"7.2 Grid & Snap","text":""},{"location":"services/klausur-service/Worksheet-Editor-Architecture/#73-export","title":"7.3 Export","text":""},{"location":"services/klausur-service/Worksheet-Editor-Architecture/#74-speicherung","title":"7.4 Speicherung","text":""},{"location":"services/klausur-service/Worksheet-Editor-Architecture/#8-ki-bildgenerierung","title":"8. KI-Bildgenerierung","text":""},{"location":"services/klausur-service/Worksheet-Editor-Architecture/#81-ollama-integration","title":"8.1 Ollama Integration","text":"

Der Editor nutzt Ollama f\u00fcr die KI-Bildgenerierung:

OLLAMA_URL = \"http://host.docker.internal:11434\"\n
"},{"location":"services/klausur-service/Worksheet-Editor-Architecture/#82-placeholder-system","title":"8.2 Placeholder-System","text":"

Falls Ollama nicht verf\u00fcgbar ist, wird ein Placeholder-Bild generiert: - Farbcodiert nach Stil - Prompt-Text als Beschreibung - \"KI-Bild (Platzhalter)\"-Badge

"},{"location":"services/klausur-service/Worksheet-Editor-Architecture/#83-stil-prompts","title":"8.3 Stil-Prompts","text":"

Jeder Stil f\u00fcgt automatisch Modifikatoren zum Prompt hinzu:

STYLE_PROMPTS = {\n    \"realistic\": \"photorealistic, high detail\",\n    \"cartoon\": \"cartoon style, colorful, child-friendly\",\n    \"sketch\": \"pencil sketch, hand-drawn\",\n    \"clipart\": \"clipart style, flat design\",\n    \"educational\": \"educational illustration, textbook style\"\n}\n
"},{"location":"services/klausur-service/Worksheet-Editor-Architecture/#9-glassmorphism-design","title":"9. Glassmorphism Design","text":"

Der Editor folgt dem Glassmorphism-Design des Studio v2:

// Dark Theme\n'backdrop-blur-xl bg-white/10 border border-white/20'\n\n// Light Theme\n'backdrop-blur-xl bg-white/70 border border-black/10 shadow-xl'\n
"},{"location":"services/klausur-service/Worksheet-Editor-Architecture/#10-internationalisierung","title":"10. Internationalisierung","text":"

Unterst\u00fctzte Sprachen: - \ud83c\udde9\ud83c\uddea Deutsch - \ud83c\uddec\ud83c\udde7 English - \ud83c\uddf9\ud83c\uddf7 T\u00fcrk\u00e7e - \ud83c\uddf8\ud83c\udde6 \u0627\u0644\u0639\u0631\u0628\u064a\u0629 (RTL) - \ud83c\uddf7\ud83c\uddfa \u0420\u0443\u0441\u0441\u043a\u0438\u0439 - \ud83c\uddfa\ud83c\udde6 \u0423\u043a\u0440\u0430\u0457\u043d\u0441\u044c\u043a\u0430 - \ud83c\uddf5\ud83c\uddf1 Polski

Translation Key: nav_worksheet_editor

"},{"location":"services/klausur-service/Worksheet-Editor-Architecture/#11-sicherheit","title":"11. Sicherheit","text":""},{"location":"services/klausur-service/Worksheet-Editor-Architecture/#111-bild-upload","title":"11.1 Bild-Upload","text":""},{"location":"services/klausur-service/Worksheet-Editor-Architecture/#112-cors","title":"11.2 CORS","text":"

Aktiviert f\u00fcr lokale Entwicklung und Docker-Umgebung.

"},{"location":"services/klausur-service/Worksheet-Editor-Architecture/#12-deployment","title":"12. Deployment","text":""},{"location":"services/klausur-service/Worksheet-Editor-Architecture/#121-frontend","title":"12.1 Frontend","text":"
cd studio-v2\nnpm install\nnpm run dev  # Port 3001\n
"},{"location":"services/klausur-service/Worksheet-Editor-Architecture/#122-backend","title":"12.2 Backend","text":"

Der klausur-service l\u00e4uft auf Port 8086:

cd klausur-service/backend\npython main.py\n
"},{"location":"services/klausur-service/Worksheet-Editor-Architecture/#123-docker","title":"12.3 Docker","text":"

Der Service ist Teil des docker-compose.yml.

"},{"location":"services/klausur-service/Worksheet-Editor-Architecture/#13-zukunftige-erweiterungen","title":"13. Zuk\u00fcnftige Erweiterungen","text":""},{"location":"services/klausur-service/byoeh-system-erklaerung/","title":"Wie funktioniert das Klausur-Namespace-System?","text":"

Eine umfassende Erklaerung des BYOEH-Systems -- von der Anonymisierung bis zur sicheren KI-Korrektur.

"},{"location":"services/klausur-service/byoeh-system-erklaerung/#1-was-ist-das-namespace-system","title":"1. Was ist das Namespace-System?","text":"

Das BYOEH-System (Bring Your Own Expectation Horizon) ist eine Datenschutz-Architektur, die es Lehrern ermoeglicht, Klausuren anonym und verschluesselt von einer KI korrigieren zu lassen -- ohne dass jemals der Name eines Schuelers den Rechner des Lehrers verlaesst.

\"Die Klausuren gehen anonym in die Cloud, werden dort von KI korrigiert, und kommen korrigiert zurueck. Nur der Lehrer kann die Ergebnisse wieder den Schuelern zuordnen -- denn nur seine Hardware hat den Schluessel dafuer.\"

Das System loest ein grundlegendes Problem: Klausurkorrektur mit KI-Unterstuetzung ohne Datenschutzrisiko. Die Loesung besteht aus vier Bausteinen:

  1. Pseudonymisierung: Namen werden durch zufaellige Codes ersetzt. Niemand ausser dem Lehrer kennt die Zuordnung.
  2. Verschluesselung: Alles wird im Browser des Lehrers verschluesselt, bevor es den Rechner verlaesst. Der Server sieht nur unlesbaren Datensalat.
  3. Namespace-Isolation: Jeder Lehrer hat einen eigenen, abgeschotteten Bereich (Namespace). Kein Lehrer kann auf die Daten eines anderen zugreifen.
  4. KI-Korrektur: Die KI arbeitet mit den verschluesselten Daten und dem Erwartungshorizont (EH) des Lehrers. Korrekturvorschlaege gehen zurueck an den Lehrer.

Kern-Designprinzip: Operator Blindness

Breakpilot kann die Klausuren nicht lesen. Der Server sieht nur verschluesselte Daten und einen Schluessel-Hash (nicht den Schluessel selbst). Die Passphrase zum Entschluesseln existiert nur im Browser des Lehrers und wird niemals uebertragen. Selbst ein Angriff auf den Server wuerde keine Klausurtexte preisgeben.

"},{"location":"services/klausur-service/byoeh-system-erklaerung/#2-der-komplette-ablauf-im-ueberblick","title":"2. Der komplette Ablauf im Ueberblick","text":"

Der Prozess laesst sich in sieben Schritte unterteilen. Stellen Sie sich vor, der Lehrer sitzt an seinem Rechner und hat einen Stapel gescannter Klausuren:

Der komplette Workflow: Von der Klausur zur KI-Korrektur
SCHRITT 1: KLAUSUREN SCANNEN & HOCHLADEN\n\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\nLehrer scannt Klausuren ein (PDF oder Bild)\n  \u2192 System erkennt automatisch den Kopfbereich mit Namen\n  \u2192 Kopfbereich wird permanent entfernt (Header-Redaction)\n  \u2192 Jede Klausur erhaelt einen zufaelligen Code (doc_token)\n\nSCHRITT 2: VERSCHLUESSELUNG IM BROWSER\n\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\nLehrer gibt eine Passphrase ein (z.B. \"MeinGeheimesPasswort2025!\")\n  \u2192 Browser leitet daraus einen 256-Bit-Schluessel ab (PBKDF2)\n  \u2192 Klausur wird mit AES-256-GCM verschluesselt\n  \u2192 Nur der Hash des Schluessels wird an den Server gesendet\n  \u2192 Passphrase und Schluessel verlassen NIEMALS den Browser\n\nSCHRITT 3: IDENTITAETS-MAP SICHERN\n\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\nDie Zuordnung \"doc_token \u2192 Schuelername\" wird verschluesselt:\n  \u2192 Tabelle: \"a7f3c2d1... = Max Mustermann, b9e4a1f8... = Anna Schmidt\"\n  \u2192 Diese Tabelle wird mit dem gleichen Schluessel verschluesselt\n  \u2192 Ohne Passphrase kann niemand die Zuordnung wiederherstellen\n\nSCHRITT 4: UPLOAD IN DEN NAMESPACE\n\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\nDie verschluesselten Dateien gehen in den persoenlichen Namespace:\n  \u2192 Jeder Lehrer hat eine eigene tenant_id\n  \u2192 Daten werden in MinIO (verschluesselt) + Qdrant (Vektoren) gespeichert\n  \u2192 Server sieht: verschluesselter Blob + Schluessel-Hash + Salt\n\nSCHRITT 5: KI-KORREKTUR\n\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\nDer Lehrer startet die KI-Korrektur:\n  \u2192 RAG-System durchsucht den Erwartungshorizont (EH)\n  \u2192 KI generiert Korrekturvorschlaege pro Kriterium\n  \u2192 Vorschlaege basieren auf dem EH, nicht auf Halluzinationen\n\nSCHRITT 6: ERGEBNISSE ZURUECK\n\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\nKorrekturvorschlaege gehen an den Lehrer:\n  \u2192 Lehrer gibt Passphrase ein\n  \u2192 Browser entschluesselt die Ergebnisse\n  \u2192 Lehrer sieht: Vorschlaege pro Kriterium + Gesamtnote\n\nSCHRITT 7: ZUORDNUNG & FINALISIERUNG\n\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\nLehrer ordnet Ergebnisse den Schuelern zu:\n  \u2192 Identitaets-Map wird entschluesselt\n  \u2192 doc_token wird wieder dem echten Namen zugeordnet\n  \u2192 Lehrer ueberprueft/korrigiert KI-Vorschlaege\n  \u2192 Fertige Korrektur + Gutachten koennen exportiert werden\n
"},{"location":"services/klausur-service/byoeh-system-erklaerung/#3-pseudonymisierung-wie-namen-verschwinden","title":"3. Pseudonymisierung: Wie Namen verschwinden","text":"

Pseudonymisierung bedeutet: personenbezogene Daten werden durch zufaellige Codes ersetzt, sodass ohne Zusatzinformation kein Rueckschluss auf die Person moeglich ist. Im BYOEH-System passiert das auf zwei Ebenen:

"},{"location":"services/klausur-service/byoeh-system-erklaerung/#31-der-doc_token-ein-zufaelliger-ausweis","title":"3.1 Der doc_token: Ein zufaelliger Ausweis","text":"

Jede Klausur erhaelt einen doc_token -- einen 128-Bit-Zufallscode im UUID4-Format (z.B. a7f3c2d1-4e9b-4a5f-8c7d-6b2e1f0a9d3c). Dieser Code:

"},{"location":"services/klausur-service/byoeh-system-erklaerung/#32-header-redaction-der-name-wird-entfernt","title":"3.2 Header-Redaction: Der Name wird entfernt","text":"

Bevor eine Klausur verarbeitet wird, entfernt das System den Kopfbereich der gescannten Seite -- dort, wo typischerweise Name, Klasse und Datum stehen. Diese Entfernung ist permanent: Die Originaldaten werden nicht gespeichert.

Methode Wie es funktioniert Wann verwendet Einfache Redaction Obere ~2,5 cm der Seite werden weiss ueberschrieben Standard bei allen Uploads Smarte Redaction OpenCV erkennt Textbereiche und entfernt gezielt den Kopf, verschont aber QR-Codes Wenn QR-Codes auf der Klausur sind"},{"location":"services/klausur-service/byoeh-system-erklaerung/#33-die-identitaets-map-nur-der-lehrer-kennt-die-zuordnung","title":"3.3 Die Identitaets-Map: Nur der Lehrer kennt die Zuordnung","text":"

Die Zuordnung doc_token \u2192 Schuelername wird als verschluesselte Tabelle gespeichert:

Datenbank: ExamSession (vereinfacht)
ExamSession\n\u251c\u2500\u2500 teacher_id            = \"lehrer-uuid-123\"     \u2190 Pflichtfeld (Isolation)\n\u251c\u2500\u2500 encrypted_identity_map = [verschluesselte Bytes]  \u2190 Nur mit Passphrase lesbar\n\u251c\u2500\u2500 identity_map_iv       = \"a3f2c1...\"           \u2190 Initialisierungsvektor (fuer AES)\n\u2502\n\u2514\u2500\u2500 PseudonymizedDocument (pro Klausur)\n    \u251c\u2500\u2500 doc_token          = \"a7f3c2d1-...\"       \u2190 Zufaelliger Code (Primary Key)\n    \u251c\u2500\u2500 exam_session_id    = [Referenz]\n    \u2514\u2500\u2500 (Kein Name, keine Klasse, kein persoenliches Datum)\n

DSGVO Art. 4 Nr. 5 konform

Die Pseudonymisierung erfuellt die Definition aus der DSGVO: Die personenbezogenen Daten (Schuelernamen) koennen ohne Hinzuziehung zusaetzlicher Informationen (der verschluesselten Identitaets-Map + der Passphrase des Lehrers) nicht mehr einer bestimmten Person zugeordnet werden.

"},{"location":"services/klausur-service/byoeh-system-erklaerung/#4-verschluesselung-wie-daten-geschuetzt-werden","title":"4. Verschluesselung: Wie Daten geschuetzt werden","text":"

Die Verschluesselung ist das Herzstueck des Datenschutzes. Sie findet vollstaendig im Browser statt -- der Server bekommt nur verschluesselte Daten zu sehen.

"},{"location":"services/klausur-service/byoeh-system-erklaerung/#41-der-verschluesselungsvorgang","title":"4.1 Der Verschluesselungsvorgang","text":"

Wenn der Lehrer eine Klausur oder einen Erwartungshorizont hochlaedt, passiert im Browser folgendes:

Client-seitige Verschluesselung (im Browser)
\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502                    Browser des Lehrers                           \u2502\n\u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n\u2502                                                                 \u2502\n\u2502  1. Lehrer gibt Passphrase ein (z.B. \"MeinGeheimesPasswort!\")   \u2502\n\u2502     \u2502           \u2191                                               \u2502\n\u2502     \u2502           \u2502 Passphrase bleibt hier -- wird NIE gesendet   \u2502\n\u2502     \u25bc                                                           \u2502\n\u2502  2. Schluessel-Ableitung:                                       \u2502\n\u2502     PBKDF2-SHA256(Passphrase, zufaelliger Salt, 100.000 Runden) \u2502\n\u2502     \u2502                                                           \u2502\n\u2502     \u2502  \u2192 Ergebnis: 256-Bit-Schluessel (32 Bytes)                \u2502\n\u2502     \u2502  \u2192 Selbst bei Kenntnis des Salts sind 100.000 Runden      \u2502\n\u2502     \u2502    noetig, um den Schluessel zu erraten                    \u2502\n\u2502     \u25bc                                                           \u2502\n\u2502  3. Verschluesselung:                                           \u2502\n\u2502     AES-256-GCM(Schluessel, zufaelliger IV, Datei-Inhalt)       \u2502\n\u2502     \u2502                                                           \u2502\n\u2502     \u2502  \u2192 AES-256: Militaerstandard, 2^256 moegliche Schluessel  \u2502\n\u2502     \u2502  \u2192 GCM: Garantiert Integritaet (Manipulation erkennbar)   \u2502\n\u2502     \u25bc                                                           \u2502\n\u2502  4. Schluessel-Hash:                                            \u2502\n\u2502     SHA-256(abgeleiteter Schluessel) \u2192 Hash fuer Verifikation   \u2502\n\u2502     \u2502                                                           \u2502\n\u2502     \u2502  \u2192 Der Server speichert nur diesen Hash                   \u2502\n\u2502     \u2502  \u2192 Damit kann geprueft werden ob die Passphrase stimmt    \u2502\n\u2502     \u2502  \u2192 Vom Hash kann der Schluessel NICHT zurueckgerechnet    \u2502\n\u2502     \u2502    werden                                                 \u2502\n\u2502     \u25bc                                                           \u2502\n\u2502  5. Upload: Nur diese Daten gehen an den Server:                \u2502\n\u2502     \u2022 Verschluesselter Blob (unlesbar ohne Schluessel)          \u2502\n\u2502     \u2022 Salt (zufaellige Bytes, harmlos)                          \u2502\n\u2502     \u2022 IV (Initialisierungsvektor, harmlos)                      \u2502\n\u2502     \u2022 Schluessel-Hash (zur Verifikation, nicht umkehrbar)       \u2502\n\u2502                                                                 \u2502\n\u2502     Was NICHT an den Server geht:                               \u2502\n\u2502     \u2717 Passphrase                                                \u2502\n\u2502     \u2717 Abgeleiteter Schluessel                                   \u2502\n\u2502     \u2717 Unverschluesselter Klartext                               \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n
"},{"location":"services/klausur-service/byoeh-system-erklaerung/#42-warum-ist-das-sicher","title":"4.2 Warum ist das sicher?","text":"Angriffsszenario Was der Angreifer sieht Ergebnis Server wird gehackt Verschluesselte Blobs + Hashes Keine lesbaren Klausuren Datenbank wird geleakt encrypted_identity_map (verschluesselt) Keine Schuelernamen Netzwerkverkehr abgefangen Verschluesselte Daten (HTTPS + AES) Doppelt verschluesselt Betreiber will mitlesen Verschluesselte Blobs, kein Schluessel Operator Blindness Anderer Lehrer versucht Zugriff Nichts (Tenant-Isolation) Namespace blockiert"},{"location":"services/klausur-service/byoeh-system-erklaerung/#5-namespace-isolation-jeder-lehrer-hat-seinen-eigenen-bereich","title":"5. Namespace-Isolation: Jeder Lehrer hat seinen eigenen Bereich","text":"

Ein Namespace (auch \"Tenant\" genannt) ist ein abgeschotteter Bereich im System. Man kann es sich wie separate Schliessfaecher in einer Bank vorstellen: Jeder Lehrer hat sein eigenes Fach, und kein Schluessel passt in ein anderes Fach.

"},{"location":"services/klausur-service/byoeh-system-erklaerung/#51-wie-die-isolation-funktioniert","title":"5.1 Wie die Isolation funktioniert","text":"

Jeder Lehrer erhaelt beim ersten Login eine eindeutige tenant_id. Diese ID wird bei jeder einzelnen Datenbankabfrage als Pflichtfilter mitgefuehrt:

Tenant-Isolation in der Vektordatenbank (Qdrant)
Lehrer A (tenant_id: \"school-A-lehrer-1\")\n\u251c\u2500\u2500 Klausur 1 (verschluesselt)\n\u251c\u2500\u2500 Klausur 2 (verschluesselt)\n\u2514\u2500\u2500 Erwartungshorizont Deutsch LK 2025\n\nLehrer B (tenant_id: \"school-B-lehrer-2\")\n\u251c\u2500\u2500 Klausur 1 (verschluesselt)\n\u2514\u2500\u2500 Erwartungshorizont Mathe GK 2025\n\nSuchanfrage von Lehrer A:\n  \"Wie soll die Einleitung strukturiert sein?\"\n  \u2192 Suche NUR in tenant_id = \"school-A-lehrer-1\"\n  \u2192 Lehrer B's Daten sind UNSICHTBAR\n\nEs gibt KEINE Abfrage ohne tenant_id-Filter.\n
"},{"location":"services/klausur-service/byoeh-system-erklaerung/#52-drei-ebenen-der-isolation","title":"5.2 Drei Ebenen der Isolation","text":"Ebene System Isolation Dateisystem MinIO (S3-Storage) Eigener Ordner pro Lehrer: /tenant-id/eh-id/encrypted.bin Vektordatenbank Qdrant Pflichtfilter tenant_id bei jeder Suche Metadaten-DB PostgreSQL Jede Tabelle hat teacher_id als Pflichtfeld

Kein Training mit Lehrerdaten

Auf allen Vektoren in Qdrant ist das Flag training_allowed: false gesetzt. Das bedeutet: Die Inhalte der Lehrer werden ausschliesslich fuer RAG-Suchen (Abruf relevanter Textpassagen) verwendet und niemals zum Trainieren eines KI-Modells eingesetzt.

"},{"location":"services/klausur-service/byoeh-system-erklaerung/#6-der-erwartungshorizont-die-grundlage-fuer-ki-korrektur","title":"6. Der Erwartungshorizont: Die Grundlage fuer KI-Korrektur","text":"

Ein Erwartungshorizont (EH) ist das Dokument, das beschreibt, was in einer Klausur erwartet wird: welche Inhalte in welcher Qualitaet vorkommen sollen. Im BYOEH-System laedt der Lehrer seinen eigenen EH hoch, und die KI nutzt ihn als Referenz fuer Korrekturvorschlaege.

"},{"location":"services/klausur-service/byoeh-system-erklaerung/#61-upload-wizard-5-schritte","title":"6.1 Upload-Wizard (5 Schritte)","text":"Schritt Was passiert Warum 1. Datei waehlen PDF per Drag & Drop hochladen Der EH als digitales Dokument 2. Metadaten Titel, Fach, Niveau (eA/gA), Jahr Fuer Filterung und Organisation 3. Rechtebestaetigung Checkbox: \"Ich bin berechtigt\" Rechtliche Absicherung (Urheberrecht) 4. Verschluesselung Passphrase eingeben (2x bestaetigen) Schluessel fuer Ende-zu-Ende-Verschluesselung 5. Zusammenfassung Pruefen und bestaetigen Letzte Kontrolle vor dem Upload"},{"location":"services/klausur-service/byoeh-system-erklaerung/#62-rag-pipeline-wie-der-eh-fuer-die-ki-nutzbar-wird","title":"6.2 RAG-Pipeline: Wie der EH fuer die KI nutzbar wird","text":"

Nach dem Upload wird der EH fuer die KI-Suche vorbereitet. Dieser Vorgang heisst Indexierung und funktioniert wie das Erstellen eines Stichwortverzeichnisses fuer ein Buch:

Indexierung: Vom PDF zum durchsuchbaren EH
Erwartungshorizont (verschluesselt auf Server)\n     |\n     v\n\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502  1. Passphrase-Verifikation    \u2502  \u2190 Lehrer gibt Passphrase ein\n\u2502     Hash pruefen               \u2502     Server vergleicht mit gespeichertem Hash\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n           |\n           v\n\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502  2. Entschluesselung           \u2502  \u2190 Temporaer im Arbeitsspeicher\n\u2502     AES-256-GCM Decrypt        \u2502     (wird nach Verarbeitung geloescht)\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n           |\n           v\n\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502  3. Text-Extraktion            \u2502  \u2190 PDF \u2192 Klartext\n\u2502     Tabellen, Listen erkennen  \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n           |\n           v\n\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502  4. Chunking                   \u2502  \u2190 Text in 1.000-Zeichen-Abschnitte zerlegen\n\u2502     Ueberlappung: 200 Zeichen  \u2502     (mit Ueberlappung fuer Kontext)\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n           |\n           v\n\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502  5. Embedding                  \u2502  \u2190 Jeder Abschnitt wird in einen\n\u2502     Text \u2192 1.536 Zahlen        \u2502     Bedeutungsvektor umgewandelt\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n           |\n           v\n\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502  6. Re-Encryption              \u2502  \u2190 Jeder Chunk wird ERNEUT verschluesselt\n\u2502     AES-256-GCM pro Chunk      \u2502     bevor er gespeichert wird\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n           |\n           v\n\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502  7. Qdrant-Indexierung          \u2502  \u2190 Vektor + verschluesselter Chunk\n\u2502     tenant_id: \"lehrer-123\"    \u2502     werden mit Tenant-Filter gespeichert\n\u2502     training_allowed: false    \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n
"},{"location":"services/klausur-service/byoeh-system-erklaerung/#63-wie-die-ki-den-eh-nutzt-rag-query","title":"6.3 Wie die KI den EH nutzt (RAG-Query)","text":"

Wenn der Lehrer bei der Korrektur einen Vorschlag anfordert, passiert folgendes:

  1. Frage formulieren: Das System erstellt eine Suchanfrage aus dem Klausurtext und dem aktuellen Bewertungskriterium.
  2. Semantische Suche: Die Anfrage wird in einen Vektor umgewandelt und gegen die EH-Vektoren in Qdrant gesucht -- nur im Namespace des Lehrers.
  3. Entschluesselung: Die gefundenen Chunks werden mit der Passphrase des Lehrers entschluesselt.
  4. KI-Antwort: Die entschluesselten EH-Passagen werden als Kontext an die KI uebergeben, die daraus einen Korrekturvorschlag generiert.
"},{"location":"services/klausur-service/byoeh-system-erklaerung/#7-key-sharing-zweitkorrektur-ermoeglichen","title":"7. Key Sharing: Zweitkorrektur ermoeglichen","text":"

Bei Abiturklausuren muss eine Zweitkorrektur durch einen anderen Lehrer erfolgen. Das Key-Sharing-System ermoeglicht es dem Erstpruefer, seinen Erwartungshorizont sicher mit dem Zweitpruefer zu teilen -- ohne die Verschluesselung aufzugeben.

"},{"location":"services/klausur-service/byoeh-system-erklaerung/#71-einladungs-workflow","title":"7.1 Einladungs-Workflow","text":"Key Sharing: Sicheres Teilen zwischen Pruefern
Erstpruefer                        Server                     Zweitpruefer\n     \u2502                                \u2502                             \u2502\n     \u2502  1. Einladung senden            \u2502                             \u2502\n     \u2502     (E-Mail + Rolle + Klausur)  \u2502                             \u2502\n     \u2502\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u25b6                             \u2502\n     \u2502                                \u2502                             \u2502\n     \u2502                                \u2502  2. Einladung erstellt       \u2502\n     \u2502                                \u2502     (14 Tage gueltig)        \u2502\n     \u2502                                \u2502                             \u2502\n     \u2502                                \u2502  3. Benachrichtigung \u2500\u2500\u2500\u2500\u2500\u2500\u25b6\u2502\n     \u2502                                \u2502                             \u2502\n     \u2502                                \u2502                      4. Annehmen\n     \u2502                                \u2502\u25c0\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2502\n     \u2502                                \u2502                             \u2502\n     \u2502                                \u2502  5. Key-Share erstellt       \u2502\n     \u2502                                \u2502                             \u2502\n     \u2502                                \u2502  6. Zweitpruefer kann \u2500\u2500\u2500\u2500\u2500\u2500\u25b6\u2502\n     \u2502                                \u2502     RAG-Queries ausfuehren   \u2502\n     \u2502                                \u2502                             \u2502\n     \u2502  7. Zugriff widerrufen          \u2502                             \u2502\n     \u2502     (jederzeit moeglich)       \u2502                             \u2502\n     \u2502\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u25b6                             \u2502\n
"},{"location":"services/klausur-service/byoeh-system-erklaerung/#72-rollen-beim-key-sharing","title":"7.2 Rollen beim Key-Sharing","text":"Rolle Wer Rechte Erstpruefer (EK) Kurslehrer Vollzugriff, kann teilen & widerrufen Zweitpruefer (ZK) Anderer Fachlehrer Nur Lesen, RAG-Queries, eigene Annotations Drittpruefer (DK) Bei Differenz \u2265 4 Punkte Nur Lesen, RAG-Queries Fachvorsitz Fachbereichsleitung Nur Lesen (Aufsichtsfunktion)"},{"location":"services/klausur-service/byoeh-system-erklaerung/#8-ki-gestuetzte-bewertung-wie-die-korrektur-funktioniert","title":"8. KI-gestuetzte Bewertung: Wie die Korrektur funktioniert","text":"

Die KI bewertet jede Klausur anhand von fuenf Kriterien, die zusammen 100% ergeben:

Kriterium Gewichtung Was geprueft wird Rechtschreibung 15% Orthographie, Zeichensetzung Grammatik 15% Satzbau, Kongruenz, Tempus Inhalt 40% Bezug zum EH, Vollstaendigkeit, Argumentation Struktur 15% Gliederung, Einleitung/Schluss, roter Faden Stil 15% Ausdruck, Wortwahl, Fachsprache

Die Bewertung folgt dem 15-Punkte-System (0-15 Notenpunkte) der gymnasialen Oberstufe.

KI schlaegt vor, Lehrer entscheidet

Alle KI-Bewertungen sind Vorschlaege. Der Lehrer hat bei jedem Kriterium die volle Kontrolle: Er kann den Vorschlag annehmen, aendern oder komplett ueberschreiben. Die finale Note setzt immer der Lehrer.

"},{"location":"services/klausur-service/byoeh-system-erklaerung/#9-audit-trail-alles-wird-protokolliert","title":"9. Audit-Trail: Alles wird protokolliert","text":"

Jede Aktion im System wird revisionssicher im Audit-Log gespeichert. Das ist wichtig fuer die Nachvollziehbarkeit und fuer den Fall, dass Schueler oder Eltern eine Korrektur anfechten.

Aktion Was protokolliert wird upload EH hochgeladen (Dateigroesse, Metadaten, Zeitstempel) index EH fuer RAG indexiert (Anzahl Chunks, Dauer) rag_query RAG-Suchanfrage ausgefuehrt (Query-Hash, Anzahl Ergebnisse, Score) share EH mit anderem Pruefer geteilt (Empfaenger, Rolle) revoke_share Zugriff widerrufen (wer, wann) link_klausur EH mit Klausur verknuepft delete EH geloescht (Soft Delete, bleibt in Logs)"},{"location":"services/klausur-service/byoeh-system-erklaerung/#10-api-endpunkte-technische-referenz","title":"10. API-Endpunkte (Technische Referenz)","text":"

Alle Endpunkte laufen ueber den klausur-service auf Port 8086.

"},{"location":"services/klausur-service/byoeh-system-erklaerung/#101-erwartungshorizont-verwaltung","title":"10.1 Erwartungshorizont-Verwaltung","text":"Methode Endpunkt Beschreibung POST /api/v1/eh/upload Verschluesselten EH hochladen GET /api/v1/eh Eigene EHs auflisten GET /api/v1/eh/{id} Einzelnen EH abrufen DELETE /api/v1/eh/{id} EH loeschen (Soft Delete) POST /api/v1/eh/{id}/index EH fuer RAG indexieren POST /api/v1/eh/rag-query RAG-Suchanfrage ausfuehren"},{"location":"services/klausur-service/byoeh-system-erklaerung/#102-key-sharing","title":"10.2 Key Sharing","text":"Methode Endpunkt Beschreibung POST /api/v1/eh/{id}/share EH mit Pruefer teilen GET /api/v1/eh/{id}/shares Geteilte Zugriffe auflisten DELETE /api/v1/eh/{id}/shares/{shareId} Zugriff widerrufen GET /api/v1/eh/shared-with-me Mit mir geteilte EHs"},{"location":"services/klausur-service/byoeh-system-erklaerung/#103-klausur-integration","title":"10.3 Klausur-Integration","text":"Methode Endpunkt Beschreibung POST /api/v1/eh/{id}/link-klausur EH mit Klausur verknuepfen DELETE /api/v1/eh/{id}/link-klausur/{klausurId} Verknuepfung loesen GET /api/v1/klausuren/{id}/linked-eh Verknuepften EH abrufen"},{"location":"services/klausur-service/byoeh-system-erklaerung/#11-dateistruktur-im-code","title":"11. Dateistruktur im Code","text":"Relevante Dateien im Repository
klausur-service/\n\u251c\u2500\u2500 backend/\n\u2502   \u251c\u2500\u2500 main.py                 # API-Endpunkte + Datenmodelle\n\u2502   \u251c\u2500\u2500 qdrant_service.py       # Vektordatenbank-Operationen (Tenant-Filter)\n\u2502   \u2514\u2500\u2500 eh_pipeline.py          # Chunking, Embedding, Verschluesselung\n\u2502\n\u251c\u2500\u2500 frontend/\n\u2502   \u2514\u2500\u2500 src/\n\u2502       \u251c\u2500\u2500 components/\n\u2502       \u2502   \u2514\u2500\u2500 EHUploadWizard.tsx    # 5-Schritt-Upload-Wizard\n\u2502       \u2514\u2500\u2500 services/\n\u2502           \u251c\u2500\u2500 api.ts                # API-Client\n\u2502           \u2514\u2500\u2500 encryption.ts         # Client-seitige Kryptographie\n\u2502\n\u2514\u2500\u2500 docs/\n    \u251c\u2500\u2500 BYOEH-Architecture.md         # Technische Architektur\n    \u2514\u2500\u2500 BYOEH-Developer-Guide.md      # Entwickler-Handbuch\n\nbackend/klausur/\n\u251c\u2500\u2500 db_models.py                # ExamSession, PseudonymizedDocument\n\u2514\u2500\u2500 services/\n    \u2514\u2500\u2500 pseudonymizer.py        # QR-Codes, Header-Redaction, doc_tokens\n
"},{"location":"services/klausur-service/byoeh-system-erklaerung/#12-zusammenfassung-die-sicherheitsgarantien","title":"12. Zusammenfassung: Die Sicherheitsgarantien","text":"Garantie Wie umgesetzt Regelwerk Kein Name verlaesst den Rechner Header-Redaction + verschluesselte Identity-Map DSGVO Art. 4 Nr. 5 Betreiber kann nicht mitlesen Client-seitige AES-256-GCM Verschluesselung DSGVO Art. 32 Kein Zugriff durch andere Lehrer Tenant-Isolation (Namespace) auf allen 3 Ebenen DSGVO Art. 25 Kein KI-Training mit Schuelerdaten training_allowed: false auf allen Vektoren AI Act Art. 10 Alles nachvollziehbar Vollstaendiger Audit-Trail aller Aktionen DSGVO Art. 5 Abs. 2 Lehrer behaelt volle Kontrolle KI-Vorschlaege, keine KI-Entscheidungen + jederzeitiger Widerruf DSGVO Art. 22

Das Wichtigste in einem Satz

Das BYOEH-System ermoeglicht KI-gestuetzte Klausurkorrektur, bei der kein Schuelername den Rechner des Lehrers verlaesst, alle Daten Ende-zu-Ende verschluesselt sind, jeder Lehrer seinen eigenen abgeschotteten Namespace hat, und die KI nur Vorschlaege macht -- die finale Bewertung trifft immer der Lehrer.

"},{"location":"services/voice-service/","title":"Voice Service","text":"

Der Voice Service ist eine Voice-First Interface f\u00fcr die Breakpilot-Plattform mit DSGVO-konformem Design.

"},{"location":"services/voice-service/#ubersicht","title":"\u00dcbersicht","text":"Eigenschaft Wert Port 8082 Framework FastAPI (Python) Streaming WebSocket DSGVO Privacy-by-Design"},{"location":"services/voice-service/#architektur","title":"Architektur","text":"
\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502                    Voice Service (Port 8082)                      \u2502\n\u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n\u2502                                                                   \u2502\n\u2502   \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510    \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510    \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510      \u2502\n\u2502   \u2502   Sessions   \u2502\u2500\u2500\u2500>\u2502    Task      \u2502\u2500\u2500\u2500>\u2502    BQAS      \u2502      \u2502\n\u2502   \u2502   API        \u2502    \u2502 Orchestrator \u2502    \u2502  (Quality)   \u2502      \u2502\n\u2502   \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518    \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518    \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518      \u2502\n\u2502                              \u2502                                    \u2502\n\u2502         \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510              \u2502\n\u2502         \u2502                    \u2502                    \u2502              \u2502\n\u2502         \u25bc                    \u25bc                    \u25bc              \u2502\n\u2502   \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510    \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510    \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510      \u2502\n\u2502   \u2502  WebSocket   \u2502    \u2502  Encryption  \u2502    \u2502   Logging    \u2502      \u2502\n\u2502   \u2502  Streaming   \u2502    \u2502  Service     \u2502    \u2502  (structlog) \u2502      \u2502\n\u2502   \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518    \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518    \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518      \u2502\n\u2502                                                                   \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n
"},{"location":"services/voice-service/#kernkomponenten","title":"Kernkomponenten","text":""},{"location":"services/voice-service/#personaplex-taskorchestrator","title":"PersonaPlex + TaskOrchestrator","text":""},{"location":"services/voice-service/#dsgvo-compliance-privacy-by-design","title":"DSGVO-Compliance (Privacy-by-Design)","text":"Feature Beschreibung Keine Audio-Persistenz Nur RAM-basiert, keine dauerhafte Speicherung Namespace-Verschl\u00fcsselung Schl\u00fcssel nur auf Lehrer-Ger\u00e4t TTL-basierte L\u00f6schung Automatische Datenl\u00f6schung nach Zeitablauf Transcript-Verschl\u00fcsselung Verschl\u00fcsselte Transkripte"},{"location":"services/voice-service/#api-endpunkte","title":"API-Endpunkte","text":""},{"location":"services/voice-service/#sessions","title":"Sessions","text":"Method Endpoint Beschreibung POST /api/v1/sessions Session erstellen GET /api/v1/sessions/:id Session abrufen DELETE /api/v1/sessions/:id Session beenden"},{"location":"services/voice-service/#task-orchestration","title":"Task Orchestration","text":"Method Endpoint Beschreibung POST /api/v1/tasks Task erstellen GET /api/v1/tasks/:id Task-Status abrufen"},{"location":"services/voice-service/#bqas-quality-assessment","title":"BQAS (Quality Assessment)","text":"Method Endpoint Beschreibung POST /api/v1/bqas/evaluate Qualit\u00e4tsbewertung GET /api/v1/bqas/metrics Metriken abrufen"},{"location":"services/voice-service/#websocket","title":"WebSocket","text":"Endpoint Beschreibung /ws/voice Real-time Voice Streaming"},{"location":"services/voice-service/#health","title":"Health","text":"Method Endpoint Beschreibung GET /health Health Check GET /ready Readiness Check"},{"location":"services/voice-service/#verzeichnisstruktur","title":"Verzeichnisstruktur","text":"
voice-service/\n\u251c\u2500\u2500 main.py                    # FastAPI Application\n\u251c\u2500\u2500 config.py                  # Konfiguration\n\u251c\u2500\u2500 pyproject.toml             # Projekt-Metadaten\n\u251c\u2500\u2500 requirements.txt           # Dependencies\n\u251c\u2500\u2500 api/\n\u2502   \u251c\u2500\u2500 sessions.py            # Session-Management\n\u2502   \u251c\u2500\u2500 streaming.py           # WebSocket Voice Streaming\n\u2502   \u251c\u2500\u2500 tasks.py               # Task Orchestration\n\u2502   \u2514\u2500\u2500 bqas.py                # Quality Assessment\n\u251c\u2500\u2500 services/\n\u2502   \u251c\u2500\u2500 task_orchestrator.py   # Task-Routing\n\u2502   \u2514\u2500\u2500 encryption.py          # Verschl\u00fcsselung\n\u251c\u2500\u2500 bqas/\n\u2502   \u251c\u2500\u2500 judge.py               # LLM Judge\n\u2502   \u2514\u2500\u2500 quality_judge_agent.py # Agent-Integration\n\u251c\u2500\u2500 models/                    # Datenmodelle\n\u251c\u2500\u2500 scripts/                   # Utility-Scripts\n\u2514\u2500\u2500 tests/                     # Test-Suite\n
"},{"location":"services/voice-service/#konfiguration","title":"Konfiguration","text":"
# .env\nVOICE_SERVICE_PORT=8082\nREDIS_URL=redis://localhost:6379\nDATABASE_URL=postgresql://...\nENCRYPTION_KEY=...\nTTL_MINUTES=60\n
"},{"location":"services/voice-service/#entwicklung","title":"Entwicklung","text":"
# Dependencies installieren\ncd voice-service\npip install -r requirements.txt\n\n# Server starten\nuvicorn main:app --reload --port 8082\n\n# Tests ausf\u00fchren\npytest -v\n
"},{"location":"services/voice-service/#docker","title":"Docker","text":"

Der Service l\u00e4uft als Teil von docker-compose.yml:

voice-service:\n  build:\n    context: ./voice-service\n  ports:\n    - \"8082:8082\"\n  environment:\n    - REDIS_URL=redis://valkey:6379\n  depends_on:\n    - valkey\n    - postgres\n
"},{"location":"services/voice-service/#weiterfuhrende-dokumentation","title":"Weiterf\u00fchrende Dokumentation","text":""}]}