This repository has been archived on 2026-02-15. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
breakpilot-pwa/docs-site/search/search_index.json
BreakPilot Dev 557305db5d
Some checks failed
ci/woodpecker/push/integration Pipeline failed
ci/woodpecker/push/main Pipeline failed
CI/CD Pipeline / Go Tests (push) Has been cancelled
CI/CD Pipeline / Python Tests (push) Has been cancelled
CI/CD Pipeline / Website Tests (push) Has been cancelled
CI/CD Pipeline / Linting (push) Has been cancelled
CI/CD Pipeline / Security Scan (push) Has been cancelled
CI/CD Pipeline / Docker Build & Push (push) Has been cancelled
CI/CD Pipeline / Integration Tests (push) Has been cancelled
CI/CD Pipeline / Deploy to Staging (push) Has been cancelled
CI/CD Pipeline / Deploy to Production (push) Has been cancelled
CI/CD Pipeline / CI Summary (push) Has been cancelled
Security Scanning / Secret Scanning (push) Has been cancelled
Security Scanning / Dependency Vulnerability Scan (push) Has been cancelled
Security Scanning / Go Security Scan (push) Has been cancelled
Security Scanning / Python Security Scan (push) Has been cancelled
Security Scanning / Node.js Security Scan (push) Has been cancelled
Security Scanning / Docker Image Security (push) Has been cancelled
Security Scanning / Security Summary (push) Has been cancelled
Tests / Go Tests (push) Has been cancelled
Tests / Python Tests (push) Has been cancelled
Tests / Integration Tests (push) Has been cancelled
Tests / Go Lint (push) Has been cancelled
Tests / Python Lint (push) Has been cancelled
Tests / Security Scan (push) Has been cancelled
Tests / All Checks Passed (push) Has been cancelled
feat: Add Academy, Whistleblower, Incidents SDK modules, pitch-deck, blog and CI/CD config
- Academy, Whistleblower, Incidents frontend pages with API proxies and types
- Vendor compliance API proxy route
- Go backend handlers and models for all new SDK modules
- Investor pitch-deck app with interactive slides
- Blog section with DSGVO, AI Act, NIS2, glossary articles
- MkDocs documentation site
- CI/CD pipelines (Woodpecker, GitHub Actions), security scanning config
- Planning and implementation documentation

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-13 21:12:16 +01:00

1 line
568 KiB
JSON

{"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":"<p>Willkommen zur zentralen Dokumentation des Breakpilot-Projekts.</p>"},{"location":"#was-ist-breakpilot","title":"Was ist Breakpilot?","text":"<p>Breakpilot ist eine DSGVO-konforme Bildungsplattform fuer Lehrkraefte mit folgenden Kernfunktionen:</p> <ul> <li>Consent-Management - Datenschutzkonforme Einwilligungsverwaltung</li> <li>KI-gestuetzte Klausurkorrektur - Automatische Bewertungsvorschlaege fuer Abiturklausuren</li> <li>Zeugnisgenerierung - Workflow-basierte Zeugniserstellung mit Rollenkonzept</li> <li>Lernmaterial-Generator - MC-Tests, Lueckentexte, Mindmaps, Quiz</li> <li>Elternbriefe - GFK-basierte Kommunikation mit PDF-Export</li> </ul>"},{"location":"#schnellstart","title":"Schnellstart","text":"<ul> <li> <p>:material-rocket-launch:{ .lg .middle } Erste Schritte</p> <p>Entwicklungsumgebung einrichten und das Projekt starten.</p> <p>:octicons-arrow-right-24: Umgebung einrichten</p> </li> <li> <p>:material-server:{ .lg .middle } Mac Mini Setup</p> <p>Headless Server-Konfiguration fuer den Entwicklungsserver.</p> <p>:octicons-arrow-right-24: Mac Mini Setup</p> </li> </ul>"},{"location":"#architektur","title":"Architektur","text":"<ul> <li> <p>:material-sitemap:{ .lg .middle } System-Architektur</p> <p>Ueberblick ueber alle Komponenten und deren Zusammenspiel.</p> <p>:octicons-arrow-right-24: Architektur</p> </li> <li> <p>:material-shield-lock:{ .lg .middle } Auth-System</p> <p>Hybrid-Authentifizierung mit Keycloak und lokalem JWT.</p> <p>:octicons-arrow-right-24: Auth-System</p> </li> <li> <p>:material-robot:{ .lg .middle } Multi-Agent System</p> <p>Verteilte Agent-Architektur fuer KI-Funktionen.</p> <p>:octicons-arrow-right-24: Multi-Agent</p> </li> <li> <p>:material-key-chain:{ .lg .middle } Secrets Management</p> <p>HashiCorp Vault Integration fuer sichere Credentials.</p> <p>:octicons-arrow-right-24: Secrets</p> </li> </ul>"},{"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":"<ul> <li>Testing - Test-Standards und Ausfuehrung</li> <li>Dokumentation - Dokumentations-Richtlinien</li> <li>DevSecOps - Security Pipeline</li> <li>Umgebungen - Dev/Staging/Prod</li> </ul>"},{"location":"#weitere-ressourcen","title":"Weitere Ressourcen","text":"<ul> <li>GitHub Repository: Internes GitLab</li> <li>Issue Tracker: GitLab Issues</li> <li>API Playground: http://macmini:8000/docs</li> </ul>"},{"location":"#projektstruktur","title":"Projektstruktur","text":"<pre><code>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</code></pre>"},{"location":"#support","title":"Support","text":"<p>Bei Fragen oder Problemen:</p> <ol> <li>Pruefen Sie zuerst die relevante Dokumentation</li> <li>Suchen Sie im Issue Tracker nach aehnlichen Problemen</li> <li>Erstellen Sie ein neues Issue mit detaillierter Beschreibung</li> </ol>"},{"location":"api/backend-api/","title":"BreakPilot Backend API Dokumentation","text":""},{"location":"api/backend-api/#ubersicht","title":"\u00dcbersicht","text":"<p>Base URL: <code>http://localhost:8000/api</code></p> <p>Alle Endpoints erfordern Authentifizierung via JWT im Authorization-Header: <pre><code>Authorization: Bearer &lt;token&gt;\n</code></pre></p>"},{"location":"api/backend-api/#worksheets-api","title":"Worksheets API","text":"<p>Generiert Lernmaterialien (MC-Tests, L\u00fcckentexte, Mindmaps, Quiz).</p>"},{"location":"api/backend-api/#post-worksheetsgeneratemultiple-choice","title":"POST /worksheets/generate/multiple-choice","text":"<p>Generiert Multiple-Choice-Fragen aus Quelltext.</p> <p>Request Body: <pre><code>{\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</code></pre></p> <p>Response (200): <pre><code>{\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</code></pre></p>"},{"location":"api/backend-api/#post-worksheetsgeneratecloze","title":"POST /worksheets/generate/cloze","text":"<p>Generiert L\u00fcckentexte.</p>"},{"location":"api/backend-api/#post-worksheetsgeneratemindmap","title":"POST /worksheets/generate/mindmap","text":"<p>Generiert Mindmap als Mermaid-Diagramm.</p>"},{"location":"api/backend-api/#post-worksheetsgeneratequiz","title":"POST /worksheets/generate/quiz","text":"<p>Generiert Mix aus verschiedenen Fragetypen.</p>"},{"location":"api/backend-api/#corrections-api","title":"Corrections API","text":"<p>OCR-basierte Klausurkorrektur mit automatischer Bewertung.</p>"},{"location":"api/backend-api/#post-corrections","title":"POST /corrections/","text":"<p>Erstellt neue Korrektur-Session.</p>"},{"location":"api/backend-api/#post-correctionsidupload","title":"POST /corrections/{id}/upload","text":"<p>L\u00e4dt gescannte Klausur hoch und startet OCR im Hintergrund.</p>"},{"location":"api/backend-api/#get-correctionsid","title":"GET /corrections/{id}","text":"<p>Ruft Korrektur-Status ab.</p> <p>Status-Werte: - <code>uploaded</code> - Datei hochgeladen - <code>processing</code> - OCR l\u00e4uft - <code>ocr_complete</code> - OCR fertig - <code>analyzing</code> - Analyse l\u00e4uft - <code>analyzed</code> - Analyse abgeschlossen - <code>completed</code> - Fertig - <code>error</code> - Fehler</p>"},{"location":"api/backend-api/#post-correctionsidanalyze","title":"POST /corrections/{id}/analyze","text":"<p>Analysiert extrahierten Text und bewertet Antworten.</p>"},{"location":"api/backend-api/#get-correctionsidexport-pdf","title":"GET /corrections/{id}/export-pdf","text":"<p>Exportiert korrigierte Arbeit als PDF.</p>"},{"location":"api/backend-api/#letters-api","title":"Letters API","text":"<p>Elternbriefe mit GFK-Integration und PDF-Export.</p>"},{"location":"api/backend-api/#post-letters","title":"POST /letters/","text":"<p>Erstellt neuen Elternbrief.</p> <p>letter_type Werte: - <code>general</code> - Allgemeine Information - <code>halbjahr</code> - Halbjahresinformation - <code>fehlzeiten</code> - Fehlzeiten-Mitteilung - <code>elternabend</code> - Einladung Elternabend - <code>lob</code> - Positives Feedback - <code>custom</code> - Benutzerdefiniert</p>"},{"location":"api/backend-api/#post-lettersimprove","title":"POST /letters/improve","text":"<p>Verbessert Text nach GFK-Prinzipien.</p>"},{"location":"api/backend-api/#state-engine-api","title":"State Engine API","text":"<p>Begleiter-Modus mit Phasen-Management und Antizipation.</p>"},{"location":"api/backend-api/#get-statedashboard","title":"GET /state/dashboard","text":"<p>Komplettes Dashboard f\u00fcr Begleiter-Modus.</p>"},{"location":"api/backend-api/#get-statesuggestions","title":"GET /state/suggestions","text":"<p>Ruft Vorschl\u00e4ge f\u00fcr Lehrer ab.</p>"},{"location":"api/backend-api/#post-statemilestone","title":"POST /state/milestone","text":"<p>Schlie\u00dft Meilenstein ab.</p>"},{"location":"api/backend-api/#klausur-korrektur-api-abitur","title":"Klausur-Korrektur API (Abitur)","text":"<p>Abitur-Klausurkorrektur mit 15-Punkte-System, Erst-/Zweitpr\u00fcfer-Workflow und KI-gest\u00fctzter Bewertung.</p>"},{"location":"api/backend-api/#klausur-modi","title":"Klausur-Modi","text":"Modus Beschreibung <code>landes_abitur</code> NiBiS Niedersachsen - rechtlich gekl\u00e4rte Aufgaben <code>vorabitur</code> Lehrer-erstellte Klausuren mit Rights-Gate"},{"location":"api/backend-api/#post-klausur-korrekturklausuren","title":"POST /klausur-korrektur/klausuren","text":"<p>Erstellt neue Abitur-Klausur.</p>"},{"location":"api/backend-api/#post-klausur-korrekturstudentsidevaluate","title":"POST /klausur-korrektur/students/{id}/evaluate","text":"<p>Startet KI-Bewertung.</p> <p>Response (200): <pre><code>{\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</code></pre></p>"},{"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 &lt;20% 6"},{"location":"api/backend-api/#bewertungskriterien","title":"Bewertungskriterien","text":"Kriterium Gewicht Beschreibung <code>rechtschreibung</code> 15% Orthografie <code>grammatik</code> 15% Grammatik &amp; Syntax <code>inhalt</code> 40% Inhaltliche Qualit\u00e4t <code>struktur</code> 15% Aufbau &amp; Gliederung <code>stil</code> 15% Ausdruck &amp; Stil"},{"location":"api/backend-api/#security-api-devsecops-dashboard","title":"Security API (DevSecOps Dashboard)","text":"<p>API fuer das Security Dashboard mit DevSecOps-Tools Integration.</p>"},{"location":"api/backend-api/#get-v1securitytools","title":"GET /v1/security/tools","text":"<p>Gibt Status aller DevSecOps-Tools zurueck.</p>"},{"location":"api/backend-api/#get-v1securityfindings","title":"GET /v1/security/findings","text":"<p>Gibt alle Security-Findings zurueck.</p>"},{"location":"api/backend-api/#get-v1securitysbom","title":"GET /v1/security/sbom","text":"<p>Gibt SBOM (Software Bill of Materials) zurueck.</p>"},{"location":"api/backend-api/#post-v1securityscantype","title":"POST /v1/security/scan/{type}","text":"<p>Startet einen Security-Scan.</p> <p>Path Parameter: - <code>type</code>: Scan-Typ (secrets, sast, deps, containers, sbom, all)</p>"},{"location":"api/backend-api/#fehler-responses","title":"Fehler-Responses","text":""},{"location":"api/backend-api/#400-bad-request","title":"400 Bad Request","text":"<pre><code>{\n \"detail\": \"Beschreibung des Fehlers\"\n}\n</code></pre>"},{"location":"api/backend-api/#401-unauthorized","title":"401 Unauthorized","text":"<pre><code>{\n \"detail\": \"Not authenticated\"\n}\n</code></pre>"},{"location":"api/backend-api/#404-not-found","title":"404 Not Found","text":"<pre><code>{\n \"detail\": \"Ressource nicht gefunden\"\n}\n</code></pre>"},{"location":"api/backend-api/#500-internal-server-error","title":"500 Internal Server Error","text":"<pre><code>{\n \"detail\": \"Interner Serverfehler\"\n}\n</code></pre>"},{"location":"architecture/auth-system/","title":"BreakPilot Authentifizierung &amp; Autorisierung","text":""},{"location":"architecture/auth-system/#uebersicht","title":"Uebersicht","text":"<p>BreakPilot verwendet einen Hybrid-Ansatz fuer Authentifizierung und Autorisierung:</p> <pre><code>\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</code></pre>"},{"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":"<ol> <li>Keycloak fuer Authentifizierung:</li> <li>Bew\u00e4hrtes IAM-System</li> <li>SSO, Federation, MFA</li> <li> <p>Apache-2.0 Lizenz</p> </li> <li> <p>Eigenes rbac.py fuer Autorisierung:</p> </li> <li>Domaenenspezifische Logik (Korrekturkette, Zeugnis-Workflow)</li> <li>Bundesland-spezifische Regeln</li> <li>Zeitlich begrenzte Zuweisungen</li> <li>Key-Sharing fuer verschluesselte Klausuren</li> </ol>"},{"location":"architecture/auth-system/#authentifizierung-authkeycloak_authpy","title":"Authentifizierung (auth/keycloak_auth.py)","text":""},{"location":"architecture/auth-system/#konfiguration","title":"Konfiguration","text":"<pre><code># 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</code></pre>"},{"location":"architecture/auth-system/#token-erkennung","title":"Token-Erkennung","text":"<p>Der <code>HybridAuthenticator</code> erkennt automatisch den Token-Typ:</p> <pre><code># 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</code></pre>"},{"location":"architecture/auth-system/#fastapi-integration","title":"FastAPI Integration","text":"<pre><code>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</code></pre>"},{"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 <code>erstkorrektor</code> Erster Pr\u00fcfer Klausur <code>zweitkorrektor</code> Zweiter Pr\u00fcfer Klausur <code>drittkorrektor</code> Dritter Pr\u00fcfer Klausur <code>klassenlehrer</code> Klassenleitung Zeugnis <code>fachlehrer</code> Fachlehrkraft Noten <code>fachvorsitz</code> Fachkonferenz-Leitung Fachschaft <code>schulleitung</code> Schulleiter/in Schule <code>zeugnisbeauftragter</code> Zeugnis-Koordination Zeugnis <code>sekretariat</code> Verwaltung Schule <code>data_protection_officer</code> DSB DSGVO ..."},{"location":"architecture/auth-system/#ressourcentypen-25","title":"Ressourcentypen (25+)","text":"<pre><code>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</code></pre>"},{"location":"architecture/auth-system/#aktionen-17","title":"Aktionen (17)","text":"<pre><code>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</code></pre>"},{"location":"architecture/auth-system/#permission-pruefung","title":"Permission-Pruefung","text":"<pre><code>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</code></pre>"},{"location":"architecture/auth-system/#bundesland-spezifische-policies","title":"Bundesland-spezifische Policies","text":"<pre><code>@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</code></pre>"},{"location":"architecture/auth-system/#beispiel-niedersachsen","title":"Beispiel: Niedersachsen","text":"<pre><code>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</code></pre>"},{"location":"architecture/auth-system/#workflow-beispiele","title":"Workflow-Beispiele","text":""},{"location":"architecture/auth-system/#klausurkorrektur-workflow","title":"Klausurkorrektur-Workflow","text":"<pre><code>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</code></pre>"},{"location":"architecture/auth-system/#zeugnis-workflow","title":"Zeugnis-Workflow","text":"<pre><code>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</code></pre>"},{"location":"architecture/auth-system/#dateien","title":"Dateien","text":"Datei Beschreibung <code>backend/auth/__init__.py</code> Auth-Modul Exports <code>backend/auth/keycloak_auth.py</code> Hybrid-Authentifizierung <code>klausur-service/backend/rbac.py</code> Autorisierungs-Engine <code>backend/rbac_api.py</code> 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":"<pre><code># .env\nENVIRONMENT=development\nJWT_SECRET=dev-secret-32-chars-minimum-here\n</code></pre>"},{"location":"architecture/auth-system/#produktion-mit-keycloak","title":"Produktion (mit Keycloak)","text":"<pre><code># .env\nENVIRONMENT=production\nJWT_SECRET=&lt;openssl rand -hex 32&gt;\nKEYCLOAK_SERVER_URL=https://keycloak.breakpilot.app\nKEYCLOAK_REALM=breakpilot\nKEYCLOAK_CLIENT_ID=breakpilot-backend\nKEYCLOAK_CLIENT_SECRET=&lt;from keycloak admin console&gt;\n</code></pre>"},{"location":"architecture/auth-system/#sicherheitshinweise","title":"Sicherheitshinweise","text":"<ol> <li>Secrets niemals im Code - Immer Umgebungsvariablen verwenden</li> <li>JWT_SECRET in Produktion - Mindestens 32 Bytes, generiert mit <code>openssl rand -hex 32</code></li> <li>Keycloak HTTPS - KEYCLOAK_VERIFY_SSL=true in Produktion</li> <li>Token-Expiration - Keycloak-Tokens kurz halten (5-15 Minuten)</li> <li>Audit-Trail - Alle Berechtigungspruefungen werden geloggt</li> </ol>"},{"location":"architecture/devsecops/","title":"BreakPilot DevSecOps Architecture","text":""},{"location":"architecture/devsecops/#uebersicht","title":"Uebersicht","text":"<p>BreakPilot implementiert einen umfassenden DevSecOps-Ansatz mit Security-by-Design fuer die Entwicklung und den Betrieb der Bildungsplattform.</p> <pre><code>\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 &amp; Scan \u2502 \u2502 &amp; 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</code></pre>"},{"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 <p>Konfiguration: <code>.gitleaks.toml</code></p> <pre><code># Lokal ausfuehren\ngitleaks detect --source . -v\n\n# Pre-commit (automatisch)\ngitleaks protect --staged -v\n</code></pre>"},{"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) <p>Konfiguration: <code>.semgrep.yml</code></p> <pre><code># Semgrep ausfuehren\nsemgrep scan --config auto --config .semgrep.yml\n\n# Bandit ausfuehren\nbandit -r backend/ -ll\n</code></pre>"},{"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 <p>Konfiguration: <code>.trivy.yaml</code></p> <pre><code># Filesystem-Scan\ntrivy fs . --severity HIGH,CRITICAL\n\n# Container-Scan\ntrivy image breakpilot-pwa-backend:latest\n</code></pre>"},{"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 <pre><code># SBOM generieren\nsyft dir:. -o cyclonedx-json=sbom.json\nsyft dir:. -o spdx-json=sbom-spdx.json\n</code></pre>"},{"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) <pre><code># ZAP Scan gegen Staging\ndocker run -t owasp/zap2docker-stable zap-baseline.py \\\n -t http://staging.breakpilot.app -r zap-report.html\n</code></pre>"},{"location":"architecture/devsecops/#pre-commit-hooks","title":"Pre-Commit Hooks","text":"<p>Die Pre-Commit-Konfiguration (<code>.pre-commit-config.yaml</code>) fuehrt automatisch bei jedem Commit aus:</p> <ol> <li>Schnelle Checks (&lt; 10 Sekunden):</li> <li>Gitleaks (Secrets)</li> <li>Trailing Whitespace</li> <li> <p>YAML/JSON Validierung</p> </li> <li> <p>Code Quality (&lt; 30 Sekunden):</p> </li> <li>Black/Ruff (Python Formatting)</li> <li>Go fmt/vet</li> <li> <p>ESLint (JavaScript)</p> </li> <li> <p>Security Checks (&lt; 60 Sekunden):</p> </li> <li>Bandit (Python Security)</li> <li>Semgrep (Error-Severity)</li> </ol>"},{"location":"architecture/devsecops/#installation","title":"Installation","text":"<pre><code># 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</code></pre>"},{"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":"<p>Das BreakPilot Admin Panel enthaelt ein integriertes Security Dashboard unter Verwaltung &gt; Security.</p>"},{"location":"architecture/devsecops/#features","title":"Features","text":"<p>Fuer Entwickler: - Scan-Ergebnisse auf einen Blick - Pre-commit Hook Status - Quick-Fix Suggestions - SBOM Viewer mit Suchfunktion</p> <p>Fuer Security-Experten: - Vulnerability Severity Distribution (Critical/High/Medium/Low) - CVE-Tracking mit Fix-Verfuegbarkeit - Compliance-Status (OWASP Top 10, DSGVO) - Secrets Detection History</p> <p>Fuer Ops: - Container Image Scan Results - Dependency Update Status - Security Scan Scheduling - Auto-Refresh alle 30 Sekunden</p>"},{"location":"architecture/devsecops/#api-endpoints","title":"API Endpoints","text":"<pre><code>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</code></pre>"},{"location":"architecture/devsecops/#compliance","title":"Compliance","text":"<p>Die DevSecOps-Pipeline unterstuetzt folgende Compliance-Anforderungen:</p> <ul> <li>DSGVO/GDPR: Automatische Erkennung von PII-Leaks</li> <li>OWASP Top 10: SAST/DAST-Scans gegen bekannte Schwachstellen</li> <li>Supply Chain Security: SBOM-Generierung fuer Audit-Trails</li> <li>CVE Tracking: Automatischer Abgleich mit NVD/CVE-Datenbanken</li> </ul>"},{"location":"architecture/devsecops/#tool-installation","title":"Tool-Installation","text":""},{"location":"architecture/devsecops/#macos-homebrew","title":"macOS (Homebrew)","text":"<pre><code># 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</code></pre>"},{"location":"architecture/devsecops/#linux-aptsnap","title":"Linux (apt/snap)","text":"<pre><code># Gitleaks\nsudo snap install gitleaks\n\n# Trivy\nsudo apt-get install trivy\n\n# Python Tools\npip install semgrep bandit pre-commit\n</code></pre>"},{"location":"architecture/environments/","title":"Umgebungs-Architektur","text":""},{"location":"architecture/environments/#ubersicht","title":"\u00dcbersicht","text":"<p>BreakPilot verwendet eine 3-Umgebungs-Strategie f\u00fcr sichere Entwicklung und Deployment:</p> <pre><code>\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</code></pre>"},{"location":"architecture/environments/#umgebungen","title":"Umgebungen","text":""},{"location":"architecture/environments/#development-dev","title":"Development (Dev)","text":"<p>Zweck: T\u00e4gliche Entwicklungsarbeit</p> Eigenschaft Wert Git Branch <code>develop</code> Compose File <code>docker-compose.yml</code> + <code>docker-compose.override.yml</code> (auto) Env File <code>.env.dev</code> Database <code>breakpilot_dev</code> Debug Aktiviert Hot-Reload Aktiviert <p>Start: <pre><code>./scripts/start.sh dev\n# oder einfach:\ndocker compose up -d\n</code></pre></p>"},{"location":"architecture/environments/#staging","title":"Staging","text":"<p>Zweck: Getesteter, freigegebener Code vor Produktion</p> Eigenschaft Wert Git Branch <code>staging</code> Compose File <code>docker-compose.yml</code> + <code>docker-compose.staging.yml</code> Env File <code>.env.staging</code> Database <code>breakpilot_staging</code> (separates Volume) Debug Deaktiviert Hot-Reload Deaktiviert <p>Start: <pre><code>./scripts/start.sh staging\n# oder:\ndocker compose -f docker-compose.yml -f docker-compose.staging.yml up -d\n</code></pre></p>"},{"location":"architecture/environments/#production-prod","title":"Production (Prod)","text":"<p>Zweck: Live-System f\u00fcr Endbenutzer (ab Launch)</p> Eigenschaft Wert Git Branch <code>main</code> Compose File <code>docker-compose.yml</code> + <code>docker-compose.prod.yml</code> Env File <code>.env.prod</code> (NICHT im Repository!) Database <code>breakpilot_prod</code> (separates Volume) Debug Deaktiviert Vault Pflicht (keine Env-Fallbacks)"},{"location":"architecture/environments/#datenbank-trennung","title":"Datenbank-Trennung","text":"<p>Jede Umgebung verwendet separate Docker Volumes f\u00fcr vollst\u00e4ndige Datenisolierung:</p> <pre><code>\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</code></pre>"},{"location":"architecture/environments/#port-mapping","title":"Port-Mapping","text":"<p>Um mehrere Umgebungen gleichzeitig laufen zu lassen, verwenden sie unterschiedliche Ports:</p> 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":"<pre><code>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</code></pre>"},{"location":"architecture/environments/#workflow","title":"Workflow","text":"<ol> <li>Entwicklung: Arbeite auf <code>develop</code></li> <li>Code-Review: Erstelle PR von Feature-Branch \u2192 <code>develop</code></li> <li>Staging: Promote <code>develop</code> \u2192 <code>staging</code> mit Tests</li> <li>Release: Promote <code>staging</code> \u2192 <code>main</code> nach Freigabe</li> </ol>"},{"location":"architecture/environments/#promotion-befehle","title":"Promotion-Befehle","text":"<pre><code># develop \u2192 staging\n./scripts/promote.sh dev-to-staging\n\n# staging \u2192 main (Production)\n./scripts/promote.sh staging-to-prod\n</code></pre>"},{"location":"architecture/environments/#secrets-management","title":"Secrets Management","text":""},{"location":"architecture/environments/#development","title":"Development","text":"<ul> <li><code>.env.dev</code> enth\u00e4lt Entwicklungs-Credentials</li> <li>Vault optional (Dev-Token)</li> <li>Mailpit f\u00fcr E-Mail-Tests</li> </ul>"},{"location":"architecture/environments/#staging_1","title":"Staging","text":"<ul> <li><code>.env.staging</code> enth\u00e4lt Test-Credentials</li> <li>Vault empfohlen</li> <li>Mailpit f\u00fcr E-Mail-Sicherheit</li> </ul>"},{"location":"architecture/environments/#production","title":"Production","text":"<ul> <li><code>.env.prod</code> NICHT im Repository</li> <li>Vault PFLICHT</li> <li>Echte SMTP-Konfiguration</li> </ul> <p>Siehe auch: Secrets Management</p>"},{"location":"architecture/environments/#docker-compose-architektur","title":"Docker Compose Architektur","text":"<pre><code>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</code></pre>"},{"location":"architecture/environments/#automatisches-laden","title":"Automatisches Laden","text":"<p>Docker Compose l\u00e4dt automatisch: 1. <code>docker-compose.yml</code> 2. <code>docker-compose.override.yml</code> (falls vorhanden)</p> <p>Daher startet <code>docker compose up</code> automatisch die Dev-Umgebung.</p>"},{"location":"architecture/environments/#helper-scripts","title":"Helper Scripts","text":"Script Beschreibung <code>scripts/env-switch.sh</code> Wechselt zwischen Umgebungen <code>scripts/start.sh</code> Startet Services f\u00fcr Umgebung <code>scripts/stop.sh</code> Stoppt Services <code>scripts/promote.sh</code> Promotet Code zwischen Branches <code>scripts/status.sh</code> Zeigt aktuellen Status"},{"location":"architecture/environments/#verifikation","title":"Verifikation","text":"<p>Nach Setup pr\u00fcfen:</p> <pre><code># 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</code></pre>"},{"location":"architecture/environments/#verwandte-dokumentation","title":"Verwandte Dokumentation","text":"<ul> <li>Secrets Management - Vault &amp; Secrets</li> <li>DevSecOps - CI/CD &amp; Security</li> <li>System-Architektur - Gesamtarchitektur</li> </ul>"},{"location":"architecture/mail-rbac-architecture/","title":"Mail-RBAC Architektur mit Mitarbeiter-Anonymisierung","text":"<p>Version: 1.0.0 Status: Architekturplanung</p>"},{"location":"architecture/mail-rbac-architecture/#executive-summary","title":"Executive Summary","text":"<p>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.</p>"},{"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":"<pre><code>max.mustermann@firma.de \u2192 Person gebunden\n \u2192 DSGVO: Daten m\u00fcssen gel\u00f6scht werden\n \u2192 Gesch\u00e4ftshistorie geht verloren\n</code></pre>"},{"location":"architecture/mail-rbac-architecture/#breakpilot-losung-rollenbasierte-e-mail","title":"BreakPilot-L\u00f6sung: Rollenbasierte E-Mail","text":"<pre><code>klassenlehrer.5a@schule.breakpilot.app \u2192 Rolle gebunden\n \u2192 Person kann anonymisiert werden\n \u2192 Kommunikationshistorie bleibt erhalten\n</code></pre>"},{"location":"architecture/mail-rbac-architecture/#2-architektur-ubersicht","title":"2. Architektur-\u00dcbersicht","text":"<pre><code>\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</code></pre>"},{"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":"<p>Empfehlung: Stalwart Mail Server</p> 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":"<p>Option A: SOGo (empfohlen) - Lizenz: GPL-2.0 / LGPL-2.1 - Kalender, Kontakte, Mail in einem - ActiveSync Support - Outlook-\u00e4hnliche Oberfl\u00e4che</p> <p>Option B: Roundcube - Lizenz: GPL-3.0 - Nur Webmail - Ben\u00f6tigt separaten Kalender</p>"},{"location":"architecture/mail-rbac-architecture/#4-anonymisierungs-workflow","title":"4. Anonymisierungs-Workflow","text":"<pre><code>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</code></pre>"},{"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":"<p>Die Unified Inbox wurde als Teil des klausur-service implementiert:</p> Komponente Pfad Beschreibung Models <code>klausur-service/backend/mail/models.py</code> Pydantic Models f\u00fcr Accounts, E-Mails, Tasks Database <code>klausur-service/backend/mail/mail_db.py</code> PostgreSQL-Operationen mit asyncpg Credentials <code>klausur-service/backend/mail/credentials.py</code> Vault-Integration f\u00fcr IMAP/SMTP-Passw\u00f6rter Aggregator <code>klausur-service/backend/mail/aggregator.py</code> Multi-Account IMAP Sync AI Service <code>klausur-service/backend/mail/ai_service.py</code> KI-Analyse (Absender, Fristen, Kategorien) Task Service <code>klausur-service/backend/mail/task_service.py</code> Arbeitsvorrat-Management API <code>klausur-service/backend/mail/api.py</code> FastAPI Router mit 30+ Endpoints"},{"location":"architecture/mail-rbac-architecture/#api-endpoints-port-8086","title":"API-Endpoints (Port 8086)","text":"<pre><code># 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</code></pre>"},{"location":"architecture/mail-rbac-architecture/#niedersachsen-spezifische-absendererkennung","title":"Niedersachsen-spezifische Absendererkennung","text":"<pre><code>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</code></pre>"},{"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":"<ul> <li>Stalwart Mail Server</li> <li>SOGo Groupware</li> <li>Roundcube Webmail</li> <li>CalDAV Standard</li> <li>DSGVO Art. 17 - Recht auf L\u00f6schung</li> </ul>"},{"location":"architecture/multi-agent/","title":"Multi-Agent Architektur - Entwicklerdokumentation","text":"<p>Status: Implementiert Modul: <code>/agent-core/</code></p>"},{"location":"architecture/multi-agent/#1-ubersicht","title":"1. \u00dcbersicht","text":"<p>Die Multi-Agent-Architektur erweitert Breakpilot um ein verteiltes Agent-System basierend auf Mission Control Konzepten.</p>"},{"location":"architecture/multi-agent/#kernkomponenten","title":"Kernkomponenten","text":"Komponente Pfad Beschreibung Session Management <code>/agent-core/sessions/</code> Lifecycle &amp; Recovery Shared Brain <code>/agent-core/brain/</code> Langzeit-Ged\u00e4chtnis Orchestrator <code>/agent-core/orchestrator/</code> Koordination SOUL Files <code>/agent-core/soul/</code> Agent-Pers\u00f6nlichkeiten"},{"location":"architecture/multi-agent/#2-agent-typen","title":"2. Agent-Typen","text":"Agent Aufgabe SOUL-Datei TutorAgent Lernbegleitung, Fragen beantworten <code>tutor-agent.soul.md</code> GraderAgent Klausur-Korrektur, Bewertung <code>grader-agent.soul.md</code> QualityJudge BQAS Qualit\u00e4tspr\u00fcfung <code>quality-judge.soul.md</code> AlertAgent Monitoring, Benachrichtigungen <code>alert-agent.soul.md</code> Orchestrator Task-Koordination <code>orchestrator.soul.md</code>"},{"location":"architecture/multi-agent/#3-wichtige-dateien","title":"3. Wichtige Dateien","text":""},{"location":"architecture/multi-agent/#session-management","title":"Session Management","text":"<pre><code>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</code></pre>"},{"location":"architecture/multi-agent/#shared-brain","title":"Shared Brain","text":"<pre><code>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</code></pre>"},{"location":"architecture/multi-agent/#orchestrator","title":"Orchestrator","text":"<pre><code>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</code></pre>"},{"location":"architecture/multi-agent/#4-datenbank-schema","title":"4. Datenbank-Schema","text":"<p>Die Migration befindet sich in: <code>/backend/migrations/add_agent_core_tables.sql</code></p>"},{"location":"architecture/multi-agent/#tabellen","title":"Tabellen","text":"<ol> <li>agent_sessions - Session-Daten mit Checkpoints</li> <li>agent_memory - Langzeit-Ged\u00e4chtnis mit TTL</li> <li>agent_messages - Audit-Trail f\u00fcr Inter-Agent Kommunikation</li> </ol>"},{"location":"architecture/multi-agent/#helper-funktionen","title":"Helper-Funktionen","text":"<pre><code>-- Abgelaufene Memories bereinigen\nSELECT cleanup_expired_agent_memory();\n\n-- Inaktive Sessions bereinigen\nSELECT cleanup_stale_agent_sessions(48); -- 48 Stunden\n</code></pre>"},{"location":"architecture/multi-agent/#5-integration-voice-service","title":"5. Integration Voice-Service","text":"<p>Der <code>EnhancedTaskOrchestrator</code> erweitert den bestehenden <code>TaskOrchestrator</code>:</p> <pre><code># 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</code></pre> <p>Wichtig: Der Enhanced Orchestrator ist abw\u00e4rtskompatibel und kann parallel zum Original verwendet werden.</p>"},{"location":"architecture/multi-agent/#6-integration-bqas","title":"6. Integration BQAS","text":"<p>Der <code>QualityJudgeAgent</code> integriert BQAS mit dem Multi-Agent-System:</p> <pre><code># 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</code></pre>"},{"location":"architecture/multi-agent/#7-code-beispiele","title":"7. Code-Beispiele","text":""},{"location":"architecture/multi-agent/#session-erstellen","title":"Session erstellen","text":"<pre><code>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</code></pre>"},{"location":"architecture/multi-agent/#memory-speichern","title":"Memory speichern","text":"<pre><code>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</code></pre>"},{"location":"architecture/multi-agent/#nachricht-senden","title":"Nachricht senden","text":"<pre><code>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</code></pre>"},{"location":"architecture/multi-agent/#8-tests-ausfuhren","title":"8. Tests ausf\u00fchren","text":"<pre><code># Alle Agent-Core Tests\ncd agent-core &amp;&amp; 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</code></pre>"},{"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":"<pre><code>psql -h localhost -U breakpilot -d breakpilot \\\n -f backend/migrations/add_agent_core_tables.sql\n</code></pre>"},{"location":"architecture/multi-agent/#2-voice-service-aktualisieren","title":"2. Voice-Service aktualisieren","text":"<pre><code># 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</code></pre>"},{"location":"architecture/multi-agent/#3-verifizieren","title":"3. Verifizieren","text":"<pre><code># 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</code></pre>"},{"location":"architecture/multi-agent/#10-monitoring","title":"10. Monitoring","text":""},{"location":"architecture/multi-agent/#metriken","title":"Metriken","text":"Metrik Beschreibung <code>agent_session_count</code> Anzahl aktiver Sessions <code>agent_heartbeat_delay_ms</code> Zeit seit letztem Heartbeat <code>agent_message_latency_ms</code> Nachrichtenlatenz <code>agent_memory_count</code> Gespeicherte Memories <code>agent_routing_success_rate</code> Erfolgreiche Routings"},{"location":"architecture/multi-agent/#health-check-endpunkte","title":"Health-Check-Endpunkte","text":"<pre><code>GET /api/v1/agents/health # Supervisor Status\nGET /api/v1/agents/sessions # Aktive Sessions\nGET /api/v1/agents/memory/stats # Memory-Statistiken\n</code></pre>"},{"location":"architecture/multi-agent/#11-troubleshooting","title":"11. Troubleshooting","text":""},{"location":"architecture/multi-agent/#problem-session-nicht-gefunden","title":"Problem: Session nicht gefunden","text":"<ol> <li>Pr\u00fcfen ob Valkey l\u00e4uft: <code>redis-cli ping</code></li> <li>Session-Timeout pr\u00fcfen (default 24h)</li> <li>Heartbeat-Status checken</li> </ol>"},{"location":"architecture/multi-agent/#problem-message-bus-timeout","title":"Problem: Message Bus Timeout","text":"<ol> <li>Redis Pub/Sub Status pr\u00fcfen</li> <li>Ziel-Agent registriert?</li> <li>Timeout erh\u00f6hen (default 30s)</li> </ol>"},{"location":"architecture/multi-agent/#problem-memory-nicht-gefunden","title":"Problem: Memory nicht gefunden","text":"<ol> <li>Namespace korrekt?</li> <li>TTL abgelaufen?</li> <li>Cleanup-Job gelaufen?</li> </ol>"},{"location":"architecture/multi-agent/#12-erweiterungen","title":"12. Erweiterungen","text":""},{"location":"architecture/multi-agent/#neuen-agent-hinzufugen","title":"Neuen Agent hinzuf\u00fcgen","text":"<ol> <li>SOUL-Datei erstellen in <code>/agent-core/soul/</code></li> <li>Routing-Regel in <code>task_router.py</code> hinzuf\u00fcgen</li> <li>Handler beim Supervisor registrieren</li> <li>Tests schreiben</li> </ol>"},{"location":"architecture/multi-agent/#neuen-memory-typ-hinzufugen","title":"Neuen Memory-Typ hinzuf\u00fcgen","text":"<ol> <li>Key-Schema definieren (z.B. <code>student:*:progress</code>)</li> <li>TTL festlegen</li> <li>Access-Pattern dokumentieren</li> </ol>"},{"location":"architecture/multi-agent/#13-referenzen","title":"13. Referenzen","text":"<ul> <li>Agent-Core README: <code>/agent-core/README.md</code></li> <li>Migration: <code>/backend/migrations/add_agent_core_tables.sql</code></li> <li>Voice-Service Integration: <code>/voice-service/services/enhanced_task_orchestrator.py</code></li> <li>BQAS Integration: <code>/voice-service/bqas/quality_judge_agent.py</code></li> <li>Tests: <code>/agent-core/tests/</code></li> </ul>"},{"location":"architecture/sdk-protection/","title":"SDK Protection Middleware","text":""},{"location":"architecture/sdk-protection/#1-worum-geht-es","title":"1. Worum geht es?","text":"<p>Die SDK Protection Middleware schuetzt die Compliance-SDK-Endpunkte vor einer bestimmten Art von Angriff: der systematischen Enumeration. Was bedeutet das?</p> <p>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.</p> <p>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.</p> <p>Kern-Designprinzip</p> <p>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.</p>"},{"location":"architecture/sdk-protection/#2-wie-funktioniert-der-schutz","title":"2. Wie funktioniert der Schutz?","text":"<p>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.</p> <p>Man kann es sich wie eine Ampel vorstellen:</p> 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":"<p>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.</p>"},{"location":"architecture/sdk-protection/#3-was-wird-erkannt","title":"3. Was wird erkannt?","text":"<p>Die Middleware erkennt fuenf verschiedene Anomalie-Muster:</p>"},{"location":"architecture/sdk-protection/#31-hohe-kategorie-diversitaet","title":"3.1 Hohe Kategorie-Diversitaet","text":"<p>Was: Ein Benutzer greift innerhalb einer Stunde auf mehr als 40 verschiedene SDK-Kategorien zu.</p> <p>Warum verdaechtig: Ein normaler Nutzer arbeitet in der Regel mit 3-10 Kategorien. Wer systematisch alle durchlaeuft, sammelt vermutlich Daten.</p> <p>Score-Erhoehung: +15</p> <pre><code>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</code></pre>"},{"location":"architecture/sdk-protection/#32-burst-erkennung","title":"3.2 Burst-Erkennung","text":"<p>Was: Ein Benutzer sendet mehr als 15 Anfragen an die gleiche Kategorie innerhalb von 2 Minuten.</p> <p>Warum verdaechtig: Selbst ein eifriger Nutzer klickt nicht 15-mal pro Minute auf denselben Endpunkt. Das deutet auf automatisiertes Scraping hin.</p> <p>Score-Erhoehung: +20</p>"},{"location":"architecture/sdk-protection/#33-sequentielle-enumeration","title":"3.3 Sequentielle Enumeration","text":"<p>Was: Die letzten 10 aufgerufenen Kategorien sind zu mindestens 70% in alphabetischer oder numerischer Reihenfolge.</p> <p>Warum verdaechtig: Menschen springen zwischen Kategorien -- sie arbeiten thematisch, nicht alphabetisch. Ein Skript dagegen iteriert oft ueber eine sortierte Liste.</p> <p>Score-Erhoehung: +25</p> <pre><code>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</code></pre>"},{"location":"architecture/sdk-protection/#34-ungewoehnliche-uhrzeiten","title":"3.4 Ungewoehnliche Uhrzeiten","text":"<p>Was: Anfragen zwischen 0:00 und 5:00 Uhr UTC.</p> <p>Warum verdaechtig: Lehrer arbeiten tags\u00fcber. Wer um 3 Uhr morgens SDK-Endpunkte abfragt, ist wahrscheinlich ein automatisierter Prozess.</p> <p>Score-Erhoehung: +10</p>"},{"location":"architecture/sdk-protection/#35-multi-tenant-zugriff","title":"3.5 Multi-Tenant-Zugriff","text":"<p>Was: Ein Benutzer greift innerhalb einer Stunde auf mehr als 3 verschiedene Mandanten (Tenants) zu.</p> <p>Warum verdaechtig: Ein normaler Nutzer gehoert zu einem Mandanten. Wer mehrere durchprobiert, koennte versuchen, mandantenuebergreifend Daten zu sammeln.</p> <p>Score-Erhoehung: +15</p>"},{"location":"architecture/sdk-protection/#4-quota-system-mengenbegrenzung","title":"4. Quota-System (Mengenbegrenzung)","text":"<p>Zusaetzlich zum Anomaly-Score gibt es klassische Mengenbegrenzungen in vier Zeitfenstern:</p> 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 <p>Wenn ein Limit in irgendeinem Zeitfenster ueberschritten wird, erhaelt der Nutzer sofort HTTP 429 -- unabhaengig vom Anomaly-Score.</p>"},{"location":"architecture/sdk-protection/#5-architektur","title":"5. Architektur","text":""},{"location":"architecture/sdk-protection/#datenfluss-eines-sdk-requests","title":"Datenfluss eines SDK-Requests","text":"<pre><code>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 &gt;40 Kategorien/h) \u2502\n\u2502 \u251c\u2500\u2500 Burst-Detection (+20 wenn &gt;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 &gt;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</code></pre>"},{"location":"architecture/sdk-protection/#valkey-datenstrukturen","title":"Valkey-Datenstrukturen","text":"<p>Die Middleware speichert alle Tracking-Daten in Valkey (Redis-Fork). Wenn Valkey nicht erreichbar ist, wird automatisch auf eine In-Memory-Implementierung zurueckgefallen.</p> Zweck Valkey-Typ Key-Muster TTL Quota pro Zeitfenster Sorted Set <code>sdk_protect:quota:{user}:{window}</code> Fenster + 10s Kategorie-Diversitaet Set <code>sdk_protect:diversity:{user}:{stunde}</code> 3660s Burst-Tracking Sorted Set <code>sdk_protect:burst:{user}:{kategorie}</code> 130s Sequenz-Tracking List <code>sdk_protect:seq:{user}</code> 310s Anomaly-Score Hash <code>sdk_protect:score:{user}</code> 86400s Tenant-Tracking Set <code>sdk_protect:tenants:{user}:{stunde}</code> 3660s"},{"location":"architecture/sdk-protection/#watermarking","title":"Watermarking","text":"<p>Jede Antwort enthaelt einen <code>X-BP-Trace</code> 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.</p>"},{"location":"architecture/sdk-protection/#6-geschuetzte-endpunkte","title":"6. Geschuetzte Endpunkte","text":"<p>Die Middleware schuetzt alle Pfade, die SDK- und Compliance-relevante Daten liefern:</p> Pfad-Prefix Bereich <code>/api/sdk/*</code> SDK-Hauptendpunkte <code>/api/compliance/*</code> Compliance-Bewertungen <code>/api/v1/tom/*</code> Technisch-organisatorische Massnahmen <code>/api/v1/dsfa/*</code> Datenschutz-Folgenabschaetzung <code>/api/v1/vvt/*</code> Verarbeitungsverzeichnis <code>/api/v1/controls/*</code> Controls und Massnahmen <code>/api/v1/assessment/*</code> Assessment-Bewertungen <code>/api/v1/eh/*</code> Erwartungshorizonte <code>/api/v1/namespace/*</code> Namespace-Verwaltung <p>Nicht geschuetzt sind <code>/health</code>, <code>/metrics</code> und <code>/api/health</code>.</p>"},{"location":"architecture/sdk-protection/#7-admin-verwaltung","title":"7. Admin-Verwaltung","text":"<p>Ueber das Admin-Dashboard koennen Anomaly-Scores eingesehen und verwaltet werden:</p> Endpoint Methode Beschreibung <code>/api/admin/middleware/sdk-protection/scores</code> GET Aktuelle Anomaly-Scores aller Benutzer <code>/api/admin/middleware/sdk-protection/stats</code> GET Statistik: Benutzer pro Throttle-Level <code>/api/admin/middleware/sdk-protection/reset-score/{user_id}</code> POST Score eines Benutzers zuruecksetzen <code>/api/admin/middleware/sdk-protection/tiers</code> GET Tier-Konfigurationen anzeigen <code>/api/admin/middleware/sdk-protection/tiers/{name}</code> PUT Tier-Limits aendern"},{"location":"architecture/sdk-protection/#8-dateien-und-quellcode","title":"8. Dateien und Quellcode","text":"Datei Beschreibung <code>backend/middleware/sdk_protection.py</code> Kern-Middleware (~460 Zeilen) <code>backend/middleware/__init__.py</code> Export der Middleware-Klassen <code>backend/main.py</code> Registrierung im FastAPI-Stack <code>backend/middleware_admin_api.py</code> Admin-API-Endpoints <code>backend/migrations/add_sdk_protection_tables.sql</code> Datenbank-Migration <code>backend/tests/test_middleware.py</code> 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":"<p>Speichert Snapshots der Anomaly-Scores fuer Audit und Analyse.</p> Spalte Typ Beschreibung <code>id</code> UUID Primaerschluessel <code>user_id</code> VARCHAR(255) Benutzer-Identifikation <code>score</code> DECIMAL(5,2) Aktueller Anomaly-Score <code>throttle_level</code> SMALLINT Aktueller Throttle-Level (0-3) <code>triggered_rules</code> JSONB Welche Regeln ausgeloest wurden <code>endpoint_diversity_count</code> INT Anzahl verschiedener Kategorien <code>request_count_1h</code> INT Anfragen in der letzten Stunde <code>snapshot_at</code> TIMESTAMPTZ Zeitpunkt des Snapshots"},{"location":"architecture/sdk-protection/#sdk_protection_tiers","title":"sdk_protection_tiers","text":"<p>Konfigurierbare Quota-Tiers, editierbar ueber die Admin-API.</p> Spalte Typ Beschreibung <code>tier_name</code> VARCHAR(50) Name des Tiers (free, standard, enterprise) <code>quota_per_minute</code> INT Maximale Anfragen pro Minute <code>quota_per_hour</code> INT Maximale Anfragen pro Stunde <code>quota_per_day</code> INT Maximale Anfragen pro Tag <code>quota_per_month</code> INT Maximale Anfragen pro Monat <code>diversity_threshold</code> INT Max verschiedene Kategorien pro Stunde <code>burst_threshold</code> INT Max gleiche Kategorie in 2 Minuten"},{"location":"architecture/sdk-protection/#10-konfiguration","title":"10. Konfiguration","text":"<p>Die Middleware wird in <code>main.py</code> registriert:</p> <pre><code>from middleware import SDKProtectionMiddleware\n\napp.add_middleware(SDKProtectionMiddleware)\n</code></pre> <p>Alle Parameter koennen ueber die <code>SDKProtectionConfig</code> Dataclass angepasst werden. Die wichtigsten Umgebungsvariablen:</p> Variable Default Beschreibung <code>VALKEY_URL</code> <code>redis://localhost:6379</code> Verbindung zur Valkey-Instanz <code>SDK_WATERMARK_SECRET</code> (generiert) HMAC-Secret fuer Watermarks"},{"location":"architecture/sdk-protection/#11-tests","title":"11. Tests","text":"<p>Die Middleware wird durch 14 automatisierte Tests abgedeckt:</p> <pre><code># Alle SDK Protection Tests ausfuehren\ndocker compose run --rm --no-deps backend \\\n python -m pytest tests/test_middleware.py -v -k sdk\n</code></pre> Test Prueft <code>test_allows_normal_request</code> Normaler Request wird durchgelassen <code>test_blocks_after_quota_exceeded</code> 429 bei Quota-Ueberschreitung <code>test_diversity_tracking_increments_score</code> Viele Kategorien erhoehen den Score <code>test_burst_detection</code> Schnelle gleiche Anfragen erhoehen den Score <code>test_sequential_enumeration_detection</code> Alphabetische Muster werden erkannt <code>test_progressive_throttling_level_1</code> Delay bei Score &gt;= 30 <code>test_progressive_throttling_level_3_blocks</code> Block bei Score &gt;= 85 <code>test_score_decay_over_time</code> Score sinkt ueber die Zeit <code>test_skips_non_protected_paths</code> Nicht-SDK-Pfade bleiben frei <code>test_watermark_header_present</code> X-BP-Trace Header vorhanden <code>test_fallback_to_inmemory</code> Funktioniert ohne Valkey <code>test_no_user_passes_through</code> Anonyme Requests passieren <code>test_category_extraction</code> Korrekte Kategorie-Zuordnung <code>test_quota_headers_present</code> Response-Headers vorhanden"},{"location":"architecture/secrets-management/","title":"BreakPilot Secrets Management","text":""},{"location":"architecture/secrets-management/#uebersicht","title":"Uebersicht","text":"<p>BreakPilot verwendet HashiCorp Vault als zentrales Secrets-Management-System.</p> <pre><code>\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</code></pre>"},{"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":"<pre><code>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</code></pre>"},{"location":"architecture/secrets-management/#python-integration","title":"Python Integration","text":"<pre><code>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</code></pre>"},{"location":"architecture/secrets-management/#fallback-reihenfolge","title":"Fallback-Reihenfolge","text":"<pre><code>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</code></pre>"},{"location":"architecture/secrets-management/#setup","title":"Setup","text":""},{"location":"architecture/secrets-management/#entwicklung-dev-mode","title":"Entwicklung (Dev Mode)","text":"<pre><code># 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</code></pre>"},{"location":"architecture/secrets-management/#secrets-setzen","title":"Secrets setzen","text":"<pre><code># 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</code></pre>"},{"location":"architecture/secrets-management/#secrets-lesen","title":"Secrets lesen","text":"<pre><code># 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</code></pre>"},{"location":"architecture/secrets-management/#produktion","title":"Produktion","text":""},{"location":"architecture/secrets-management/#approle-authentication","title":"AppRole Authentication","text":"<p>In Produktion verwenden Services AppRole statt Token-Auth:</p> <pre><code># 1. AppRole aktivieren (einmalig)\nvault auth enable approle\n\n# 2. Policy erstellen\nvault policy write breakpilot-backend - &lt;&lt;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</code></pre>"},{"location":"architecture/secrets-management/#environment-fuer-services","title":"Environment fuer Services","text":"<pre><code># Docker-Compose / Kubernetes\nVAULT_ADDR=https://vault.breakpilot.app:8200\nVAULT_AUTH_METHOD=approle\nVAULT_ROLE_ID=&lt;role-id&gt;\nVAULT_SECRET_ID=&lt;secret-id&gt;\nVAULT_SECRETS_PATH=breakpilot\n</code></pre>"},{"location":"architecture/secrets-management/#sicherheits-checkliste","title":"Sicherheits-Checkliste","text":""},{"location":"architecture/secrets-management/#muss-erfuellt-sein","title":"Muss erfuellt sein","text":"<ul> <li>[ ] Keine echten Secrets in <code>.env</code> Dateien</li> <li>[ ] <code>.env</code> in <code>.gitignore</code></li> <li>[ ] Vault im Sealed-State wenn nicht in Verwendung</li> <li>[ ] TLS fuer Vault in Produktion</li> <li>[ ] AppRole statt Token-Auth in Produktion</li> <li>[ ] Audit-Logging aktiviert</li> <li>[ ] Minimale Policies (Least Privilege)</li> </ul>"},{"location":"architecture/secrets-management/#sollte-erfuellt-sein","title":"Sollte erfuellt sein","text":"<ul> <li>[ ] Automatische Secret-Rotation</li> <li>[ ] Separate Vault-Instanz fuer Produktion</li> <li>[ ] HSM-basiertes Auto-Unseal</li> <li>[ ] Disaster Recovery Plan</li> </ul>"},{"location":"architecture/secrets-management/#dateien","title":"Dateien","text":"Datei Beschreibung <code>backend/secrets/__init__.py</code> Secrets-Modul Exports <code>backend/secrets/vault_client.py</code> Vault Client Implementation <code>docker-compose.vault.yml</code> Vault Docker Configuration <code>vault/init-secrets.sh</code> Entwicklungs-Secrets Initialisierung <code>vault/policies/</code> Vault Policy Files"},{"location":"architecture/secrets-management/#fehlerbehebung","title":"Fehlerbehebung","text":""},{"location":"architecture/secrets-management/#vault-nicht-erreichbar","title":"Vault nicht erreichbar","text":"<pre><code># Status pruefen\nvault status\n\n# Falls sealed\nvault operator unseal &lt;unseal-key&gt;\n</code></pre>"},{"location":"architecture/secrets-management/#secret-nicht-gefunden","title":"Secret nicht gefunden","text":"<pre><code># Pfad pruefen\nvault kv list secret/breakpilot/\n\n# Cache leeren (Python)\nfrom secrets import get_secrets_manager\nget_secrets_manager().clear_cache()\n</code></pre>"},{"location":"architecture/secrets-management/#token-abgelaufen","title":"Token abgelaufen","text":"<pre><code># Neuen Token holen (AppRole)\nvault write auth/approle/login \\\n role_id=$VAULT_ROLE_ID \\\n secret_id=$VAULT_SECRET_ID\n</code></pre>"},{"location":"architecture/secrets-management/#referenzen","title":"Referenzen","text":"<ul> <li>HashiCorp Vault Documentation</li> <li>hvac Python Client</li> <li>Vault Best Practices</li> </ul>"},{"location":"architecture/system-architecture/","title":"BreakPilot PWA - System-Architektur","text":""},{"location":"architecture/system-architecture/#ubersicht","title":"\u00dcbersicht","text":"<p>BreakPilot ist eine modulare Bildungsplattform f\u00fcr Lehrkr\u00e4fte mit folgenden Hauptkomponenten:</p> <pre><code>\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</code></pre>"},{"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":"<p>Das Admin Frontend ist eine vollst\u00e4ndige Next.js 15 Anwendung f\u00fcr Developer und Administratoren:</p> <p>Technologie: Next.js 15, React 18, TypeScript, Tailwind CSS</p> <p>Container: <code>breakpilot-pwa-website</code> auf Port 3000</p> <p>Verzeichnis: <code>/website</code></p> Modul Route Beschreibung Dashboard <code>/admin</code> \u00dcbersicht &amp; Statistiken GPU Infrastruktur <code>/admin/gpu</code> vast.ai GPU Management Consent Verwaltung <code>/admin/consent</code> Rechtliche Dokumente &amp; Versionen Datenschutzanfragen <code>/admin/dsr</code> DSGVO Art. 15-21 Anfragen DSMS <code>/admin/dsms</code> Datenschutz-Management-System Education Search <code>/admin/edu-search</code> Bildungsquellen &amp; Crawler Personensuche <code>/admin/staff-search</code> Uni-Mitarbeiter &amp; Publikationen Uni-Crawler <code>/admin/uni-crawler</code> Universit\u00e4ts-Crawling Orchestrator LLM Vergleich <code>/admin/llm-compare</code> KI-Provider Vergleich PCA Platform <code>/admin/pca-platform</code> Bot-Erkennung &amp; Monetarisierung Production Backlog <code>/admin/backlog</code> Go-Live Checkliste Developer Docs <code>/admin/docs</code> API &amp; Architektur Dokumentation Kommunikation <code>/admin/communication</code> Matrix &amp; Jitsi Monitoring Security <code>/admin/security</code> DevSecOps Dashboard, Scans, Findings SBOM <code>/admin/sbom</code> Software Bill of Materials"},{"location":"architecture/system-architecture/#2-lehrer-frontend-studio-ui","title":"2. Lehrer Frontend (Studio UI)","text":"<p>Das Lehrer Frontend ist ein Single-Page-Application-\u00e4hnliches System f\u00fcr Lehrkr\u00e4fte, das in Python-Modulen organisiert ist:</p> Modul Datei Beschreibung Base <code>frontend/modules/base.py</code> TopBar, Sidebar, Theme, Login Dashboard <code>frontend/modules/dashboard.py</code> \u00dcbersichtsseite Worksheets <code>frontend/modules/worksheets.py</code> Lerneinheiten-Generator Correction <code>frontend/modules/correction.py</code> OCR-Klausurkorrektur Letters <code>frontend/modules/letters.py</code> Elternkommunikation Companion <code>frontend/modules/companion.py</code> Begleiter-Modus mit State Engine School <code>frontend/modules/school.py</code> Schulverwaltung Gradebook <code>frontend/modules/gradebook.py</code> Notenbuch ContentCreator <code>frontend/modules/content_creator.py</code> H5P Content Creator ContentFeed <code>frontend/modules/content_feed.py</code> Content Discovery Messenger <code>frontend/modules/messenger.py</code> Matrix Messenger Jitsi <code>frontend/modules/jitsi.py</code> Videokonferenzen KlausurKorrektur <code>frontend/modules/klausur_korrektur.py</code> Abitur-Klausurkorrektur (15-Punkte-System) AbiturDocsAdmin <code>frontend/modules/abitur_docs_admin.py</code> Admin f\u00fcr Abitur-Dokumente (NiBiS) <p>Jedes Modul exportiert: - <code>get_css()</code> - CSS-Styles - <code>get_html()</code> - HTML-Template - <code>get_js()</code> - JavaScript-Logik</p>"},{"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 <code>worksheets_api</code> <code>/api/worksheets</code> Content-Generatoren (MC, Cloze, Mindmap, Quiz) <code>correction_api</code> <code>/api/corrections</code> OCR-Pipeline f\u00fcr Klausurkorrektur <code>letters_api</code> <code>/api/letters</code> Elternbriefe mit GFK-Integration <code>state_engine_api</code> <code>/api/state</code> Begleiter-Modus Phasen &amp; Vorschl\u00e4ge <code>school_api</code> <code>/api/school</code> Schulverwaltung (Proxy zu school-service) <code>certificates_api</code> <code>/api/certificates</code> Zeugniserstellung <code>messenger_api</code> <code>/api/messenger</code> Matrix Messenger Integration <code>jitsi_api</code> <code>/api/jitsi</code> Jitsi Meeting-Einladungen <code>consent_api</code> <code>/api/consent</code> DSGVO Consent-Verwaltung <code>gdpr_api</code> <code>/api/gdpr</code> GDPR-Export <code>klausur_korrektur_api</code> <code>/api/klausur-korrektur</code> Abitur-Klausuren (15-Punkte, Gutachten, Fairness) <code>abitur_docs_api</code> <code>/api/abitur-docs</code> NiBiS-Dokumentenverwaltung f\u00fcr RAG"},{"location":"architecture/system-architecture/#services","title":"Services","text":"Service Datei Beschreibung FileProcessor <code>services/file_processor.py</code> OCR mit PaddleOCR PDFService <code>services/pdf_service.py</code> PDF-Generierung ContentGenerators <code>services/content_generators/</code> MC, Cloze, Mindmap, Quiz StateEngine <code>state_engine/</code> Phasen-Management &amp; Antizipation"},{"location":"architecture/system-architecture/#4-klausur-korrektur-system-abitur","title":"4. Klausur-Korrektur System (Abitur)","text":"<p>Das Klausur-Korrektur-System implementiert die vollst\u00e4ndige Abitur-Bewertungspipeline:</p> <pre><code>\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 &amp; \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 &amp; 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</code></pre>"},{"location":"architecture/system-architecture/#15-punkte-notensystem","title":"15-Punkte-Notensystem","text":"<p>Das System verwendet den deutschen Abitur-Notenschl\u00fcssel:</p> 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 &lt;20% 6"},{"location":"architecture/system-architecture/#bewertungskriterien","title":"Bewertungskriterien","text":"Kriterium Gewicht Beschreibung Rechtschreibung 15% Orthografie Grammatik 15% Grammatik &amp; Syntax Inhalt 40% Inhaltliche Qualit\u00e4t (h\u00f6chste Gewichtung) Struktur 15% Aufbau &amp; Gliederung Stil 15% Ausdruck &amp; Stil"},{"location":"architecture/system-architecture/#5-go-consent-service","title":"5. Go Consent Service","text":"<p>Verwaltet DSGVO-Einwilligungen:</p> <pre><code>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</code></pre>"},{"location":"architecture/system-architecture/#6-llm-gateway-optional","title":"6. LLM Gateway (Optional)","text":"<p>Wenn <code>LLM_GATEWAY_ENABLED=true</code>:</p> <pre><code>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</code></pre>"},{"location":"architecture/system-architecture/#datenfluss","title":"Datenfluss","text":""},{"location":"architecture/system-architecture/#worksheet-generierung","title":"Worksheet-Generierung","text":"<pre><code>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</code></pre>"},{"location":"architecture/system-architecture/#klausurkorrektur","title":"Klausurkorrektur","text":"<pre><code>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</code></pre>"},{"location":"architecture/system-architecture/#sicherheit","title":"Sicherheit","text":""},{"location":"architecture/system-architecture/#authentifizierung-autorisierung","title":"Authentifizierung &amp; Autorisierung","text":"<p>BreakPilot verwendet einen Hybrid-Ansatz:</p> Schicht Komponente Beschreibung Authentifizierung Keycloak (Prod) / Lokales JWT (Dev) Token-Validierung via JWKS oder HS256 Autorisierung rbac.py (Eigenentwicklung) Domaenenspezifische Berechtigungen <p>Siehe: Auth-System</p>"},{"location":"architecture/system-architecture/#basis-rollen","title":"Basis-Rollen","text":"Rolle Beschreibung <code>user</code> Normaler Benutzer <code>teacher</code> / <code>lehrer</code> Lehrkraft <code>admin</code> Administrator <code>data_protection_officer</code> Datenschutzbeauftragter"},{"location":"architecture/system-architecture/#erweiterte-rollen-rbacpy","title":"Erweiterte Rollen (rbac.py)","text":"<p>15+ domaenenspezifische Rollen fuer Klausurkorrektur und Zeugnisse: - <code>erstkorrektor</code>, <code>zweitkorrektor</code>, <code>drittkorrektor</code> - <code>klassenlehrer</code>, <code>fachlehrer</code>, <code>fachvorsitz</code> - <code>schulleitung</code>, <code>zeugnisbeauftragter</code>, <code>sekretariat</code></p>"},{"location":"architecture/system-architecture/#sicherheitsfeatures","title":"Sicherheitsfeatures","text":"<ul> <li>JWT-basierte Authentifizierung (RS256/HS256)</li> <li>CORS konfiguriert f\u00fcr Frontend-Zugriff</li> <li>DSGVO-konformes Consent-Management</li> <li>HashiCorp Vault fuer Secrets-Management (keine hardcodierten Secrets)</li> <li>Bundesland-spezifische Policy-Sets</li> <li>DevSecOps Pipeline mit automatisierten Security-Scans (SAST, SCA, Secrets Detection)</li> </ul> <p>Siehe: - Secrets Management - DevSecOps</p>"},{"location":"architecture/system-architecture/#deployment","title":"Deployment","text":"<pre><code>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</code></pre>"},{"location":"architecture/system-architecture/#erweiterung","title":"Erweiterung","text":"<p>Neues Frontend-Modul hinzuf\u00fcgen:</p> <ol> <li>Modul erstellen: <code>frontend/modules/new_module.py</code></li> <li>Klasse mit <code>get_css()</code>, <code>get_html()</code>, <code>get_js()</code> implementieren</li> <li>In <code>frontend/modules/__init__.py</code> importieren und exportieren</li> <li>Optional: Zugeh\u00f6rige API in <code>new_module_api.py</code> erstellen</li> <li>In <code>main.py</code> Router registrieren</li> </ol>"},{"location":"architecture/zeugnis-system/","title":"Zeugnis-System - Architecture Documentation","text":""},{"location":"architecture/zeugnis-system/#overview","title":"Overview","text":"<p>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.</p>"},{"location":"architecture/zeugnis-system/#architecture-diagram","title":"Architecture Diagram","text":"<pre><code> \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</code></pre>"},{"location":"architecture/zeugnis-system/#zeugnis-workflow-role-chain","title":"Zeugnis Workflow (Role Chain)","text":"<p>The certificate workflow follows a strict approval chain from subject teachers to school principal:</p> <pre><code>\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 &amp; Lock Print &amp; Archive\n (Oral/Written) Grades &amp; Review\n</code></pre>"},{"location":"architecture/zeugnis-system/#workflow-states","title":"Workflow States","text":"<pre><code>\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</code></pre>"},{"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 <code>FACHLEHRER</code> Fachlehrer Subject teacher - enters grades <code>KLASSENLEHRER</code> Klassenlehrer Class teacher - approves class grades <code>ZEUGNISBEAUFTRAGTER</code> Zeugnisbeauftragter Certificate coordinator - quality control <code>SCHULLEITUNG</code> Schulleitung Principal - final sign-off <code>SEKRETARIAT</code> Sekretariat Secretary - printing &amp; archiving"},{"location":"architecture/zeugnis-system/#certificate-resource-types","title":"Certificate Resource Types","text":"ResourceType Description <code>ZEUGNIS</code> Final certificate document <code>ZEUGNIS_VORLAGE</code> Certificate template (per Bundesland) <code>ZEUGNIS_ENTWURF</code> Draft certificate (before approval) <code>FACHNOTE</code> Subject grade <code>KOPFNOTE</code> Head grade (Arbeits-/Sozialverhalten) <code>BEMERKUNG</code> Certificate remarks <code>STATISTIK</code> Class/subject statistics <code>NOTENSPIEGEL</code> 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":"<pre><code>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</code></pre>"},{"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 <code>/api/v1/school/grades/:classId</code> Get class grades GET <code>/api/v1/school/grades/student/:studentId</code> Get student grades PUT <code>/api/v1/school/grades/:studentId/:subjectId/oral</code> Update oral grade POST <code>/api/v1/school/grades/calculate</code> Calculate final grades PUT <code>/api/v1/school/grades/:studentId/:subjectId/lock</code> Lock final grade"},{"location":"architecture/zeugnis-system/#statistics","title":"Statistics","text":"Method Endpoint Description GET <code>/api/v1/school/statistics/:classId</code> Class statistics GET <code>/api/v1/school/statistics/:classId/subject/:subjectId</code> Subject statistics GET <code>/api/v1/school/statistics/student/:studentId</code> Student statistics GET <code>/api/v1/school/statistics/:classId/notenspiegel</code> Grade distribution"},{"location":"architecture/zeugnis-system/#certificates","title":"Certificates","text":"Method Endpoint Description GET <code>/api/v1/school/certificates/templates</code> List templates GET <code>/api/v1/school/certificates/class/:classId</code> Class certificates POST <code>/api/v1/school/certificates/generate</code> Generate single POST <code>/api/v1/school/certificates/generate-bulk</code> Generate bulk GET <code>/api/v1/school/certificates/detail/:id/pdf</code> Download PDF"},{"location":"architecture/zeugnis-system/#security-considerations","title":"Security Considerations","text":"<ol> <li>RBAC Enforcement: All certificate operations check user role permissions</li> <li>Tenant Isolation: Teachers only see their own classes/students</li> <li>Audit Trail: All grade changes and approvals logged</li> <li>Lock Mechanism: Finalized certificates cannot be modified</li> <li>Workflow Enforcement: Cannot skip approval steps</li> </ol>"},{"location":"backend/venv/lib/python3.9/site-packages/anthropic/lib/foundry/","title":"Anthropic Foundry","text":"<p>To use this library with Foundry, use the <code>AnthropicFoundry</code> class instead of the <code>Anthropic</code> class.</p>"},{"location":"backend/venv/lib/python3.9/site-packages/anthropic/lib/foundry/#installation","title":"Installation","text":"<pre><code>pip install anthropic\n</code></pre>"},{"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":"<pre><code>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</code></pre>"},{"location":"backend/venv/lib/python3.9/site-packages/anthropic/lib/foundry/#using-azure-ad-token-provider","title":"Using Azure AD Token Provider","text":"<p>For enhanced security, you can use Azure AD (Microsoft Entra) authentication instead of an API key:</p> <pre><code>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</code></pre>"},{"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":"<pre><code>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</code></pre>"},{"location":"backend/venv/lib/python3.9/site-packages/anthropic/lib/foundry/#async-usage","title":"Async Usage","text":"<pre><code>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</code></pre>"},{"location":"backend/venv/lib/python3.9/site-packages/anthropic/lib/foundry/#async-streaming","title":"Async Streaming","text":"<pre><code>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</code></pre>"},{"location":"backend/venv/lib/python3.9/site-packages/backports_asyncio_runner-1.2.0.dist-info/licenses/LICENSE/","title":"LICENSE","text":"<p>PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2</p> <ol> <li>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.</li> <li>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.</li> <li>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.</li> <li>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.</li> <li>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.</li> <li>This License Agreement will automatically terminate upon a material breach of its terms and conditions.</li> <li>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.</li> <li>By copying, installing or otherwise using Python, Licensee agrees to be bound by the terms and conditions of this License Agreement.</li> </ol>"},{"location":"backend/venv/lib/python3.9/site-packages/docstring_parser-0.17.0.dist-info/licenses/LICENSE/","title":"LICENSE","text":"<p>The MIT License (MIT)</p> <p>Copyright (c) 2018 Marcin Kurczewski</p> <p>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:</p> <p>The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.</p> <p>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.</p>"},{"location":"backend/venv/lib/python3.9/site-packages/httpcore-1.0.9.dist-info/licenses/LICENSE/","title":"LICENSE","text":"<p>Copyright \u00a9 2020, Encode OSS Ltd. All rights reserved.</p> <p>Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:</p> <ul> <li> <p>Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.</p> </li> <li> <p>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.</p> </li> <li> <p>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.</p> </li> </ul> <p>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.</p>"},{"location":"backend/venv/lib/python3.9/site-packages/httpx-0.28.1.dist-info/licenses/LICENSE/","title":"LICENSE","text":"<p>Copyright \u00a9 2019, Encode OSS Ltd. All rights reserved.</p> <p>Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:</p> <ul> <li> <p>Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.</p> </li> <li> <p>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.</p> </li> <li> <p>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.</p> </li> </ul> <p>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.</p>"},{"location":"backend/venv/lib/python3.9/site-packages/idna-3.11.dist-info/licenses/LICENSE/","title":"LICENSE","text":"<p>BSD 3-Clause License</p> <p>Copyright (c) 2013-2025, Kim Davies and contributors. All rights reserved.</p> <p>Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:</p> <ol> <li> <p>Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.</p> </li> <li> <p>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.</p> </li> <li> <p>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.</p> </li> </ol> <p>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.</p>"},{"location":"backend/venv/lib/python3.9/site-packages/markdown-3.9.dist-info/licenses/LICENSE/","title":"LICENSE","text":"<p>BSD 3-Clause License</p> <p>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)</p> <p>Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:</p> <ol> <li> <p>Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.</p> </li> <li> <p>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.</p> </li> <li> <p>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.</p> </li> </ol> <p>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.</p>"},{"location":"backend/venv/lib/python3.9/site-packages/numpy/random/LICENSE/","title":"LICENSE","text":"<p>This software is dual-licensed under the The University of Illinois/NCSA Open Source License (NCSA) and The 3-Clause BSD License</p>"},{"location":"backend/venv/lib/python3.9/site-packages/numpy/random/LICENSE/#ncsa-open-source-license","title":"NCSA Open Source License","text":"<p>Copyright (c) 2019 Kevin Sheppard. All rights reserved.</p> <p>Developed by: Kevin Sheppard (kevin.sheppard@economics.ox.ac.uk, kevin.k.sheppard@gmail.com) http://www.kevinsheppard.com</p> <p>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:</p> <p>Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimers.</p> <p>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.</p> <p>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.</p> <p>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.</p>"},{"location":"backend/venv/lib/python3.9/site-packages/numpy/random/LICENSE/#3-clause-bsd-license","title":"3-Clause BSD License","text":"<p>Copyright (c) 2019 Kevin Sheppard. All rights reserved.</p> <p>Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:</p> <ol> <li> <p>Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.</p> </li> <li> <p>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.</p> </li> <li> <p>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.</p> </li> </ol> <p>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.</p>"},{"location":"backend/venv/lib/python3.9/site-packages/numpy/random/LICENSE/#components","title":"Components","text":"<p>Many parts of this module have been derived from original sources, often the algorithm's designer. Component licenses are located with the component code.</p>"},{"location":"backend/venv/lib/python3.9/site-packages/pip/_vendor/idna/LICENSE/","title":"LICENSE","text":"<p>BSD 3-Clause License</p> <p>Copyright (c) 2013-2024, Kim Davies and contributors. All rights reserved.</p> <p>Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:</p> <ol> <li> <p>Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.</p> </li> <li> <p>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.</p> </li> <li> <p>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.</p> </li> </ol> <p>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.</p>"},{"location":"backend/venv/lib/python3.9/site-packages/pip-25.3.dist-info/licenses/src/pip/_vendor/idna/LICENSE/","title":"LICENSE","text":"<p>BSD 3-Clause License</p> <p>Copyright (c) 2013-2024, Kim Davies and contributors. All rights reserved.</p> <p>Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:</p> <ol> <li> <p>Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.</p> </li> <li> <p>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.</p> </li> <li> <p>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.</p> </li> </ol> <p>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.</p>"},{"location":"backend/venv/lib/python3.9/site-packages/soupsieve-2.8.3.dist-info/licenses/LICENSE/","title":"LICENSE","text":"<p>MIT License</p> <p>Copyright (c) 2018 - 2026 Isaac Muse isaacmuse@gmail.com</p> <p>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:</p> <p>The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.</p> <p>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.</p>"},{"location":"backend/venv/lib/python3.9/site-packages/starlette-0.49.3.dist-info/licenses/LICENSE/","title":"LICENSE","text":"<p>Copyright \u00a9 2018, Encode OSS Ltd. All rights reserved.</p> <p>Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:</p> <ul> <li> <p>Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.</p> </li> <li> <p>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.</p> </li> <li> <p>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.</p> </li> </ul> <p>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.</p>"},{"location":"backend/venv/lib/python3.9/site-packages/uvicorn-0.38.0.dist-info/licenses/LICENSE/","title":"LICENSE","text":"<p>Copyright \u00a9 2017-present, Encode OSS Ltd. All rights reserved.</p> <p>Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:</p> <ul> <li> <p>Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.</p> </li> <li> <p>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.</p> </li> <li> <p>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.</p> </li> </ul> <p>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.</p>"},{"location":"development/ci-cd-pipeline/","title":"CI/CD Pipeline","text":"<p>\u00dcbersicht \u00fcber den Deployment-Prozess f\u00fcr Breakpilot.</p>"},{"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":"<pre><code>\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</code></pre>"},{"location":"development/ci-cd-pipeline/#sync-deploy-workflow","title":"Sync &amp; Deploy Workflow","text":""},{"location":"development/ci-cd-pipeline/#1-dateien-synchronisieren","title":"1. Dateien synchronisieren","text":"<pre><code># 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</code></pre>"},{"location":"development/ci-cd-pipeline/#2-container-bauen","title":"2. Container bauen","text":"<pre><code># Einzelnen Service bauen\nssh macmini \"/usr/local/bin/docker compose \\\n -f /Users/benjaminadmin/Projekte/breakpilot-pwa/docker-compose.yml \\\n build --no-cache &lt;service-name&gt;\"\n\n# Beispiele:\n# studio-v2, admin-v2, website, backend, klausur-service, docs\n</code></pre>"},{"location":"development/ci-cd-pipeline/#3-container-deployen","title":"3. Container deployen","text":"<pre><code># Container neu starten\nssh macmini \"/usr/local/bin/docker compose \\\n -f /Users/benjaminadmin/Projekte/breakpilot-pwa/docker-compose.yml \\\n up -d &lt;service-name&gt;\"\n</code></pre>"},{"location":"development/ci-cd-pipeline/#4-logs-prufen","title":"4. Logs pr\u00fcfen","text":"<pre><code># Container-Logs anzeigen\nssh macmini \"/usr/local/bin/docker compose \\\n -f /Users/benjaminadmin/Projekte/breakpilot-pwa/docker-compose.yml \\\n logs -f &lt;service-name&gt;\"\n</code></pre>"},{"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":"<pre><code># 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 &amp; Deploy\nssh macmini \"/usr/local/bin/docker compose \\\n -f /Users/benjaminadmin/Projekte/breakpilot-pwa/docker-compose.yml \\\n build --no-cache studio-v2 &amp;&amp; \\\n /usr/local/bin/docker compose \\\n -f /Users/benjaminadmin/Projekte/breakpilot-pwa/docker-compose.yml \\\n up -d studio-v2\"\n</code></pre>"},{"location":"development/ci-cd-pipeline/#python-services-backend-klausur-service-voice-service","title":"Python Services (backend, klausur-service, voice-service)","text":"<pre><code># 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 &amp;&amp; \\\n /usr/local/bin/docker compose \\\n -f /Users/benjaminadmin/Projekte/breakpilot-pwa/docker-compose.yml \\\n up -d klausur-service\"\n</code></pre>"},{"location":"development/ci-cd-pipeline/#go-services-consent-service-ai-compliance-sdk","title":"Go Services (consent-service, ai-compliance-sdk)","text":"<pre><code># 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 &amp;&amp; \\\n /usr/local/bin/docker compose \\\n -f /Users/benjaminadmin/Projekte/breakpilot-pwa/docker-compose.yml \\\n up -d consent-service\"\n</code></pre>"},{"location":"development/ci-cd-pipeline/#mkdocs-dokumentation","title":"MkDocs Dokumentation","text":"<pre><code># Build &amp; Deploy\nssh macmini \"/usr/local/bin/docker compose \\\n -f /Users/benjaminadmin/Projekte/breakpilot-pwa/docker-compose.yml \\\n build --no-cache docs &amp;&amp; \\\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</code></pre>"},{"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":"<pre><code># 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</code></pre>"},{"location":"development/ci-cd-pipeline/#logs-analysieren","title":"Logs analysieren","text":"<pre><code># 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</code></pre>"},{"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":"<pre><code># 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</code></pre>"},{"location":"development/ci-cd-pipeline/#troubleshooting","title":"Troubleshooting","text":""},{"location":"development/ci-cd-pipeline/#container-startet-nicht","title":"Container startet nicht","text":"<pre><code># 1. Logs pr\u00fcfen\nssh macmini \"docker logs breakpilot-pwa-&lt;service&gt;-1\"\n\n# 2. Container manuell starten f\u00fcr Debug-Output\nssh macmini \"docker compose -f .../docker-compose.yml run --rm &lt;service&gt;\"\n\n# 3. In Container einloggen\nssh macmini \"docker exec -it breakpilot-pwa-&lt;service&gt;-1 /bin/sh\"\n</code></pre>"},{"location":"development/ci-cd-pipeline/#port-bereits-belegt","title":"Port bereits belegt","text":"<pre><code># Port-Belegung pr\u00fcfen\nssh macmini \"lsof -i :8000\"\n\n# Container mit dem Port finden\nssh macmini \"docker ps --filter publish=8000\"\n</code></pre>"},{"location":"development/ci-cd-pipeline/#build-fehler","title":"Build-Fehler","text":"<pre><code># Cache komplett leeren\nssh macmini \"docker builder prune -a\"\n\n# Ohne Cache bauen\nssh macmini \"docker compose build --no-cache &lt;service&gt;\"\n</code></pre>"},{"location":"development/ci-cd-pipeline/#monitoring","title":"Monitoring","text":""},{"location":"development/ci-cd-pipeline/#resource-nutzung","title":"Resource-Nutzung","text":"<pre><code># CPU/Memory aller Container\nssh macmini \"docker stats --no-stream\"\n\n# Disk-Nutzung\nssh macmini \"docker system df\"\n</code></pre>"},{"location":"development/ci-cd-pipeline/#cleanup","title":"Cleanup","text":"<pre><code># Ungenutzte Images/Container entfernen\nssh macmini \"docker system prune -a --volumes\"\n\n# Nur dangling Images\nssh macmini \"docker image prune\"\n</code></pre>"},{"location":"development/ci-cd-pipeline/#umgebungsvariablen","title":"Umgebungsvariablen","text":"<p>Umgebungsvariablen werden \u00fcber <code>.env</code> Dateien und docker-compose.yml verwaltet:</p> <pre><code># docker-compose.yml\nservices:\n backend:\n environment:\n - DATABASE_URL=postgresql://...\n - REDIS_URL=redis://valkey:6379\n - SECRET_KEY=${SECRET_KEY}\n</code></pre> <p>Wichtig: Sensible Werte niemals in Git committen. Stattdessen: - <code>.env</code> Datei auf dem Server pflegen - Secrets \u00fcber HashiCorp Vault (siehe unten)</p>"},{"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":"<p>Die OAuth-Integration zwischen Woodpecker CI und Gitea ist vollst\u00e4ndig automatisiert. Credentials werden in HashiCorp Vault gespeichert und bei Bedarf automatisch regeneriert.</p> <p>Warum automatisiert?</p> <p>Diese Automatisierung ist eine DevSecOps Best Practice:</p> <ul> <li>Infrastructure-as-Code: Alles ist reproduzierbar</li> <li>Disaster Recovery: Verlorene Credentials k\u00f6nnen automatisch regeneriert werden</li> <li>Security: Secrets werden zentral in Vault verwaltet</li> <li>Onboarding: Neue Entwickler m\u00fcssen nichts manuell konfigurieren</li> </ul>"},{"location":"development/ci-cd-pipeline/#architektur","title":"Architektur","text":"<pre><code>\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</code></pre>"},{"location":"development/ci-cd-pipeline/#credentials-speicherorte","title":"Credentials-Speicherorte","text":"Ort Pfad Inhalt HashiCorp Vault <code>secret/cicd/woodpecker</code> Client ID + Secret (Quelle der Wahrheit) .env Datei <code>WOODPECKER_GITEA_CLIENT/SECRET</code> F\u00fcr Docker Compose (aus Vault geladen) Gitea PostgreSQL <code>oauth2_application</code> Tabelle OAuth App Registration (gehashtes Secret)"},{"location":"development/ci-cd-pipeline/#troubleshooting-oauth-fehler","title":"Troubleshooting: OAuth Fehler","text":"<p>Falls der Fehler \"Client ID not registered\" oder \"user does not exist [uid: 0]\" auftritt:</p> <pre><code># 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=&lt;client_id&gt;\nWOODPECKER_GITEA_SECRET=&lt;client_secret&gt;\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 &amp;&amp; \\\n docker compose up -d --force-recreate woodpecker-server\"\n</code></pre>"},{"location":"development/ci-cd-pipeline/#das-sync-script","title":"Das Sync-Script","text":"<p>Das Script <code>scripts/sync-woodpecker-credentials.sh</code> automatisiert den gesamten Prozess:</p> <pre><code># 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</code></pre> <p>Was das Script macht:</p> <ol> <li>Liest die aktuellen Credentials aus Vault</li> <li>Aktualisiert die .env Datei automatisch</li> <li>Bei <code>--regenerate</code>:</li> <li>L\u00f6scht alte OAuth Apps in Gitea</li> <li>Erstellt neue OAuth App mit neuem Client ID/Secret</li> <li>Speichert Credentials in Vault</li> <li>Aktualisiert .env</li> </ol>"},{"location":"development/ci-cd-pipeline/#vault-zugriff","title":"Vault-Zugriff","text":"<pre><code># 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</code></pre>"},{"location":"development/ci-cd-pipeline/#services-neustarten-nach-credentials-anderung","title":"Services neustarten nach Credentials-\u00c4nderung","text":"<pre><code># 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</code></pre>"},{"location":"development/documentation/","title":"Dokumentations-Regeln","text":""},{"location":"development/documentation/#automatische-dokumentations-aktualisierung","title":"Automatische Dokumentations-Aktualisierung","text":"<p>WICHTIG: Bei JEDER Code-Aenderung muss die entsprechende Dokumentation aktualisiert werden!</p>"},{"location":"development/documentation/#wann-dokumentation-aktualisieren","title":"Wann Dokumentation aktualisieren?","text":""},{"location":"development/documentation/#api-aenderungen","title":"API-Aenderungen","text":"<p>Wenn du einen Endpoint aenderst, hinzufuegst oder entfernst:</p> <ul> <li>Aktualisiere die Backend API Dokumentation</li> <li>Aktualisiere Service-spezifische API-Docs</li> </ul>"},{"location":"development/documentation/#neue-funktionenklassen","title":"Neue Funktionen/Klassen","text":"<p>Wenn du neue Funktionen, Klassen oder Module erstellst:</p> <ul> <li>Aktualisiere die entsprechende Service-Dokumentation</li> <li>Fuege Code-Beispiele hinzu</li> </ul>"},{"location":"development/documentation/#architektur-aenderungen","title":"Architektur-Aenderungen","text":"<p>Wenn du die Systemarchitektur aenderst:</p> <ul> <li>Aktualisiere die System-Architektur</li> <li>Aktualisiere Datenmodell-Dokumentation bei DB-Aenderungen</li> </ul>"},{"location":"development/documentation/#neue-konfigurationsoptionen","title":"Neue Konfigurationsoptionen","text":"<p>Wenn du neue Umgebungsvariablen oder Konfigurationen hinzufuegst:</p> <ul> <li>Aktualisiere die entsprechende README</li> <li>Fuege zur Umgebungs-Setup hinzu</li> </ul>"},{"location":"development/documentation/#dokumentations-format","title":"Dokumentations-Format","text":""},{"location":"development/documentation/#api-endpoints-dokumentieren","title":"API-Endpoints dokumentieren","text":"<pre><code>### METHOD /path/to/endpoint\n\nKurze Beschreibung.\n\n**Request Body:**\n```json\n{\n \"field\": \"value\"\n}\n</code></pre> <p>Response (200): <pre><code>{\n \"result\": \"value\"\n}\n</code></pre></p> <p>Errors: - <code>400</code>: Beschreibung - <code>401</code>: Beschreibung <pre><code>### Funktionen dokumentieren\n\n```markdown\n### FunctionName (file.go:123)\n\n```go\nfunc FunctionName(param Type) ReturnType\n</code></pre></p> <p>Beschreibung: Was macht die Funktion?</p> <p>Parameter: - <code>param</code>: Beschreibung</p> <p>Rueckgabe: Beschreibung <pre><code>## 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</code></pre> 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 ```</p>"},{"location":"development/documentation/#mkdocs-konventionen","title":"MkDocs Konventionen","text":"<p>Diese Dokumentation wird mit MkDocs + Material Theme generiert:</p> <ul> <li>Admonitions fuer Hinweise: ```markdown !!! note \"Hinweis\" Wichtige Information hier.</li> </ul> <p>!!! warning \"Warnung\" Vorsicht bei dieser Aktion. ```</p> <ul> <li>Code-Tabs fuer mehrere Sprachen: <code>markdown === \"Python\"</code>python print(\"Hello\") ```</li> </ul> <p>=== \"Go\" <code>go fmt.Println(\"Hello\")</code> ```</p> <ul> <li>Mermaid-Diagramme fuer Visualisierungen: <code>markdown</code>mermaid graph LR A --&gt; B --&gt; C <code></code></li> </ul>"},{"location":"development/testing/","title":"Test-Regeln","text":""},{"location":"development/testing/#automatische-test-erweiterung","title":"Automatische Test-Erweiterung","text":"<p>WICHTIG: Bei JEDER Code-Aenderung muessen entsprechende Tests erstellt oder aktualisiert werden!</p>"},{"location":"development/testing/#wann-tests-schreiben","title":"Wann Tests schreiben?","text":""},{"location":"development/testing/#immer-wenn-du","title":"IMMER wenn du:","text":"<ol> <li>Neue Funktionen erstellst \u2192 Unit Test</li> <li>Neue API-Endpoints hinzufuegst \u2192 Handler Test</li> <li>Bugs fixst \u2192 Regression Test (der Bug sollte nie wieder auftreten)</li> <li>Bestehenden Code aenderst \u2192 Bestehende Tests anpassen</li> </ol>"},{"location":"development/testing/#test-struktur","title":"Test-Struktur","text":""},{"location":"development/testing/#go-tests-consent-service","title":"Go Tests (Consent Service)","text":"<p>Speicherort: Im gleichen Verzeichnis wie der Code</p> <pre><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</code></pre> <p>Test-Namenskonvention:</p> <pre><code>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</code></pre> <p>Test-Template:</p> <pre><code>func TestFunctionName(t *testing.T) {\n // Arrange\n service := &amp;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</code></pre> <p>Table-Driven Tests bevorzugen:</p> <pre><code>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</code></pre>"},{"location":"development/testing/#python-tests-backend","title":"Python Tests (Backend)","text":"<p>Speicherort: <code>/backend/tests/</code></p> <pre><code>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</code></pre> <p>Test-Namenskonvention:</p> <pre><code>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</code></pre> <p>Test-Template:</p> <pre><code>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</code></pre>"},{"location":"development/testing/#test-kategorien","title":"Test-Kategorien","text":""},{"location":"development/testing/#1-unit-tests-hoechste-prioritaet","title":"1. Unit Tests (Hoechste Prioritaet)","text":"<ul> <li>Testen einzelne Funktionen/Methoden</li> <li>Keine externen Abhaengigkeiten (Mocks verwenden)</li> <li>Schnell ausfuehrbar</li> </ul>"},{"location":"development/testing/#2-integration-tests","title":"2. Integration Tests","text":"<ul> <li>Testen Zusammenspiel mehrerer Komponenten</li> <li>Koennen echte DB verwenden (Test-DB)</li> </ul>"},{"location":"development/testing/#3-security-tests","title":"3. Security Tests","text":"<ul> <li>Auth/JWT Validierung</li> <li>Passwort-Hashing</li> <li>Berechtigungspruefung</li> </ul>"},{"location":"development/testing/#checkliste-vor-abschluss","title":"Checkliste vor Abschluss","text":"<p>Vor dem Abschluss einer Aufgabe:</p> <ul> <li>[ ] Gibt es Tests fuer alle neuen Funktionen?</li> <li>[ ] Gibt es Tests fuer alle Edge Cases?</li> <li>[ ] Gibt es Tests fuer Fehlerfaelle?</li> <li>[ ] Laufen alle bestehenden Tests noch? (<code>go test ./...</code> / <code>pytest</code>)</li> <li>[ ] Ist die Test-Coverage angemessen?</li> </ul>"},{"location":"development/testing/#tests-ausfuehren","title":"Tests ausfuehren","text":"<pre><code># Go - Alle Tests\ncd consent-service &amp;&amp; go test -v ./...\n\n# Go - Mit Coverage\ncd consent-service &amp;&amp; go test -cover ./...\n\n# Python - Alle Tests\ncd backend &amp;&amp; source venv/bin/activate &amp;&amp; pytest -v\n\n# Python - Mit Coverage\ncd backend &amp;&amp; pytest --cov=. --cov-report=html\n</code></pre>"},{"location":"development/testing/#beispiel-vollstaendiger-test-workflow","title":"Beispiel: Vollstaendiger Test-Workflow","text":"<p>Wenn du z.B. eine neue <code>GetUserStats()</code> Funktion im Go Service hinzufuegst:</p> <ol> <li>Funktion schreiben in <code>internal/services/stats_service.go</code></li> <li>Test erstellen in <code>internal/services/stats_service_test.go</code>: <pre><code>func TestGetUserStats_ValidUser_ReturnsStats(t *testing.T) {...}\nfunc TestGetUserStats_InvalidUser_ReturnsError(t *testing.T) {...}\nfunc TestGetUserStats_NoConsents_ReturnsEmptyStats(t *testing.T) {...}\n</code></pre></li> <li>Tests ausfuehren: <code>go test -v ./internal/services/...</code></li> <li>Dokumentation aktualisieren (siehe Dokumentation)</li> </ol>"},{"location":"getting-started/environment-setup/","title":"Entwickler-Guide: Umgebungs-Setup","text":"<p>Dieser Guide erkl\u00e4rt das t\u00e4gliche Arbeiten mit den Dev/Staging/Prod-Umgebungen.</p>"},{"location":"getting-started/environment-setup/#schnellstart","title":"Schnellstart","text":"<pre><code># 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</code></pre>"},{"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":"<pre><code># 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</code></pre>"},{"location":"getting-started/environment-setup/#wahrend-der-arbeit","title":"W\u00e4hrend der Arbeit","text":"<pre><code># 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</code></pre>"},{"location":"getting-started/environment-setup/#anderungen-committen","title":"\u00c4nderungen committen","text":"<pre><code># \u00c4nderungen anzeigen\ngit status\n\n# Dateien hinzuf\u00fcgen\ngit add .\n\n# Commit erstellen\ngit commit -m \"Feature: Beschreibung der \u00c4nderung\"\n</code></pre>"},{"location":"getting-started/environment-setup/#abends-umgebung-stoppen","title":"Abends: Umgebung stoppen","text":"<pre><code>./scripts/stop.sh dev\n</code></pre>"},{"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":"<pre><code># Stoppe Dev\n./scripts/stop.sh dev\n\n# Starte Staging\n./scripts/start.sh staging\n</code></pre>"},{"location":"getting-started/environment-setup/#zuruck-zu-dev","title":"Zur\u00fcck zu Dev","text":"<pre><code>./scripts/stop.sh staging\n./scripts/start.sh dev\n</code></pre>"},{"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":"<pre><code># 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</code></pre>"},{"location":"getting-started/environment-setup/#staging-production-release","title":"Staging \u2192 Production (Release)","text":"<pre><code># Nur nach vollst\u00e4ndigem Test auf Staging!\n./scripts/promote.sh staging-to-prod\n\n# Push zu Remote\ngit push origin main\n</code></pre>"},{"location":"getting-started/environment-setup/#nutzliche-befehle","title":"N\u00fctzliche Befehle","text":""},{"location":"getting-started/environment-setup/#docker","title":"Docker","text":"<pre><code># 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</code></pre>"},{"location":"getting-started/environment-setup/#git","title":"Git","text":"<pre><code># 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</code></pre>"},{"location":"getting-started/environment-setup/#datenbank","title":"Datenbank","text":"<pre><code># 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</code></pre>"},{"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":"<p>Ein anderer Prozess oder Container verwendet den Port.</p> <pre><code># 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</code></pre>"},{"location":"getting-started/environment-setup/#container-startet-nicht","title":"Container startet nicht","text":"<pre><code># Logs pr\u00fcfen\ndocker compose logs backend\n\n# Container neu bauen\ndocker compose build backend\ndocker compose up -d backend\n</code></pre>"},{"location":"getting-started/environment-setup/#datenbank-verbindungsfehler","title":"Datenbank-Verbindungsfehler","text":"<pre><code># 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</code></pre>"},{"location":"getting-started/environment-setup/#falsche-umgebung-aktiv","title":"Falsche Umgebung aktiv","text":"<pre><code># Status pr\u00fcfen\n./scripts/status.sh\n\n# Auf richtige Umgebung wechseln\n./scripts/env-switch.sh dev\n</code></pre>"},{"location":"getting-started/environment-setup/#umgebungs-dateien","title":"Umgebungs-Dateien","text":"Datei Beschreibung Im Git? <code>.env</code> Aktive Umgebung Nein <code>.env.dev</code> Development Werte Ja <code>.env.staging</code> Staging Werte Ja <code>.env.prod</code> Production Werte NEIN <code>.env.example</code> 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":"<pre><code># Status und \u00dcbersicht\n./scripts/status.sh\n\n# Script-Hilfe\n./scripts/env-switch.sh --help\n./scripts/promote.sh --help\n</code></pre>"},{"location":"getting-started/environment-setup/#verwandte-dokumentation","title":"Verwandte Dokumentation","text":"<ul> <li>Architektur: Umgebungen</li> <li>Secrets Management</li> <li>System-Architektur</li> </ul>"},{"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":"<ul> <li>IP (LAN): 192.168.178.100</li> <li>User: benjaminadmin</li> <li>SSH: <code>ssh benjaminadmin@192.168.178.100</code></li> </ul>"},{"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 - <p>Keine Aktion n\u00f6tig nach Neustart! Einfach 2-3 Minuten warten.</p>"},{"location":"getting-started/mac-mini-setup/#status-prufen","title":"Status pr\u00fcfen","text":"<pre><code>./scripts/mac-mini/status.sh\n</code></pre>"},{"location":"getting-started/mac-mini-setup/#services-ports","title":"Services &amp; 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":"<ul> <li>Qwen 2.5 14B (14.8 Milliarden Parameter)</li> </ul>"},{"location":"getting-started/mac-mini-setup/#scripts-auf-macbook","title":"Scripts (auf MacBook)","text":"<pre><code>./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</code></pre>"},{"location":"getting-started/mac-mini-setup/#docker-befehle","title":"Docker-Befehle","text":"<pre><code>./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</code></pre>"},{"location":"getting-started/mac-mini-setup/#launchagents-auto-start","title":"LaunchAgents (Auto-Start)","text":"<p>Pfad auf Mac Mini: <code>~/Library/LaunchAgents/</code></p> Agent Funktion <code>com.docker.desktop.plist</code> Docker Desktop <code>com.breakpilot.docker-containers.plist</code> Container Auto-Start <code>com.ollama.serve.plist</code> Ollama Server <code>com.unity.hub.plist</code> Unity Hub <code>com.microsoft.vscode.plist</code> VS Code"},{"location":"getting-started/mac-mini-setup/#projekt-pfade","title":"Projekt-Pfade","text":"<ul> <li>MacBook: <code>/Users/benjaminadmin/Projekte/breakpilot-pwa/</code></li> <li>Mac Mini: <code>/Users/benjaminadmin/Projekte/breakpilot-pwa/</code></li> </ul>"},{"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":"<p>Docker-Einstellungen sind gesichert in <code>~/docker-settings-backup/</code></p> <pre><code># Wiederherstellen:\ncp -r ~/docker-settings-backup/* ~/Library/Group\\ Containers/group.com.docker/\n</code></pre>"},{"location":"getting-started/mac-mini-setup/#container-starten-nicht-automatisch","title":"Container starten nicht automatisch","text":"<p>Log pr\u00fcfen:</p> <pre><code>ssh benjaminadmin@192.168.178.100 \"cat /tmp/docker-autostart.log\"\n</code></pre> <p>Manuell starten:</p> <pre><code>./scripts/mac-mini/docker.sh up\n</code></pre>"},{"location":"getting-started/mac-mini-setup/#ssh-nicht-erreichbar","title":"SSH nicht erreichbar","text":"<ul> <li>Pr\u00fcfe ob Mac Mini an ist (Ping: <code>ping 192.168.178.100</code>)</li> <li>Warte 1-2 Minuten nach Boot</li> <li>Pr\u00fcfe Netzwerkverbindung</li> </ul>"},{"location":"services/agent-core/","title":"Breakpilot Agent Core","text":"<p>Multi-Agent Architecture Infrastructure fuer Breakpilot.</p>"},{"location":"services/agent-core/#uebersicht","title":"Uebersicht","text":"<p>Das <code>agent-core</code> Modul stellt die gemeinsame Infrastruktur fuer Breakpilots Multi-Agent-System bereit:</p> <ul> <li>Session Management: Agent-Sessions mit Checkpoints und Recovery</li> <li>Shared Brain: Langzeit-Gedaechtnis und Kontext-Verwaltung</li> <li>Orchestration: Message Bus, Supervisor und Task-Routing</li> </ul>"},{"location":"services/agent-core/#architektur","title":"Architektur","text":"<pre><code>\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</code></pre>"},{"location":"services/agent-core/#verzeichnisstruktur","title":"Verzeichnisstruktur","text":"<pre><code>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</code></pre>"},{"location":"services/agent-core/#komponenten","title":"Komponenten","text":""},{"location":"services/agent-core/#1-session-management","title":"1. Session Management","text":"<p>Verwaltet Agent-Sessions mit State-Machine und Recovery-Faehigkeiten.</p> <pre><code>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</code></pre> <p>Session States:</p> <ul> <li><code>ACTIVE</code> - Session laeuft</li> <li><code>PAUSED</code> - Session pausiert</li> <li><code>COMPLETED</code> - Session erfolgreich beendet</li> <li><code>FAILED</code> - Session fehlgeschlagen</li> </ul>"},{"location":"services/agent-core/#2-heartbeat-monitoring","title":"2. Heartbeat Monitoring","text":"<p>Ueberwacht Agent-Liveness und triggert Recovery bei Timeout.</p> <pre><code>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</code></pre>"},{"location":"services/agent-core/#3-memory-store","title":"3. Memory Store","text":"<p>Langzeit-Gedaechtnis fuer Agents mit TTL und Access-Tracking.</p> <pre><code>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</code></pre>"},{"location":"services/agent-core/#4-context-manager","title":"4. Context Manager","text":"<p>Verwaltet Konversationskontext mit automatischer Komprimierung.</p> <pre><code>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</code></pre>"},{"location":"services/agent-core/#5-message-bus","title":"5. Message Bus","text":"<p>Inter-Agent Kommunikation via Redis Pub/Sub.</p> <pre><code>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</code></pre>"},{"location":"services/agent-core/#6-agent-supervisor","title":"6. Agent Supervisor","text":"<p>Ueberwacht und koordiniert alle Agents.</p> <pre><code>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</code></pre>"},{"location":"services/agent-core/#7-task-router","title":"7. Task Router","text":"<p>Intent-basiertes Routing mit Fallback-Ketten.</p> <pre><code>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</code></pre>"},{"location":"services/agent-core/#soul-files","title":"SOUL Files","text":"<p>SOUL-Dateien definieren die Persoenlichkeit und Verhaltensregeln jedes Agents.</p> 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":"<pre><code>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</code></pre>"},{"location":"services/agent-core/#agent_memory","title":"agent_memory","text":"<pre><code>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</code></pre>"},{"location":"services/agent-core/#agent_messages","title":"agent_messages","text":"<pre><code>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</code></pre>"},{"location":"services/agent-core/#integration","title":"Integration","text":""},{"location":"services/agent-core/#mit-voice-service","title":"Mit Voice-Service","text":"<pre><code>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</code></pre>"},{"location":"services/agent-core/#mit-bqas","title":"Mit BQAS","text":"<pre><code>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</code></pre>"},{"location":"services/agent-core/#tests","title":"Tests","text":"<pre><code># 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</code></pre>"},{"location":"services/agent-core/#metriken","title":"Metriken","text":"<p>Das Agent-Core exportiert folgende Metriken:</p> Metrik Beschreibung <code>agent_session_duration_seconds</code> Dauer von Agent-Sessions <code>agent_heartbeat_delay_seconds</code> Zeit seit letztem Heartbeat <code>agent_message_latency_ms</code> Latenz der Inter-Agent Kommunikation <code>agent_memory_access_total</code> Memory-Zugriffe pro Agent <code>agent_error_total</code> Fehler pro Agent-Typ"},{"location":"services/agent-core/#naechste-schritte","title":"Naechste Schritte","text":"<ol> <li>Migration ausfuehren: <code>psql -f backend/migrations/add_agent_core_tables.sql</code></li> <li>Voice-Service erweitern: Enhanced Orchestrator aktivieren</li> <li>BQAS integrieren: Quality Judge Agent starten</li> <li>Monitoring aufsetzen: Metriken in Grafana integrieren</li> </ol>"},{"location":"services/ai-compliance-sdk/","title":"AI Compliance SDK","text":"<p>Das AI Compliance SDK ist ein Go-basierter Service zur Compliance-Bewertung von KI-Anwendungsf\u00e4llen.</p>"},{"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":"<pre><code>\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&gt;\u2502 SDK API \u2502\u2500\u2500\u2500&gt;\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</code></pre>"},{"location":"services/ai-compliance-sdk/#features","title":"Features","text":"<ul> <li>UCCA (Use-Case Compliance Advisor): Deterministische Bewertung von KI-Anwendungsf\u00e4llen</li> <li>Policy Engine: 45 regelbasierte Compliance-Pr\u00fcfungen</li> <li>License Policy Engine: Standards/Normen-Compliance (DIN, ISO, VDI)</li> <li>Legal RAG: Semantische Suche in EU-Verordnungen (DSGVO, AI Act, NIS2)</li> <li>Eskalations-Workflow: E0-E3 Stufen mit Human-in-the-Loop</li> <li>Wizard &amp; Legal Assistant: Gef\u00fchrte Eingabe mit Rechtsassistent</li> <li>Generic Obligations Framework: NIS2, DSGVO, AI Act Module</li> </ul>"},{"location":"services/ai-compliance-sdk/#kernprinzip","title":"Kernprinzip","text":"<p>\"LLM ist NICHT die Quelle der Wahrheit. Wahrheit = Regeln + Evidenz. LLM = \u00dcbersetzer + Subsumptionshelfer\"</p> <p>Das System folgt einem strikten Human-in-the-Loop Ansatz:</p> <ol> <li>Deterministische Regeln treffen alle Compliance-Entscheidungen</li> <li>LLM erkl\u00e4rt nur Ergebnisse, \u00fcberschreibt nie BLOCK-Entscheidungen</li> <li>Menschen (DSB, Legal) treffen finale Entscheidungen bei kritischen F\u00e4llen</li> </ol>"},{"location":"services/ai-compliance-sdk/#api-endpunkte","title":"API-Endpunkte","text":""},{"location":"services/ai-compliance-sdk/#assessment","title":"Assessment","text":"Method Endpoint Beschreibung POST <code>/sdk/v1/ucca/assess</code> Assessment erstellen GET <code>/sdk/v1/ucca/assessments</code> Assessments auflisten GET <code>/sdk/v1/ucca/assessments/:id</code> Assessment abrufen POST <code>/sdk/v1/ucca/assessments/:id/explain</code> LLM-Erkl\u00e4rung generieren"},{"location":"services/ai-compliance-sdk/#eskalation","title":"Eskalation","text":"Method Endpoint Beschreibung GET <code>/sdk/v1/ucca/escalations</code> Eskalationen auflisten POST <code>/sdk/v1/ucca/escalations/:id/decide</code> Entscheidung treffen"},{"location":"services/ai-compliance-sdk/#obligations-framework","title":"Obligations Framework","text":"Method Endpoint Beschreibung POST <code>/sdk/v1/ucca/obligations/assess</code> Pflichten-Assessment POST <code>/sdk/v1/ucca/obligations/export/memo</code> PDF-Export"},{"location":"services/ai-compliance-sdk/#weiterfuhrende-dokumentation","title":"Weiterf\u00fchrende Dokumentation","text":"<ul> <li>Architektur - Detaillierte Systemarchitektur</li> <li>Entwickler-Guide - Entwickler-Dokumentation</li> <li>Auditor-Dokumentation - Dokumentation f\u00fcr externe Auditoren</li> </ul>"},{"location":"services/ai-compliance-sdk/#tests","title":"Tests","text":"<pre><code>cd ai-compliance-sdk\ngo test -v ./...\n\n# Mit Coverage\ngo test -cover ./...\n</code></pre>"},{"location":"services/ai-compliance-sdk/ARCHITECTURE/","title":"UCCA - Use-Case Compliance &amp; 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":"<p>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.</p> <pre><code>\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&gt;\u2502 SDK API \u2502\u2500\u2500\u2500&gt;\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</code></pre>"},{"location":"services/ai-compliance-sdk/ARCHITECTURE/#2-kernprinzip","title":"2. Kernprinzip","text":"<p>\"LLM ist NICHT die Quelle der Wahrheit. Wahrheit = Regeln + Evidenz. LLM = \u00dcbersetzer + Subsumptionshelfer\"</p> <p>Das System folgt einem strikten Human-in-the-Loop Ansatz:</p> <ol> <li>Deterministische Regeln treffen alle Compliance-Entscheidungen</li> <li>LLM erkl\u00e4rt nur Ergebnisse, \u00fcberschreibt nie BLOCK-Entscheidungen</li> <li>Menschen (DSB, Legal) treffen finale Entscheidungen bei kritischen F\u00e4llen</li> </ol>"},{"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 (<code>internal/ucca/rules.go</code>)","text":"<p>Die Policy Engine evaluiert Use-Cases gegen ~45 deterministische Regeln.</p> <pre><code>\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&gt; \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 &amp; 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</code></pre> <p>Regel-Severities: - <code>INFO</code>: Informativ, kein Risiko-Impact - <code>WARN</code>: Warnung, erh\u00f6ht Risk Score - <code>BLOCK</code>: Kritisch, f\u00fchrt zu <code>feasibility=NO</code></p>"},{"location":"services/ai-compliance-sdk/ARCHITECTURE/#32-escalation-workflow-internaluccaescalation_go","title":"3.2 Escalation Workflow (<code>internal/ucca/escalation_*.go</code>)","text":"<p>Das Eskalationssystem routet kritische Assessments zur menschlichen Pr\u00fcfung.</p> <pre><code>\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&gt; \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 &lt; 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</code></pre>"},{"location":"services/ai-compliance-sdk/ARCHITECTURE/#33-legal-rag-internalllmlegal_raggo","title":"3.3 Legal RAG (<code>internal/llm/legal_rag.go</code>)","text":"<p>Semantische Suche in 19 EU-Regulierungen f\u00fcr kontextbasierte Erkl\u00e4rungen.</p> <pre><code>\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&gt; \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&gt; \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</code></pre>"},{"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":"<pre><code>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 &gt; 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 &gt; 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</code></pre>"},{"location":"services/ai-compliance-sdk/ARCHITECTURE/#42-erklarung-mit-legal-rag","title":"4.2 Erkl\u00e4rung mit Legal RAG","text":"<pre><code>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&gt;\u2502 Qdrant \u2502\n\u2502 Keywords \u2502 \u2502 bp_legal_ \u2502\n\u2502 from Rules \u2502&lt;\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</code></pre>"},{"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":"<pre><code> 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</code></pre>"},{"location":"services/ai-compliance-sdk/ARCHITECTURE/#52-escalation-level-entscheidung","title":"5.2 Escalation-Level-Entscheidung","text":"<pre><code> 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</code></pre>"},{"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":"<pre><code>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</code></pre>"},{"location":"services/ai-compliance-sdk/ARCHITECTURE/#62-ucca_escalations","title":"6.2 ucca_escalations","text":"<pre><code>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 &amp; 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</code></pre>"},{"location":"services/ai-compliance-sdk/ARCHITECTURE/#63-ucca_dsb_pool","title":"6.3 ucca_dsb_pool","text":"<pre><code>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</code></pre>"},{"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 <code>/sdk/v1/ucca/assess</code> Assessment erstellen GET <code>/sdk/v1/ucca/assessments</code> Assessments auflisten GET <code>/sdk/v1/ucca/assessments/:id</code> Assessment abrufen DELETE <code>/sdk/v1/ucca/assessments/:id</code> Assessment l\u00f6schen POST <code>/sdk/v1/ucca/assessments/:id/explain</code> LLM-Erkl\u00e4rung generieren GET <code>/sdk/v1/ucca/export/:id</code> Assessment exportieren"},{"location":"services/ai-compliance-sdk/ARCHITECTURE/#72-kataloge","title":"7.2 Kataloge","text":"Method Endpoint Beschreibung GET <code>/sdk/v1/ucca/patterns</code> Architektur-Patterns GET <code>/sdk/v1/ucca/examples</code> Didaktische Beispiele GET <code>/sdk/v1/ucca/rules</code> Alle Regeln GET <code>/sdk/v1/ucca/controls</code> Required Controls GET <code>/sdk/v1/ucca/problem-solutions</code> Problem-L\u00f6sungen"},{"location":"services/ai-compliance-sdk/ARCHITECTURE/#73-eskalation","title":"7.3 Eskalation","text":"Method Endpoint Beschreibung GET <code>/sdk/v1/ucca/escalations</code> Eskalationen auflisten GET <code>/sdk/v1/ucca/escalations/:id</code> Eskalation abrufen POST <code>/sdk/v1/ucca/escalations</code> Manuelle Eskalation POST <code>/sdk/v1/ucca/escalations/:id/assign</code> Zuweisen POST <code>/sdk/v1/ucca/escalations/:id/review</code> Review starten POST <code>/sdk/v1/ucca/escalations/:id/decide</code> Entscheidung treffen GET <code>/sdk/v1/ucca/escalations/stats</code> Statistiken"},{"location":"services/ai-compliance-sdk/ARCHITECTURE/#74-dsb-pool","title":"7.4 DSB Pool","text":"Method Endpoint Beschreibung GET <code>/sdk/v1/ucca/dsb-pool</code> Pool-Mitglieder auflisten POST <code>/sdk/v1/ucca/dsb-pool</code> 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":"<ul> <li>JWT-basierte Authentifizierung</li> <li>Header: <code>X-User-ID</code>, <code>X-Tenant-ID</code></li> <li>Multi-Tenant-Isolation</li> </ul>"},{"location":"services/ai-compliance-sdk/ARCHITECTURE/#82-autorisierung","title":"8.2 Autorisierung","text":"<ul> <li>RBAC (Role-Based Access Control)</li> <li>Permissions: <code>ucca:assess</code>, <code>ucca:review</code>, <code>ucca:admin</code></li> <li>Namespace-Level Isolation</li> </ul>"},{"location":"services/ai-compliance-sdk/ARCHITECTURE/#83-datenschutz","title":"8.3 Datenschutz","text":"<ul> <li>Use-Case-Text optional (Opt-in)</li> <li>SHA-256 Hash statt Klartext</li> <li>Audit-Trail f\u00fcr alle Operationen</li> <li>Legal RAG: <code>training_allowed: false</code></li> </ul>"},{"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":"<pre><code>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</code></pre>"},{"location":"services/ai-compliance-sdk/ARCHITECTURE/#92-abhangigkeiten","title":"9.2 Abh\u00e4ngigkeiten","text":"<ul> <li>PostgreSQL 15+</li> <li>Qdrant 1.12+</li> <li>Embedding Service (BGE-M3)</li> <li>Ollama (optional, f\u00fcr LLM)</li> </ul>"},{"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":"<pre><code>GET /sdk/v1/health\n\u2192 {\"status\": \"ok\"}\n</code></pre>"},{"location":"services/ai-compliance-sdk/ARCHITECTURE/#102-metriken","title":"10.2 Metriken","text":"<ul> <li>Assessment-Durchsatz</li> <li>Escalation-SLA-Compliance</li> <li>LLM-Latenz</li> <li>RAG-Trefferqualit\u00e4t</li> </ul>"},{"location":"services/ai-compliance-sdk/ARCHITECTURE/#11-wizard-legal-assistant","title":"11. Wizard &amp; Legal Assistant","text":""},{"location":"services/ai-compliance-sdk/ARCHITECTURE/#111-wizard-architektur","title":"11.1 Wizard-Architektur","text":"<p>Der UCCA-Wizard f\u00fchrt Benutzer durch 9 Schritte zur Erfassung aller relevanten Compliance-Fakten.</p> <pre><code>\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 &amp; 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 &amp; Compliance (AVV, DSFA) \u2502\n\u2502 Step 8: Automatisierung &amp; Human Oversight \u2502\n\u2502 Step 9: Standards &amp; 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</code></pre>"},{"location":"services/ai-compliance-sdk/ARCHITECTURE/#112-legal-assistant-wizard-chat","title":"11.2 Legal Assistant (Wizard Chat)","text":"<p>Integrierter Rechtsassistent f\u00fcr Echtzeit-Hilfe bei Wizard-Fragen.</p> <pre><code>\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&gt;\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&gt;\u2502 Qdrant \u2502 \u2502\n\u2502 \u2502 Client \u2502 \u2502 bp_legal_corpus \u2502 \u2502\n\u2502 \u2502 \u2502&lt;\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</code></pre> <p>API-Endpunkte:</p> Method Endpoint Beschreibung GET <code>/sdk/v1/ucca/wizard/schema</code> Wizard-Schema abrufen POST <code>/sdk/v1/ucca/wizard/ask</code> 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":"<p>Die License Policy Engine verwaltet die Lizenz-/Urheberrechts-Compliance f\u00fcr Standards und Normen (DIN, ISO, VDI, etc.).</p> <pre><code>\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&gt;\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&gt; 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&gt; 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&gt; 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&gt; 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&gt; 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&gt; 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</code></pre>"},{"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 &amp; 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":"<p>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</p>"},{"location":"services/ai-compliance-sdk/ARCHITECTURE/#124-stop-lines-hard-deny","title":"12.4 Stop-Lines (Hard Deny)","text":"<pre><code>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</code></pre>"},{"location":"services/ai-compliance-sdk/ARCHITECTURE/#13-scc-transfer-impact-assessment","title":"13. SCC &amp; Transfer Impact Assessment","text":""},{"location":"services/ai-compliance-sdk/ARCHITECTURE/#131-drittlandtransfer-bewertung","title":"13.1 Drittlandtransfer-Bewertung","text":"<p>Das System unterst\u00fctzt die vollst\u00e4ndige Bewertung internationaler Datentransfers.</p> <pre><code>\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&gt; 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&gt; 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&gt; OK (SCC empfohlen als Backup) \u2502\u2502\n\u2502 \u2502 \u2514\u2500\u2500 Nicht zertifiziert \u2500\u2500\u2500&gt; 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&gt; Transfer OK \u2502\u2502\n\u2502 \u2502 \u251c\u2500\u2500 Adequate + Measures \u2500\u2500&gt; + Technical Supplementary \u2502\u2502\n\u2502 \u2502 \u251c\u2500\u2500 Inadequate \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500&gt; Fix required \u2502\u2502\n\u2502 \u2502 \u2514\u2500\u2500 Not Feasible \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500&gt; 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</code></pre>"},{"location":"services/ai-compliance-sdk/ARCHITECTURE/#132-scc-versionen","title":"13.2 SCC-Versionen","text":"<ul> <li>Neue SCC (EU 2021/914) - erforderlich seit 27.12.2022</li> <li>Alte SCC (vor 2021) - nicht mehr g\u00fcltig</li> </ul>"},{"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":"<p>Der Controls Catalog enth\u00e4lt ~30 Ma\u00dfnahmenbausteine mit detaillierten Handlungsanweisungen.</p> <pre><code>\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</code></pre>"},{"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":"<pre><code>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</code></pre>"},{"location":"services/ai-compliance-sdk/ARCHITECTURE/#152-versions-management","title":"15.2 Versions-Management","text":"<ul> <li>Jedes Assessment speichert die <code>policy_version</code></li> <li>Regel\u00e4nderungen erzeugen neue Version</li> <li>Audit-Trail zeigt welche Policy-Version verwendet wurde</li> </ul>"},{"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":"<p>Das Generic Obligations Framework erm\u00f6glicht die automatische Ableitung regulatorischer Pflichten aus mehreren Verordnungen basierend auf Unternehmensfakten.</p> <pre><code>\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 &amp; 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</code></pre>"},{"location":"services/ai-compliance-sdk/ARCHITECTURE/#162-regulation-modules","title":"16.2 Regulation Modules","text":"<p>Jede Regulierung wird als eigenst\u00e4ndiges Modul implementiert:</p> <p>Implementierte Module:</p> Modul ID Datei Pflichten Kontrollen NIS2 <code>nis2</code> <code>nis2_module.go</code> ~15 ~8 DSGVO <code>dsgvo</code> <code>dsgvo_module.go</code> ~12 ~6 AI Act <code>ai_act</code> <code>ai_act_module.go</code> ~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 <code>/sdk/v1/ucca/obligations/assess</code> Pflichten-Assessment erstellen GET <code>/sdk/v1/ucca/obligations/:id</code> Assessment abrufen GET <code>/sdk/v1/ucca/obligations</code> Assessments auflisten"},{"location":"services/ai-compliance-sdk/ARCHITECTURE/#172-export","title":"17.2 Export","text":"Method Endpoint Beschreibung POST <code>/sdk/v1/ucca/obligations/export/memo</code> Memo exportieren (gespeichert) POST <code>/sdk/v1/ucca/obligations/export/direct</code> Direkt-Export ohne Speicherung"},{"location":"services/ai-compliance-sdk/ARCHITECTURE/#173-regulations","title":"17.3 Regulations","text":"Method Endpoint Beschreibung GET <code>/sdk/v1/ucca/regulations</code> Liste aller Regulierungsmodule GET <code>/sdk/v1/ucca/regulations/:id/decision-tree</code> 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":"<pre><code>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</code></pre>"},{"location":"services/ai-compliance-sdk/ARCHITECTURE/#182-policy-dateien-yaml","title":"18.2 Policy-Dateien (YAML)","text":"<pre><code>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</code></pre> <p>Dokumentation erstellt: 2026-01-29 Version: 2.1.0</p>"},{"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":"<p>Verantwortlicher: [Name des Unternehmens] Datenschutzbeauftragter: [Kontakt] Dokumentationsstand: 2026-01-29 Version: 1.0.0</p>"},{"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":"<p>UCCA - Use-Case Compliance &amp; Feasibility Advisor</p>"},{"location":"services/ai-compliance-sdk/AUDITOR_DOCUMENTATION/#12-zweckbeschreibung","title":"1.2 Zweckbeschreibung","text":"<p>Das UCCA-System ist ein Compliance-Pr\u00fcfwerkzeug, das Organisationen bei der Bewertung geplanter KI-Anwendungsf\u00e4lle hinsichtlich ihrer datenschutzrechtlichen Zul\u00e4ssigkeit unterst\u00fctzt.</p> <p>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</p>"},{"location":"services/ai-compliance-sdk/AUDITOR_DOCUMENTATION/#13-rechtsgrundlage","title":"1.3 Rechtsgrundlage","text":"<p>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)</p>"},{"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 <p>Wichtig: Der System speichert standardm\u00e4\u00dfig keine Freitexte, sondern nur: - SHA-256 Hash des Textes (zur Deduplizierung) - Strukturierte Metadaten (Checkboxen, Dropdowns)</p>"},{"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":"<p>Das System verwendet ausschlie\u00dflich deterministische Regeln f\u00fcr Compliance-Entscheidungen. Diese Regeln sind:</p> <ol> <li>Transparent - Alle Regeln sind im Quellcode einsehbar</li> <li>Nachvollziehbar - Jede ausgel\u00f6ste Regel wird dokumentiert</li> <li>\u00dcberpr\u00fcfbar - Regellogik basiert auf konkreten DSGVO-Artikeln</li> </ol> <p>Beispiel-Regel R-F001: <pre><code>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</code></pre></p>"},{"location":"services/ai-compliance-sdk/AUDITOR_DOCUMENTATION/#32-keine-autonomen-ki-entscheidungen","title":"3.2 Keine autonomen KI-Entscheidungen","text":"<p>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)</p> <p>KI wird ausschlie\u00dflich verwendet f\u00fcr: - Erkl\u00e4rung bereits getroffener Regelentscheidungen - Zusammenfassung von Rechtstexten - Sprachliche Formulierung von Hinweisen</p>"},{"location":"services/ai-compliance-sdk/AUDITOR_DOCUMENTATION/#33-human-in-the-loop","title":"3.3 Human-in-the-Loop","text":"<p>Bei allen kritischen Entscheidungen ist ein menschlicher Pr\u00fcfer eingebunden:</p> 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 <p>BLOCK-Entscheidungen k\u00f6nnen NICHT durch KI \u00fcberschrieben werden.</p>"},{"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":"<p>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</p>"},{"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":"<p>Betroffene k\u00f6nnen Auskunft erhalten \u00fcber: - Gespeicherte Assessments mit ihren Daten - Audit-Trail ihrer Interaktionen - Regelbasierte Entscheidungsbegr\u00fcndungen</p>"},{"location":"services/ai-compliance-sdk/AUDITOR_DOCUMENTATION/#62-recht-auf-berichtigung-art-16","title":"6.2 Recht auf Berichtigung (Art. 16)","text":"<p>Betroffene k\u00f6nnen die Korrektur fehlerhafter Eingabedaten verlangen.</p>"},{"location":"services/ai-compliance-sdk/AUDITOR_DOCUMENTATION/#63-recht-auf-loschung-art-17","title":"6.3 Recht auf L\u00f6schung (Art. 17)","text":"<p>Assessments k\u00f6nnen gel\u00f6scht werden, sofern: - Keine gesetzlichen Aufbewahrungspflichten bestehen - Keine laufenden Eskalationsverfahren existieren</p>"},{"location":"services/ai-compliance-sdk/AUDITOR_DOCUMENTATION/#64-recht-auf-einschrankung-art-18","title":"6.4 Recht auf Einschr\u00e4nkung (Art. 18)","text":"<p>Die Verarbeitung kann eingeschr\u00e4nkt werden durch: - Archivierung statt L\u00f6schung - Sperrung des Datensatzes</p>"},{"location":"services/ai-compliance-sdk/AUDITOR_DOCUMENTATION/#65-automatisierte-entscheidungen-art-22","title":"6.5 Automatisierte Entscheidungen (Art. 22)","text":"<p>Das System trifft keine automatisierten Einzelentscheidungen im Sinne von Art. 22 DSGVO, da:</p> <ol> <li>Regelauswertung ist keine rechtlich bindende Entscheidung</li> <li>Alle kritischen F\u00e4lle werden menschlich gepr\u00fcft (E1-E3)</li> <li>BLOCK-Entscheidungen erfordern immer menschliche Freigabe</li> <li>Betroffene haben Anfechtungsm\u00f6glichkeit \u00fcber Eskalation</li> </ol>"},{"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 <p>Hinweis: Das System kann vollst\u00e4ndig on-premise betrieben werden ohne externe Dienste.</p>"},{"location":"services/ai-compliance-sdk/AUDITOR_DOCUMENTATION/#72-internationale-transfers","title":"7.2 Internationale Transfers","text":"<p>Bei Nutzung von Cloud-LLM-Anbietern: - Anthropic Claude: US (DPF-zertifiziert) - OpenAI: US (DPF-zertifiziert)</p> <p>Empfehlung: Nutzung des lokalen Ollama-Providers f\u00fcr sensible Daten.</p>"},{"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 &amp; Normen-Compliance (\u00a744b UrhG)","text":""},{"location":"services/ai-compliance-sdk/AUDITOR_DOCUMENTATION/#91-zweck","title":"9.1 Zweck","text":"<p>Das System enth\u00e4lt einen spezialisierten License Policy Engine zur Compliance-Pr\u00fcfung bei der Verarbeitung urheberrechtlich gesch\u00fctzter Inhalte, insbesondere:</p> <ul> <li>DIN-Normen (DIN Media / Beuth Verlag)</li> <li>VDI-Richtlinien</li> <li>ISO/IEC-Standards</li> <li>VDE-Normen</li> </ul>"},{"location":"services/ai-compliance-sdk/AUDITOR_DOCUMENTATION/#92-rechtlicher-hintergrund","title":"9.2 Rechtlicher Hintergrund","text":"<p>\u00a744b UrhG - Text und Data Mining:</p> <p>\"Die Vervielf\u00e4ltigung von rechtm\u00e4\u00dfig zug\u00e4nglichen Werken f\u00fcr das Text und Data Mining ist zul\u00e4ssig.\"</p> <p>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)</p>"},{"location":"services/ai-compliance-sdk/AUDITOR_DOCUMENTATION/#93-operationsmodi-im-system","title":"9.3 Operationsmodi im System","text":"Modus Beschreibung Lizenzanforderung <code>LINK_ONLY</code> Nur Verlinkung zum Original Keine <code>NOTES_ONLY</code> Eigene Notizen/Zusammenfassungen Keine (\u00a751 UrhG) <code>EXCERPT_ONLY</code> Kurze Zitate (&lt;100 W\u00f6rter) Standard-Lizenz <code>FULLTEXT_RAG</code> Volltextsuche mit Embedding Explizite KI-Lizenz <code>TRAINING</code> 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":"<p>Das System blockiert automatisch folgende Kombinationen:</p> Stop-Line ID Bedingung Aktion <code>STOP_DIN_FULLTEXT_AI_NOT_ALLOWED</code> DIN Media + FULLTEXT_RAG + keine KI-Lizenz Ablehnung <code>STOP_LICENSE_UNKNOWN_FULLTEXT</code> Lizenz unbekannt + FULLTEXT_RAG Warnung + Eskalation <code>STOP_TRAINING_WITHOUT_ENTERPRISE</code> 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":"<pre><code>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</code></pre>"},{"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 <code>CTRL-LICENSE-PROOF</code> Lizenznachweis dokumentieren Lizenzvertrag, Rechnung <code>CTRL-LICENSE-GATED-INGEST</code> Technische Sperre vor Ingest Konfiguration, Logs <code>CTRL-NO-CRAWLING-DIN</code> Kein automatisches Crawling System-Konfiguration <code>CTRL-OUTPUT-GUARD</code> Ausgabe-Beschr\u00e4nkung (Zitatlimit) API-Logs"},{"location":"services/ai-compliance-sdk/AUDITOR_DOCUMENTATION/#97-audit-relevante-protokollierung","title":"9.7 Audit-relevante Protokollierung","text":"<p>Bei jeder Verarbeitung lizenzierter Inhalte wird dokumentiert:</p> Feld Beschreibung Aufbewahrung <code>license_check_timestamp</code> Zeitpunkt der Pr\u00fcfung 10 Jahre <code>license_decision</code> Ergebnis (allowed/denied) 10 Jahre <code>license_proof_hash</code> Hash des Lizenznachweises 10 Jahre <code>operation_mode_requested</code> Angefragter Modus 10 Jahre <code>operation_mode_granted</code> Erlaubter Modus 10 Jahre <code>publisher</code> 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":"<p>F\u00fcr Unternehmen mit strengen Compliance-Anforderungen:</p> 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":"<p>[Name und Adresse des Unternehmens]</p>"},{"location":"services/ai-compliance-sdk/AUDITOR_DOCUMENTATION/#102-datenschutzbeauftragter","title":"10.2 Datenschutzbeauftragter","text":"<p>Name: [Name] E-Mail: [E-Mail] Telefon: [Telefon]</p>"},{"location":"services/ai-compliance-sdk/AUDITOR_DOCUMENTATION/#103-technischer-ansprechpartner","title":"10.3 Technischer Ansprechpartner","text":"<p>Name: [Name] E-Mail: [E-Mail]</p>"},{"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 &amp; Standards-Compliance (\u00a744b UrhG) [Autor] 1.0.0 2026-01-29 Erstversion [Autor] <p>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).</p>"},{"location":"services/ai-compliance-sdk/DEVELOPER/","title":"AI Compliance SDK - Entwickler-Dokumentation","text":""},{"location":"services/ai-compliance-sdk/DEVELOPER/#inhaltsverzeichnis","title":"Inhaltsverzeichnis","text":"<ol> <li>Schnellstart</li> <li>Architektur-\u00dcbersicht</li> <li>Policy Engine</li> <li>License Policy Engine</li> <li>Legal RAG Integration</li> <li>Wizard &amp; Legal Assistant</li> <li>Eskalations-System</li> <li>API-Endpoints</li> <li>Policy-Dateien</li> <li>Tests ausf\u00fchren</li> </ol>"},{"location":"services/ai-compliance-sdk/DEVELOPER/#1-schnellstart","title":"1. Schnellstart","text":""},{"location":"services/ai-compliance-sdk/DEVELOPER/#voraussetzungen","title":"Voraussetzungen","text":"<ul> <li>Go 1.21+</li> <li>PostgreSQL (f\u00fcr Eskalations-Store)</li> <li>Qdrant (f\u00fcr Legal RAG)</li> <li>Ollama oder Anthropic API Key (f\u00fcr LLM)</li> </ul>"},{"location":"services/ai-compliance-sdk/DEVELOPER/#build-run","title":"Build &amp; Run","text":"<pre><code># 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</code></pre>"},{"location":"services/ai-compliance-sdk/DEVELOPER/#erste-anfrage","title":"Erste Anfrage","text":"<pre><code># 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</code></pre>"},{"location":"services/ai-compliance-sdk/DEVELOPER/#2-architektur-ubersicht","title":"2. Architektur-\u00dcbersicht","text":"<pre><code>\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</code></pre>"},{"location":"services/ai-compliance-sdk/DEVELOPER/#kernprinzip","title":"Kernprinzip","text":"<p>LLM ist NICHT die Quelle der Wahrheit!</p> 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":"<p>Die Policy Engine (<code>internal/ucca/policy_engine.go</code>) evaluiert Use Cases gegen deterministische Regeln.</p>"},{"location":"services/ai-compliance-sdk/DEVELOPER/#verwendung","title":"Verwendung","text":"<pre><code>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 := &amp;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</code></pre>"},{"location":"services/ai-compliance-sdk/DEVELOPER/#ergebnis-struktur","title":"Ergebnis-Struktur","text":"<pre><code>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</code></pre>"},{"location":"services/ai-compliance-sdk/DEVELOPER/#regeln-hinzufugen","title":"Regeln hinzuf\u00fcgen","text":"<p>Neue Regeln werden in <code>policies/ucca_policy_v1.yaml</code> definiert:</p> <pre><code>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</code></pre>"},{"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":"<p>Die License Policy Engine (<code>internal/ucca/license_policy.go</code>) pr\u00fcft die Lizenz-Compliance f\u00fcr Standards und Normen.</p>"},{"location":"services/ai-compliance-sdk/DEVELOPER/#operationsmodi","title":"Operationsmodi","text":"Modus Beschreibung Lizenzanforderung <code>LINK_ONLY</code> Nur Verweise Keine <code>NOTES_ONLY</code> Eigene Notizen Keine <code>EXCERPT_ONLY</code> Kurzzitate (&lt;150 Zeichen) Standard-Lizenz <code>FULLTEXT_RAG</code> Volltext-Embedding Explizite KI-Lizenz <code>TRAINING</code> Modell-Training Enterprise + Vertrag"},{"location":"services/ai-compliance-sdk/DEVELOPER/#verwendung_1","title":"Verwendung","text":"<pre><code>import \"ai-compliance-sdk/internal/ucca\"\n\nengine := ucca.NewLicensePolicyEngine()\n\nfacts := &amp;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</code></pre>"},{"location":"services/ai-compliance-sdk/DEVELOPER/#ingest-entscheidung","title":"Ingest-Entscheidung","text":"<pre><code>// 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</code></pre>"},{"location":"services/ai-compliance-sdk/DEVELOPER/#audit-logging","title":"Audit-Logging","text":"<pre><code>// 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</code></pre>"},{"location":"services/ai-compliance-sdk/DEVELOPER/#publisher-spezifische-regeln","title":"Publisher-spezifische Regeln","text":"<p>DIN Media hat explizite Restriktionen:</p> <pre><code>// DIN Media blockiert FULLTEXT_RAG ohne AI-Lizenz\nif facts.Publisher == \"DIN_MEDIA\" &amp;&amp; facts.AIUsePermitted != \"YES\" {\n // \u2192 STOP_DIN_FULLTEXT_AI_NOT_ALLOWED\n // \u2192 Downgrade auf LINK_ONLY\n}\n</code></pre>"},{"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":"<p>Das Legal RAG System (<code>internal/ucca/legal_rag.go</code>) generiert Erkl\u00e4rungen mit rechtlichem Kontext.</p>"},{"location":"services/ai-compliance-sdk/DEVELOPER/#verwendung_2","title":"Verwendung","text":"<pre><code>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</code></pre>"},{"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 &amp; Legal Assistant","text":""},{"location":"services/ai-compliance-sdk/DEVELOPER/#wizard-schema","title":"Wizard-Schema","text":"<p>Das Wizard-Schema (<code>policies/wizard_schema_v1.yaml</code>) definiert die Fragen f\u00fcr das Frontend.</p>"},{"location":"services/ai-compliance-sdk/DEVELOPER/#legal-assistant-verwenden","title":"Legal Assistant verwenden","text":"<pre><code>// 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</code></pre>"},{"location":"services/ai-compliance-sdk/DEVELOPER/#beispiel-api-call","title":"Beispiel API-Call","text":"<pre><code>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</code></pre>"},{"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":"<pre><code>import \"ai-compliance-sdk/internal/ucca\"\n\nstore := ucca.NewEscalationStore(db)\n\nescalation := &amp;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</code></pre>"},{"location":"services/ai-compliance-sdk/DEVELOPER/#sla-monitor","title":"SLA-Monitor","text":"<pre><code>monitor := ucca.NewSLAMonitor(store, notificationService)\n\n// Im Hintergrund starten\ngo monitor.Start(ctx)\n</code></pre>"},{"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 <code>/sdk/v1/ucca/assess</code> Assessment erstellen GET <code>/sdk/v1/ucca/assess/:id</code> Assessment abrufen POST <code>/sdk/v1/ucca/explain</code> Erkl\u00e4rung generieren GET <code>/sdk/v1/ucca/wizard/schema</code> Wizard-Schema abrufen POST <code>/sdk/v1/ucca/wizard/ask</code> Legal Assistant fragen"},{"location":"services/ai-compliance-sdk/DEVELOPER/#license-endpoints","title":"License Endpoints","text":"Method Endpoint Beschreibung POST <code>/sdk/v1/license/evaluate</code> Lizenz-Pr\u00fcfung POST <code>/sdk/v1/license/decide-ingest</code> Ingest-Entscheidung"},{"location":"services/ai-compliance-sdk/DEVELOPER/#eskalations-endpoints","title":"Eskalations-Endpoints","text":"Method Endpoint Beschreibung GET <code>/sdk/v1/escalations</code> Offene Eskalationen GET <code>/sdk/v1/escalations/:id</code> Eskalation abrufen POST <code>/sdk/v1/escalations/:id/decide</code> 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":"<pre><code>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</code></pre>"},{"location":"services/ai-compliance-sdk/DEVELOPER/#policy-version","title":"Policy-Version","text":"<p>Jede Policy hat eine Version:</p> <pre><code>metadata:\n version: \"1.0.0\"\n effective_date: \"2025-01-01\"\n author: \"Compliance Team\"\n</code></pre>"},{"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":"<pre><code>cd ai-compliance-sdk\ngo test -v ./...\n</code></pre>"},{"location":"services/ai-compliance-sdk/DEVELOPER/#spezifische-tests","title":"Spezifische Tests","text":"<pre><code># 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</code></pre>"},{"location":"services/ai-compliance-sdk/DEVELOPER/#test-coverage","title":"Test-Coverage","text":"<pre><code>go test -cover ./...\n\n# HTML-Report\ngo test -coverprofile=coverage.out ./...\ngo tool cover -html=coverage.out\n</code></pre>"},{"location":"services/ai-compliance-sdk/DEVELOPER/#beispiel-neuen-test-hinzufugen","title":"Beispiel: Neuen Test hinzuf\u00fcgen","text":"<pre><code>func TestMyNewFeature(t *testing.T) {\n engine := NewLicensePolicyEngine()\n\n facts := &amp;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</code></pre>"},{"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":"<p>Das Obligations Framework erm\u00f6glicht die automatische Ableitung regulatorischer Pflichten aus NIS2, DSGVO und AI Act.</p>"},{"location":"services/ai-compliance-sdk/DEVELOPER/#verwendung_3","title":"Verwendung","text":"<pre><code>import \"ai-compliance-sdk/internal/ucca\"\n\n// Registry erstellen (l\u00e4dt alle Module)\nregistry := ucca.NewObligationsRegistry()\n\n// UnifiedFacts aufbauen\nfacts := &amp;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</code></pre>"},{"location":"services/ai-compliance-sdk/DEVELOPER/#neues-regulierungsmodul-erstellen","title":"Neues Regulierungsmodul erstellen","text":"<pre><code>// 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 := &amp;MyRegulationModule{}\n // YAML laden oder hardcoded Pflichten definieren\n return m, nil\n}\n\n// In obligations_registry.go:\n// r.Register(NewMyRegulationModule())\n</code></pre>"},{"location":"services/ai-compliance-sdk/DEVELOPER/#yaml-basierte-pflichten","title":"YAML-basierte Pflichten","text":"<pre><code># 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</code></pre>"},{"location":"services/ai-compliance-sdk/DEVELOPER/#pdf-export","title":"PDF Export","text":"<pre><code>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</code></pre>"},{"location":"services/ai-compliance-sdk/DEVELOPER/#api-endpoints","title":"API-Endpoints","text":"<pre><code># 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</code></pre>"},{"location":"services/ai-compliance-sdk/DEVELOPER/#12-tests-fur-obligations-framework","title":"12. Tests f\u00fcr Obligations Framework","text":"<pre><code># 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</code></pre>"},{"location":"services/ai-compliance-sdk/DEVELOPER/#beispiel-tests","title":"Beispiel-Tests","text":"<pre><code>func TestNIS2Module_LargeCompanyInAnnexISector(t *testing.T) {\n module, _ := ucca.NewNIS2Module()\n\n facts := &amp;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 := &amp;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</code></pre>"},{"location":"services/ai-compliance-sdk/DEVELOPER/#anhang-wichtige-dateien","title":"Anhang: Wichtige Dateien","text":"Datei Beschreibung <code>internal/ucca/policy_engine.go</code> Haupt-Policy-Engine <code>internal/ucca/license_policy.go</code> License Policy Engine <code>internal/ucca/obligations_framework.go</code> Obligations Interfaces &amp; Typen <code>internal/ucca/obligations_registry.go</code> Modul-Registry <code>internal/ucca/nis2_module.go</code> NIS2 Decision Tree <code>internal/ucca/dsgvo_module.go</code> DSGVO Pflichten <code>internal/ucca/ai_act_module.go</code> AI Act Risk Classification <code>internal/ucca/pdf_export.go</code> PDF/Markdown Export <code>internal/api/handlers/obligations_handlers.go</code> Obligations API <code>policies/obligations/*.yaml</code> Pflichten-Kataloge <p>Dokumentationsstand: 2026-01-29</p>"},{"location":"services/ai-compliance-sdk/SBOM/","title":"AI Compliance SDK - Software Bill of Materials (SBOM)","text":"<p>Erstellt: 2026-01-29 Go-Version: 1.24.0</p>"},{"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 <code>github.com/gin-gonic/gin</code> v1.10.1 MIT \u2705 Ja <code>github.com/gin-contrib/cors</code> v1.7.6 MIT \u2705 Ja <code>github.com/google/uuid</code> v1.6.0 BSD-3-Clause \u2705 Ja <code>github.com/jackc/pgx/v5</code> v5.5.3 MIT \u2705 Ja <code>github.com/joho/godotenv</code> v1.5.1 MIT \u2705 Ja <code>github.com/xuri/excelize/v2</code> v2.9.1 BSD-3-Clause \u2705 Ja <code>gopkg.in/yaml.v3</code> 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 <code>github.com/bytedance/sonic</code> v1.13.3 Apache-2.0 \u2705 Ja <code>github.com/goccy/go-json</code> v0.10.5 MIT \u2705 Ja <code>github.com/json-iterator/go</code> v1.1.12 MIT \u2705 Ja <code>github.com/pelletier/go-toml/v2</code> v2.2.4 MIT \u2705 Ja <code>gopkg.in/yaml.v3</code> v3.0.1 MIT / Apache-2.0 \u2705 Ja <code>github.com/ugorji/go/codec</code> 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 <code>github.com/gin-contrib/sse</code> v1.1.0 MIT \u2705 Ja <code>github.com/go-playground/validator/v10</code> v10.26.0 MIT \u2705 Ja <code>github.com/go-playground/locales</code> v0.14.1 MIT \u2705 Ja <code>github.com/go-playground/universal-translator</code> v0.18.1 MIT \u2705 Ja <code>github.com/leodido/go-urn</code> v1.4.0 MIT \u2705 Ja"},{"location":"services/ai-compliance-sdk/SBOM/#datenbank-postgresql","title":"Datenbank (PostgreSQL)","text":"Package Version Lizenz Kommerziell nutzbar <code>github.com/jackc/pgpassfile</code> v1.0.0 MIT \u2705 Ja <code>github.com/jackc/pgservicefile</code> v0.0.0-... MIT \u2705 Ja <code>github.com/jackc/puddle/v2</code> v2.2.1 MIT \u2705 Ja"},{"location":"services/ai-compliance-sdk/SBOM/#excel-verarbeitung","title":"Excel-Verarbeitung","text":"Package Version Lizenz Kommerziell nutzbar <code>github.com/xuri/excelize/v2</code> v2.9.1 BSD-3-Clause \u2705 Ja <code>github.com/xuri/efp</code> v0.0.1 BSD-3-Clause \u2705 Ja <code>github.com/xuri/nfp</code> v0.0.2-... BSD-3-Clause \u2705 Ja <code>github.com/richardlehane/mscfb</code> v1.0.4 Apache-2.0 \u2705 Ja <code>github.com/richardlehane/msoleps</code> 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 <code>github.com/jung-kurt/gofpdf</code> v1.16.2 MIT \u2705 Ja"},{"location":"services/ai-compliance-sdk/SBOM/#utilities","title":"Utilities","text":"Package Version Lizenz Kommerziell nutzbar <code>github.com/gabriel-vasile/mimetype</code> v1.4.9 MIT \u2705 Ja <code>github.com/mattn/go-isatty</code> v0.0.20 MIT \u2705 Ja <code>github.com/modern-go/concurrent</code> v0.0.0-... Apache-2.0 \u2705 Ja <code>github.com/modern-go/reflect2</code> v1.0.2 Apache-2.0 \u2705 Ja <code>github.com/klauspost/cpuid/v2</code> v2.2.10 MIT \u2705 Ja <code>github.com/tiendc/go-deepcopy</code> v1.7.1 MIT \u2705 Ja <code>github.com/twitchyliquid64/golang-asm</code> v0.15.1 MIT \u2705 Ja <code>github.com/cloudwego/base64x</code> 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 <code>golang.org/x/arch</code> v0.18.0 BSD-3-Clause \u2705 Ja <code>golang.org/x/crypto</code> v0.43.0 BSD-3-Clause \u2705 Ja <code>golang.org/x/net</code> v0.46.0 BSD-3-Clause \u2705 Ja <code>golang.org/x/sync</code> v0.17.0 BSD-3-Clause \u2705 Ja <code>golang.org/x/sys</code> v0.37.0 BSD-3-Clause \u2705 Ja <code>golang.org/x/text</code> 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 <code>google.golang.org/protobuf</code> 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":"<p>Die folgenden Komponenten wurden im Rahmen des AI Compliance SDK entwickelt und haben keine zus\u00e4tzlichen Abh\u00e4ngigkeiten:</p> Komponente Dateien Externe Deps Policy Engine <code>internal/ucca/policy_engine.go</code> Keine License Policy Engine <code>internal/ucca/license_policy.go</code> Keine Legal RAG <code>internal/ucca/legal_rag.go</code> Keine Escalation System <code>internal/ucca/escalation_*.go</code> Keine SLA Monitor <code>internal/ucca/sla_monitor.go</code> Keine UCCA Handlers <code>internal/api/handlers/ucca_handlers.go</code> Gin (MIT) Obligations Framework <code>internal/ucca/obligations_framework.go</code> Keine Obligations Registry <code>internal/ucca/obligations_registry.go</code> Keine NIS2 Module <code>internal/ucca/nis2_module.go</code> Keine DSGVO Module <code>internal/ucca/dsgvo_module.go</code> Keine AI Act Module <code>internal/ucca/ai_act_module.go</code> Keine PDF Export <code>internal/ucca/pdf_export.go</code> gofpdf (MIT) Obligations Handlers <code>internal/api/handlers/obligations_handlers.go</code> Gin (MIT) Funding Models <code>internal/funding/models.go</code> Keine Funding Store <code>internal/funding/store.go</code>, <code>postgres_store.go</code> pgx (MIT) Funding Export <code>internal/funding/export.go</code> gofpdf (MIT), excelize (BSD-3) Funding Handlers <code>internal/api/handlers/funding_handlers.go</code> Gin (MIT)"},{"location":"services/ai-compliance-sdk/SBOM/#policy-dateien-reine-yamljson","title":"Policy-Dateien (Reine YAML/JSON)","text":"Datei Format Abh\u00e4ngigkeiten <code>ucca_policy_v1.yaml</code> YAML Keine <code>wizard_schema_v1.yaml</code> YAML Keine <code>controls_catalog.yaml</code> YAML Keine <code>gap_mapping.yaml</code> YAML Keine <code>licensed_content_policy.yaml</code> YAML Keine <code>financial_regulations_policy.yaml</code> YAML Keine <code>financial_regulations_corpus.yaml</code> YAML Keine <code>scc_legal_corpus.yaml</code> YAML Keine <code>obligations/nis2_obligations.yaml</code> YAML Keine <code>obligations/dsgvo_obligations.yaml</code> YAML Keine <code>obligations/ai_act_obligations.yaml</code> YAML Keine <code>funding/foerderantrag_wizard_v1.yaml</code> YAML Keine <code>funding/bundesland_profiles.yaml</code> 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":"<p>Alle verwendeten Abh\u00e4ngigkeiten verwenden permissive Open-Source-Lizenzen:</p> <ol> <li> <p>MIT-Lizenz: Erlaubt kommerzielle Nutzung, Modifikation, Distribution. Nur Lizenzhinweis erforderlich.</p> </li> <li> <p>Apache-2.0-Lizenz: Erlaubt kommerzielle Nutzung, Modifikation, Distribution. Patentgew\u00e4hrung enthalten.</p> </li> <li> <p>BSD-3-Clause: Erlaubt kommerzielle Nutzung, Modifikation, Distribution. Nur Lizenzhinweis erforderlich.</p> </li> </ol>"},{"location":"services/ai-compliance-sdk/SBOM/#keine-copyleft-lizenzen","title":"Keine Copyleft-Lizenzen","text":"<p>Es werden keine Copyleft-Lizenzen (GPL, AGPL, LGPL) verwendet, die eine Offenlegung des eigenen Quellcodes erfordern w\u00fcrden.</p>"},{"location":"services/ai-compliance-sdk/SBOM/#empfohlene-manahmen","title":"Empfohlene Ma\u00dfnahmen","text":"<ol> <li>NOTICE-Datei pflegen: Alle Lizenztexte in einer NOTICE-Datei zusammenfassen</li> <li>Regelm\u00e4\u00dfige Updates: Abh\u00e4ngigkeiten auf bekannte Schwachstellen pr\u00fcfen</li> <li>License-Scanner: Tool wie <code>go-licenses</code> oder <code>fossa</code> f\u00fcr automatisierte Pr\u00fcfung</li> </ol>"},{"location":"services/ai-compliance-sdk/SBOM/#generierung-des-sbom","title":"Generierung des SBOM","text":"<pre><code># 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</code></pre> <p>Dokumentationsstand: 2026-01-29</p>"},{"location":"services/ki-daten-pipeline/","title":"KI-Daten-Pipeline","text":"<p>Die KI-Daten-Pipeline ist ein zusammenhaengendes System aus drei Modulen, das den Datenfluss von der Erfassung bis zur semantischen Suche abbildet.</p>"},{"location":"services/ki-daten-pipeline/#uebersicht","title":"Uebersicht","text":"<pre><code>flowchart LR\n subgraph OCR[\"OCR-Labeling\"]\n A[Klausur-Scans] --&gt; B[OCR Erkennung]\n B --&gt; C[Ground Truth Labels]\n end\n\n subgraph RAG[\"RAG Pipeline\"]\n D[PDF Dokumente] --&gt; E[Text-Extraktion]\n E --&gt; F[Chunking]\n F --&gt; G[Embedding]\n end\n\n subgraph SEARCH[\"Daten &amp; RAG\"]\n H[Qdrant Collections]\n I[Semantische Suche]\n end\n\n C --&gt;|Export| D\n G --&gt;|Indexierung| H\n H --&gt; I\n I --&gt;|Ergebnisse| J[Klausur-Korrektur]</code></pre>"},{"location":"services/ki-daten-pipeline/#module","title":"Module","text":"Modul Pfad Funktion Backend OCR-Labeling <code>/ai/ocr-labeling</code> Ground Truth fuer Handschrift-OCR klausur-service:8086 RAG Pipeline <code>/ai/rag-pipeline</code> Dokument-Indexierung klausur-service:8086 Daten &amp; RAG <code>/ai/rag</code> Vektor-Suche &amp; 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":"<p>Das OCR-Labeling-Modul erfasst Ground Truth Daten fuer das Training von Handschrift-Erkennungsmodellen:</p> <ul> <li>Upload: Klausur-Scans (PDF/Bilder) werden hochgeladen</li> <li>OCR-Verarbeitung: Mehrere OCR-Modelle erkennen den Text</li> <li><code>llama3.2-vision:11b</code> - Vision LLM (beste Qualitaet)</li> <li><code>trocr</code> - Microsoft Transformer (schnell)</li> <li><code>paddleocr</code> - PaddleOCR + LLM (4x schneller)</li> <li><code>donut</code> - Document Understanding (strukturiert)</li> <li>Labeling: Manuelles Pruefen und Korrigieren der OCR-Ergebnisse</li> <li>Export: Gelabelte Daten koennen exportiert werden fuer:</li> <li>TrOCR Fine-Tuning</li> <li>Llama Vision Fine-Tuning</li> <li>Generic JSON</li> </ul>"},{"location":"services/ki-daten-pipeline/#2-rag-pipeline-verarbeitung","title":"2. RAG Pipeline (Verarbeitung)","text":"<p>Die RAG Pipeline verarbeitet Dokumente und macht sie suchbar:</p> <pre><code>flowchart TD\n A[Datenquellen] --&gt; B[OCR/Text-Extraktion]\n B --&gt; C[Chunking]\n C --&gt; D[Embedding]\n D --&gt; E[Qdrant Indexierung]\n\n subgraph sources[\"Datenquellen\"]\n S1[NiBiS PDFs]\n S2[Eigene EH]\n S3[Rechtskorpus]\n S4[Schulordnungen]\n end</code></pre> <p>Verarbeitungsschritte:</p> <ol> <li>Dokumentenextraktion: PDFs und Bilder werden per OCR in Text umgewandelt</li> <li>Chunking: Lange Texte werden in Abschnitte aufgeteilt</li> <li>Chunk-Groesse: 1000 Zeichen</li> <li>Ueberlappung: 200 Zeichen</li> <li>Embedding: Jeder Chunk wird in einen Vektor umgewandelt</li> <li>Modell: <code>text-embedding-3-small</code></li> <li>Dimensionen: 1536</li> <li>Indexierung: Vektoren werden in Qdrant gespeichert</li> </ol>"},{"location":"services/ki-daten-pipeline/#3-daten-rag-ausgabe","title":"3. Daten &amp; RAG (Ausgabe)","text":"<p>Das Daten &amp; RAG Modul ermoeglicht die Verwaltung und Suche:</p> <ul> <li>Collection-Uebersicht: Status aller Qdrant Collections</li> <li>Semantische Suche: Fragen werden in Vektoren umgewandelt und aehnliche Dokumente gefunden</li> <li>Regulierungs-Mapping: Zeigt welche Regulierungen indexiert sind</li> </ul>"},{"location":"services/ki-daten-pipeline/#qdrant-collections","title":"Qdrant Collections","text":"Collection Inhalt Status <code>bp_nibis_eh</code> Offizielle NiBiS Erwartungshorizonte Aktiv <code>bp_eh</code> Benutzerdefinierte Erwartungshorizonte Aktiv <code>bp_schulordnungen</code> Schulordnungen aller Bundeslaender In Arbeit <code>bp_legal_corpus</code> 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":"<pre><code>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 --&gt; B1\n F2 --&gt; B2\n F3 --&gt; B3\n\n B1 --&gt; D1\n B1 --&gt; D3\n B2 --&gt; D2\n B3 --&gt; D2</code></pre>"},{"location":"services/ki-daten-pipeline/#backend-endpunkte","title":"Backend-Endpunkte","text":""},{"location":"services/ki-daten-pipeline/#ocr-labeling-apiv1ocr-label","title":"OCR-Labeling (<code>/api/v1/ocr-label/</code>)","text":"Endpoint Methode Beschreibung <code>/sessions</code> GET/POST Session-Verwaltung <code>/sessions/{id}/upload</code> POST Bilder hochladen <code>/queue</code> GET Labeling-Queue <code>/confirm</code> POST OCR bestaetigen <code>/correct</code> POST OCR korrigieren <code>/skip</code> POST Item ueberspringen <code>/stats</code> GET Statistiken <code>/export</code> POST Trainingsdaten exportieren"},{"location":"services/ki-daten-pipeline/#rag-pipeline-apiairag-pipeline","title":"RAG Pipeline (<code>/api/ai/rag-pipeline</code>)","text":"Action Beschreibung <code>jobs</code> Indexierungs-Jobs auflisten <code>dataset-stats</code> Datensatz-Statistiken <code>create-job</code> Neue Indexierung starten <code>pause</code> Job pausieren <code>resume</code> Job fortsetzen <code>cancel</code> Job abbrechen"},{"location":"services/ki-daten-pipeline/#legal-corpus-apilegal-corpus","title":"Legal Corpus (<code>/api/legal-corpus/</code>)","text":"Endpoint Beschreibung <code>/status</code> Collection-Status <code>/search</code> Semantische Suche <code>/ingest</code> Dokumente indexieren"},{"location":"services/ki-daten-pipeline/#integration-mit-klausur-korrektur","title":"Integration mit Klausur-Korrektur","text":"<p>Die KI-Daten-Pipeline liefert Erwartungshorizont-Vorschlaege fuer die Klausur-Korrektur:</p> <pre><code>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-&gt;&gt;K: Schueler-Antwort pruefen\n K-&gt;&gt;R: EH-Vorschlaege laden\n R-&gt;&gt;Q: Semantische Suche\n Q-&gt;&gt;R: Top-k Chunks\n R-&gt;&gt;K: Relevante EH-Passagen\n K-&gt;&gt;L: Bewertungsvorschlaege</code></pre>"},{"location":"services/ki-daten-pipeline/#deployment","title":"Deployment","text":"<p>Die Module werden als Teil des admin-v2 Containers deployed:</p> <pre><code># 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 &amp; Deploy\nssh macmini \"/usr/local/bin/docker compose \\\n -f /Users/benjaminadmin/Projekte/breakpilot-pwa/docker-compose.yml \\\n build --no-cache admin-v2 &amp;&amp; \\\n /usr/local/bin/docker compose \\\n -f /Users/benjaminadmin/Projekte/breakpilot-pwa/docker-compose.yml \\\n up -d admin-v2\"\n</code></pre>"},{"location":"services/ki-daten-pipeline/#verwandte-dokumentation","title":"Verwandte Dokumentation","text":"<ul> <li>OCR Labeling Spezifikation</li> <li>RAG Admin Spezifikation</li> <li>NiBiS Ingestion Pipeline</li> <li>Multi-Agent Architektur</li> </ul>"},{"location":"services/ki-daten-pipeline/architecture/","title":"KI-Daten-Pipeline Architektur","text":"<p>Diese Seite dokumentiert die technische Architektur der KI-Daten-Pipeline im Detail.</p>"},{"location":"services/ki-daten-pipeline/architecture/#systemuebersicht","title":"Systemuebersicht","text":"<pre><code>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&lt;br/&gt;/ai/ocr-labeling\"]\n F2[\"RAG Pipeline&lt;br/&gt;/ai/rag-pipeline\"]\n F3[\"Daten &amp; RAG&lt;br/&gt;/ai/rag\"]\n F4[\"Klausur-Korrektur&lt;br/&gt;/ai/klausur-korrektur\"]\n end\n\n subgraph Backend[\"Backend Services\"]\n direction TB\n B1[\"klausur-service&lt;br/&gt;Port 8086\"]\n B2[\"embedding-service&lt;br/&gt;Port 8087\"]\n end\n\n subgraph Storage[\"Persistenz\"]\n direction TB\n D1[(PostgreSQL&lt;br/&gt;Metadaten)]\n D2[(Qdrant&lt;br/&gt;Vektoren)]\n D3[(MinIO&lt;br/&gt;Bilder/PDFs)]\n end\n\n subgraph External[\"Externe APIs\"]\n E1[OpenAI API]\n E2[Ollama]\n end\n\n U1 --&gt; F1\n U2 --&gt; F2\n U3 --&gt; F4\n\n F1 --&gt; B1\n F2 --&gt; B1\n F3 --&gt; B1\n F4 --&gt; B1\n\n B1 --&gt; D1\n B1 --&gt; D2\n B1 --&gt; D3\n B1 --&gt; B2\n\n B2 --&gt; E1\n B1 --&gt; E2</code></pre>"},{"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":"<pre><code>flowchart TB\n subgraph Upload[\"Upload-Prozess\"]\n U1[Bilder hochladen] --&gt; U2[MinIO speichern]\n U2 --&gt; U3[Session erstellen]\n end\n\n subgraph OCR[\"OCR-Verarbeitung\"]\n O1[Bild laden] --&gt; O2{Modell w\u00e4hlen}\n O2 --&gt;|llama3.2-vision| O3a[Vision LLM]\n O2 --&gt;|trocr| O3b[Transformer]\n O2 --&gt;|paddleocr| O3c[PaddleOCR]\n O2 --&gt;|donut| O3d[Document AI]\n O3a --&gt; O4[OCR-Text]\n O3b --&gt; O4\n O3c --&gt; O4\n O3d --&gt; O4\n end\n\n subgraph Labeling[\"Labeling-Prozess\"]\n L1[Queue laden] --&gt; L2[Item anzeigen]\n L2 --&gt; L3{Entscheidung}\n L3 --&gt;|korrekt| L4[Bestaetigen]\n L3 --&gt;|falsch| L5[Korrigieren]\n L3 --&gt;|unklar| L6[Ueberspringen]\n L4 --&gt; L7[PostgreSQL]\n L5 --&gt; L7\n L6 --&gt; L7\n end\n\n subgraph Export[\"Export\"]\n E1[Gelabelte Items] --&gt; E2{Format}\n E2 --&gt;|TrOCR| E3a[Transformer Format]\n E2 --&gt;|Llama| E3b[Vision Format]\n E2 --&gt;|Generic| E3c[JSON]\n end\n\n Upload --&gt; OCR\n OCR --&gt; Labeling\n Labeling --&gt; Export</code></pre>"},{"location":"services/ki-daten-pipeline/architecture/#rag-pipeline-modul","title":"RAG Pipeline Modul","text":"<pre><code>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] --&gt; P2[OCR falls noetig]\n P2 --&gt; P3[Text Cleaning]\n P3 --&gt; P4[Chunking&lt;br/&gt;1000 chars, 200 overlap]\n P4 --&gt; P5[Metadata Extraction]\n end\n\n subgraph Embedding[\"Embedding\"]\n E1[embedding-service] --&gt; E2[OpenAI API]\n E2 --&gt; E3[1536-dim Vektor]\n end\n\n subgraph Indexing[\"Indexierung\"]\n I1{Collection waehlen}\n I1 --&gt;|EH| I2a[bp_nibis_eh]\n I1 --&gt;|Custom| I2b[bp_eh]\n I1 --&gt;|Legal| I2c[bp_legal_corpus]\n I1 --&gt;|Schul| I2d[bp_schulordnungen]\n I2a --&gt; I3[Qdrant upsert]\n I2b --&gt; I3\n I2c --&gt; I3\n I2d --&gt; I3\n end\n\n Sources --&gt; Processing\n Processing --&gt; Embedding\n Embedding --&gt; Indexing</code></pre>"},{"location":"services/ki-daten-pipeline/architecture/#daten-rag-modul","title":"Daten &amp; RAG Modul","text":"<pre><code>flowchart TB\n subgraph Query[\"Suchanfrage\"]\n Q1[User Query] --&gt; Q2[Query Embedding]\n Q2 --&gt; Q3[1536-dim Vektor]\n end\n\n subgraph Search[\"Qdrant Suche\"]\n S1[Collection waehlen] --&gt; S2[Vector Search]\n S2 --&gt; S3[Top-k Results]\n S3 --&gt; S4[Score Filtering]\n end\n\n subgraph Results[\"Ergebnisse\"]\n R1[Chunks] --&gt; R2[Metadata anreichern]\n R2 --&gt; R3[Source URLs]\n R3 --&gt; R4[Response]\n end\n\n Query --&gt; Search\n Search --&gt; Results</code></pre>"},{"location":"services/ki-daten-pipeline/architecture/#datenmodelle","title":"Datenmodelle","text":""},{"location":"services/ki-daten-pipeline/architecture/#ocr-labeling","title":"OCR-Labeling","text":"<pre><code>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</code></pre>"},{"location":"services/ki-daten-pipeline/architecture/#rag-pipeline","title":"RAG Pipeline","text":"<pre><code>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</code></pre>"},{"location":"services/ki-daten-pipeline/architecture/#legal-corpus","title":"Legal Corpus","text":"<pre><code>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</code></pre>"},{"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 <code>bp_nibis_eh</code> 1536 COSINE bundesland, fach, aufgabe <code>bp_eh</code> 1536 COSINE user_id, klausur_id <code>bp_legal_corpus</code> 1536 COSINE regulation, article, source_url <code>bp_schulordnungen</code> 1536 COSINE bundesland, typ, datum"},{"location":"services/ki-daten-pipeline/architecture/#chunk-strategie","title":"Chunk-Strategie","text":"<pre><code>\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</code></pre>"},{"location":"services/ki-daten-pipeline/architecture/#api-authentifizierung","title":"API-Authentifizierung","text":"<p>Alle Endpunkte nutzen die zentrale Auth-Middleware:</p> <pre><code>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-&gt;&gt;A: Request + JWT Token\n A-&gt;&gt;A: Token validieren\n A-&gt;&gt;S: Forwarded Request\n S-&gt;&gt;D: Daten abfragen\n D-&gt;&gt;S: Response\n S-&gt;&gt;C: JSON Response</code></pre>"},{"location":"services/ki-daten-pipeline/architecture/#monitoring-metriken","title":"Monitoring &amp; Metriken","text":""},{"location":"services/ki-daten-pipeline/architecture/#verfuegbare-metriken","title":"Verfuegbare Metriken","text":"Metrik Beschreibung Endpoint <code>ocr_items_total</code> Gesamtzahl OCR-Items <code>/api/v1/ocr-label/stats</code> <code>ocr_accuracy_rate</code> OCR-Genauigkeit <code>/api/v1/ocr-label/stats</code> <code>rag_chunk_count</code> Anzahl indexierter Chunks <code>/api/legal-corpus/status</code> <code>rag_collection_status</code> Collection-Status <code>/api/legal-corpus/status</code>"},{"location":"services/ki-daten-pipeline/architecture/#logging","title":"Logging","text":"<pre><code># 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</code></pre>"},{"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":"<pre><code>flowchart TD\n A[Embedding Request] --&gt; B{OpenAI verfuegbar?}\n B --&gt;|Ja| C[OpenAI API]\n B --&gt;|Nein| D{Lokales Modell?}\n D --&gt;|Ja| E[Ollama Embedding]\n D --&gt;|Nein| F[Error + Queue]</code></pre>"},{"location":"services/ki-daten-pipeline/architecture/#skalierung","title":"Skalierung","text":""},{"location":"services/ki-daten-pipeline/architecture/#aktueller-stand","title":"Aktueller Stand","text":"<ul> <li>Single Node: Alle Services auf Mac Mini</li> <li>Qdrant: Standalone, ~50k Chunks</li> <li>PostgreSQL: Shared mit anderen Services</li> </ul>"},{"location":"services/ki-daten-pipeline/architecture/#geplante-erweiterungen","title":"Geplante Erweiterungen","text":"<ol> <li>Qdrant Cluster: Bei &gt; 1M Chunks</li> <li>Worker Queue: Redis-basiert fuer Batch-Jobs</li> <li>GPU-Offloading: OCR auf vast.ai GPU-Instanzen</li> </ol>"},{"location":"services/klausur-service/","title":"Klausur-Service","text":"<p>Der Klausur-Service ist ein FastAPI-basierter Microservice fuer KI-gestuetzte Abitur-Klausurkorrektur.</p>"},{"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":"<ul> <li>OCR-Erkennung: Automatische Texterkennung aus gescannten Klausuren</li> <li>KI-Bewertung: Automatische Bewertungsvorschlaege basierend auf Erwartungshorizont</li> <li>BYOEH: Bring-Your-Own-Expectation-Horizon mit Client-seitiger Verschluesselung</li> <li>Fairness-Analyse: Statistische Analyse der Bewertungskonsistenz</li> <li>PDF-Export: Gutachten und Notenuebersichten als PDF</li> <li>Zweitkorrektur: Vollstaendiger Workflow fuer Erst-, Zweit- und Drittkorrektur</li> </ul>"},{"location":"services/klausur-service/#architektur","title":"Architektur","text":"<pre><code>\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</code></pre>"},{"location":"services/klausur-service/#api-endpoints","title":"API Endpoints","text":""},{"location":"services/klausur-service/#klausur-verwaltung","title":"Klausur-Verwaltung","text":"Method Endpoint Beschreibung GET <code>/api/v1/klausuren</code> Liste aller Klausuren POST <code>/api/v1/klausuren</code> Neue Klausur erstellen GET <code>/api/v1/klausuren/{id}</code> Klausur-Details DELETE <code>/api/v1/klausuren/{id}</code> Klausur loeschen"},{"location":"services/klausur-service/#studenten-arbeiten","title":"Studenten-Arbeiten","text":"Method Endpoint Beschreibung POST <code>/api/v1/klausuren/{id}/students</code> Arbeit hochladen GET <code>/api/v1/klausuren/{id}/students</code> Studenten-Liste GET <code>/api/v1/students/{id}</code> Einzelne Arbeit PUT <code>/api/v1/students/{id}/criteria</code> Kriterien bewerten PUT <code>/api/v1/students/{id}/gutachten</code> Gutachten speichern"},{"location":"services/klausur-service/#ki-funktionen","title":"KI-Funktionen","text":"Method Endpoint Beschreibung POST <code>/api/v1/students/{id}/gutachten/generate</code> Gutachten generieren GET <code>/api/v1/klausuren/{id}/fairness</code> Fairness-Analyse POST <code>/api/v1/students/{id}/eh-suggestions</code> EH-Vorschlaege via RAG"},{"location":"services/klausur-service/#pdf-export","title":"PDF-Export","text":"Method Endpoint Beschreibung GET <code>/api/v1/students/{id}/export/gutachten</code> Einzelgutachten PDF GET <code>/api/v1/students/{id}/export/annotations</code> Anmerkungen PDF GET <code>/api/v1/klausuren/{id}/export/overview</code> Notenuebersicht PDF GET <code>/api/v1/klausuren/{id}/export/all-gutachten</code> Alle Gutachten PDF"},{"location":"services/klausur-service/#notensystem","title":"Notensystem","text":"<p>Das System verwendet das deutsche 15-Punkte-System fuer Abiturklausuren:</p> Punkte Prozent Note 15 &gt;= 95% 1+ 14 &gt;= 90% 1 13 &gt;= 85% 1- 12 &gt;= 80% 2+ 11 &gt;= 75% 2 10 &gt;= 70% 2- 9 &gt;= 65% 3+ 8 &gt;= 60% 3 7 &gt;= 55% 3- 6 &gt;= 50% 4+ 5 &gt;= 45% 4 4 &gt;= 40% 4- 3 &gt;= 33% 5+ 2 &gt;= 27% 5 1 &gt;= 20% 5- 0 &lt; 20% 6"},{"location":"services/klausur-service/#bewertungskriterien","title":"Bewertungskriterien","text":"Kriterium Gewicht Beschreibung Rechtschreibung 15% Orthografie Grammatik 15% Grammatik &amp; Syntax Inhalt 40% Inhaltliche Qualitaet Struktur 15% Aufbau &amp; Gliederung Stil 15% Ausdruck &amp; Stil"},{"location":"services/klausur-service/#verzeichnisstruktur","title":"Verzeichnisstruktur","text":"<pre><code>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</code></pre>"},{"location":"services/klausur-service/#konfiguration","title":"Konfiguration","text":""},{"location":"services/klausur-service/#umgebungsvariablen","title":"Umgebungsvariablen","text":"<pre><code># 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</code></pre>"},{"location":"services/klausur-service/#weiterfuhrende-dokumentation","title":"Weiterf\u00fchrende Dokumentation","text":"<ul> <li>BYOEH Architektur - Client-seitige Verschluesselung</li> <li>OCR Compare - Block Review Feature fuer OCR-Vergleich</li> <li>Zeugnis-System - Zeugniserstellung</li> <li>Backend API - Allgemeine API-Dokumentation</li> </ul>"},{"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":"<p>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:</p> <ul> <li>Tenant Isolation: Each teacher/school has an isolated namespace</li> <li>No Training Guarantee: EH content is only used for RAG, never for model training</li> <li>Operator Blindness: Client-side encryption ensures Breakpilot cannot view plaintext</li> <li>Rights Confirmation: Required legal acknowledgment at upload time</li> </ul>"},{"location":"services/klausur-service/BYOEH-Architecture/#architecture-diagram","title":"Architecture Diagram","text":"<pre><code>\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</code></pre>"},{"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":"<pre><code>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</code></pre>"},{"location":"services/klausur-service/BYOEH-Architecture/#2-indexing-flow-rag-preparation","title":"2. Indexing Flow (RAG Preparation)","text":"<pre><code>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</code></pre>"},{"location":"services/klausur-service/BYOEH-Architecture/#3-rag-query-flow","title":"3. RAG Query Flow","text":"<pre><code>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</code></pre>"},{"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":"<pre><code>\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</code></pre>"},{"location":"services/klausur-service/BYOEH-Architecture/#security-guarantees","title":"Security Guarantees","text":"Guarantee Implementation No Training <code>training_allowed: false</code> on all Qdrant points Operator Blindness Passphrase never leaves browser; server only sees key hash Tenant Isolation Every query filtered by <code>tenant_id</code> Audit Trail All actions logged with timestamps"},{"location":"services/klausur-service/BYOEH-Architecture/#key-sharing-system","title":"Key Sharing System","text":"<p>The key sharing system enables first examiners to grant access to their EH to second examiners and supervisors.</p>"},{"location":"services/klausur-service/BYOEH-Architecture/#share-flow","title":"Share Flow","text":"<pre><code>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</code></pre>"},{"location":"services/klausur-service/BYOEH-Architecture/#data-structures","title":"Data Structures","text":"<pre><code>@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</code></pre>"},{"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 <code>/api/v1/eh/upload</code> Upload encrypted EH GET <code>/api/v1/eh</code> List user's EH GET <code>/api/v1/eh/{id}</code> Get single EH DELETE <code>/api/v1/eh/{id}</code> Soft delete EH POST <code>/api/v1/eh/{id}/index</code> Index EH for RAG POST <code>/api/v1/eh/rag-query</code> Query EH content"},{"location":"services/klausur-service/BYOEH-Architecture/#key-sharing-endpoints","title":"Key Sharing Endpoints","text":"Method Endpoint Description POST <code>/api/v1/eh/{id}/share</code> Share EH with examiner GET <code>/api/v1/eh/{id}/shares</code> List shares (owner) DELETE <code>/api/v1/eh/{id}/shares/{shareId}</code> Revoke share GET <code>/api/v1/eh/shared-with-me</code> List EH shared with user"},{"location":"services/klausur-service/BYOEH-Architecture/#klausur-integration-endpoints","title":"Klausur Integration Endpoints","text":"Method Endpoint Description POST <code>/api/v1/eh/{id}/link-klausur</code> Link EH to Klausur DELETE <code>/api/v1/eh/{id}/link-klausur/{klausurId}</code> Unlink EH GET <code>/api/v1/klausuren/{id}/linked-eh</code> Get linked EH for Klausur"},{"location":"services/klausur-service/BYOEH-Architecture/#audit-admin-endpoints","title":"Audit &amp; Admin Endpoints","text":"Method Endpoint Description GET <code>/api/v1/eh/audit-log</code> Get audit log GET <code>/api/v1/eh/rights-text</code> Get rights confirmation text GET <code>/api/v1/eh/qdrant-status</code> 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":"<p>5-step wizard for uploading Erwartungshorizonte:</p> <ol> <li>File Selection - Choose PDF file</li> <li>Metadata - Title, Subject, Niveau, Year</li> <li>Rights Confirmation - Legal acknowledgment</li> <li>Encryption - Set passphrase (2x confirmation)</li> <li>Summary - Review and upload</li> </ol>"},{"location":"services/klausur-service/BYOEH-Architecture/#integration-points","title":"Integration Points","text":"<ul> <li>KorrekturPage: Shows EH prompt after first student upload</li> <li>GutachtenGeneration: Uses RAG context from linked EH</li> <li>Sidebar Badge: Shows linked EH count</li> </ul>"},{"location":"services/klausur-service/BYOEH-Architecture/#file-structure","title":"File Structure","text":"<pre><code>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</code></pre>"},{"location":"services/klausur-service/BYOEH-Architecture/#configuration","title":"Configuration","text":""},{"location":"services/klausur-service/BYOEH-Architecture/#environment-variables","title":"Environment Variables","text":"<pre><code>QDRANT_URL=http://qdrant:6333\nOPENAI_API_KEY=sk-... # For embeddings\nBYOEH_ENCRYPTION_ENABLED=true\nEH_UPLOAD_DIR=/app/eh-uploads\n</code></pre>"},{"location":"services/klausur-service/BYOEH-Architecture/#docker-services","title":"Docker Services","text":"<pre><code># 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</code></pre>"},{"location":"services/klausur-service/BYOEH-Architecture/#audit-events","title":"Audit Events","text":"Action Description <code>upload</code> EH uploaded <code>index</code> EH indexed for RAG <code>rag_query</code> RAG query executed <code>delete</code> EH soft deleted <code>share</code> EH shared with examiner <code>revoke_share</code> Share revoked <code>link_klausur</code> EH linked to Klausur <code>unlink_klausur</code> EH unlinked from Klausur"},{"location":"services/klausur-service/BYOEH-Architecture/#see-also","title":"See Also","text":"<ul> <li>Zeugnis-System Architektur</li> <li>Klausur-Service Index</li> </ul>"},{"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":"<ul> <li>Python 3.10+</li> <li>Node.js 18+</li> <li>Docker &amp; Docker Compose</li> <li>OpenAI API Key (for embeddings)</li> </ul>"},{"location":"services/klausur-service/BYOEH-Developer-Guide/#setup","title":"Setup","text":"<ol> <li> <p>Start services: <pre><code>docker-compose up -d qdrant\n</code></pre></p> </li> <li> <p>Configure environment: <pre><code>QDRANT_URL=http://localhost:6333\nOPENAI_API_KEY=sk-your-key\nBYOEH_ENCRYPTION_ENABLED=true\n</code></pre></p> </li> <li> <p>Run klausur-service: <pre><code>cd klausur-service/backend\npip install -r requirements.txt\nuvicorn main:app --reload --port 8086\n</code></pre></p> </li> <li> <p>Run frontend: <pre><code>cd klausur-service/frontend\nnpm install\nnpm run dev\n</code></pre></p> </li> </ol>"},{"location":"services/klausur-service/BYOEH-Developer-Guide/#client-side-encryption","title":"Client-Side Encryption","text":"<p>The encryption service (<code>encryption.ts</code>) handles all cryptographic operations in the browser:</p>"},{"location":"services/klausur-service/BYOEH-Developer-Guide/#encrypting-a-file","title":"Encrypting a File","text":"<pre><code>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</code></pre>"},{"location":"services/klausur-service/BYOEH-Developer-Guide/#decrypting-content","title":"Decrypting Content","text":"<pre><code>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</code></pre>"},{"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":"<pre><code># 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\": &lt;encrypted_blob&gt;,\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</code></pre>"},{"location":"services/klausur-service/BYOEH-Developer-Guide/#index-for-rag","title":"Index for RAG","text":"<pre><code>POST /api/v1/eh/{eh_id}/index\nContent-Type: application/json\n\n{\n \"passphrase\": \"user-secret-password\"\n}\n</code></pre> <p>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</p>"},{"location":"services/klausur-service/BYOEH-Developer-Guide/#rag-query","title":"RAG Query","text":"<pre><code>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</code></pre> <p>Response: <pre><code>{\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</code></pre></p>"},{"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":"<p>The invitation flow provides a two-phase sharing process: Invite -&gt; Accept</p> <pre><code>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</code></pre>"},{"location":"services/klausur-service/BYOEH-Developer-Guide/#invitation-management","title":"Invitation Management","text":"<pre><code>// 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</code></pre>"},{"location":"services/klausur-service/BYOEH-Developer-Guide/#direct-sharing-legacy","title":"Direct Sharing (Legacy)","text":"<p>For immediate sharing without invitation:</p> <pre><code>// 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</code></pre>"},{"location":"services/klausur-service/BYOEH-Developer-Guide/#accessing-shared-eh","title":"Accessing Shared EH","text":"<pre><code>// 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</code></pre>"},{"location":"services/klausur-service/BYOEH-Developer-Guide/#revoking-access","title":"Revoking Access","text":"<pre><code>// List all shares for an EH\nconst shares = await ehApi.listShares(ehId)\n\n// Revoke a share\nawait ehApi.revokeShare(ehId, shareId)\n</code></pre>"},{"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":"<p>The <code>KorrekturPage</code> shows an EH upload prompt after the first student work is uploaded:</p> <pre><code>// In KorrekturPage.tsx\nuseEffect(() =&gt; {\n if (\n currentKlausur?.students.length === 1 &amp;&amp;\n linkedEHs.length === 0 &amp;&amp;\n !ehPromptDismissed\n ) {\n setShowEHPrompt(true)\n }\n}, [currentKlausur?.students.length])\n</code></pre>"},{"location":"services/klausur-service/BYOEH-Developer-Guide/#linking-eh-to-klausur","title":"Linking EH to Klausur","text":"<pre><code>// 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</code></pre>"},{"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":"<pre><code>interface EHUploadWizardProps {\n onClose: () =&gt; void\n onComplete?: (ehId: string) =&gt; 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&lt;EHUploadWizard\n onClose={() =&gt; setShowWizard(false)}\n onComplete={(ehId) =&gt; console.log('Uploaded:', ehId)}\n defaultSubject={klausur.subject}\n defaultYear={klausur.year}\n klausurId={klausur.id}\n/&gt;\n</code></pre>"},{"location":"services/klausur-service/BYOEH-Developer-Guide/#wizard-steps","title":"Wizard Steps","text":"<ol> <li>file - PDF file selection with drag &amp; drop</li> <li>metadata - Form for title, subject, niveau, year</li> <li>rights - Rights confirmation checkbox</li> <li>encryption - Passphrase input with strength meter</li> <li>summary - Review and confirm upload</li> </ol>"},{"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":"<pre><code># 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</code></pre>"},{"location":"services/klausur-service/BYOEH-Developer-Guide/#tenant-isolated-search","title":"Tenant-Isolated Search","text":"<pre><code>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</code></pre>"},{"location":"services/klausur-service/BYOEH-Developer-Guide/#testing","title":"Testing","text":""},{"location":"services/klausur-service/BYOEH-Developer-Guide/#unit-tests","title":"Unit Tests","text":"<pre><code>cd klausur-service/backend\npytest tests/test_byoeh.py -v\n</code></pre>"},{"location":"services/klausur-service/BYOEH-Developer-Guide/#test-structure","title":"Test Structure","text":"<pre><code># 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</code></pre>"},{"location":"services/klausur-service/BYOEH-Developer-Guide/#frontend-tests","title":"Frontend Tests","text":"<pre><code>// EHUploadWizard.test.tsx\ndescribe('EHUploadWizard', () =&gt; {\n it('completes all steps successfully', async () =&gt; {\n // ...\n })\n\n it('validates passphrase strength', async () =&gt; {\n // ...\n })\n\n it('auto-links to klausur when klausurId provided', async () =&gt; {\n // ...\n })\n})\n</code></pre>"},{"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 <code>Passphrase verification failed</code> Wrong passphrase Ask user to re-enter <code>EH not found</code> Invalid ID or deleted Check ID, reload list <code>Access denied</code> User not owner/shared Check permissions <code>Qdrant connection failed</code> Service unavailable Check Qdrant container"},{"location":"services/klausur-service/BYOEH-Developer-Guide/#error-response-format","title":"Error Response Format","text":"<pre><code>{\n \"detail\": \"Passphrase verification failed\"\n}\n</code></pre>"},{"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":"<ul> <li>Store key hash, never the key itself</li> <li>Always filter by tenant_id</li> <li>Log all access in audit trail</li> <li>Use HTTPS in production</li> </ul>"},{"location":"services/klausur-service/BYOEH-Developer-Guide/#donts","title":"Don'ts","text":"<ul> <li>Never log passphrase or decrypted content</li> <li>Never store passphrase in localStorage</li> <li>Never send passphrase as URL parameter</li> <li>Never return decrypted content without auth</li> </ul>"},{"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":"<pre><code>CHUNK_SIZE = 1000 # Characters per chunk\nCHUNK_OVERLAP = 200 # Overlap for context continuity\n</code></pre>"},{"location":"services/klausur-service/BYOEH-Developer-Guide/#embedding-batching","title":"Embedding Batching","text":"<pre><code># Generate embeddings in batches of 20\nEMBEDDING_BATCH_SIZE = 20\n</code></pre>"},{"location":"services/klausur-service/BYOEH-Developer-Guide/#qdrant-optimization","title":"Qdrant Optimization","text":"<pre><code># Use HNSW index for fast approximate search\n# Collection is automatically optimized on creation\n</code></pre>"},{"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":"<pre><code>import logging\nlogging.getLogger('byoeh').setLevel(logging.DEBUG)\n</code></pre>"},{"location":"services/klausur-service/BYOEH-Developer-Guide/#check-qdrant-status","title":"Check Qdrant Status","text":"<pre><code>curl http://localhost:6333/collections/bp_eh\n</code></pre>"},{"location":"services/klausur-service/BYOEH-Developer-Guide/#verify-encryption","title":"Verify Encryption","text":"<pre><code>import { isEncryptionSupported } from '../services/encryption'\n\nif (!isEncryptionSupported()) {\n console.error('Web Crypto API not available')\n}\n</code></pre>"},{"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":"<ol> <li>Added key sharing system</li> <li>Added Klausur linking</li> <li>EH prompt after student upload</li> </ol> <p>No database migrations required - all data structures are additive.</p>"},{"location":"services/klausur-service/NiBiS-Ingestion-Pipeline/","title":"NiBiS Ingestion Pipeline","text":""},{"location":"services/klausur-service/NiBiS-Ingestion-Pipeline/#overview","title":"Overview","text":"<p>Die NiBiS Ingestion Pipeline verarbeitet Abitur-Erwartungshorizonte aus Niedersachsen und indexiert sie in Qdrant f\u00fcr RAG-basierte Klausurkorrektur.</p>"},{"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 <code>docs/za-download</code> 2024, 2025 <code>{Jahr}_{Fach}_{niveau}_{Nr}_EWH.pdf</code> <code>docs/za-download-2</code> 2016 <code>{Jahr}{Fach}{Niveau}Lehrer/{Jahr}{Fach}{Niveau}A{Nr}L.pdf</code> <code>docs/za-download-3</code> 2017 <code>{Jahr}{Fach}{Niveau}Lehrer/{Jahr}{Fach}{Niveau}A{Nr}L.pdf</code>"},{"location":"services/klausur-service/NiBiS-Ingestion-Pipeline/#dokumenttypen","title":"Dokumenttypen","text":"<ul> <li>EWH - Erwartungshorizont (Hauptziel)</li> <li>Aufgabe - Pr\u00fcfungsaufgaben</li> <li>Material - Zusatzmaterialien</li> <li>GBU - Gef\u00e4hrdungsbeurteilung (Chemie/Biologie)</li> <li>Bewertungsbogen - Standardisierte Bewertungsb\u00f6gen</li> </ul>"},{"location":"services/klausur-service/NiBiS-Ingestion-Pipeline/#facher","title":"F\u00e4cher","text":"<p>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</p>"},{"location":"services/klausur-service/NiBiS-Ingestion-Pipeline/#architektur","title":"Architektur","text":"<pre><code>\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</code></pre>"},{"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":"<pre><code># 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</code></pre>"},{"location":"services/klausur-service/NiBiS-Ingestion-Pipeline/#via-cli","title":"Via CLI","text":"<pre><code># 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</code></pre>"},{"location":"services/klausur-service/NiBiS-Ingestion-Pipeline/#via-shell-script","title":"Via Shell Script","text":"<pre><code>./klausur-service/scripts/run_nibis_ingestion.sh --dry-run\n./klausur-service/scripts/run_nibis_ingestion.sh --year 2024 --subject Deutsch\n</code></pre>"},{"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: <code>bp_nibis_eh</code>","text":"<pre><code>{\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</code></pre>"},{"location":"services/klausur-service/NiBiS-Ingestion-Pipeline/#api-endpoints","title":"API Endpoints","text":"Methode Endpoint Beschreibung GET <code>/api/v1/admin/nibis/status</code> Ingestion-Status POST <code>/api/v1/admin/nibis/extract-zips</code> ZIP-Dateien entpacken GET <code>/api/v1/admin/nibis/discover</code> Dokumente finden POST <code>/api/v1/admin/nibis/ingest</code> Ingestion starten POST <code>/api/v1/admin/nibis/search</code> Semantische Suche GET <code>/api/v1/admin/nibis/stats</code> Statistiken GET <code>/api/v1/admin/nibis/collections</code> Qdrant Collections DELETE <code>/api/v1/admin/nibis/collection</code> Collection l\u00f6schen"},{"location":"services/klausur-service/NiBiS-Ingestion-Pipeline/#erweiterung-fur-andere-bundeslander","title":"Erweiterung f\u00fcr andere Bundesl\u00e4nder","text":"<p>Die Pipeline ist so designed, dass sie leicht erweitert werden kann:</p>"},{"location":"services/klausur-service/NiBiS-Ingestion-Pipeline/#1-neues-bundesland-hinzufugen","title":"1. Neues Bundesland hinzuf\u00fcgen","text":"<pre><code># 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) -&gt; Optional[Dict]:\n # Berlin-spezifische Namenskonvention\n pass\n</code></pre>"},{"location":"services/klausur-service/NiBiS-Ingestion-Pipeline/#2-neues-verzeichnis-registrieren","title":"2. Neues Verzeichnis registrieren","text":"<pre><code># 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</code></pre>"},{"location":"services/klausur-service/NiBiS-Ingestion-Pipeline/#3-dokumenttyp-erweiterung","title":"3. Dokumenttyp-Erweiterung","text":"<p>F\u00fcr Zeugnisgeneration oder andere Dokumenttypen:</p> <pre><code>DOC_TYPES = {\n \"EWH\": \"Erwartungshorizont\",\n \"ZEUGNIS_VORLAGE\": \"Zeugnisvorlage\",\n \"NOTENSPIEGEL\": \"Notenspiegel\",\n \"BEMERKUNG\": \"Bemerkungstexte\",\n}\n</code></pre>"},{"location":"services/klausur-service/NiBiS-Ingestion-Pipeline/#rechtliche-hinweise","title":"Rechtliche Hinweise","text":"<ul> <li>NiBiS-Daten sind unter den NiBiS-Nutzungsbedingungen frei nutzbar</li> <li><code>training_allowed: true</code> - Strukturelles Wissen darf f\u00fcr KI-Training genutzt werden</li> <li>F\u00fcr Lehrer-eigene Erwartungshorizonte (BYOEH) gilt: <code>training_allowed: false</code></li> </ul>"},{"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":"<pre><code># Pr\u00fcfen ob Qdrant l\u00e4uft\ncurl http://localhost:6333/health\n\n# Docker starten\ndocker-compose up -d qdrant\n</code></pre>"},{"location":"services/klausur-service/NiBiS-Ingestion-Pipeline/#openai-api-fehler","title":"OpenAI API Fehler","text":"<pre><code># API Key setzen\nexport OPENAI_API_KEY=sk-...\n</code></pre>"},{"location":"services/klausur-service/NiBiS-Ingestion-Pipeline/#pdf-extraktion-fehlgeschlagen","title":"PDF-Extraktion fehlgeschlagen","text":"<p>Einige PDFs k\u00f6nnen problematisch sein (gescannte Dokumente ohne OCR). Diese werden \u00fcbersprungen und im Error-Log protokolliert.</p>"},{"location":"services/klausur-service/NiBiS-Ingestion-Pipeline/#performance","title":"Performance","text":"<ul> <li>~500-1000 Chunks pro Minute (abh\u00e4ngig von OpenAI API)</li> <li>~2-3 GB Qdrant Storage f\u00fcr alle NiBiS-Daten (2016-2025)</li> <li>Embeddings werden nur einmal generiert (idempotent via Hash)</li> </ul>"},{"location":"services/klausur-service/OCR-Compare/","title":"OCR Compare - Block Review Feature","text":"<p>Status: Produktiv Letzte Aktualisierung: 2026-02-08 URL: https://macmini:3002/ai/ocr-compare</p>"},{"location":"services/klausur-service/OCR-Compare/#uebersicht","title":"Uebersicht","text":"<p>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.</p>"},{"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":"<pre><code>\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 &amp; 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</code></pre>"},{"location":"services/klausur-service/OCR-Compare/#komponenten","title":"Komponenten","text":""},{"location":"services/klausur-service/OCR-Compare/#gridoverlay","title":"GridOverlay","text":"<p>SVG-Overlay zur Visualisierung der erkannten Grid-Struktur.</p> <p>Datei: <code>/admin-v2/components/ocr/GridOverlay.tsx</code></p> <pre><code>interface GridOverlayProps {\n grid: GridData\n imageUrl?: string\n onCellClick?: (cell: GridCell) =&gt; 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</code></pre> <p>Zellenstatus-Farben:</p> Status Farbe Bedeutung <code>recognized</code> Gruen Text erfolgreich erkannt <code>problematic</code> Orange Niedriger Confidence-Wert <code>manual</code> Blau Manuell korrigiert <code>empty</code> Transparent Keine Erkennung"},{"location":"services/klausur-service/OCR-Compare/#blockreviewpanel","title":"BlockReviewPanel","text":"<p>Panel zur Block-fuer-Block Ueberpruefung der OCR-Ergebnisse.</p> <p>Datei: <code>/admin-v2/components/ocr/BlockReviewPanel.tsx</code></p> <pre><code>interface BlockReviewPanelProps {\n grid: GridData\n methodResults: Record&lt;string, { vocabulary: Array&lt;...&gt; }&gt;\n currentBlockNumber: number\n onBlockChange: (blockNumber: number) =&gt; void\n onApprove: (blockNumber: number, methodId: string, text: string) =&gt; void\n onCorrect: (blockNumber: number, correctedText: string) =&gt; void\n onSkip: (blockNumber: number) =&gt; void\n reviewData: Record&lt;number, BlockReviewData&gt;\n className?: string\n}\n</code></pre> <p>Review-Status:</p> Status Beschreibung <code>pending</code> Noch nicht ueberprueft <code>approved</code> OCR-Ergebnis akzeptiert <code>corrected</code> Manuell korrigiert <code>skipped</code> Uebersprungen"},{"location":"services/klausur-service/OCR-Compare/#blockreviewsummary","title":"BlockReviewSummary","text":"<p>Zusammenfassung aller ueberprueften Bloecke.</p> <pre><code>interface BlockReviewSummaryProps {\n reviewData: Record&lt;number, BlockReviewData&gt;\n totalBlocks: number\n onBlockClick: (blockNumber: number) =&gt; void\n className?: string\n}\n</code></pre>"},{"location":"services/klausur-service/OCR-Compare/#ocr-methoden","title":"OCR-Methoden","text":"ID Name Beschreibung <code>vision_llm</code> Vision LLM Qwen VL 32B ueber Ollama <code>tesseract</code> Tesseract Klassisches OCR (lokal) <code>paddleocr</code> PaddleOCR PaddleOCR Engine <code>claude_vision</code> 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 <code>/api/v1/vocab/upload-pdf-info</code> PDF hochladen GET <code>/api/v1/vocab/sessions/{id}</code> Session-Details DELETE <code>/api/v1/vocab/sessions/{id}</code> Session loeschen"},{"location":"services/klausur-service/OCR-Compare/#bildexport","title":"Bildexport","text":"Method Endpoint Beschreibung GET <code>/api/v1/vocab/sessions/{id}/pdf-thumbnail/{page}</code> Thumbnail (zoom=0.5) GET <code>/api/v1/vocab/sessions/{id}/pdf-thumbnail/{page}?hires=true</code> High-Res (zoom=2.0)"},{"location":"services/klausur-service/OCR-Compare/#grid-erkennung","title":"Grid-Erkennung","text":"Method Endpoint Beschreibung POST <code>/api/v1/vocab/sessions/{id}/detect-grid</code> Grid-Struktur erkennen POST <code>/api/v1/vocab/sessions/{id}/run-ocr</code> OCR auf Grid ausfuehren"},{"location":"services/klausur-service/OCR-Compare/#session-persistence","title":"Session Persistence","text":"<p>Die aktive Session wird im localStorage gespeichert:</p> <pre><code>// 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</code></pre>"},{"location":"services/klausur-service/OCR-Compare/#block-review-workflow","title":"Block Review Workflow","text":"<ol> <li>PDF hochladen - Dokument in das System laden</li> <li>Grid erkennen - Automatische Tabellenerkennung</li> <li>OCR ausfuehren - Alle Methoden parallel ausfuehren</li> <li>Block Review starten - \"Block Review\" Button klicken</li> <li>Bloecke pruefen - Fuer jeden Block:</li> <li>Ergebnisse aller Methoden vergleichen</li> <li>Bestes Ergebnis waehlen oder manuell korrigieren</li> <li>Zusammenfassung - Uebersicht der Korrekturen</li> </ol>"},{"location":"services/klausur-service/OCR-Compare/#high-resolution-bilder","title":"High-Resolution Bilder","text":"<p>Fuer die Anzeige werden hochaufloesende Bilder verwendet:</p> <pre><code>// Thumbnail URL mit High-Resolution Parameter\nconst imageUrl = `${KLAUSUR_API}/api/v1/vocab/sessions/${sessionId}/pdf-thumbnail/${pageNumber}?hires=true`\n</code></pre> Parameter Zoom Verwendung Ohne <code>hires</code> 0.5 Vorschau/Thumbnails Mit <code>hires=true</code> 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 <code>app/(admin)/ai/ocr-compare/page.tsx</code> Haupt-UI <code>components/ocr/GridOverlay.tsx</code> SVG Grid-Overlay <code>components/ocr/BlockReviewPanel.tsx</code> Review-Panel <code>components/ocr/CellCorrectionDialog.tsx</code> Korrektur-Dialog <code>components/ocr/index.ts</code> Exports"},{"location":"services/klausur-service/OCR-Compare/#backend-klausur-service","title":"Backend (klausur-service)","text":"Datei Beschreibung <code>vocab_worksheet_api.py</code> API-Router <code>hybrid_vocab_extractor.py</code> 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":"<p>Version: 1.1.0 Status: In Produktion (Mac Mini)</p>"},{"location":"services/klausur-service/OCR-Labeling-Spec/#ubersicht","title":"\u00dcbersicht","text":"<p>Das OCR-Labeling System erm\u00f6glicht das Erstellen von Trainingsdaten f\u00fcr Handschrift-OCR-Modelle aus eingescannten Klausuren. Es unterst\u00fctzt folgende OCR-Modelle:</p> 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":"<p>PaddleOCR ist ein zweistufiger Ansatz: 1. PaddleOCR - Schnelle, pr\u00e4zise Texterkennung mit Bounding-Boxes 2. qwen2.5:14b - Semantische Strukturierung des erkannten Texts</p> <p>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</p> <p>Dateien: - <code>/klausur-service/backend/hybrid_vocab_extractor.py</code> - PaddleOCR Integration</p>"},{"location":"services/klausur-service/OCR-Labeling-Spec/#donut-document-understanding-transformer","title":"Donut (Document Understanding Transformer)","text":"<p>Donut ist speziell f\u00fcr strukturierte Dokumente optimiert: - Tabellen und Formulare - Rechnungen und Quittungen - Multi-Spalten-Layouts</p> <p>Dateien: - <code>/klausur-service/backend/services/donut_ocr_service.py</code> - Donut Service</p>"},{"location":"services/klausur-service/OCR-Labeling-Spec/#architektur","title":"Architektur","text":"<pre><code>\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</code></pre>"},{"location":"services/klausur-service/OCR-Labeling-Spec/#datenmodell","title":"Datenmodell","text":""},{"location":"services/klausur-service/OCR-Labeling-Spec/#postgresql-tabellen","title":"PostgreSQL Tabellen","text":"<pre><code>-- 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</code></pre>"},{"location":"services/klausur-service/OCR-Labeling-Spec/#api-referenz","title":"API Referenz","text":"<p>Base URL: <code>http://macmini:8086/api/v1/ocr-label</code></p>"},{"location":"services/klausur-service/OCR-Labeling-Spec/#sessions","title":"Sessions","text":""},{"location":"services/klausur-service/OCR-Labeling-Spec/#post-sessions","title":"POST /sessions","text":"<p>Neue Labeling-Session erstellen.</p> <p>Request: <pre><code>{\n \"name\": \"Klausur Deutsch 12a Q1\",\n \"source_type\": \"klausur\",\n \"description\": \"Gedichtanalyse Expressionismus\",\n \"ocr_model\": \"llama3.2-vision:11b\"\n}\n</code></pre></p> <p>Response: <pre><code>{\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</code></pre></p>"},{"location":"services/klausur-service/OCR-Labeling-Spec/#get-sessions","title":"GET /sessions","text":"<p>Sessions auflisten.</p> <p>Query Parameter: - <code>limit</code> (int, default: 50) - Maximale Anzahl</p>"},{"location":"services/klausur-service/OCR-Labeling-Spec/#get-sessionssession_id","title":"GET /sessions/{session_id}","text":"<p>Einzelne Session abrufen.</p>"},{"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":"<p>Bilder zu einer Session hochladen.</p> <p>Request: Multipart Form Data - <code>files</code> (File[]) - PNG/JPG/PDF Dateien - <code>run_ocr</code> (bool, default: true) - OCR direkt ausf\u00fchren - <code>metadata</code> (JSON string) - Optional: Metadaten</p> <p>Response: <pre><code>{\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</code></pre></p>"},{"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":"<p>N\u00e4chste zu labelnde Items abrufen.</p> <p>Query Parameter: - <code>session_id</code> (str, optional) - Nach Session filtern - <code>status</code> (str, default: \"pending\") - Status-Filter - <code>limit</code> (int, default: 10) - Maximale Anzahl</p> <p>Response: <pre><code>[\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</code></pre></p>"},{"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":"<p>OCR-Text als korrekt best\u00e4tigen.</p> <p>Request: <pre><code>{\n \"item_id\": \"item-456\",\n \"label_time_seconds\": 5\n}\n</code></pre></p> <p>Effect: <code>ground_truth = ocr_text</code>, <code>status = 'confirmed'</code></p>"},{"location":"services/klausur-service/OCR-Labeling-Spec/#post-correct","title":"POST /correct","text":"<p>Ground Truth korrigieren.</p> <p>Request: <pre><code>{\n \"item_id\": \"item-456\",\n \"ground_truth\": \"Korrigierter Text hier\",\n \"label_time_seconds\": 15\n}\n</code></pre></p> <p>Effect: <code>ground_truth = &lt;input&gt;</code>, <code>status = 'corrected'</code></p>"},{"location":"services/klausur-service/OCR-Labeling-Spec/#post-skip","title":"POST /skip","text":"<p>Item \u00fcberspringen (unbrauchbar).</p> <p>Request: <pre><code>{\n \"item_id\": \"item-456\"\n}\n</code></pre></p> <p>Effect: <code>status = 'skipped'</code> (wird nicht exportiert)</p>"},{"location":"services/klausur-service/OCR-Labeling-Spec/#statistiken","title":"Statistiken","text":""},{"location":"services/klausur-service/OCR-Labeling-Spec/#get-stats","title":"GET /stats","text":"<p>Labeling-Statistiken abrufen.</p> <p>Query Parameter: - <code>session_id</code> (str, optional) - F\u00fcr Session-spezifische Stats</p> <p>Response: <pre><code>{\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</code></pre></p>"},{"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":"<p>Trainingsdaten exportieren.</p> <p>Request: <pre><code>{\n \"export_format\": \"trocr\",\n \"session_id\": \"abc-123\",\n \"batch_id\": \"batch_20260121\"\n}\n</code></pre></p> <p>Export Formate:</p> Format Beschreibung Output <code>generic</code> Allgemeines JSONL <code>{\"id\", \"image_path\", \"ground_truth\", ...}</code> <code>trocr</code> Microsoft TrOCR <code>{\"file_name\", \"text\", \"id\"}</code> <code>llama_vision</code> Llama 3.2 Vision OpenAI-style Messages mit image_url <p>Response: <pre><code>{\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</code></pre></p>"},{"location":"services/klausur-service/OCR-Labeling-Spec/#get-exports","title":"GET /exports","text":"<p>Verf\u00fcgbare Exports auflisten.</p> <p>Query Parameter: - <code>export_format</code> (str, optional) - Nach Format filtern</p>"},{"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":"<pre><code>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</code></pre> <p>train.jsonl: <pre><code>{\"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</code></pre></p>"},{"location":"services/klausur-service/OCR-Labeling-Spec/#llama-vision-format","title":"Llama Vision Format","text":"<pre><code>{\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</code></pre>"},{"location":"services/klausur-service/OCR-Labeling-Spec/#generic-format","title":"Generic Format","text":"<pre><code>{\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</code></pre>"},{"location":"services/klausur-service/OCR-Labeling-Spec/#frontend-integration","title":"Frontend Integration","text":"<p>Die OCR-Labeling UI ist unter <code>/admin/ocr-labeling</code> verf\u00fcgbar.</p>"},{"location":"services/klausur-service/OCR-Labeling-Spec/#keyboard-shortcuts","title":"Keyboard Shortcuts","text":"Taste Aktion <code>Enter</code> Best\u00e4tigen (OCR korrekt) <code>Tab</code> Ins Korrekturfeld springen <code>Escape</code> \u00dcberspringen <code>\u2190</code> / <code>\u2192</code> Navigation (Prev/Next)"},{"location":"services/klausur-service/OCR-Labeling-Spec/#workflow","title":"Workflow","text":"<ol> <li>Session erstellen - Name, Typ, OCR-Modell w\u00e4hlen</li> <li>Bilder hochladen - Drag &amp; Drop oder File-Browser</li> <li>Labeling durchf\u00fchren - Bild + OCR-Text vergleichen</li> <li>Korrekt \u2192 Best\u00e4tigen (Enter)</li> <li>Falsch \u2192 Korrigieren + Speichern</li> <li>Unbrauchbar \u2192 \u00dcberspringen</li> <li>Export - Format w\u00e4hlen (TrOCR, Llama Vision, Generic)</li> <li>Training starten - Export-Ordner f\u00fcr Fine-Tuning nutzen</li> </ol>"},{"location":"services/klausur-service/OCR-Labeling-Spec/#umgebungsvariablen","title":"Umgebungsvariablen","text":"<pre><code># 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</code></pre>"},{"location":"services/klausur-service/OCR-Labeling-Spec/#sicherheit-datenschutz","title":"Sicherheit &amp; Datenschutz","text":"<ul> <li>100% Lokale Verarbeitung - Alle Daten bleiben auf dem Mac Mini</li> <li>Keine Cloud-Uploads - Ollama l\u00e4uft vollst\u00e4ndig offline</li> <li>DSGVO-konform - Keine Sch\u00fclerdaten verlassen das Schulnetzwerk</li> <li>Deduplizierung - SHA256-Hash verhindert doppelte Bilder</li> </ul>"},{"location":"services/klausur-service/OCR-Labeling-Spec/#dateien","title":"Dateien","text":"Datei Beschreibung <code>klausur-service/backend/ocr_labeling_api.py</code> FastAPI Router mit OCR Model Dispatcher <code>klausur-service/backend/training_export_service.py</code> Export-Service f\u00fcr TrOCR/Llama <code>klausur-service/backend/metrics_db.py</code> PostgreSQL CRUD Funktionen <code>klausur-service/backend/minio_storage.py</code> MinIO OCR-Image Storage <code>klausur-service/backend/hybrid_vocab_extractor.py</code> PaddleOCR Integration <code>klausur-service/backend/services/donut_ocr_service.py</code> Donut OCR Service (NEU) <code>klausur-service/backend/services/trocr_service.py</code> TrOCR Service (NEU) <code>website/app/admin/ocr-labeling/page.tsx</code> Frontend UI mit Model-Auswahl <code>website/app/admin/ocr-labeling/types.ts</code> TypeScript Interfaces inkl. OCRModel Type"},{"location":"services/klausur-service/OCR-Labeling-Spec/#tests","title":"Tests","text":"<pre><code># 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</code></pre>"},{"location":"services/klausur-service/RAG-Admin-Spec/","title":"RAG &amp; Daten-Management Spezifikation","text":""},{"location":"services/klausur-service/RAG-Admin-Spec/#ubersicht","title":"\u00dcbersicht","text":"<p>Admin-Frontend f\u00fcr die Verwaltung von Trainingsdaten und RAG-Systemen in BreakPilot.</p> <p>Location: <code>/admin/docs</code> \u2192 Tab \"Daten &amp; RAG\" Backend: <code>klausur-service</code> (Port 8086) Storage: MinIO (persistentes Docker Volume <code>minio_data</code>) Vector DB: Qdrant (Port 6333)</p>"},{"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 <code>bp_{bundesland}_{usecase}</code> Lehrer-Daten Lehrer-Upload (BYOEH) \u274c Nein Pro Tenant (Schule/Lehrer) <code>bp_eh</code> (verschl\u00fcsselt)"},{"location":"services/klausur-service/RAG-Admin-Spec/#bundesland-codes-iso-3166-2de","title":"Bundesland-Codes (ISO 3166-2:DE)","text":"<pre><code>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</code></pre>"},{"location":"services/klausur-service/RAG-Admin-Spec/#use-cases-rag-sammlungen","title":"Use Cases (RAG-Sammlungen)","text":"Use Case Collection Pattern Beschreibung Klausurkorrektur <code>bp_{bl}_klausur</code> Erwartungshorizonte f\u00fcr Abitur Zeugnisgenerator <code>bp_{bl}_zeugnis</code> Textbausteine f\u00fcr Zeugnisse Lehrplan <code>bp_{bl}_lehrplan</code> Kerncurricula, Rahmenrichtlinien <p>Beispiel: <code>bp_ni_klausur</code> = Niedersachsen Klausurkorrektur</p>"},{"location":"services/klausur-service/RAG-Admin-Spec/#minio-bucket-struktur","title":"MinIO Bucket-Struktur","text":"<pre><code>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</code></pre>"},{"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. <code>bp_ni_klausur</code>)","text":"<pre><code>{\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</code></pre>"},{"location":"services/klausur-service/RAG-Admin-Spec/#lehrer-daten-collection-bp_eh","title":"Lehrer-Daten Collection (<code>bp_eh</code>)","text":"<pre><code>{\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</code></pre>"},{"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 (<code>/admin/rag/collections</code>)","text":"<pre><code>\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 &amp; 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</code></pre>"},{"location":"services/klausur-service/RAG-Admin-Spec/#2-upload-bereich-adminragupload","title":"2. Upload-Bereich (<code>/admin/rag/upload</code>)","text":"<pre><code>\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 &amp; 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</code></pre>"},{"location":"services/klausur-service/RAG-Admin-Spec/#3-ingestion-status-adminragingestion","title":"3. Ingestion-Status (<code>/admin/rag/ingestion</code>)","text":"<pre><code>\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</code></pre>"},{"location":"services/klausur-service/RAG-Admin-Spec/#4-suche-qualitatstest-adminragsearch","title":"4. Suche &amp; Qualit\u00e4tstest (<code>/admin/rag/search</code>)","text":"<pre><code>\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 &amp; 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</code></pre>"},{"location":"services/klausur-service/RAG-Admin-Spec/#5-metriken-dashboard-adminragmetrics","title":"5. Metriken-Dashboard (<code>/admin/rag/metrics</code>)","text":"<pre><code>\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 &lt;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</code></pre>"},{"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":"<pre><code>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</code></pre>"},{"location":"services/klausur-service/RAG-Admin-Spec/#upload-api","title":"Upload API","text":"<pre><code>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</code></pre>"},{"location":"services/klausur-service/RAG-Admin-Spec/#ingestion-api","title":"Ingestion API","text":"<pre><code>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</code></pre>"},{"location":"services/klausur-service/RAG-Admin-Spec/#search-api","title":"Search API","text":"<pre><code>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</code></pre>"},{"location":"services/klausur-service/RAG-Admin-Spec/#metrics-api","title":"Metrics API","text":"<pre><code>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</code></pre>"},{"location":"services/klausur-service/RAG-Admin-Spec/#embedding-konfiguration","title":"Embedding-Konfiguration","text":"<pre><code># 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</code></pre>"},{"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":"<pre><code>volumes:\n minio_data: # Alle hochgeladenen Dokumente\n qdrant_data: # Alle Vektoren und Embeddings\n postgres_data: # Metadaten, Bewertungen, History\n</code></pre>"},{"location":"services/klausur-service/RAG-Admin-Spec/#backup-strategie","title":"Backup-Strategie","text":"<pre><code># 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</code></pre>"},{"location":"services/klausur-service/RAG-Admin-Spec/#implementierungsreihenfolge","title":"Implementierungsreihenfolge","text":"<ol> <li>\u2705 Backend: Basis-Ingestion (nibis_ingestion.py)</li> <li>\u2705 Backend: Lokale Embeddings (sentence-transformers)</li> <li>\u2705 Backend: MinIO-Integration (minio_storage.py)</li> <li>\u2705 Backend: Collections API (admin_api.py)</li> <li>\u2705 Backend: Upload API mit ZIP-Support</li> <li>\u2705 Backend: Metrics API mit PostgreSQL (metrics_db.py)</li> <li>\u2705 Frontend: Sammlungen-\u00dcbersicht</li> <li>\u2705 Frontend: Upload-Bereich (Drag &amp; Drop)</li> <li>\u2705 Frontend: Ingestion-Status</li> <li>\u2705 Frontend: Suche &amp; Qualit\u00e4tstest (mit Stern-Bewertungen)</li> <li>\u2705 Frontend: Metriken-Dashboard</li> </ol>"},{"location":"services/klausur-service/RAG-Admin-Spec/#technologie-stack","title":"Technologie-Stack","text":"<ul> <li>Frontend: Next.js 15 (<code>/website/app/admin/rag/page.tsx</code>)</li> <li>Backend: FastAPI (<code>klausur-service/backend/</code>)</li> <li>Vector DB: Qdrant v1.7.4 (384-dim Vektoren)</li> <li>Object Storage: MinIO (S3-kompatibel)</li> <li>Embeddings: sentence-transformers <code>all-MiniLM-L6-v2</code></li> <li>Metrics DB: PostgreSQL 16</li> </ul>"},{"location":"services/klausur-service/RAG-Admin-Spec/#entwickler-dokumentation","title":"Entwickler-Dokumentation","text":""},{"location":"services/klausur-service/RAG-Admin-Spec/#projektstruktur","title":"Projektstruktur","text":"<pre><code>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</code></pre>"},{"location":"services/klausur-service/RAG-Admin-Spec/#schnellstart-fur-entwickler","title":"Schnellstart f\u00fcr Entwickler","text":"<pre><code># 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</code></pre>"},{"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":"<pre><code>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</code></pre>"},{"location":"services/klausur-service/RAG-Admin-Spec/#rag-upload-storage","title":"RAG Upload &amp; Storage","text":"<pre><code>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</code></pre>"},{"location":"services/klausur-service/RAG-Admin-Spec/#metrics-feedback","title":"Metrics &amp; Feedback","text":"<pre><code>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</code></pre>"},{"location":"services/klausur-service/RAG-Admin-Spec/#umgebungsvariablen","title":"Umgebungsvariablen","text":"<pre><code># 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</code></pre>"},{"location":"services/klausur-service/RAG-Admin-Spec/#aktuelle-indexierungs-statistik","title":"Aktuelle Indexierungs-Statistik","text":"<ul> <li>Dokumente: 579 Erwartungshorizonte (NiBiS)</li> <li>Chunks: 7.352</li> <li>Jahre: 2016, 2017, 2024, 2025</li> <li>F\u00e4cher: Deutsch, Englisch, Mathematik, Physik, Chemie, Biologie, Geschichte, Politik-Wirtschaft, Erdkunde, Sport, Kunst, Musik, Latein, Informatik, Ev. Religion, Kath. Religion, Werte und Normen, etc.</li> <li>Collection: <code>bp_nibis_eh</code></li> <li>Vektor-Dimensionen: 384</li> </ul>"},{"location":"services/klausur-service/Worksheet-Editor-Architecture/","title":"Visual Worksheet Editor - Architecture Documentation","text":"<p>Version: 1.0 Status: Implementiert</p>"},{"location":"services/klausur-service/Worksheet-Editor-Architecture/#1-ubersicht","title":"1. \u00dcbersicht","text":"<p>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.</p>"},{"location":"services/klausur-service/Worksheet-Editor-Architecture/#11-hauptfunktionen","title":"1.1 Hauptfunktionen","text":"<ul> <li>Canvas-basiertes Editieren mit Fabric.js</li> <li>Freie Positionierung von Text, Bildern und Formen</li> <li>Typografie-Steuerung (Schriftarten, Gr\u00f6\u00dfen, Stile)</li> <li>Bilder &amp; Grafiken hochladen und einf\u00fcgen</li> <li>KI-generierte Bilder via Ollama/Stable Diffusion</li> <li>PDF/Bild-Export f\u00fcr Druck und digitale Nutzung</li> <li>Mehrseitige Dokumente mit Seitennavigation</li> </ul>"},{"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":"<pre><code>\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</code></pre>"},{"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":"<pre><code>/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</code></pre>"},{"location":"services/klausur-service/Worksheet-Editor-Architecture/#32-backend-klausur-service","title":"3.2 Backend (klausur-service)","text":"<pre><code>/klausur-service/backend/\n\u251c\u2500\u2500 worksheet_editor_api.py # API Endpoints\n\u2514\u2500\u2500 main.py # Router-Registrierung\n</code></pre>"},{"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":"<pre><code>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</code></pre> <p>Response: <pre><code>{\n \"image_base64\": \"data:image/png;base64,...\",\n \"prompt_used\": \"...\",\n \"error\": null\n}\n</code></pre></p> <p>Styles: - <code>realistic</code> - Fotorealistisch - <code>cartoon</code> - Cartoon/Comic - <code>sketch</code> - Handgezeichnete Skizze - <code>clipart</code> - Einfache Clipart-Grafiken - <code>educational</code> - Bildungs-Illustrationen</p>"},{"location":"services/klausur-service/Worksheet-Editor-Architecture/#42-worksheet-speichern","title":"4.2 Worksheet speichern","text":"<pre><code>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</code></pre>"},{"location":"services/klausur-service/Worksheet-Editor-Architecture/#43-worksheet-laden","title":"4.3 Worksheet laden","text":"<pre><code>GET /api/v1/worksheet/{id}\n</code></pre>"},{"location":"services/klausur-service/Worksheet-Editor-Architecture/#44-pdf-exportieren","title":"4.4 PDF exportieren","text":"<pre><code>POST /api/v1/worksheet/{id}/export-pdf\n</code></pre> <p>Response: PDF-Datei als Download</p>"},{"location":"services/klausur-service/Worksheet-Editor-Architecture/#45-worksheets-auflisten","title":"4.5 Worksheets auflisten","text":"<pre><code>GET /api/v1/worksheet/list/all\n</code></pre>"},{"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":"<p>Die Kernkomponente f\u00fcr den Canvas-Bereich:</p> <ul> <li>A4-Format: 794 x 1123 Pixel (96 DPI)</li> <li>Grid-Overlay: Optionales Raster mit Snap-Funktion</li> <li>Zoom/Pan: Mausrad und Controls</li> <li>Selection: Einzel- und Mehrfachauswahl</li> <li>Keyboard Shortcuts: Del, Ctrl+C/V/Z/D</li> </ul>"},{"location":"services/klausur-service/Worksheet-Editor-Architecture/#52-editortoolbar","title":"5.2 EditorToolbar","text":"<p>Werkzeuge f\u00fcr die Bearbeitung:</p> 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":"<p>Eigenschaften-Editor f\u00fcr ausgew\u00e4hlte Objekte:</p> <p>Text-Eigenschaften: - Schriftart (Arial, Times, Georgia, OpenDyslexic, Schulschrift) - Schriftgr\u00f6\u00dfe (8-120pt) - Schriftstil (Normal, Fett, Kursiv) - Zeilenh\u00f6he, Zeichenabstand - Textausrichtung - Textfarbe</p> <p>Form-Eigenschaften: - F\u00fcllfarbe - Rahmenfarbe und -st\u00e4rke - Eckenradius</p> <p>Allgemein: - Deckkraft - L\u00f6schen-Button</p>"},{"location":"services/klausur-service/Worksheet-Editor-Architecture/#54-worksheetcontext","title":"5.4 WorksheetContext","text":"<p>React Context f\u00fcr globalen State:</p> <pre><code>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</code></pre>"},{"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":"<pre><code>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</code></pre>"},{"location":"services/klausur-service/Worksheet-Editor-Architecture/#62-worksheetpage","title":"6.2 WorksheetPage","text":"<pre><code>interface WorksheetPage {\n id: string\n index: number\n canvasJSON: string // Serialisierter Fabric.js Canvas\n thumbnail?: string\n}\n</code></pre>"},{"location":"services/klausur-service/Worksheet-Editor-Architecture/#63-pageformat","title":"6.3 PageFormat","text":"<pre><code>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</code></pre>"},{"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":"<ul> <li>History-Stack mit max. 50 Eintr\u00e4gen</li> <li>Automatische Speicherung bei jeder \u00c4nderung</li> <li>Keyboard: Ctrl+Z (Undo), Ctrl+Y (Redo)</li> </ul>"},{"location":"services/klausur-service/Worksheet-Editor-Architecture/#72-grid-snap","title":"7.2 Grid &amp; Snap","text":"<ul> <li>Konfigurierbares Raster (5mm, 10mm, 15mm, 20mm)</li> <li>Snap-to-Grid beim Verschieben</li> <li>Ein-/Ausblendbar</li> </ul>"},{"location":"services/klausur-service/Worksheet-Editor-Architecture/#73-export","title":"7.3 Export","text":"<ul> <li>PDF: Mehrseitig, A4-Format</li> <li>PNG: Hochaufl\u00f6send (2x Multiplier)</li> <li>JPG: Mit Qualit\u00e4tseinstellung</li> </ul>"},{"location":"services/klausur-service/Worksheet-Editor-Architecture/#74-speicherung","title":"7.4 Speicherung","text":"<ul> <li>Backend: REST API mit JSON-Persistierung</li> <li>Fallback: localStorage bei Offline-Betrieb</li> </ul>"},{"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":"<p>Der Editor nutzt Ollama f\u00fcr die KI-Bildgenerierung:</p> <pre><code>OLLAMA_URL = \"http://host.docker.internal:11434\"\n</code></pre>"},{"location":"services/klausur-service/Worksheet-Editor-Architecture/#82-placeholder-system","title":"8.2 Placeholder-System","text":"<p>Falls Ollama nicht verf\u00fcgbar ist, wird ein Placeholder-Bild generiert: - Farbcodiert nach Stil - Prompt-Text als Beschreibung - \"KI-Bild (Platzhalter)\"-Badge</p>"},{"location":"services/klausur-service/Worksheet-Editor-Architecture/#83-stil-prompts","title":"8.3 Stil-Prompts","text":"<p>Jeder Stil f\u00fcgt automatisch Modifikatoren zum Prompt hinzu:</p> <pre><code>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</code></pre>"},{"location":"services/klausur-service/Worksheet-Editor-Architecture/#9-glassmorphism-design","title":"9. Glassmorphism Design","text":"<p>Der Editor folgt dem Glassmorphism-Design des Studio v2:</p> <pre><code>// 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</code></pre>"},{"location":"services/klausur-service/Worksheet-Editor-Architecture/#10-internationalisierung","title":"10. Internationalisierung","text":"<p>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</p> <p>Translation Key: <code>nav_worksheet_editor</code></p>"},{"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":"<ul> <li>Nur Bildformate (image/*)</li> <li>Client-seitige Validierung</li> <li>Base64-Konvertierung</li> </ul>"},{"location":"services/klausur-service/Worksheet-Editor-Architecture/#112-cors","title":"11.2 CORS","text":"<p>Aktiviert f\u00fcr lokale Entwicklung und Docker-Umgebung.</p>"},{"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":"<pre><code>cd studio-v2\nnpm install\nnpm run dev # Port 3001\n</code></pre>"},{"location":"services/klausur-service/Worksheet-Editor-Architecture/#122-backend","title":"12.2 Backend","text":"<p>Der klausur-service l\u00e4uft auf Port 8086:</p> <pre><code>cd klausur-service/backend\npython main.py\n</code></pre>"},{"location":"services/klausur-service/Worksheet-Editor-Architecture/#123-docker","title":"12.3 Docker","text":"<p>Der Service ist Teil des docker-compose.yml.</p>"},{"location":"services/klausur-service/Worksheet-Editor-Architecture/#13-zukunftige-erweiterungen","title":"13. Zuk\u00fcnftige Erweiterungen","text":"<ul> <li>[ ] Tabellen-Tool mit Zellbearbeitung</li> <li>[ ] Vorlagen-Bibliothek</li> <li>[ ] Kollaboratives Editieren</li> <li>[ ] Drag &amp; Drop aus Dokumentenbibliothek</li> <li>[ ] Integration mit Vocab-Worksheet</li> </ul>"},{"location":"services/klausur-service/byoeh-system-erklaerung/","title":"Wie funktioniert das Klausur-Namespace-System?","text":"<p>Eine umfassende Erklaerung des BYOEH-Systems -- von der Anonymisierung bis zur sicheren KI-Korrektur.</p>"},{"location":"services/klausur-service/byoeh-system-erklaerung/#1-was-ist-das-namespace-system","title":"1. Was ist das Namespace-System?","text":"<p>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.</p> <p>\"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.\"</p> <p>Das System loest ein grundlegendes Problem: Klausurkorrektur mit KI-Unterstuetzung ohne Datenschutzrisiko. Die Loesung besteht aus vier Bausteinen:</p> <ol> <li>Pseudonymisierung: Namen werden durch zufaellige Codes ersetzt. Niemand ausser dem Lehrer kennt die Zuordnung.</li> <li>Verschluesselung: Alles wird im Browser des Lehrers verschluesselt, bevor es den Rechner verlaesst. Der Server sieht nur unlesbaren Datensalat.</li> <li>Namespace-Isolation: Jeder Lehrer hat einen eigenen, abgeschotteten Bereich (Namespace). Kein Lehrer kann auf die Daten eines anderen zugreifen.</li> <li>KI-Korrektur: Die KI arbeitet mit den verschluesselten Daten und dem Erwartungshorizont (EH) des Lehrers. Korrekturvorschlaege gehen zurueck an den Lehrer.</li> </ol> <p>Kern-Designprinzip: Operator Blindness</p> <p>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.</p>"},{"location":"services/klausur-service/byoeh-system-erklaerung/#2-der-komplette-ablauf-im-ueberblick","title":"2. Der komplette Ablauf im Ueberblick","text":"<p>Der Prozess laesst sich in sieben Schritte unterteilen. Stellen Sie sich vor, der Lehrer sitzt an seinem Rechner und hat einen Stapel gescannter Klausuren:</p> Der komplette Workflow: Von der Klausur zur KI-Korrektur<pre><code>SCHRITT 1: KLAUSUREN SCANNEN &amp; 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 &amp; 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</code></pre>"},{"location":"services/klausur-service/byoeh-system-erklaerung/#3-pseudonymisierung-wie-namen-verschwinden","title":"3. Pseudonymisierung: Wie Namen verschwinden","text":"<p>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:</p>"},{"location":"services/klausur-service/byoeh-system-erklaerung/#31-der-doc_token-ein-zufaelliger-ausweis","title":"3.1 Der doc_token: Ein zufaelliger Ausweis","text":"<p>Jede Klausur erhaelt einen doc_token -- einen 128-Bit-Zufallscode im UUID4-Format (z.B. <code>a7f3c2d1-4e9b-4a5f-8c7d-6b2e1f0a9d3c</code>). Dieser Code:</p> <ul> <li>Ist kryptographisch zufaellig -- es gibt keinen Zusammenhang zwischen Token und Schueler</li> <li>Kann nicht zurueckgerechnet werden -- auch mit Kenntnis des Algorithmus ist kein Rueckschluss moeglich</li> <li>Wird auf der Klausur aufgedruckt (als QR-Code), damit die physische Klausur spaeter wieder zugeordnet werden kann</li> </ul>"},{"location":"services/klausur-service/byoeh-system-erklaerung/#32-header-redaction-der-name-wird-entfernt","title":"3.2 Header-Redaction: Der Name wird entfernt","text":"<p>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.</p> 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":"<p>Die Zuordnung doc_token \u2192 Schuelername wird als verschluesselte Tabelle gespeichert:</p> Datenbank: ExamSession (vereinfacht)<pre><code>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</code></pre> <p>DSGVO Art. 4 Nr. 5 konform</p> <p>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.</p>"},{"location":"services/klausur-service/byoeh-system-erklaerung/#4-verschluesselung-wie-daten-geschuetzt-werden","title":"4. Verschluesselung: Wie Daten geschuetzt werden","text":"<p>Die Verschluesselung ist das Herzstueck des Datenschutzes. Sie findet vollstaendig im Browser statt -- der Server bekommt nur verschluesselte Daten zu sehen.</p>"},{"location":"services/klausur-service/byoeh-system-erklaerung/#41-der-verschluesselungsvorgang","title":"4.1 Der Verschluesselungsvorgang","text":"<p>Wenn der Lehrer eine Klausur oder einen Erwartungshorizont hochlaedt, passiert im Browser folgendes:</p> Client-seitige Verschluesselung (im Browser)<pre><code>\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</code></pre>"},{"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":"<p>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.</p>"},{"location":"services/klausur-service/byoeh-system-erklaerung/#51-wie-die-isolation-funktioniert","title":"5.1 Wie die Isolation funktioniert","text":"<p>Jeder Lehrer erhaelt beim ersten Login eine eindeutige <code>tenant_id</code>. Diese ID wird bei jeder einzelnen Datenbankabfrage als Pflichtfilter mitgefuehrt:</p> Tenant-Isolation in der Vektordatenbank (Qdrant)<pre><code>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</code></pre>"},{"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: <code>/tenant-id/eh-id/encrypted.bin</code> Vektordatenbank Qdrant Pflichtfilter <code>tenant_id</code> bei jeder Suche Metadaten-DB PostgreSQL Jede Tabelle hat <code>teacher_id</code> als Pflichtfeld <p>Kein Training mit Lehrerdaten</p> <p>Auf allen Vektoren in Qdrant ist das Flag <code>training_allowed: false</code> gesetzt. Das bedeutet: Die Inhalte der Lehrer werden ausschliesslich fuer RAG-Suchen (Abruf relevanter Textpassagen) verwendet und niemals zum Trainieren eines KI-Modells eingesetzt.</p>"},{"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":"<p>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.</p>"},{"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 &amp; 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":"<p>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:</p> Indexierung: Vom PDF zum durchsuchbaren EH<pre><code>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</code></pre>"},{"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":"<p>Wenn der Lehrer bei der Korrektur einen Vorschlag anfordert, passiert folgendes:</p> <ol> <li>Frage formulieren: Das System erstellt eine Suchanfrage aus dem Klausurtext und dem aktuellen Bewertungskriterium.</li> <li>Semantische Suche: Die Anfrage wird in einen Vektor umgewandelt und gegen die EH-Vektoren in Qdrant gesucht -- nur im Namespace des Lehrers.</li> <li>Entschluesselung: Die gefundenen Chunks werden mit der Passphrase des Lehrers entschluesselt.</li> <li>KI-Antwort: Die entschluesselten EH-Passagen werden als Kontext an die KI uebergeben, die daraus einen Korrekturvorschlag generiert.</li> </ol>"},{"location":"services/klausur-service/byoeh-system-erklaerung/#7-key-sharing-zweitkorrektur-ermoeglichen","title":"7. Key Sharing: Zweitkorrektur ermoeglichen","text":"<p>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.</p>"},{"location":"services/klausur-service/byoeh-system-erklaerung/#71-einladungs-workflow","title":"7.1 Einladungs-Workflow","text":"Key Sharing: Sicheres Teilen zwischen Pruefern<pre><code>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</code></pre>"},{"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 &amp; 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":"<p>Die KI bewertet jede Klausur anhand von fuenf Kriterien, die zusammen 100% ergeben:</p> 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 <p>Die Bewertung folgt dem 15-Punkte-System (0-15 Notenpunkte) der gymnasialen Oberstufe.</p> <p>KI schlaegt vor, Lehrer entscheidet</p> <p>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.</p>"},{"location":"services/klausur-service/byoeh-system-erklaerung/#9-audit-trail-alles-wird-protokolliert","title":"9. Audit-Trail: Alles wird protokolliert","text":"<p>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.</p> Aktion Was protokolliert wird <code>upload</code> EH hochgeladen (Dateigroesse, Metadaten, Zeitstempel) <code>index</code> EH fuer RAG indexiert (Anzahl Chunks, Dauer) <code>rag_query</code> RAG-Suchanfrage ausgefuehrt (Query-Hash, Anzahl Ergebnisse, Score) <code>share</code> EH mit anderem Pruefer geteilt (Empfaenger, Rolle) <code>revoke_share</code> Zugriff widerrufen (wer, wann) <code>link_klausur</code> EH mit Klausur verknuepft <code>delete</code> 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":"<p>Alle Endpunkte laufen ueber den klausur-service auf Port 8086.</p>"},{"location":"services/klausur-service/byoeh-system-erklaerung/#101-erwartungshorizont-verwaltung","title":"10.1 Erwartungshorizont-Verwaltung","text":"Methode Endpunkt Beschreibung <code>POST</code> <code>/api/v1/eh/upload</code> Verschluesselten EH hochladen <code>GET</code> <code>/api/v1/eh</code> Eigene EHs auflisten <code>GET</code> <code>/api/v1/eh/{id}</code> Einzelnen EH abrufen <code>DELETE</code> <code>/api/v1/eh/{id}</code> EH loeschen (Soft Delete) <code>POST</code> <code>/api/v1/eh/{id}/index</code> EH fuer RAG indexieren <code>POST</code> <code>/api/v1/eh/rag-query</code> RAG-Suchanfrage ausfuehren"},{"location":"services/klausur-service/byoeh-system-erklaerung/#102-key-sharing","title":"10.2 Key Sharing","text":"Methode Endpunkt Beschreibung <code>POST</code> <code>/api/v1/eh/{id}/share</code> EH mit Pruefer teilen <code>GET</code> <code>/api/v1/eh/{id}/shares</code> Geteilte Zugriffe auflisten <code>DELETE</code> <code>/api/v1/eh/{id}/shares/{shareId}</code> Zugriff widerrufen <code>GET</code> <code>/api/v1/eh/shared-with-me</code> Mit mir geteilte EHs"},{"location":"services/klausur-service/byoeh-system-erklaerung/#103-klausur-integration","title":"10.3 Klausur-Integration","text":"Methode Endpunkt Beschreibung <code>POST</code> <code>/api/v1/eh/{id}/link-klausur</code> EH mit Klausur verknuepfen <code>DELETE</code> <code>/api/v1/eh/{id}/link-klausur/{klausurId}</code> Verknuepfung loesen <code>GET</code> <code>/api/v1/klausuren/{id}/linked-eh</code> Verknuepften EH abrufen"},{"location":"services/klausur-service/byoeh-system-erklaerung/#11-dateistruktur-im-code","title":"11. Dateistruktur im Code","text":"Relevante Dateien im Repository<pre><code>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</code></pre>"},{"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 <code>training_allowed: false</code> 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 <p>Das Wichtigste in einem Satz</p> <p>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.</p>"},{"location":"services/voice-service/","title":"Voice Service","text":"<p>Der Voice Service ist eine Voice-First Interface f\u00fcr die Breakpilot-Plattform mit DSGVO-konformem Design.</p>"},{"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":"<pre><code>\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&gt;\u2502 Task \u2502\u2500\u2500\u2500&gt;\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</code></pre>"},{"location":"services/voice-service/#kernkomponenten","title":"Kernkomponenten","text":""},{"location":"services/voice-service/#personaplex-taskorchestrator","title":"PersonaPlex + TaskOrchestrator","text":"<ul> <li>Voice-first Interface f\u00fcr Breakpilot</li> <li>Real-time Voice Processing</li> <li>Multi-Agent Integration</li> </ul>"},{"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 <code>/api/v1/sessions</code> Session erstellen GET <code>/api/v1/sessions/:id</code> Session abrufen DELETE <code>/api/v1/sessions/:id</code> Session beenden"},{"location":"services/voice-service/#task-orchestration","title":"Task Orchestration","text":"Method Endpoint Beschreibung POST <code>/api/v1/tasks</code> Task erstellen GET <code>/api/v1/tasks/:id</code> Task-Status abrufen"},{"location":"services/voice-service/#bqas-quality-assessment","title":"BQAS (Quality Assessment)","text":"Method Endpoint Beschreibung POST <code>/api/v1/bqas/evaluate</code> Qualit\u00e4tsbewertung GET <code>/api/v1/bqas/metrics</code> Metriken abrufen"},{"location":"services/voice-service/#websocket","title":"WebSocket","text":"Endpoint Beschreibung <code>/ws/voice</code> Real-time Voice Streaming"},{"location":"services/voice-service/#health","title":"Health","text":"Method Endpoint Beschreibung GET <code>/health</code> Health Check GET <code>/ready</code> Readiness Check"},{"location":"services/voice-service/#verzeichnisstruktur","title":"Verzeichnisstruktur","text":"<pre><code>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</code></pre>"},{"location":"services/voice-service/#konfiguration","title":"Konfiguration","text":"<pre><code># .env\nVOICE_SERVICE_PORT=8082\nREDIS_URL=redis://localhost:6379\nDATABASE_URL=postgresql://...\nENCRYPTION_KEY=...\nTTL_MINUTES=60\n</code></pre>"},{"location":"services/voice-service/#entwicklung","title":"Entwicklung","text":"<pre><code># 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</code></pre>"},{"location":"services/voice-service/#docker","title":"Docker","text":"<p>Der Service l\u00e4uft als Teil von docker-compose.yml:</p> <pre><code>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</code></pre>"},{"location":"services/voice-service/#weiterfuhrende-dokumentation","title":"Weiterf\u00fchrende Dokumentation","text":"<ul> <li>Multi-Agent Architektur</li> <li>BQAS Quality System</li> </ul>"}]}