diff --git a/.claude/CLAUDE.md b/.claude/CLAUDE.md index 41f522b..ff8322a 100644 --- a/.claude/CLAUDE.md +++ b/.claude/CLAUDE.md @@ -1,37 +1,114 @@ -# BreakPilot Lehrer — KI-Bildungsplattform +# BreakPilot Lehrer - KI-Bildungsplattform -## Entwicklungsumgebung +## Entwicklungsumgebung (WICHTIG - IMMER ZUERST LESEN) ### Zwei-Rechner-Setup -| Gerät | Rolle | -|-------|-------| -| **MacBook** | Client/Terminal | -| **Mac Mini** | Server/Docker/Git | + +| Geraet | Rolle | Aufgaben | +|--------|-------|----------| +| **MacBook** | Client | Claude Terminal, Browser (Frontend-Tests) | +| **Mac Mini** | Server | Docker, alle Services, Code-Ausfuehrung, Tests, Git | + +**WICHTIG:** Die Entwicklung findet vollstaendig auf dem **Mac Mini** statt! + +### SSH-Verbindung ```bash +ssh macmini +# Projektverzeichnis: +cd /Users/benjaminadmin/Projekte/breakpilot-lehrer + +# Einzelbefehle (BEVORZUGT): ssh macmini "cd /Users/benjaminadmin/Projekte/breakpilot-lehrer && " ``` +--- + ## Voraussetzung -**breakpilot-core MUSS laufen!** Dieses Projekt nutzt Core-Services (DB, Cache, Auth, RAG). -## Projektübersicht +**breakpilot-core MUSS laufen!** Dieses Projekt nutzt Core-Services: +- PostgreSQL (Schema: `lehrer`, `core`) +- Valkey (Session-Cache) +- Vault (Secrets) +- RAG-Service (Vektorsuche) +- Embedding-Service (Text-Embeddings) +- Nginx (Reverse Proxy) -**breakpilot-lehrer** ist die Lehrer-KI-Plattform mit Klausurkorrektur, Unterrichtsplanung und Schülerverwaltung. +Pruefen: `curl -sf http://macmini:8099/health` -### Enthaltene Services (~12 Container) +--- -| Service | Port | Beschreibung | -|---------|------|--------------| -| admin-lehrer | 3002 | Admin-Dashboard (Next.js) | -| studio-v2 | 443 | Lehrer-/Schüler-Studio | -| website | 3000 | Öffentliche Website | -| backend-lehrer | 8001 | Lehrer APIs (FastAPI) | -| klausur-service | 8086 | Prüfungen, OCR, RAG | -| school-service | 8082 | Schulverwaltung | -| geo-service | 8084 | Geo-Daten | -| voice-service | 8091 | Spracheingabe | -| agent-core | - | Multi-Agent System | +## Haupt-URLs (Browser auf MacBook) + +### Frontends + +| URL | Service | Beschreibung | +|-----|---------|--------------| +| **https://macmini/** | Studio v2 | Lehrer-/Schueler-Interface | +| **https://macmini:3000/** | Website | Oeffentliche Website | +| **https://macmini:3002/** | Admin Lehrer | Dashboard, AI-Tools, Architektur | + +### Backend-APIs + +| URL | Service | Beschreibung | +|-----|---------|--------------| +| https://macmini:8001/ | Backend Lehrer | Classroom, Units, Meetings, State Engine | +| https://macmini:8086/ | Klausur-Service | Pruefungen, OCR, Vokabel-Worksheets, RAG | +| wss://macmini:8091/ | Voice-Service | Spracheingabe WebSocket | + +### Admin Lehrer Module (https://macmini:3002/) + +| Pfad | Modul | +|------|-------| +| `/dashboard` | Dashboard + Catalog-Manager | +| `/ai/llm-compare` | LLM Vergleich | +| `/ai/ocr-compare` | OCR Vergleich | +| `/ai/ocr-labeling` | OCR Trainingsdaten | +| `/ai/test-quality` | Test Quality (BQAS) | +| `/ai/gpu` | GPU Infrastruktur (vast.ai) | +| `/ai/rag-pipeline` | RAG Pipeline | +| `/ai/magic-help` | KI-Assistent | +| `/education` | Bildungsmodule | +| `/communication` | Messenger, Meetings | +| `/development` | Entwickler-Tools, Docs | +| `/infrastructure` | Night-Mode, Security, SBOM | +| `/architecture` | Architektur-Visualisierung | +| `/rbac` | Rollenverwaltung | +| `/website` | Website-Management | + +### Lehrer-Tools (Studio v2 - https://macmini/) + +| Pfad | Tool | Beschreibung | +|------|------|--------------| +| `/vocab-worksheet` | Vokabel-Arbeitsblatt | OCR-Scan + Arbeitsblatt-Generator | +| `/korrektur` | Korrekturplattform | Abiturklausur-Korrektur | + +--- + +## Services (~12 Container) + +| Service | Tech | Port | Container | +|---------|------|------|-----------| +| admin-lehrer | Next.js 15 | 3002 (via nginx) | bp-lehrer-admin | +| studio-v2 | Next.js 15 | 443 (via nginx) | bp-lehrer-studio-v2 | +| website | Next.js 14 | 3000 (via nginx) | bp-lehrer-website | +| backend-lehrer | Python/FastAPI | 8001 | bp-lehrer-backend | +| klausur-service | Python/FastAPI | 8086 | bp-lehrer-klausur-service | +| school-service | Python | 8082 | bp-lehrer-school-service | +| voice-service | Python/FastAPI | 8091 | bp-lehrer-voice-service | +| geo-service | Python/FastAPI | 8084 | bp-lehrer-geo-service | +| breakpilot-drive | Node.js | - | bp-lehrer-drive (Profil: game) | +| paddleocr-service | Python | - | bp-lehrer-paddleocr (Profil: ocr) | +| agent-core | Python | - | bp-lehrer-agent-core (Profil: dev) | + +### Profile (nur bei Bedarf) + +| Profil | Services | Start mit | +|--------|----------|-----------| +| game | breakpilot-drive | `--profile game` | +| ocr | paddleocr-service | `--profile ocr` | +| dev | agent-core | `--profile dev` | +| recording | transcription-worker | `--profile recording` | ### Docker-Netzwerk Nutzt das externe Core-Netzwerk: @@ -45,7 +122,127 @@ networks: ### Container-Naming: `bp-lehrer-*` ### DB search_path: `lehrer,core,public` -## Git Remotes -Immer zu BEIDEN pushen: -- `origin`: lokale Gitea (macmini:3003) -- `gitea`: gitea.meghsakha.com +--- + +## Verzeichnisstruktur + +``` +breakpilot-lehrer/ +├── .claude/ +│ ├── CLAUDE.md # Diese Datei +│ └── rules/ # Automatische Regeln +├── admin-lehrer/ # Next.js Admin Dashboard +│ ├── app/(admin)/ # 12 Route-Groups +│ ├── components/ # UI-Komponenten +│ └── lib/ # Utilities, Navigation +├── studio-v2/ # Next.js Lehrer-/Schueler-Studio +├── website/ # Next.js Oeffentliche Website +├── backend-lehrer/ # Python/FastAPI Backend +│ ├── classroom_api.py +│ ├── state_engine_api.py +│ ├── worksheets_api.py +│ ├── correction_api.py +│ ├── meetings_api.py +│ ├── messenger_api.py +│ └── ... +├── klausur-service/ # Klausur/OCR/RAG Service +├── school-service/ # Schulverwaltung +├── voice-service/ # Spracheingabe (Whisper) +├── geo-service/ # Geo-Daten (PostGIS) +├── agent-core/ # Multi-Agent System +├── breakpilot-drive/ # Dateiablage (IPFS) +├── scripts/ # Helper Scripts +└── docker-compose.yml # Lehrer Compose (~12 Services) +``` + +--- + +## Haeufige Befehle + +### Docker + +```bash +# Lehrer-Services starten (Core muss laufen!) +ssh macmini "cd /Users/benjaminadmin/Projekte/breakpilot-lehrer && /usr/local/bin/docker compose up -d" + +# Einzelnen Service neu bauen +ssh macmini "cd /Users/benjaminadmin/Projekte/breakpilot-lehrer && /usr/local/bin/docker compose build --no-cache " + +# Logs +ssh macmini "/usr/local/bin/docker logs -f bp-lehrer-" + +# Status +ssh macmini "/usr/local/bin/docker ps --filter name=bp-lehrer" +``` + +**WICHTIG:** Docker-Pfad auf Mac Mini ist `/usr/local/bin/docker` (nicht im Standard-SSH-PATH). + +### Frontend-Entwicklung + +```bash +# Admin Lehrer im Browser testen: +# https://macmini:3002/ + +# Studio v2 im Browser testen: +# https://macmini/ + +# Website im Browser testen: +# https://macmini:3000/ +``` + +### Git + +```bash +# Zu BEIDEN Remotes pushen (PFLICHT!): +ssh macmini "cd /Users/benjaminadmin/Projekte/breakpilot-lehrer && git push all main" + +# Remotes: +# origin: lokale Gitea (macmini:3003) +# gitea: gitea.meghsakha.com +# all: beide gleichzeitig +``` + +--- + +## Kernprinzipien + +### 1. Open Source Policy +- **NUR Open Source mit kommerziell nutzbarer Lizenz** +- Erlaubt: MIT, Apache-2.0, BSD, ISC, MPL-2.0, LGPL +- **VERBOTEN:** GPL (ausser LGPL), AGPL, proprietaer + +### 2. Testing & Dokumentation +- Tests sind Pflicht bei jeder Aenderung +- Dokumentation aktualisieren in MkDocs + +### 3. Sensitive Dateien +**NIEMALS aendern oder committen:** +- `.env`, `.env.local`, Vault-Tokens, SSL-Zertifikate +- `*.pdf`, `*.docx`, kompilierte Binaries, grosse Medien + +--- + +## Tech-Stack + +| Sprache | Services | +|---------|----------| +| Python/FastAPI | backend-lehrer, klausur-service, voice-service, geo-service | +| TypeScript/Next.js | admin-lehrer, studio-v2, website | +| Node.js | breakpilot-drive | +| Python | agent-core, paddleocr-service | + +--- + +## Wichtige Dateien (Referenz) + +| Datei | Beschreibung | +|-------|--------------| +| `klausur-service/backend/main.py` | Haupt-API: Klausuren, OCR, Vocab | +| `klausur-service/backend/nru_worksheet_generator.py` | NRU Arbeitsblatt-Generator | +| `klausur-service/backend/hybrid_vocab_extractor.py` | OCR-Extraktion | +| `admin-lehrer/app/(admin)/` | Alle 12 Admin Route-Groups | +| `admin-lehrer/lib/navigation.ts` | Sidebar-Navigation | +| `studio-v2/app/vocab-worksheet/page.tsx` | Vokabel-Arbeitsblatt UI | +| `website/app/admin/klausur-korrektur/` | Korrektur-Workspace | +| `backend-lehrer/classroom_api.py` | Classroom Engine | +| `backend-lehrer/state_engine_api.py` | State Engine | diff --git a/.claude/rules/abiturkorrektur.md b/.claude/rules/abiturkorrektur.md new file mode 100644 index 0000000..6353a10 --- /dev/null +++ b/.claude/rules/abiturkorrektur.md @@ -0,0 +1,614 @@ +# Abiturkorrektur-System - Entwicklerdokumentation + +**WICHTIG: Diese Datei wird bei jedem Compacting gelesen. Alle Implementierungsdetails hier dokumentieren!** + +--- + +## 1. Projektziel + +Entwicklung eines KI-gestützten Korrektur-Systems für Deutsch-Abiturklausuren: +- **Zielgruppe**: Lehrer in Niedersachsen (Pilot), später alle Bundesländer +- **Kernproblem**: Erstkorrektur dauert 6 Stunden pro Arbeit +- **Lösung**: KI schlägt Bewertungen vor, Lehrer bestätigt/korrigiert + +--- + +## 2. Architektur-Übersicht + +``` +┌─────────────────────────────────────────────────────────────┐ +│ Frontend (Next.js) │ +│ /website/app/admin/klausur-korrektur/ │ +│ - page.tsx (Klausur-Liste) │ +│ - [klausurId]/page.tsx (Studenten-Liste) │ +│ - [klausurId]/[studentId]/page.tsx (Korrektur-Workspace) │ +└─────────────────────────────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────────┐ +│ klausur-service (FastAPI) │ +│ Port 8086 - /klausur-service/backend/main.py │ +│ - Klausur CRUD (/api/v1/klausuren) │ +│ - Student Work (/api/v1/students) │ +│ - Annotations (/api/v1/annotations) [NEU] │ +│ - Gutachten Generation │ +│ - Fairness Analysis │ +└─────────────────────────────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────────┐ +│ Infrastruktur │ +│ - Qdrant (Vektor-DB für RAG) │ +│ - MinIO (Datei-Storage) │ +│ - PostgreSQL (Metadaten) │ +│ - Embedding-Service (Port 8087) │ +└─────────────────────────────────────────────────────────────┘ +``` + +--- + +## 3. Bestehende Backend-Komponenten (NUTZEN!) + +### 3.1 Klausur-Service API (main.py) + +```python +# Bereits implementiert: +GET/POST /api/v1/klausuren # Klausur CRUD +GET /api/v1/klausuren/{id} # Klausur Details +POST /api/v1/klausuren/{id}/students # Student Work hochladen +GET /api/v1/klausuren/{id}/students # Studenten-Liste +PUT /api/v1/students/{id}/criteria # Kriterien bewerten +PUT /api/v1/students/{id}/gutachten # Gutachten speichern +POST /api/v1/students/{id}/gutachten/generate # Gutachten generieren (KI) +GET /api/v1/klausuren/{id}/fairness # Fairness-Analyse +GET /api/v1/grade-info # Notensystem-Info +``` + +### 3.2 Datenmodelle (main.py) + +```python +@dataclass +class Klausur: + id: str + title: str + subject: str = "Deutsch" + year: int = 2025 + semester: str = "Abitur" + modus: str = "abitur" # oder "vorabitur" + eh_id: Optional[str] = None # Erwartungshorizont-Referenz + +@dataclass +class StudentKlausur: + id: str + klausur_id: str + anonym_id: str + file_path: str + ocr_text: str = "" + criteria_scores: Dict[str, int] = field(default_factory=dict) + gutachten: str = "" + status: str = "UPLOADED" + raw_points: int = 0 + grade_points: int = 0 + +# Status-Workflow: +# UPLOADED → OCR_PROCESSING → OCR_COMPLETE → ANALYZING → +# FIRST_EXAMINER → SECOND_EXAMINER → COMPLETED +``` + +### 3.3 Notensystem (15-Punkte) + +```python +GRADE_THRESHOLDS = { + 15: 95, 14: 90, 13: 85, 12: 80, 11: 75, + 10: 70, 9: 65, 8: 60, 7: 55, 6: 50, + 5: 45, 4: 40, 3: 33, 2: 27, 1: 20, 0: 0 +} + +DEFAULT_CRITERIA = { + "rechtschreibung": {"name": "Rechtschreibung", "weight": 15}, + "grammatik": {"name": "Grammatik", "weight": 15}, + "inhalt": {"name": "Inhalt", "weight": 40}, + "struktur": {"name": "Struktur", "weight": 15}, + "stil": {"name": "Stil", "weight": 15} +} +``` + +--- + +## 4. NEU ZU IMPLEMENTIEREN + +### Phase 1: Korrektur-Workspace MVP + +#### 4.1 Frontend-Struktur + +``` +/website/app/admin/klausur-korrektur/ +├── page.tsx # Klausur-Übersicht (Liste aller Klausuren) +├── types.ts # TypeScript Interfaces +├── [klausurId]/ +│ ├── page.tsx # Studenten-Liste einer Klausur +│ └── [studentId]/ +│ └── page.tsx # Korrektur-Workspace (2/3-1/3) +└── components/ + ├── KlausurCard.tsx # Klausur in Liste + ├── StudentList.tsx # Studenten-Übersicht + ├── DocumentViewer.tsx # PDF/Bild-Anzeige (links, 2/3) + ├── AnnotationLayer.tsx # SVG-Overlay für Markierungen + ├── AnnotationToolbar.tsx # Werkzeuge + ├── CorrectionPanel.tsx # Bewertungs-Panel (rechts, 1/3) + ├── CriteriaScoreCard.tsx # Einzelnes Kriterium + ├── EHSuggestionPanel.tsx # EH-Vorschläge via RAG + ├── GutachtenEditor.tsx # Gutachten bearbeiten + └── StudentNavigation.tsx # Prev/Next Navigation +``` + +#### 4.2 Annotations-Backend (NEU in main.py) + +```python +# Neues Datenmodell: +@dataclass +class Annotation: + id: str + student_work_id: str + page: int + position: dict # {x, y, width, height} in % (0-100) + type: str # 'rechtschreibung' | 'grammatik' | 'inhalt' | 'struktur' | 'stil' | 'comment' + text: str # Kommentar-Text + severity: str # 'minor' | 'major' | 'critical' + suggestion: str # Korrekturvorschlag (bei RS/Gram) + created_by: str # User-ID (EK oder ZK) + created_at: datetime + role: str # 'first_examiner' | 'second_examiner' + linked_criterion: Optional[str] # Verknüpfung zu Kriterium + +# Neue Endpoints: +POST /api/v1/students/{id}/annotations # Erstellen +GET /api/v1/students/{id}/annotations # Abrufen +PUT /api/v1/annotations/{id} # Ändern +DELETE /api/v1/annotations/{id} # Löschen +``` + +#### 4.3 UI-Layout Spezifikation + +``` +┌──────────────────────────────────────────────────────────────────────┐ +│ Header: Klausur-Titel | Student: Anonym-123 | [← Prev] [5/24] [Next →]│ +├─────────────────────────────────────────┬────────────────────────────┤ +│ │ Tabs: [Kriterien] [Gutachten]│ +│ ┌─────────────────────────────────┐ │ │ +│ │ │ │ ▼ Rechtschreibung (15%) │ +│ │ Dokument-Anzeige │ │ [====|====] 70/100 │ +│ │ (PDF/Bild mit Zoom) │ │ 12 Fehler markiert │ +│ │ │ │ │ +│ │ + Annotation-Overlay │ │ ▼ Grammatik (15%) │ +│ │ (SVG Layer) │ │ [====|====] 80/100 │ +│ │ │ │ │ +│ │ │ │ ▼ Inhalt (40%) │ +│ │ │ │ [====|====] 65/100 │ +│ │ │ │ EH-Vorschläge: [Laden] │ +│ └─────────────────────────────────┘ │ │ +│ │ ▼ Struktur (15%) │ +│ Toolbar: [RS] [Gram] [Kommentar] │ [====|====] 75/100 │ +│ [Zoom+] [Zoom-] [Fit] │ │ +│ │ ▼ Stil (15%) │ +│ Seiten: [1] [2] [3] [4] [5] │ [====|====] 70/100 │ +│ │ │ +│ │ ━━━━━━━━━━━━━━━━━━━━━━━━━━ │ +│ │ Gesamtnote: 10 Punkte (2-) │ +│ │ [Gutachten generieren] │ +│ │ [Speichern] [Abschließen] │ +├─────────────────────────────────────────┴────────────────────────────┤ +│ 2/3 Breite │ 1/3 Breite │ +└──────────────────────────────────────────────────────────────────────┘ +``` + +--- + +## 5. Implementierungs-Reihenfolge + +### Phase 1.1: Grundgerüst (AKTUELL) +1. ✅ Dokumentation erstellen +2. [ ] `/website/app/admin/klausur-korrektur/page.tsx` - Klausur-Liste +3. [ ] `/website/app/admin/klausur-korrektur/types.ts` - TypeScript Types +4. [ ] Navigation in AdminLayout.tsx hinzufügen +5. [ ] Deploy + Test + +### Phase 1.2: Korrektur-Workspace +1. [ ] `[klausurId]/page.tsx` - Studenten-Liste +2. [ ] `[klausurId]/[studentId]/page.tsx` - Workspace +3. [ ] `components/DocumentViewer.tsx` - Bild/PDF Anzeige +4. [ ] `components/CorrectionPanel.tsx` - Bewertungs-Panel +5. [ ] Deploy + Test mit Lehrer + +### Phase 1.3: Annotations-System +1. [ ] Backend: Annotations-Endpoints in main.py +2. [ ] `components/AnnotationLayer.tsx` - SVG Overlay +3. [ ] `components/AnnotationToolbar.tsx` - Werkzeuge +4. [ ] Farbkodierung: RS=rot, Gram=blau, Inhalt=grün +5. [ ] Deploy + Test + +### Phase 1.4: EH-Integration +1. [ ] `components/EHSuggestionPanel.tsx` +2. [ ] Backend: `/api/v1/students/{id}/eh-suggestions` +3. [ ] RAG-Query mit Student-Text +4. [ ] Deploy + Test + +### Phase 1.5: Gutachten-Editor +1. [ ] `components/GutachtenEditor.tsx` +2. [ ] Beleg-Verlinkung zu Annotations +3. [ ] Gutachten-Generierung Button +4. [ ] Deploy + Test + +--- + +## 6. API-Konfiguration + +```typescript +// Frontend API Base URLs +const KLAUSUR_SERVICE = process.env.NEXT_PUBLIC_KLAUSUR_SERVICE_URL || 'http://localhost:8086' + +// Endpoints: +// Klausuren +GET ${KLAUSUR_SERVICE}/api/v1/klausuren +POST ${KLAUSUR_SERVICE}/api/v1/klausuren +GET ${KLAUSUR_SERVICE}/api/v1/klausuren/{id} +GET ${KLAUSUR_SERVICE}/api/v1/klausuren/{id}/students + +// Studenten +GET ${KLAUSUR_SERVICE}/api/v1/students/{id} +GET ${KLAUSUR_SERVICE}/api/v1/students/{id}/file // Dokument-Download +PUT ${KLAUSUR_SERVICE}/api/v1/students/{id}/criteria +PUT ${KLAUSUR_SERVICE}/api/v1/students/{id}/gutachten +POST ${KLAUSUR_SERVICE}/api/v1/students/{id}/gutachten/generate + +// Annotations (NEU) +GET ${KLAUSUR_SERVICE}/api/v1/students/{id}/annotations +POST ${KLAUSUR_SERVICE}/api/v1/students/{id}/annotations +PUT ${KLAUSUR_SERVICE}/api/v1/annotations/{id} +DELETE ${KLAUSUR_SERVICE}/api/v1/annotations/{id} + +// System +GET ${KLAUSUR_SERVICE}/api/v1/grade-info +``` + +--- + +## 7. Deployment-Prozess + +```bash +# 1. Dateien auf Mac Mini synchronisieren +rsync -avz --delete \ + --exclude 'node_modules' --exclude '.next' --exclude '.git' \ + /Users/benjaminadmin/Projekte/breakpilot-pwa/website/ \ + macmini:/Users/benjaminadmin/Projekte/breakpilot-pwa/website/ + +# 2. Website-Container neu bauen +ssh macmini "/usr/local/bin/docker compose \ + -f /Users/benjaminadmin/Projekte/breakpilot-pwa/docker-compose.yml \ + build --no-cache website" + +# 3. Container neu starten +ssh macmini "/usr/local/bin/docker compose \ + -f /Users/benjaminadmin/Projekte/breakpilot-pwa/docker-compose.yml \ + up -d website" + +# 4. Testen unter: +# http://macmini:3000/admin/klausur-korrektur +``` + +--- + +## 8. Bundesland-Spezifika (Niedersachsen Pilot) + +```json +// /klausur-service/backend/policies/bundeslaender.json +{ + "NI": { + "name": "Niedersachsen", + "grading_mode": "points_15", + "requires_gutachten": true, + "zk_visibility": "full", // ZK sieht EK-Korrektur + "third_correction_threshold": 4, // Ab 4 Punkte Diff + "colors": { + "first_examiner": "#dc2626", // Rot + "second_examiner": "#16a34a" // Grün + }, + "criteria_weights": { + "rechtschreibung": 15, + "grammatik": 15, + "inhalt": 40, + "struktur": 15, + "stil": 15 + } + } +} +``` + +--- + +## 9. Wichtige Dateien (Referenz) + +| Datei | Beschreibung | +|-------|--------------| +| `/klausur-service/backend/main.py` | Haupt-API, alle Endpoints | +| `/klausur-service/backend/eh_pipeline.py` | BYOEH Verarbeitung | +| `/klausur-service/backend/qdrant_service.py` | RAG Vector-Suche | +| `/klausur-service/backend/hybrid_search.py` | Hybrid Search | +| `/website/components/admin/AdminLayout.tsx` | Admin Navigation | +| `/website/app/admin/ocr-labeling/page.tsx` | Referenz für 2/3-1/3 Layout | + +--- + +## 10. Testing-Checkliste + +### Nach jeder Phase: +- [ ] Seite lädt ohne Fehler +- [ ] API-Calls funktionieren (DevTools Network) +- [ ] Responsives Layout korrekt +- [ ] Lehrer kann Workflow durchführen + +### Lehrer-Test-Szenarien: +1. Klausur erstellen +2. 3+ Studentenarbeiten hochladen +3. Erste Arbeit korrigieren (alle Kriterien) +4. Annotations setzen +5. Gutachten generieren +6. Zur nächsten Arbeit navigieren +7. Fairness-Check nach allen Arbeiten + +--- + +## 11. Phase 2: Zweitkorrektur-System (NEU) + +### 11.1 Neue Backend-Endpoints (main.py) + +```python +# Zweitkorrektur Workflow +POST /api/v1/students/{id}/start-zweitkorrektur # ZK starten (nach EK) +POST /api/v1/students/{id}/submit-zweitkorrektur # ZK-Ergebnis abgeben + +# Einigung (bei Diff 3 Punkte) +POST /api/v1/students/{id}/einigung # Einigung einreichen + +# Drittkorrektur (bei Diff >= 4 Punkte) +POST /api/v1/students/{id}/assign-drittkorrektor # DK zuweisen +POST /api/v1/students/{id}/submit-drittkorrektur # DK-Ergebnis (final) + +# Workflow-Status & Visibility-Filtering +GET /api/v1/students/{id}/examiner-workflow # Workflow-Status abrufen +GET /api/v1/students/{id}/annotations-filtered # Policy-gefilterte Annotations +``` + +### 11.2 Workflow-Status + +```python +class ExaminerWorkflowStatus(str, Enum): + NOT_STARTED = "not_started" + EK_IN_PROGRESS = "ek_in_progress" + EK_COMPLETED = "ek_completed" + ZK_ASSIGNED = "zk_assigned" + ZK_IN_PROGRESS = "zk_in_progress" + ZK_COMPLETED = "zk_completed" + EINIGUNG_REQUIRED = "einigung_required" + EINIGUNG_COMPLETED = "einigung_completed" + DRITTKORREKTUR_REQUIRED = "drittkorrektur_required" + DRITTKORREKTUR_ASSIGNED = "drittkorrektur_assigned" + DRITTKORREKTUR_IN_PROGRESS = "drittkorrektur_in_progress" + COMPLETED = "completed" +``` + +### 11.3 Visibility-Regeln (aus bundeslaender.json) + +| Modus | ZK sieht EK-Annotations | ZK sieht EK-Note | ZK sieht EK-Gutachten | +|-------|-------------------------|------------------|----------------------| +| `blind` | Nein | Nein | Nein | +| `semi` (Bayern) | Ja | Nein | Nein | +| `full` (NI, Default) | Ja | Ja | Ja | + +### 11.4 Konsens-Regeln + +| Differenz EK-ZK | Aktion | +|-----------------|--------| +| 0-2 Punkte | Auto-Konsens (Durchschnitt) | +| 3 Punkte | Einigung erforderlich | +| >= 4 Punkte | Drittkorrektur erforderlich | + +--- + +## 12. Aktueller Stand + +**Datum**: 2026-01-21 +**Phase**: Alle Phasen abgeschlossen +**Status**: MVP komplett - bereit fuer Produktionstest + +### Abgeschlossen: +- [x] Phase 1: Korrektur-Workspace MVP +- [x] Phase 1.1: Grundgerüst (Klausur-Liste, Studenten-Liste) +- [x] Phase 1.2: Annotations-System +- [x] Phase 1.3: RS/Grammatik Overlays +- [x] Phase 1.4: EH-Vorschläge via RAG +- [x] Phase 2.1 Backend: Zweitkorrektur-Endpoints +- [x] Phase 2.2 Backend: Einigung-Endpoint +- [x] Phase 2.3 Backend: Drittkorrektur-Trigger +- [x] Phase 2.1 Frontend: ZK-Modus UI +- [x] Phase 2.2 Frontend: Einigung-Screen +- [x] Phase 3.1: Fairness-Dashboard Frontend +- [x] Phase 3.2: Ausreißer-Liste mit Quick-Adjust +- [x] Phase 3.3: Noten-Histogramm & Heatmap +- [x] Phase 4.1: PDF-Export Backend (reportlab) +- [x] Phase 4.2: PDF-Export Frontend +- [x] Phase 4.3: Vorabitur-Modus mit EH-Templates + +### URLs: +- Klausur-Korrektur: `/admin/klausur-korrektur` +- Fairness-Dashboard: `/admin/klausur-korrektur/[klausurId]/fairness` + +### PDF-Export Endpoints: +- `GET /api/v1/students/{id}/export/gutachten` - Einzelnes Gutachten als PDF +- `GET /api/v1/students/{id}/export/annotations` - Anmerkungen als PDF +- `GET /api/v1/klausuren/{id}/export/overview` - Notenübersicht als PDF +- `GET /api/v1/klausuren/{id}/export/all-gutachten` - Alle Gutachten als PDF + +### Vorabitur-Modus Endpoints: +- `GET /api/v1/vorabitur/templates` - Liste aller EH-Templates +- `GET /api/v1/vorabitur/templates/{aufgabentyp}` - Template-Details +- `POST /api/v1/klausuren/{id}/vorabitur-eh` - Custom EH erstellen +- `GET /api/v1/klausuren/{id}/vorabitur-eh` - Verknuepften EH abrufen +- `PUT /api/v1/klausuren/{id}/vorabitur-eh` - EH aktualisieren + +### Verfuegbare Aufgabentypen: +- `textanalyse_pragmatisch` - Sachtexte, Reden, Kommentare +- `gedichtanalyse` - Lyrik/Gedichte +- `prosaanalyse` - Romane, Kurzgeschichten +- `dramenanalyse` - Dramatische Texte +- `eroerterung_textgebunden` - Textgebundene Eroerterung + +--- + +## 13. Lehrer-Anleitung (Schritt-fuer-Schritt) + +### 13.1 Zugang zum System + +**Weg 1: Ueber das Haupt-Dashboard** +1. Oeffnen Sie `http://macmini:8000/app` im Browser +2. Klicken Sie auf die Kachel "Abiturklausuren" +3. Sie werden automatisch zur Korrektur-Oberflaeche weitergeleitet + +**Weg 2: Direkter Zugang** +1. Oeffnen Sie direkt `http://macmini:3000/admin/klausur-korrektur` + +### 13.2 Zwei Einstiegs-Optionen + +Beim ersten Besuch sehen Sie die Willkommens-Seite mit zwei Optionen: + +#### Option A: Schnellstart (Direkt hochladen) +- Ideal wenn Sie sofort loslegen moechten +- Keine manuelle Klausur-Erstellung erforderlich +- System erstellt automatisch eine Klausur im Hintergrund + +**Schritte:** +1. Klicken Sie auf "Schnellstart - Direkt hochladen" +2. **Schritt 1**: Ziehen Sie Ihre eingescannten Arbeiten (PDF/JPG/PNG) in den Upload-Bereich +3. **Schritt 2**: Optional - Waehlen Sie den Aufgabentyp und beschreiben Sie die Aufgabenstellung +4. **Schritt 3**: Pruefen Sie die Zusammenfassung und klicken "Korrektur starten" +5. Sie werden automatisch zur Korrektur-Ansicht weitergeleitet + +#### Option B: Neue Klausur erstellen (Standard) +- Empfohlen fuer regelmaessige Nutzung +- Volle Metadaten (Fach, Jahr, Kurs, Modus) +- Unterstuetzt Zweitkorrektur-Workflow + +**Schritte:** +1. Klicken Sie auf "Neue Klausur erstellen" +2. Geben Sie Titel, Fach, Jahr und Semester ein +3. Waehlen Sie den Modus: + - **Abitur**: Fuer offizielle Abitur-Pruefungen mit NiBiS-EH + - **Vorabitur**: Fuer Uebungsklausuren mit eigenem EH +4. Bei Vorabitur: Waehlen Sie Aufgabentyp und beschreiben Sie die Aufgabenstellung +5. Klicken Sie "Klausur erstellen" + +### 13.3 Arbeiten hochladen + +Nach Erstellung der Klausur: +1. Oeffnen Sie die Klausur aus der Liste +2. Klicken Sie "Arbeiten hochladen" +3. Waehlen Sie die eingescannten Dateien (PDF oder Bilder) +4. Geben Sie optional anonyme IDs (z.B. "Arbeit-1", "Arbeit-2") +5. Das System startet automatisch die OCR-Erkennung + +### 13.4 Korrigieren + +**Korrektur-Workspace (2/3-1/3 Layout):** +- Links (2/3): Das Originaldokument mit Zoom-Funktion +- Rechts (1/3): Bewertungspanel mit Kriterien + +**Schritt fuer Schritt:** +1. Oeffnen Sie eine Arbeit durch Klick auf "Korrigieren" +2. Lesen Sie die Arbeit im linken Bereich (Zoom mit +/-) +3. Setzen Sie Anmerkungen durch Klick auf das Dokument +4. Waehlen Sie den Anmerkungstyp: + - **RS** (rot): Rechtschreibfehler + - **Gram** (blau): Grammatikfehler + - **Inhalt** (gruen): Inhaltliche Anmerkungen + - **Kommentar**: Allgemeine Bemerkungen +5. Bewerten Sie die 5 Kriterien im rechten Panel: + - Rechtschreibung (15%) + - Grammatik (15%) + - Inhalt (40%) + - Struktur (15%) + - Stil (15%) +6. Klicken Sie "EH-Vorschlaege laden" fuer KI-Unterstuetzung +7. Klicken Sie "Gutachten generieren" fuer einen KI-Vorschlag +8. Bearbeiten Sie das Gutachten nach Bedarf +9. Klicken Sie "Speichern" und dann "Naechste Arbeit" + +### 13.5 Fairness-Analyse + +Nach Korrektur mehrerer Arbeiten: +1. Klicken Sie auf "Fairness-Dashboard" in der Klausur-Ansicht +2. Pruefen Sie: + - **Noten-Histogramm**: Ist die Verteilung realistisch? + - **Ausreisser**: Gibt es ungewoehnlich hohe/niedrige Noten? + - **Kriterien-Heatmap**: Sind Kriterien konsistent bewertet? +3. Nutzen Sie "Quick-Adjust" um Anpassungen vorzunehmen + +### 13.6 PDF-Export + +1. In der Klausur-Ansicht klicken Sie "PDF-Export" +2. Waehlen Sie: + - **Einzelgutachten**: PDF fuer einen Schueler + - **Alle Gutachten**: Gesamtes PDF fuer alle Arbeiten + - **Notenuebersicht**: Uebersicht aller Noten + - **Anmerkungen**: Alle Annotationen als PDF + +### 13.7 Zweitkorrektur (Optional) + +Fuer offizielle Abitur-Klausuren: +1. Erstkorrektur abschliessen (Status: "Abgeschlossen") +2. Klicken Sie "Zweitkorrektur starten" +3. Der Zweitkorrektor bewertet unabhaengig +4. Bei Differenz >= 3 Punkte: Einigung erforderlich +5. Bei Differenz >= 4 Punkte: Drittkorrektur wird automatisch ausgeloest + +### 13.8 Haeufige Fragen + +**F: Kann ich eine Korrektur unterbrechen und spaeter fortsetzen?** +A: Ja, alle Aenderungen werden automatisch gespeichert. + +**F: Was passiert mit meinen Daten?** +A: Alle Daten werden lokal auf dem Schulserver gespeichert. Keine Cloud-Speicherung. + +**F: Kann ich den KI-Vorschlag komplett ueberschreiben?** +A: Ja, das Gutachten ist frei editierbar. Der KI-Vorschlag ist nur ein Startpunkt. + +**F: Wie funktioniert die OCR-Erkennung?** +A: Das System erkennt Handschrift automatisch. Bei schlechter Lesbarkeit koennen Sie manuell nachbessern. + +--- + +## 14. Integration Dashboard (Port 8000) + +### 14.1 Aenderungen in dashboard.py + +Die Funktion `openKlausurService()` wurde aktualisiert: + +```javascript +// Alte Version: Oeffnete Port 8086 (Backend) +// Neue Version: Oeffnet Port 3000 (Next.js Frontend) +function openKlausurService() { + let baseUrl; + if (window.location.hostname === 'macmini') { + baseUrl = 'http://macmini:3000'; + } else { + baseUrl = 'http://localhost:3000'; + } + window.open(baseUrl + '/admin/klausur-korrektur', '_blank'); +} +``` + +### 14.2 Neue Frontend-Features + +- **Willkommens-Tab**: Erster Tab fuer neue Benutzer mit Workflow-Erklaerung +- **Direktupload-Wizard**: 3-Schritt-Wizard fuer Schnellstart +- **Drag & Drop**: Arbeiten per Drag & Drop hochladen +- **localStorage-Persistenz**: System merkt sich wiederkehrende Benutzer diff --git a/.claude/rules/documentation.md b/.claude/rules/documentation.md new file mode 100644 index 0000000..e5e035f --- /dev/null +++ b/.claude/rules/documentation.md @@ -0,0 +1,91 @@ +# Dokumentations-Regeln + +## Automatische Dokumentations-Aktualisierung + +**WICHTIG:** Bei JEDER Code-Änderung muss die entsprechende Dokumentation aktualisiert werden! + +## Wann Dokumentation aktualisieren? + +### API-Änderungen +Wenn du einen Endpoint änderst, hinzufügst oder entfernst: +- Aktualisiere `/docs/api/consent-service-api.md` (Go Endpoints) +- Aktualisiere `/docs/api/backend-api.md` (Python Endpoints) + +### Neue Funktionen/Klassen +Wenn du neue Funktionen, Klassen oder Module erstellst: +- Aktualisiere `/docs/consent-service/README.md` (für Go) +- Aktualisiere `/docs/backend/README.md` (für Python) + +### Architektur-Änderungen +Wenn du die Systemarchitektur änderst: +- Aktualisiere `/docs/architecture/system-architecture.md` +- Aktualisiere `/docs/architecture/data-model.md` (bei DB-Änderungen) + +### Neue Konfigurationsoptionen +Wenn du neue Umgebungsvariablen oder Konfigurationen hinzufügst: +- Aktualisiere die entsprechende README +- Füge zur `guides/local-development.md` hinzu + +## Dokumentations-Format + +### API-Endpoints dokumentieren + +```markdown +### METHOD /path/to/endpoint + +Kurze Beschreibung. + +**Request Body:** +\`\`\`json +{ + "field": "value" +} +\`\`\` + +**Response (200):** +\`\`\`json +{ + "result": "value" +} +\`\`\` + +**Errors:** +- `400`: Beschreibung +- `401`: Beschreibung +``` + +### Funktionen dokumentieren + +```markdown +### FunctionName (file.go:123) + +\`\`\`go +func FunctionName(param Type) ReturnType +\`\`\` + +**Beschreibung:** Was macht die Funktion? + +**Parameter:** +- `param`: Beschreibung + +**Rückgabe:** Beschreibung +``` + +## Checkliste nach Code-Änderungen + +Vor dem Abschluss einer Aufgabe prüfe: + +- [ ] Wurden neue API-Endpoints hinzugefügt? → API-Docs aktualisieren +- [ ] Wurden Datenmodelle geändert? → data-model.md aktualisieren +- [ ] Wurden neue Konfigurationen hinzugefügt? → README aktualisieren +- [ ] Wurden neue Abhängigkeiten hinzugefügt? → requirements.txt/go.mod UND Docs +- [ ] Wurde die Architektur geändert? → architecture/ aktualisieren + +## Beispiel: Vollständige Dokumentation einer neuen Funktion + +Wenn du z.B. `GetUserStats()` im Go Service hinzufügst: + +1. **Code schreiben** in `internal/services/stats_service.go` +2. **API-Doc aktualisieren** in `docs/api/consent-service-api.md` +3. **Service-Doc aktualisieren** in `docs/consent-service/README.md` +4. **Test schreiben** (siehe testing.md) diff --git a/.claude/rules/experimental-dashboard.md b/.claude/rules/experimental-dashboard.md new file mode 100644 index 0000000..2206259 --- /dev/null +++ b/.claude/rules/experimental-dashboard.md @@ -0,0 +1,250 @@ +# Experimental Dashboard - Apple Weather Style UI + +**Status:** In Entwicklung +**Letzte Aktualisierung:** 2026-01-24 +**URL:** http://macmini:3001/dashboard-experimental + +--- + +## Uebersicht + +Das Experimental Dashboard implementiert einen **Apple Weather App Style** mit: +- Ultra-transparenten Glassmorphism-Cards (~8% Opacity) +- Dunklem Sternenhimmel-Hintergrund mit Parallax +- Weisser Schrift auf monochromem Design +- Schwebenden Nachrichten (FloatingMessage) mit ~4% Background +- Nuetzlichen Widgets: Uhr, Wetter, Kompass, Diagramme + +--- + +## Design-Prinzipien + +| Prinzip | Umsetzung | +|---------|-----------| +| **Transparenz** | Cards mit 8% Opacity, Messages mit 4% | +| **Verschmelzung** | Elemente verschmelzen mit dem Hintergrund | +| **Monochrom** | Weisse Schrift, keine bunten Akzente | +| **Subtilitaet** | Dezente Hover-Effekte, sanfte Animationen | +| **Nuetzlichkeit** | Echte Informationen (Uhrzeit, Wetter) | + +--- + +## Dateistruktur + +``` +/studio-v2/ +├── app/ +│ └── dashboard-experimental/ +│ └── page.tsx # Haupt-Dashboard (740 Zeilen) +│ +├── components/ +│ └── spatial-ui/ +│ ├── index.ts # Exports +│ ├── SpatialCard.tsx # Original SpatialCard (nicht verwendet) +│ └── FloatingMessage.tsx # Schwebende Nachrichten +│ +└── lib/ + └── spatial-ui/ + ├── index.ts # Exports + ├── depth-system.ts # Design Tokens + ├── PerformanceContext.tsx # Adaptive Qualitaet + └── FocusContext.tsx # Focus-Modus +``` + +--- + +## Komponenten + +### GlassCard +Ultra-transparente Card fuer alle Inhalte. + +```typescript +interface GlassCardProps { + children: React.ReactNode + className?: string + onClick?: () => void + size?: 'sm' | 'md' | 'lg' // Padding: 16px, 20px, 24px + delay?: number // Einblend-Verzoegerung in ms +} +``` + +**Styling:** +- Background: `rgba(255, 255, 255, 0.08)` (8%) +- Hover: `rgba(255, 255, 255, 0.12)` (12%) +- Border: `1px solid rgba(255, 255, 255, 0.1)` +- Blur: 24px (adaptiv) +- Border-Radius: 24px (rounded-3xl) + +### AnalogClock +Analoge Uhr mit Sekundenzeiger. + +- Stunden-Zeiger: Weiss, dick +- Minuten-Zeiger: Weiss/80%, duenn +- Sekunden-Zeiger: Orange (#fb923c) +- 12 Stundenmarkierungen +- Aktualisiert jede Sekunde + +### Compass +Kompass im Apple Weather Style. + +```typescript +interface CompassProps { + direction?: number // Grad (0 = Nord, 90 = Ost, etc.) +} +``` + +- Nord-Nadel: Rot (#ef4444) +- Sued-Nadel: Weiss +- Kardinalrichtungen: N (rot), S, W, O + +### BarChart +Balkendiagramm fuer Wochen-Statistiken. + +```typescript +interface BarChartProps { + data: { label: string; value: number; highlight?: boolean }[] + maxValue?: number +} +``` + +- Highlight-Balken mit Gradient (blau → lila) +- Normale Balken: 20% weiss +- Labels unten, Werte oben + +### ProgressRing +Kreisfoermiger Fortschrittsanzeiger. + +```typescript +interface ProgressRingProps { + progress: number // 0-100 + size?: number // Default: 80px + strokeWidth?: number // Default: 6px + label: string + value: string + color?: string // Farbe des Fortschritts +} +``` + +### TemperatureDisplay +Wetter-Anzeige mit Icon und Temperatur. + +```typescript +interface TemperatureDisplayProps { + temp: number + condition: 'sunny' | 'cloudy' | 'rainy' | 'snowy' | 'partly_cloudy' +} +``` + +### FloatingMessage +Schwebende Benachrichtigungen von rechts. + +**Aktuell:** +- Background: 4% Opacity +- Blur: 24px +- Border: `1px solid rgba(255, 255, 255, 0.12)` +- Auto-Dismiss mit Progress-Bar +- 3 Antwort-Optionen: Antworten, Oeffnen, Spaeter +- Typewriter-Effekt fuer Text + +--- + +## Farbpalette + +| Element | Wert | +|---------|------| +| Background | `from-slate-900 via-indigo-950 to-slate-900` | +| Card Background | `rgba(255, 255, 255, 0.08)` | +| Card Hover | `rgba(255, 255, 255, 0.12)` | +| Message Background | `rgba(255, 255, 255, 0.04)` | +| Border | `rgba(255, 255, 255, 0.1)` | +| Text Primary | `text-white` | +| Text Secondary | `text-white/50` bis `text-white/40` | +| Accent Blue | `#60a5fa` | +| Accent Purple | `#a78bfa` | +| Accent Orange | `#fb923c` (Sekundenzeiger) | +| Accent Red | `#ef4444` (Kompass Nord) | + +--- + +## Performance-System + +Das Dashboard nutzt das **PerformanceContext** fuer adaptive Qualitaet: + +| Quality Level | Blur | Parallax | Animationen | +|---------------|------|----------|-------------| +| high | 24px | Ja | Spring | +| medium | 17px | Ja | Standard | +| low | 0px | Nein | Reduziert | +| minimal | 0px | Nein | Keine | + +**FPS-Monitor** unten links zeigt: +- Aktuelle FPS +- Quality Level +- Blur/Parallax Status + +--- + +## Deployment + +```bash +# 1. Sync zu Mac Mini +rsync -avz --delete \ + --exclude 'node_modules' --exclude '.next' --exclude '.git' \ + /Users/benjaminadmin/Projekte/breakpilot-pwa/studio-v2/ \ + macmini:/Users/benjaminadmin/Projekte/breakpilot-pwa/studio-v2/ + +# 2. Build +ssh macmini "/usr/local/bin/docker compose \ + -f /Users/benjaminadmin/Projekte/breakpilot-pwa/docker-compose.yml \ + build --no-cache studio-v2" + +# 3. Deploy +ssh macmini "/usr/local/bin/docker compose \ + -f /Users/benjaminadmin/Projekte/breakpilot-pwa/docker-compose.yml \ + up -d studio-v2" + +# 4. Testen +http://macmini:3001/dashboard-experimental +``` + +--- + +## Offene Punkte / Ideen + +### Kurzfristig +- [ ] Echte Wetterdaten via API integrieren +- [ ] Kompass-Richtung dynamisch (GPS oder manuell) +- [ ] Klick auf Cards fuehrt zu Detailseiten +- [ ] Light Mode Support (aktuell nur Dark) + +### Mittelfristig +- [ ] Drag & Drop fuer Card-Anordnung +- [ ] Weitere Widgets: Kalender, Termine, Erinnerungen +- [ ] Animierte Uebergaenge zwischen Seiten +- [ ] Sound-Feedback bei Interaktionen + +### Langfristig +- [ ] Personalisierbare Widgets +- [ ] Dashboard als Standard-Startseite +- [ ] Mobile-optimierte Version +- [ ] Integration mit Apple Health / Fitness Daten + +--- + +## Referenzen + +- **Apple Weather App** (iOS) - Hauptinspiration +- **Dribbble Shot:** https://dribbble.com/shots/26339637-Smart-Home-Dashboard-Glassmorphism-UI +- **Design Tokens:** `/studio-v2/lib/spatial-ui/depth-system.ts` + +--- + +## Aenderungshistorie + +| Datum | Aenderung | +|-------|-----------| +| 2026-01-24 | FloatingMessage auf 4% Opacity reduziert | +| 2026-01-24 | Kompass, Balkendiagramm, Analog-Uhr hinzugefuegt | +| 2026-01-24 | Cards auf 8% Opacity reduziert | +| 2026-01-24 | Apple Weather Style implementiert | +| 2026-01-24 | Erstes Spatial UI System erstellt | diff --git a/.claude/rules/multi-agent-architecture.md b/.claude/rules/multi-agent-architecture.md new file mode 100644 index 0000000..014f27c --- /dev/null +++ b/.claude/rules/multi-agent-architecture.md @@ -0,0 +1,295 @@ +# Multi-Agent Architektur - Entwicklerdokumentation + +**Status:** Implementiert +**Letzte Aktualisierung:** 2025-01-15 +**Modul:** `/agent-core/` + +--- + +## 1. Übersicht + +Die Multi-Agent-Architektur erweitert Breakpilot um ein verteiltes Agent-System basierend auf Mission Control Konzepten. + +### Kernkomponenten + +| Komponente | Pfad | Beschreibung | +|------------|------|--------------| +| Session Management | `/agent-core/sessions/` | Lifecycle & Recovery | +| Shared Brain | `/agent-core/brain/` | Langzeit-Gedächtnis | +| Orchestrator | `/agent-core/orchestrator/` | Koordination | +| SOUL Files | `/agent-core/soul/` | Agent-Persönlichkeiten | + +--- + +## 2. Agent-Typen + +| Agent | Aufgabe | SOUL-Datei | +|-------|---------|------------| +| **TutorAgent** | Lernbegleitung, Fragen beantworten | `tutor-agent.soul.md` | +| **GraderAgent** | Klausur-Korrektur, Bewertung | `grader-agent.soul.md` | +| **QualityJudge** | BQAS Qualitätsprüfung | `quality-judge.soul.md` | +| **AlertAgent** | Monitoring, Benachrichtigungen | `alert-agent.soul.md` | +| **Orchestrator** | Task-Koordination | `orchestrator.soul.md` | + +--- + +## 3. Wichtige Dateien + +### Session Management +``` +agent-core/sessions/ +├── session_manager.py # AgentSession, SessionManager, SessionState +├── heartbeat.py # HeartbeatMonitor, HeartbeatClient +└── checkpoint.py # CheckpointManager +``` + +### Shared Brain +``` +agent-core/brain/ +├── memory_store.py # MemoryStore, Memory (mit TTL) +├── context_manager.py # ConversationContext, ContextManager +└── knowledge_graph.py # KnowledgeGraph, Entity, Relationship +``` + +### Orchestrator +``` +agent-core/orchestrator/ +├── message_bus.py # MessageBus, AgentMessage, MessagePriority +├── supervisor.py # AgentSupervisor, AgentInfo, AgentStatus +└── task_router.py # TaskRouter, RoutingRule, RoutingResult +``` + +--- + +## 4. Datenbank-Schema + +Die Migration befindet sich in: +`/backend/migrations/add_agent_core_tables.sql` + +### Tabellen + +1. **agent_sessions** - Session-Daten mit Checkpoints +2. **agent_memory** - Langzeit-Gedächtnis mit TTL +3. **agent_messages** - Audit-Trail für Inter-Agent Kommunikation + +### Helper-Funktionen + +```sql +-- Abgelaufene Memories bereinigen +SELECT cleanup_expired_agent_memory(); + +-- Inaktive Sessions bereinigen +SELECT cleanup_stale_agent_sessions(48); -- 48 Stunden +``` + +--- + +## 5. Integration Voice-Service + +Der `EnhancedTaskOrchestrator` erweitert den bestehenden `TaskOrchestrator`: + +```python +# voice-service/services/enhanced_task_orchestrator.py + +from agent_core.sessions import SessionManager +from agent_core.orchestrator import MessageBus + +class EnhancedTaskOrchestrator(TaskOrchestrator): + # Nutzt Session-Checkpoints für Recovery + # Routet komplexe Tasks an spezialisierte Agents + # Führt Quality-Checks via BQAS durch +``` + +**Wichtig:** Der Enhanced Orchestrator ist abwärtskompatibel und kann parallel zum Original verwendet werden. + +--- + +## 6. Integration BQAS + +Der `QualityJudgeAgent` integriert BQAS mit dem Multi-Agent-System: + +```python +# voice-service/bqas/quality_judge_agent.py + +from bqas.judge import LLMJudge +from agent_core.orchestrator import MessageBus + +class QualityJudgeAgent: + # Wertet Responses in Echtzeit aus + # Nutzt Memory für konsistente Bewertungen + # Empfängt Evaluierungs-Requests via Message Bus +``` + +--- + +## 7. Code-Beispiele + +### Session erstellen + +```python +from agent_core.sessions import SessionManager + +manager = SessionManager(redis_client=redis, db_pool=pool) +session = await manager.create_session( + agent_type="tutor-agent", + user_id="user-123" +) +``` + +### Memory speichern + +```python +from agent_core.brain import MemoryStore + +store = MemoryStore(redis_client=redis, db_pool=pool) +await store.remember( + key="student:123:progress", + value={"level": 5, "score": 85}, + agent_id="tutor-agent", + ttl_days=30 +) +``` + +### Nachricht senden + +```python +from agent_core.orchestrator import MessageBus, AgentMessage + +bus = MessageBus(redis_client=redis) +await bus.publish(AgentMessage( + sender="orchestrator", + receiver="grader-agent", + message_type="grade_request", + payload={"exam_id": "exam-1"} +)) +``` + +--- + +## 8. Tests ausführen + +```bash +# Alle Agent-Core Tests +cd agent-core && pytest -v + +# Mit Coverage-Report +pytest --cov=. --cov-report=html + +# Einzelne Module +pytest tests/test_session_manager.py -v +pytest tests/test_message_bus.py -v +``` + +--- + +## 9. Deployment-Schritte + +### 1. Migration ausführen + +```bash +psql -h localhost -U breakpilot -d breakpilot \ + -f backend/migrations/add_agent_core_tables.sql +``` + +### 2. Voice-Service aktualisieren + +```bash +# Sync zu Server +rsync -avz --exclude 'node_modules' --exclude '.git' \ + /path/to/breakpilot-pwa/ server:/path/to/breakpilot-pwa/ + +# Container neu bauen +docker compose build --no-cache voice-service + +# Starten +docker compose up -d voice-service +``` + +### 3. Verifizieren + +```bash +# Session-Tabelle prüfen +psql -c "SELECT COUNT(*) FROM agent_sessions;" + +# Memory-Tabelle prüfen +psql -c "SELECT COUNT(*) FROM agent_memory;" +``` + +--- + +## 10. Monitoring + +### Metriken + +| Metrik | Beschreibung | +|--------|--------------| +| `agent_session_count` | Anzahl aktiver Sessions | +| `agent_heartbeat_delay_ms` | Zeit seit letztem Heartbeat | +| `agent_message_latency_ms` | Nachrichtenlatenz | +| `agent_memory_count` | Gespeicherte Memories | +| `agent_routing_success_rate` | Erfolgreiche Routings | + +### Health-Check-Endpunkte + +``` +GET /api/v1/agents/health # Supervisor Status +GET /api/v1/agents/sessions # Aktive Sessions +GET /api/v1/agents/memory/stats # Memory-Statistiken +``` + +--- + +## 11. Troubleshooting + +### Problem: Session nicht gefunden + +1. Prüfen ob Valkey läuft: `redis-cli ping` +2. Session-Timeout prüfen (default 24h) +3. Heartbeat-Status checken + +### Problem: Message Bus Timeout + +1. Redis Pub/Sub Status prüfen +2. Ziel-Agent registriert? +3. Timeout erhöhen (default 30s) + +### Problem: Memory nicht gefunden + +1. Namespace korrekt? +2. TTL abgelaufen? +3. Cleanup-Job gelaufen? + +--- + +## 12. Erweiterungen + +### Neuen Agent hinzufügen + +1. SOUL-Datei erstellen in `/agent-core/soul/` +2. Routing-Regel in `task_router.py` hinzufügen +3. Handler beim Supervisor registrieren +4. Tests schreiben + +### Neuen Memory-Typ hinzufügen + +1. Key-Schema definieren (z.B. `student:*:progress`) +2. TTL festlegen +3. Access-Pattern dokumentieren + +--- + +## 13. Referenzen + +- **Agent-Core README:** `/agent-core/README.md` +- **Migration:** `/backend/migrations/add_agent_core_tables.sql` +- **Voice-Service Integration:** `/voice-service/services/enhanced_task_orchestrator.py` +- **BQAS Integration:** `/voice-service/bqas/quality_judge_agent.py` +- **Tests:** `/agent-core/tests/` + +--- + +## 14. Änderungshistorie + +| Datum | Version | Änderung | +|-------|---------|----------| +| 2025-01-15 | 1.0.0 | Initial Release | diff --git a/.claude/rules/open-source-policy.md b/.claude/rules/open-source-policy.md new file mode 100644 index 0000000..af7001a --- /dev/null +++ b/.claude/rules/open-source-policy.md @@ -0,0 +1,99 @@ +# Open Source Policy + +## Lizenzprüfung (AUTOMATISCH BEI JEDER DEPENDENCY) + +### Erlaubte Lizenzen ✅ + +| Lizenz | Typ | Kommerziell OK | +|--------|-----|----------------| +| MIT | Permissive | ✅ | +| Apache-2.0 | Permissive | ✅ | +| BSD-2-Clause | Permissive | ✅ | +| BSD-3-Clause | Permissive | ✅ | +| ISC | Permissive | ✅ | +| MPL-2.0 | Weak Copyleft | ✅ | +| LGPL-2.1 / LGPL-3.0 | Weak Copyleft | ✅ (nur linking) | +| CC0-1.0 | Public Domain | ✅ | +| Unlicense | Public Domain | ✅ | + +### Verbotene Lizenzen ❌ + +| Lizenz | Grund | +|--------|-------| +| GPL-2.0 / GPL-3.0 | Copyleft - infiziert Projekt | +| AGPL-3.0 | Network Copyleft - SaaS-Killer | +| SSPL | Server Side Public License | +| BSL | Business Source License | +| "Non-Commercial" | Keine kommerzielle Nutzung | +| "Educational Only" | Nur für Bildung | +| Proprietary | Keine OSS | + +--- + +## Workflow bei neuer Dependency + +### 1. Vor dem Hinzufügen prüfen + +```bash +# NPM Package +npm view license + +# Python Package +pip show | grep License + +# Go Module +go-licenses check +``` + +### 2. Bei Unklarheit + +- README.md des Projekts lesen +- LICENSE-Datei prüfen +- SPDX-Identifier suchen +- Im Zweifel: **NICHT verwenden** + +### 3. Nach dem Hinzufügen + +**SBOM aktualisieren:** https://macmini:3002/infrastructure/sbom + +```bash +# SBOM generieren +cd /Users/benjaminadmin/Projekte/breakpilot-pwa + +# Python +pip-licenses --format=json > sbom/python-licenses.json + +# Node.js +npx license-checker --json > sbom/node-licenses.json + +# Go +go-licenses csv ./... > sbom/go-licenses.csv +``` + +--- + +## Grenzfälle + +### Dual-Licensed Packages +- Wenn MIT **oder** GPL angeboten wird → MIT wählen +- Dokumentieren welche Lizenz gewählt wurde + +### Transitive Dependencies +- Auch indirekte Abhängigkeiten prüfen +- `npm ls`, `pip-tree`, `go mod graph` + +### Fonts & Assets +- Google Fonts: ✅ (OFL) +- Font Awesome Free: ✅ (CC BY 4.0 / OFL / MIT) +- Icons8: ❌ (Attribution required, kompliziert) + +--- + +## Checkliste bei PR/Commit + +Wenn neue Dependencies hinzugefügt wurden: + +- [ ] Lizenz ist in der Whitelist +- [ ] SBOM wurde aktualisiert +- [ ] Keine GPL/AGPL-Abhängigkeiten eingeschleppt +- [ ] Bei Dual-License: MIT/Apache gewählt diff --git a/.claude/rules/testing.md b/.claude/rules/testing.md new file mode 100644 index 0000000..d7441f6 --- /dev/null +++ b/.claude/rules/testing.md @@ -0,0 +1,202 @@ +# Test-Regeln + +## Automatische Test-Erweiterung + +**WICHTIG:** Bei JEDER Code-Änderung müssen entsprechende Tests erstellt oder aktualisiert werden! + +## Wann Tests schreiben? + +### IMMER wenn du: +1. **Neue Funktionen** erstellst → Unit Test +2. **Neue API-Endpoints** hinzufügst → Handler Test +3. **Bugs fixst** → Regression Test (der Bug sollte nie wieder auftreten) +4. **Bestehenden Code änderst** → Bestehende Tests anpassen + +## Test-Struktur + +### Go Tests (Consent Service) + +**Speicherort:** Im gleichen Verzeichnis wie der Code + +``` +internal/ +├── services/ +│ ├── auth_service.go +│ └── auth_service_test.go ← Test hier +├── handlers/ +│ ├── handlers.go +│ └── handlers_test.go ← Test hier +└── middleware/ + ├── auth.go + └── middleware_test.go ← Test hier +``` + +**Test-Namenskonvention:** +```go +func TestFunctionName_Scenario_ExpectedResult(t *testing.T) + +// Beispiele: +func TestHashPassword_ValidPassword_ReturnsHash(t *testing.T) +func TestLogin_InvalidCredentials_Returns401(t *testing.T) +func TestCreateDocument_MissingTitle_ReturnsError(t *testing.T) +``` + +**Test-Template:** +```go +func TestFunctionName(t *testing.T) { + // Arrange + service := &MyService{} + input := "test-input" + + // Act + result, err := service.DoSomething(input) + + // Assert + if err != nil { + t.Fatalf("Expected no error, got %v", err) + } + if result != expected { + t.Errorf("Expected %v, got %v", expected, result) + } +} +``` + +**Table-Driven Tests bevorzugen:** +```go +func TestValidateEmail(t *testing.T) { + tests := []struct { + name string + email string + expected bool + }{ + {"valid email", "test@example.com", true}, + {"missing @", "testexample.com", false}, + {"empty", "", false}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result := ValidateEmail(tt.email) + if result != tt.expected { + t.Errorf("Expected %v, got %v", tt.expected, result) + } + }) + } +} +``` + +### Python Tests (Backend) + +**Speicherort:** `/backend/tests/` + +``` +backend/ +├── consent_client.py +├── gdpr_api.py +└── tests/ + ├── __init__.py + ├── test_consent_client.py ← Tests für consent_client.py + └── test_gdpr_api.py ← Tests für gdpr_api.py +``` + +**Test-Namenskonvention:** +```python +class TestClassName: + def test_method_scenario_expected_result(self): + pass + +# Beispiele: +class TestConsentClient: + def test_check_consent_valid_token_returns_status(self): + pass + + def test_check_consent_expired_token_raises_error(self): + pass +``` + +**Test-Template:** +```python +import pytest +from unittest.mock import AsyncMock, patch, MagicMock + +class TestMyFeature: + def test_sync_function(self): + # Arrange + input_data = "test" + + # Act + result = my_function(input_data) + + # Assert + assert result == expected + + @pytest.mark.asyncio + async def test_async_function(self): + # Arrange + client = MyClient() + + # Act + with patch("httpx.AsyncClient") as mock: + mock_instance = AsyncMock() + mock.return_value = mock_instance + result = await client.fetch_data() + + # Assert + assert result is not None +``` + +## Test-Kategorien + +### 1. Unit Tests (Höchste Priorität) +- Testen einzelne Funktionen/Methoden +- Keine externen Abhängigkeiten (Mocks verwenden) +- Schnell ausführbar + +### 2. Integration Tests +- Testen Zusammenspiel mehrerer Komponenten +- Können echte DB verwenden (Test-DB) + +### 3. Security Tests +- Auth/JWT Validierung +- Passwort-Hashing +- Berechtigungsprüfung + +## Checkliste vor Abschluss + +Vor dem Abschluss einer Aufgabe: + +- [ ] Gibt es Tests für alle neuen Funktionen? +- [ ] Gibt es Tests für alle Edge Cases? +- [ ] Gibt es Tests für Fehlerfälle? +- [ ] Laufen alle bestehenden Tests noch? (`go test ./...` / `pytest`) +- [ ] Ist die Test-Coverage angemessen? + +## Tests ausführen + +```bash +# Go - Alle Tests +cd consent-service && go test -v ./... + +# Go - Mit Coverage +cd consent-service && go test -cover ./... + +# Python - Alle Tests +cd backend && source venv/bin/activate && pytest -v + +# Python - Mit Coverage +cd backend && pytest --cov=. --cov-report=html +``` + +## Beispiel: Vollständiger Test-Workflow + +Wenn du z.B. eine neue `GetUserStats()` Funktion im Go Service hinzufügst: + +1. **Funktion schreiben** in `internal/services/stats_service.go` +2. **Test erstellen** in `internal/services/stats_service_test.go`: + ```go + func TestGetUserStats_ValidUser_ReturnsStats(t *testing.T) {...} + func TestGetUserStats_InvalidUser_ReturnsError(t *testing.T) {...} + func TestGetUserStats_NoConsents_ReturnsEmptyStats(t *testing.T) {...} + ``` +3. **Tests ausführen**: `go test -v ./internal/services/...` +4. **Dokumentation aktualisieren** (siehe documentation.md) diff --git a/.claude/rules/vocab-worksheet.md b/.claude/rules/vocab-worksheet.md new file mode 100644 index 0000000..2268ab3 --- /dev/null +++ b/.claude/rules/vocab-worksheet.md @@ -0,0 +1,205 @@ +# Vokabel-Arbeitsblatt Generator - Entwicklerdokumentation + +**Status:** Produktiv +**Letzte Aktualisierung:** 2026-02-08 +**URL:** https://macmini/vocab-worksheet + +--- + +## Uebersicht + +Der Vokabel-Arbeitsblatt Generator ermoeglicht Lehrern: +- Schulbuchseiten (PDF/Bild) zu scannen +- Vokabeln automatisch per OCR zu extrahieren +- Druckfertige Arbeitsblaetter in verschiedenen Formaten zu generieren + +--- + +## Architektur + +``` +Browser (studio-v2) klausur-service (Port 8086) PostgreSQL + │ │ │ + │ POST /upload-pdf-info │ │ + │ POST /process-single-page │ │ + │ POST /generate │ │ + │ POST /generate-nru │ ──── vocab_sessions ──────▶│ + │ GET /worksheets/{id}/pdf │ ──── vocab_entries ───────▶│ + │ │ ──── vocab_worksheets ────▶│ + └────────────────────────────┘ │ +``` + +--- + +## Arbeitsblatt-Formate + +### Standard-Format + +Klassisches Arbeitsblatt mit waehlbaren Uebungstypen: +- **Englisch → Deutsch**: Englische Woerter uebersetzen +- **Deutsch → Englisch**: Deutsche Woerter uebersetzen +- **Abschreibuebung**: Woerter mehrfach schreiben +- **Lueckensaetze**: Saetze mit Luecken ausfuellen + +### NRU-Format (Neu: 2026-02-08) + +Spezielles Format fuer strukturiertes Vokabellernen: + +**Seite 1 (pro gescannter Seite): Vokabeltabelle** +| Englisch | Deutsch | Korrektur | +|----------|---------|-----------| +| word | (leer) | (leer) | + +- Kind schreibt deutsche Uebersetzung +- Eltern korrigieren, Kind schreibt ggf. korrigierte Version + +**Seite 2 (pro gescannter Seite): Lernsaetze** +| Deutscher Satz | +|-----------------------------------| +| (2 leere Zeilen fuer EN-Uebersetzung) | + +- Deutscher Satz vorgegeben +- Kind schreibt englische Uebersetzung + +**Automatische Trennung:** +- Einzelwoerter/Phrasen → Vokabeltabelle +- Saetze (enden mit `.!?` oder > 50 Zeichen) → Lernsaetze + +--- + +## API-Endpoints + +### Standard-Format +``` +POST /api/v1/vocab/sessions/{session_id}/generate +Body: { + "worksheet_types": ["en_to_de", "de_to_en", "copy", "gap_fill"], + "title": "Vokabeln Unit 3", + "include_solutions": true, + "line_height": "normal" | "large" | "extra-large" +} +Response: { "id": "worksheet-uuid", ... } +``` + +### NRU-Format +``` +POST /api/v1/vocab/sessions/{session_id}/generate-nru +Body: { + "title": "Vokabeltest", + "include_solutions": true, + "specific_pages": [1, 2] // optional, 1-indexed +} +Response: { + "worksheet_id": "uuid", + "statistics": { + "total_entries": 96, + "vocabulary_count": 75, + "sentence_count": 21, + "source_pages": [1, 2, 3], + "worksheet_pages": 6 + }, + "download_url": "/api/v1/vocab/worksheets/{id}/pdf", + "solution_url": "/api/v1/vocab/worksheets/{id}/solution" +} +``` + +### PDF-Download +``` +GET /api/v1/vocab/worksheets/{worksheet_id}/pdf +GET /api/v1/vocab/worksheets/{worksheet_id}/solution +``` + +--- + +## Dateien + +### Backend (klausur-service) + +| Datei | Beschreibung | +|-------|--------------| +| `vocab_worksheet_api.py` | Haupt-API Router mit allen Endpoints | +| `nru_worksheet_generator.py` | NRU-Format HTML/PDF Generator | +| `vocab_session_store.py` | PostgreSQL Datenbankoperationen | +| `hybrid_vocab_extractor.py` | OCR-Extraktion (PaddleOCR + LLM) | +| `tesseract_vocab_extractor.py` | Tesseract OCR Fallback | + +### Frontend (studio-v2) + +| Datei | Beschreibung | +|-------|--------------| +| `app/vocab-worksheet/page.tsx` | Haupt-UI mit Template-Auswahl | + +--- + +## Datenbank-Schema + +```sql +-- Sessions +CREATE TABLE vocab_sessions ( + id UUID PRIMARY KEY, + name VARCHAR(255), + status VARCHAR(50), + vocabulary_count INT, + source_language VARCHAR(10), + target_language VARCHAR(10), + created_at TIMESTAMP +); + +-- Vokabeln +CREATE TABLE vocab_entries ( + id UUID PRIMARY KEY, + session_id UUID REFERENCES vocab_sessions(id), + english TEXT, + german TEXT, + example_sentence TEXT, + source_page INT, + source_row INT, + source_column INT +); + +-- Generierte Arbeitsblaetter +CREATE TABLE vocab_worksheets ( + id UUID PRIMARY KEY, + session_id UUID REFERENCES vocab_sessions(id), + worksheet_types JSONB, + pdf_path VARCHAR(500), + solution_path VARCHAR(500), + generated_at TIMESTAMP +); +``` + +--- + +## Deployment + +```bash +# 1. Backend synchronisieren +rsync -avz klausur-service/backend/ macmini:.../klausur-service/backend/ + +# 2. Frontend synchronisieren +rsync -avz studio-v2/app/vocab-worksheet/ macmini:.../studio-v2/app/vocab-worksheet/ + +# 3. Container neu bauen +ssh macmini "docker compose build --no-cache klausur-service studio-v2" + +# 4. Container starten +ssh macmini "docker compose up -d klausur-service studio-v2" +``` + +--- + +## Erweiterung: Neue Formate hinzufuegen + +1. **Backend**: Neuen Generator in `klausur-service/backend/` erstellen +2. **API**: Neuen Endpoint in `vocab_worksheet_api.py` hinzufuegen +3. **Frontend**: Format zu `worksheetFormats` Array in `page.tsx` hinzufuegen +4. **Doku**: Diese Datei aktualisieren + +--- + +## Aenderungshistorie + +| Datum | Aenderung | +|-------|-----------| +| 2026-02-08 | NRU-Format und Template-Auswahl hinzugefuegt | +| 2026-02-07 | Initiale Implementierung mit Standard-Format | diff --git a/docker-compose.yml b/docker-compose.yml index cc2e779..ec64681 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -453,3 +453,24 @@ services: restart: unless-stopped networks: - breakpilot-network + + # ========================================================= + # DOCUMENTATION + # ========================================================= + docs: + build: + context: . + dockerfile: docs-src/Dockerfile + container_name: bp-lehrer-docs + profiles: [docs] + platform: linux/arm64 + ports: + - "8010:80" + healthcheck: + test: ["CMD", "wget", "-q", "--spider", "http://127.0.0.1:80/"] + interval: 30s + timeout: 10s + retries: 3 + restart: unless-stopped + networks: + - breakpilot-network diff --git a/docs-src/Dockerfile b/docs-src/Dockerfile new file mode 100644 index 0000000..298c532 --- /dev/null +++ b/docs-src/Dockerfile @@ -0,0 +1,48 @@ +# ============================================ +# BreakPilot Lehrer Dokumentation - MkDocs Build +# Multi-stage build fuer minimale Image-Groesse +# ============================================ + +# Stage 1: Build MkDocs Site +FROM python:3.11-slim AS builder + +WORKDIR /docs + +RUN pip install --no-cache-dir \ + mkdocs==1.6.1 \ + mkdocs-material==9.5.47 \ + pymdown-extensions==10.12 + +COPY mkdocs.yml /docs/ +COPY docs-src/ /docs/docs-src/ + +RUN mkdocs build + +# Stage 2: Serve with Nginx +FROM nginx:alpine + +COPY --from=builder /docs/docs-site /usr/share/nginx/html + +RUN echo 'server { \ + listen 80; \ + server_name localhost; \ + root /usr/share/nginx/html; \ + index index.html; \ + location / { \ + try_files $uri $uri/ /index.html; \ + } \ + gzip on; \ + gzip_types text/plain text/css application/json application/javascript text/xml application/xml; \ + gzip_min_length 1000; \ + location ~* \.(css|js|png|jpg|jpeg|gif|ico|svg|woff|woff2)$ { \ + expires 1y; \ + add_header Cache-Control "public, immutable"; \ + } \ +}' > /etc/nginx/conf.d/default.conf + +EXPOSE 80 + +HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \ + CMD wget --no-verbose --tries=1 --spider http://localhost/ || exit 1 + +CMD ["nginx", "-g", "daemon off;"] diff --git a/docs-src/architecture/multi-agent.md b/docs-src/architecture/multi-agent.md new file mode 100644 index 0000000..15ff572 --- /dev/null +++ b/docs-src/architecture/multi-agent.md @@ -0,0 +1,286 @@ +# Multi-Agent Architektur - Entwicklerdokumentation + +**Status:** Implementiert +**Modul:** `/agent-core/` + +--- + +## 1. Übersicht + +Die Multi-Agent-Architektur erweitert Breakpilot um ein verteiltes Agent-System basierend auf Mission Control Konzepten. + +### Kernkomponenten + +| Komponente | Pfad | Beschreibung | +|------------|------|--------------| +| Session Management | `/agent-core/sessions/` | Lifecycle & Recovery | +| Shared Brain | `/agent-core/brain/` | Langzeit-Gedächtnis | +| Orchestrator | `/agent-core/orchestrator/` | Koordination | +| SOUL Files | `/agent-core/soul/` | Agent-Persönlichkeiten | + +--- + +## 2. Agent-Typen + +| Agent | Aufgabe | SOUL-Datei | +|-------|---------|------------| +| **TutorAgent** | Lernbegleitung, Fragen beantworten | `tutor-agent.soul.md` | +| **GraderAgent** | Klausur-Korrektur, Bewertung | `grader-agent.soul.md` | +| **QualityJudge** | BQAS Qualitätsprüfung | `quality-judge.soul.md` | +| **AlertAgent** | Monitoring, Benachrichtigungen | `alert-agent.soul.md` | +| **Orchestrator** | Task-Koordination | `orchestrator.soul.md` | + +--- + +## 3. Wichtige Dateien + +### Session Management +``` +agent-core/sessions/ +├── session_manager.py # AgentSession, SessionManager, SessionState +├── heartbeat.py # HeartbeatMonitor, HeartbeatClient +└── checkpoint.py # CheckpointManager +``` + +### Shared Brain +``` +agent-core/brain/ +├── memory_store.py # MemoryStore, Memory (mit TTL) +├── context_manager.py # ConversationContext, ContextManager +└── knowledge_graph.py # KnowledgeGraph, Entity, Relationship +``` + +### Orchestrator +``` +agent-core/orchestrator/ +├── message_bus.py # MessageBus, AgentMessage, MessagePriority +├── supervisor.py # AgentSupervisor, AgentInfo, AgentStatus +└── task_router.py # TaskRouter, RoutingRule, RoutingResult +``` + +--- + +## 4. Datenbank-Schema + +Die Migration befindet sich in: +`/backend/migrations/add_agent_core_tables.sql` + +### Tabellen + +1. **agent_sessions** - Session-Daten mit Checkpoints +2. **agent_memory** - Langzeit-Gedächtnis mit TTL +3. **agent_messages** - Audit-Trail für Inter-Agent Kommunikation + +### Helper-Funktionen + +```sql +-- Abgelaufene Memories bereinigen +SELECT cleanup_expired_agent_memory(); + +-- Inaktive Sessions bereinigen +SELECT cleanup_stale_agent_sessions(48); -- 48 Stunden +``` + +--- + +## 5. Integration Voice-Service + +Der `EnhancedTaskOrchestrator` erweitert den bestehenden `TaskOrchestrator`: + +```python +# voice-service/services/enhanced_task_orchestrator.py + +from agent_core.sessions import SessionManager +from agent_core.orchestrator import MessageBus + +class EnhancedTaskOrchestrator(TaskOrchestrator): + # Nutzt Session-Checkpoints für Recovery + # Routet komplexe Tasks an spezialisierte Agents + # Führt Quality-Checks via BQAS durch +``` + +**Wichtig:** Der Enhanced Orchestrator ist abwärtskompatibel und kann parallel zum Original verwendet werden. + +--- + +## 6. Integration BQAS + +Der `QualityJudgeAgent` integriert BQAS mit dem Multi-Agent-System: + +```python +# voice-service/bqas/quality_judge_agent.py + +from bqas.judge import LLMJudge +from agent_core.orchestrator import MessageBus + +class QualityJudgeAgent: + # Wertet Responses in Echtzeit aus + # Nutzt Memory für konsistente Bewertungen + # Empfängt Evaluierungs-Requests via Message Bus +``` + +--- + +## 7. Code-Beispiele + +### Session erstellen + +```python +from agent_core.sessions import SessionManager + +manager = SessionManager(redis_client=redis, db_pool=pool) +session = await manager.create_session( + agent_type="tutor-agent", + user_id="user-123" +) +``` + +### Memory speichern + +```python +from agent_core.brain import MemoryStore + +store = MemoryStore(redis_client=redis, db_pool=pool) +await store.remember( + key="student:123:progress", + value={"level": 5, "score": 85}, + agent_id="tutor-agent", + ttl_days=30 +) +``` + +### Nachricht senden + +```python +from agent_core.orchestrator import MessageBus, AgentMessage + +bus = MessageBus(redis_client=redis) +await bus.publish(AgentMessage( + sender="orchestrator", + receiver="grader-agent", + message_type="grade_request", + payload={"exam_id": "exam-1"} +)) +``` + +--- + +## 8. Tests ausführen + +```bash +# Alle Agent-Core Tests +cd agent-core && pytest -v + +# Mit Coverage-Report +pytest --cov=. --cov-report=html + +# Einzelne Module +pytest tests/test_session_manager.py -v +pytest tests/test_message_bus.py -v +``` + +--- + +## 9. Deployment-Schritte + +### 1. Migration ausführen + +```bash +psql -h localhost -U breakpilot -d breakpilot \ + -f backend/migrations/add_agent_core_tables.sql +``` + +### 2. Voice-Service aktualisieren + +```bash +# Sync zu Server +rsync -avz --exclude 'node_modules' --exclude '.git' \ + /path/to/breakpilot-pwa/ server:/path/to/breakpilot-pwa/ + +# Container neu bauen +docker compose build --no-cache voice-service + +# Starten +docker compose up -d voice-service +``` + +### 3. Verifizieren + +```bash +# Session-Tabelle prüfen +psql -c "SELECT COUNT(*) FROM agent_sessions;" + +# Memory-Tabelle prüfen +psql -c "SELECT COUNT(*) FROM agent_memory;" +``` + +--- + +## 10. Monitoring + +### Metriken + +| Metrik | Beschreibung | +|--------|--------------| +| `agent_session_count` | Anzahl aktiver Sessions | +| `agent_heartbeat_delay_ms` | Zeit seit letztem Heartbeat | +| `agent_message_latency_ms` | Nachrichtenlatenz | +| `agent_memory_count` | Gespeicherte Memories | +| `agent_routing_success_rate` | Erfolgreiche Routings | + +### Health-Check-Endpunkte + +``` +GET /api/v1/agents/health # Supervisor Status +GET /api/v1/agents/sessions # Aktive Sessions +GET /api/v1/agents/memory/stats # Memory-Statistiken +``` + +--- + +## 11. Troubleshooting + +### Problem: Session nicht gefunden + +1. Prüfen ob Valkey läuft: `redis-cli ping` +2. Session-Timeout prüfen (default 24h) +3. Heartbeat-Status checken + +### Problem: Message Bus Timeout + +1. Redis Pub/Sub Status prüfen +2. Ziel-Agent registriert? +3. Timeout erhöhen (default 30s) + +### Problem: Memory nicht gefunden + +1. Namespace korrekt? +2. TTL abgelaufen? +3. Cleanup-Job gelaufen? + +--- + +## 12. Erweiterungen + +### Neuen Agent hinzufügen + +1. SOUL-Datei erstellen in `/agent-core/soul/` +2. Routing-Regel in `task_router.py` hinzufügen +3. Handler beim Supervisor registrieren +4. Tests schreiben + +### Neuen Memory-Typ hinzufügen + +1. Key-Schema definieren (z.B. `student:*:progress`) +2. TTL festlegen +3. Access-Pattern dokumentieren + +--- + +## 13. Referenzen + +- **Agent-Core README:** `/agent-core/README.md` +- **Migration:** `/backend/migrations/add_agent_core_tables.sql` +- **Voice-Service Integration:** `/voice-service/services/enhanced_task_orchestrator.py` +- **BQAS Integration:** `/voice-service/bqas/quality_judge_agent.py` +- **Tests:** `/agent-core/tests/` diff --git a/docs-src/architecture/zeugnis-system.md b/docs-src/architecture/zeugnis-system.md new file mode 100644 index 0000000..ce04ea0 --- /dev/null +++ b/docs-src/architecture/zeugnis-system.md @@ -0,0 +1,169 @@ +# Zeugnis-System - Architecture Documentation + +## Overview + +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. + +## Architecture Diagram + +``` + ┌─────────────────────────────────────┐ + │ Python Backend (Port 8000) │ + │ backend/frontend/modules/school.py │ + │ │ + │ ┌─────────────────────────────────┐ │ + │ │ panel-school-certificates │ │ + │ │ - Klassenauswahl │ │ + │ │ - Notenspiegel │ │ + │ │ - Zeugnis-Wizard (5 Steps) │ │ + │ │ - Workflow-Status │ │ + │ └─────────────────────────────────┘ │ + └──────────────────┬──────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────────────────────────────────────┐ +│ School-Service (Go, Port 8084) │ +├─────────────────────────────────────────────────────────────────────────────────────────┤ +│ │ +│ ┌─────────────────────┐ ┌─────────────────────┐ ┌─────────────────────────────────┐ │ +│ │ Grade Handlers │ │ Statistics Handlers │ │ Certificate Handlers │ │ +│ │ │ │ │ │ │ │ +│ │ GetClassGrades │ │ GetClassStatistics │ │ GetCertificateTemplates │ │ +│ │ GetStudentGrades │ │ GetSubjectStatistics│ │ GetClassCertificates │ │ +│ │ UpdateOralGrade │ │ GetStudentStatistics│ │ GenerateCertificate │ │ +│ │ CalculateFinalGrades│ │ GetNotenspiegel │ │ BulkGenerateCertificates │ │ +│ │ LockFinalGrade │ │ │ │ FinalizeCertificate │ │ +│ │ UpdateGradeWeights │ │ │ │ GetCertificatePDF │ │ +│ └─────────────────────┘ └─────────────────────┘ └─────────────────────────────────┘ │ +│ │ +└─────────────────────────────────────────────────────────────────────────────────────────┘ + │ + ▼ + ┌─────────────────────────────────────┐ + │ PostgreSQL Database │ + │ │ + │ Tables: │ + │ - grade_overview │ + │ - exam_results │ + │ - students │ + │ - classes │ + │ - subjects │ + │ - certificates │ + │ - attendance │ + └─────────────────────────────────────┘ +``` + +## Zeugnis Workflow (Role Chain) + +The certificate workflow follows a strict approval chain from subject teachers to school principal: + +``` +┌──────────────────┐ ┌──────────────────┐ ┌────────────────────────┐ ┌────────────────────┐ ┌──────────────────┐ +│ FACHLEHRER │───▶│ KLASSENLEHRER │───▶│ ZEUGNISBEAUFTRAGTER │───▶│ SCHULLEITUNG │───▶│ SEKRETARIAT │ +│ (Subject │ │ (Class │ │ (Certificate │ │ (Principal) │ │ (Secretary) │ +│ Teacher) │ │ Teacher) │ │ Coordinator) │ │ │ │ │ +└──────────────────┘ └──────────────────┘ └────────────────────────┘ └────────────────────┘ └──────────────────┘ + │ │ │ │ │ + ▼ ▼ ▼ ▼ ▼ + Grades Entry Approve Quality Check Sign-off & Lock Print & Archive + (Oral/Written) Grades & Review +``` + +### Workflow States + +``` +┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ +│ DRAFT │────▶│ SUBMITTED │────▶│ REVIEWED │────▶│ SIGNED │────▶│ PRINTED │ +│ (Entwurf) │ │ (Eingereicht)│ │ (Geprueft) │ │(Unterzeichnet) │ (Gedruckt) │ +└─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘ + │ │ │ │ + ▼ ▼ ▼ ▼ + Fachlehrer Klassenlehrer Zeugnisbeauftragter Schulleitung +``` + +## RBAC Integration + +### Certificate-Related Roles + +| Role | German | Description | +|------|--------|-------------| +| `FACHLEHRER` | Fachlehrer | Subject teacher - enters grades | +| `KLASSENLEHRER` | Klassenlehrer | Class teacher - approves class grades | +| `ZEUGNISBEAUFTRAGTER` | Zeugnisbeauftragter | Certificate coordinator - quality control | +| `SCHULLEITUNG` | Schulleitung | Principal - final sign-off | +| `SEKRETARIAT` | Sekretariat | Secretary - printing & archiving | + +### Certificate Resource Types + +| ResourceType | Description | +|--------------|-------------| +| `ZEUGNIS` | Final certificate document | +| `ZEUGNIS_VORLAGE` | Certificate template (per Bundesland) | +| `ZEUGNIS_ENTWURF` | Draft certificate (before approval) | +| `FACHNOTE` | Subject grade | +| `KOPFNOTE` | Head grade (Arbeits-/Sozialverhalten) | +| `BEMERKUNG` | Certificate remarks | +| `STATISTIK` | Class/subject statistics | +| `NOTENSPIEGEL` | Grade distribution chart | + +## German Grading System + +| 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 | + +### Grade Calculation + +``` +Final Grade = (Written Weight * Written Avg) + (Oral Weight * Oral Avg) + +Default weights: +- Written (Klassenarbeiten): 50% +- Oral (muendliche Note): 50% + +Customizable per subject/student via UpdateGradeWeights endpoint. +``` + +## API Routes (School-Service) + +### Grade Management + +| Method | Endpoint | Description | +|--------|----------|-------------| +| GET | `/api/v1/school/grades/:classId` | Get class grades | +| GET | `/api/v1/school/grades/student/:studentId` | Get student grades | +| PUT | `/api/v1/school/grades/:studentId/:subjectId/oral` | Update oral grade | +| POST | `/api/v1/school/grades/calculate` | Calculate final grades | +| PUT | `/api/v1/school/grades/:studentId/:subjectId/lock` | Lock final grade | + +### Statistics + +| Method | Endpoint | Description | +|--------|----------|-------------| +| GET | `/api/v1/school/statistics/:classId` | Class statistics | +| GET | `/api/v1/school/statistics/:classId/subject/:subjectId` | Subject statistics | +| GET | `/api/v1/school/statistics/student/:studentId` | Student statistics | +| GET | `/api/v1/school/statistics/:classId/notenspiegel` | Grade distribution | + +### Certificates + +| Method | Endpoint | Description | +|--------|----------|-------------| +| GET | `/api/v1/school/certificates/templates` | List templates | +| GET | `/api/v1/school/certificates/class/:classId` | Class certificates | +| POST | `/api/v1/school/certificates/generate` | Generate single | +| POST | `/api/v1/school/certificates/generate-bulk` | Generate bulk | +| GET | `/api/v1/school/certificates/detail/:id/pdf` | Download PDF | + +## Security Considerations + +1. **RBAC Enforcement**: All certificate operations check user role permissions +2. **Tenant Isolation**: Teachers only see their own classes/students +3. **Audit Trail**: All grade changes and approvals logged +4. **Lock Mechanism**: Finalized certificates cannot be modified +5. **Workflow Enforcement**: Cannot skip approval steps diff --git a/docs-src/development/ci-cd-pipeline.md b/docs-src/development/ci-cd-pipeline.md new file mode 100644 index 0000000..b6d991e --- /dev/null +++ b/docs-src/development/ci-cd-pipeline.md @@ -0,0 +1,402 @@ +# CI/CD Pipeline + +Übersicht über den Deployment-Prozess für Breakpilot. + +## Übersicht + +| 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) | + +## Deployment-Architektur + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ Entwickler-MacBook │ +│ │ +│ breakpilot-pwa/ │ +│ ├── studio-v2/ (Next.js Frontend) │ +│ ├── admin-v2/ (Next.js Admin) │ +│ ├── backend/ (Python FastAPI) │ +│ ├── consent-service/ (Go Service) │ +│ ├── klausur-service/ (Python FastAPI) │ +│ ├── voice-service/ (Python FastAPI) │ +│ ├── ai-compliance-sdk/ (Go Service) │ +│ └── docs-src/ (MkDocs) │ +│ │ +│ $ ./sync-and-deploy.sh │ +└───────────────────────────────┬─────────────────────────────────┘ + │ + │ rsync + SSH + │ + ▼ +┌─────────────────────────────────────────────────────────────────┐ +│ Mac Mini Server │ +│ │ +│ Docker Compose │ +│ ├── website (Port 3000) │ +│ ├── studio-v2 (Port 3001) │ +│ ├── admin-v2 (Port 3002) │ +│ ├── backend (Port 8000) │ +│ ├── consent-service (Port 8081) │ +│ ├── klausur-service (Port 8086) │ +│ ├── voice-service (Port 8082) │ +│ ├── ai-compliance-sdk (Port 8090) │ +│ ├── docs (Port 8009) │ +│ ├── postgres │ +│ ├── valkey (Redis) │ +│ ├── qdrant │ +│ └── minio │ +│ │ +└─────────────────────────────────────────────────────────────────┘ +``` + +## Sync & Deploy Workflow + +### 1. Dateien synchronisieren + +```bash +# Sync aller relevanten Verzeichnisse zum Mac Mini +rsync -avz --delete \ + --exclude 'node_modules' \ + --exclude '.next' \ + --exclude '.git' \ + --exclude '__pycache__' \ + --exclude 'venv' \ + --exclude '.pytest_cache' \ + /Users/benjaminadmin/Projekte/breakpilot-pwa/ \ + macmini:/Users/benjaminadmin/Projekte/breakpilot-pwa/ +``` + +### 2. Container bauen + +```bash +# Einzelnen Service bauen +ssh macmini "/usr/local/bin/docker compose \ + -f /Users/benjaminadmin/Projekte/breakpilot-pwa/docker-compose.yml \ + build --no-cache " + +# Beispiele: +# studio-v2, admin-v2, website, backend, klausur-service, docs +``` + +### 3. Container deployen + +```bash +# Container neu starten +ssh macmini "/usr/local/bin/docker compose \ + -f /Users/benjaminadmin/Projekte/breakpilot-pwa/docker-compose.yml \ + up -d " +``` + +### 4. Logs prüfen + +```bash +# Container-Logs anzeigen +ssh macmini "/usr/local/bin/docker compose \ + -f /Users/benjaminadmin/Projekte/breakpilot-pwa/docker-compose.yml \ + logs -f " +``` + +## Service-spezifische Deployments + +### Next.js Frontend (studio-v2, admin-v2, website) + +```bash +# 1. Sync +rsync -avz --delete \ + --exclude 'node_modules' --exclude '.next' --exclude '.git' \ + /Users/benjaminadmin/Projekte/breakpilot-pwa/studio-v2/ \ + macmini:/Users/benjaminadmin/Projekte/breakpilot-pwa/studio-v2/ + +# 2. Build & Deploy +ssh macmini "/usr/local/bin/docker compose \ + -f /Users/benjaminadmin/Projekte/breakpilot-pwa/docker-compose.yml \ + build --no-cache studio-v2 && \ + /usr/local/bin/docker compose \ + -f /Users/benjaminadmin/Projekte/breakpilot-pwa/docker-compose.yml \ + up -d studio-v2" +``` + +### Python Services (backend, klausur-service, voice-service) + +```bash +# Build mit requirements.txt +ssh macmini "/usr/local/bin/docker compose \ + -f /Users/benjaminadmin/Projekte/breakpilot-pwa/docker-compose.yml \ + build klausur-service && \ + /usr/local/bin/docker compose \ + -f /Users/benjaminadmin/Projekte/breakpilot-pwa/docker-compose.yml \ + up -d klausur-service" +``` + +### Go Services (consent-service, ai-compliance-sdk) + +```bash +# Multi-stage Build (Go → Alpine) +ssh macmini "/usr/local/bin/docker compose \ + -f /Users/benjaminadmin/Projekte/breakpilot-pwa/docker-compose.yml \ + build --no-cache consent-service && \ + /usr/local/bin/docker compose \ + -f /Users/benjaminadmin/Projekte/breakpilot-pwa/docker-compose.yml \ + up -d consent-service" +``` + +### MkDocs Dokumentation + +```bash +# Build & Deploy +ssh macmini "/usr/local/bin/docker compose \ + -f /Users/benjaminadmin/Projekte/breakpilot-pwa/docker-compose.yml \ + build --no-cache docs && \ + /usr/local/bin/docker compose \ + -f /Users/benjaminadmin/Projekte/breakpilot-pwa/docker-compose.yml \ + up -d docs" + +# Verfügbar unter: http://macmini:8009 +``` + +## Health Checks + +### Service-Status prüfen + +```bash +# Alle Container-Status +ssh macmini "docker ps --format 'table {{.Names}}\t{{.Status}}\t{{.Ports}}'" + +# Health-Endpoints prüfen +curl -s http://macmini:8000/health +curl -s http://macmini:8081/health +curl -s http://macmini:8086/health +curl -s http://macmini:8090/health +``` + +### Logs analysieren + +```bash +# Letzte 100 Zeilen +ssh macmini "docker logs --tail 100 breakpilot-pwa-backend-1" + +# Live-Logs folgen +ssh macmini "docker logs -f breakpilot-pwa-backend-1" +``` + +## Rollback + +### Container auf vorherige Version zurücksetzen + +```bash +# 1. Aktuelles Image taggen +ssh macmini "docker tag breakpilot-pwa-backend:latest breakpilot-pwa-backend:backup" + +# 2. Altes Image deployen +ssh macmini "/usr/local/bin/docker compose \ + -f /Users/benjaminadmin/Projekte/breakpilot-pwa/docker-compose.yml \ + up -d backend" + +# 3. Bei Problemen: Backup wiederherstellen +ssh macmini "docker tag breakpilot-pwa-backend:backup breakpilot-pwa-backend:latest" +``` + +## Troubleshooting + +### Container startet nicht + +```bash +# 1. Logs prüfen +ssh macmini "docker logs breakpilot-pwa--1" + +# 2. Container manuell starten für Debug-Output +ssh macmini "docker compose -f .../docker-compose.yml run --rm " + +# 3. In Container einloggen +ssh macmini "docker exec -it breakpilot-pwa--1 /bin/sh" +``` + +### Port bereits belegt + +```bash +# Port-Belegung prüfen +ssh macmini "lsof -i :8000" + +# Container mit dem Port finden +ssh macmini "docker ps --filter publish=8000" +``` + +### Build-Fehler + +```bash +# Cache komplett leeren +ssh macmini "docker builder prune -a" + +# Ohne Cache bauen +ssh macmini "docker compose build --no-cache " +``` + +## Monitoring + +### Resource-Nutzung + +```bash +# CPU/Memory aller Container +ssh macmini "docker stats --no-stream" + +# Disk-Nutzung +ssh macmini "docker system df" +``` + +### Cleanup + +```bash +# Ungenutzte Images/Container entfernen +ssh macmini "docker system prune -a --volumes" + +# Nur dangling Images +ssh macmini "docker image prune" +``` + +## Umgebungsvariablen + +Umgebungsvariablen werden über `.env` Dateien und docker-compose.yml verwaltet: + +```yaml +# docker-compose.yml +services: + backend: + environment: + - DATABASE_URL=postgresql://... + - REDIS_URL=redis://valkey:6379 + - SECRET_KEY=${SECRET_KEY} +``` + +**Wichtig**: Sensible Werte niemals in Git committen. Stattdessen: +- `.env` Datei auf dem Server pflegen +- Secrets über HashiCorp Vault (siehe unten) + +## Woodpecker CI - Automatisierte OAuth Integration + +### Überblick + +Die OAuth-Integration zwischen Woodpecker CI und Gitea ist **vollständig automatisiert**. Credentials werden in HashiCorp Vault gespeichert und bei Bedarf automatisch regeneriert. + +!!! info "Warum automatisiert?" + Diese Automatisierung ist eine DevSecOps Best Practice: + + - **Infrastructure-as-Code**: Alles ist reproduzierbar + - **Disaster Recovery**: Verlorene Credentials können automatisch regeneriert werden + - **Security**: Secrets werden zentral in Vault verwaltet + - **Onboarding**: Neue Entwickler müssen nichts manuell konfigurieren + +### Architektur + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ Mac Mini Server │ +│ │ +│ ┌───────────────┐ OAuth 2.0 ┌───────────────┐ │ +│ │ Gitea │ ←─────────────────────────→│ Woodpecker │ │ +│ │ (Port 3003) │ Client ID + Secret │ (Port 8090) │ │ +│ └───────────────┘ └───────────────┘ │ +│ │ │ │ +│ │ OAuth App │ Env Vars│ +│ │ (DB: oauth2_application) │ │ +│ │ │ │ +│ ▼ ▼ │ +│ ┌───────────────────────────────────────────────────────────┐ │ +│ │ HashiCorp Vault (Port 8200) │ │ +│ │ │ │ +│ │ secret/cicd/woodpecker: │ │ +│ │ - gitea_client_id │ │ +│ │ - gitea_client_secret │ │ +│ │ │ │ +│ │ secret/cicd/api-tokens: │ │ +│ │ - gitea_token (für API-Zugriff) │ │ +│ │ - woodpecker_token (für Pipeline-Trigger) │ │ +│ └───────────────────────────────────────────────────────────┘ │ +└─────────────────────────────────────────────────────────────────┘ +``` + +### Credentials-Speicherorte + +| Ort | Pfad | Inhalt | +|-----|------|--------| +| **HashiCorp Vault** | `secret/cicd/woodpecker` | Client ID + Secret (Quelle der Wahrheit) | +| **.env Datei** | `WOODPECKER_GITEA_CLIENT/SECRET` | Für Docker Compose (aus Vault geladen) | +| **Gitea PostgreSQL** | `oauth2_application` Tabelle | OAuth App Registration (gehashtes Secret) | + +### Troubleshooting: OAuth Fehler + +Falls der Fehler "Client ID not registered" oder "user does not exist [uid: 0]" auftritt: + +```bash +# Option 1: Automatisches Regenerieren (empfohlen) +./scripts/sync-woodpecker-credentials.sh --regenerate + +# Option 2: Manuelles Vorgehen +# 1. Credentials aus Vault laden +vault kv get secret/cicd/woodpecker + +# 2. .env aktualisieren +WOODPECKER_GITEA_CLIENT= +WOODPECKER_GITEA_SECRET= + +# 3. Zu Mac Mini synchronisieren +rsync .env macmini:~/Projekte/breakpilot-pwa/ + +# 4. Woodpecker neu starten +ssh macmini "cd ~/Projekte/breakpilot-pwa && \ + docker compose up -d --force-recreate woodpecker-server" +``` + +### Das Sync-Script + +Das Script `scripts/sync-woodpecker-credentials.sh` automatisiert den gesamten Prozess: + +```bash +# Credentials aus Vault laden und .env aktualisieren +./scripts/sync-woodpecker-credentials.sh + +# Neue Credentials generieren (OAuth App in Gitea + Vault + .env) +./scripts/sync-woodpecker-credentials.sh --regenerate +``` + +Was das Script macht: + +1. **Liest** die aktuellen Credentials aus Vault +2. **Aktualisiert** die .env Datei automatisch +3. **Bei `--regenerate`**: + - Löscht alte OAuth Apps in Gitea + - Erstellt neue OAuth App mit neuem Client ID/Secret + - Speichert Credentials in Vault + - Aktualisiert .env + +### Vault-Zugriff + +```bash +# Vault Token (Development) +export VAULT_TOKEN=breakpilot-dev-token + +# Credentials lesen +docker exec -e VAULT_TOKEN=$VAULT_TOKEN breakpilot-pwa-vault \ + vault kv get secret/cicd/woodpecker + +# Credentials setzen +docker exec -e VAULT_TOKEN=$VAULT_TOKEN breakpilot-pwa-vault \ + vault kv put secret/cicd/woodpecker \ + gitea_client_id="..." \ + gitea_client_secret="..." +``` + +### Services neustarten nach Credentials-Änderung + +```bash +# Wichtig: --force-recreate um neue Env Vars zu laden +cd /Users/benjaminadmin/Projekte/breakpilot-pwa +docker compose up -d --force-recreate woodpecker-server + +# Logs prüfen +docker logs breakpilot-pwa-woodpecker-server --tail 50 +``` diff --git a/docs-src/development/documentation.md b/docs-src/development/documentation.md new file mode 100644 index 0000000..8587ef9 --- /dev/null +++ b/docs-src/development/documentation.md @@ -0,0 +1,159 @@ +# Dokumentations-Regeln + +## Automatische Dokumentations-Aktualisierung + +**WICHTIG:** Bei JEDER Code-Aenderung muss die entsprechende Dokumentation aktualisiert werden! + +## Wann Dokumentation aktualisieren? + +### API-Aenderungen + +Wenn du einen Endpoint aenderst, hinzufuegst oder entfernst: + +- Aktualisiere die [Backend API Dokumentation](../api/backend-api.md) +- Aktualisiere Service-spezifische API-Docs + +### Neue Funktionen/Klassen + +Wenn du neue Funktionen, Klassen oder Module erstellst: + +- Aktualisiere die entsprechende Service-Dokumentation +- Fuege Code-Beispiele hinzu + +### Architektur-Aenderungen + +Wenn du die Systemarchitektur aenderst: + +- Aktualisiere die [System-Architektur](../architecture/system-architecture.md) +- Aktualisiere Datenmodell-Dokumentation bei DB-Aenderungen + +### Neue Konfigurationsoptionen + +Wenn du neue Umgebungsvariablen oder Konfigurationen hinzufuegst: + +- Aktualisiere die entsprechende README +- Fuege zur [Umgebungs-Setup](../getting-started/environment-setup.md) hinzu + +## Dokumentations-Format + +### API-Endpoints dokumentieren + +```markdown +### METHOD /path/to/endpoint + +Kurze Beschreibung. + +**Request Body:** +```json +{ + "field": "value" +} +``` + +**Response (200):** +```json +{ + "result": "value" +} +``` + +**Errors:** +- `400`: Beschreibung +- `401`: Beschreibung +``` + +### Funktionen dokumentieren + +```markdown +### FunctionName (file.go:123) + +```go +func FunctionName(param Type) ReturnType +``` + +**Beschreibung:** Was macht die Funktion? + +**Parameter:** +- `param`: Beschreibung + +**Rueckgabe:** Beschreibung +``` + +## Checkliste nach Code-Aenderungen + +Vor dem Abschluss einer Aufgabe pruefen: + +- [ ] Wurden neue API-Endpoints hinzugefuegt? → API-Docs aktualisieren +- [ ] Wurden Datenmodelle geaendert? → Architektur-Docs aktualisieren +- [ ] Wurden neue Konfigurationen hinzugefuegt? → README aktualisieren +- [ ] Wurden neue Abhaengigkeiten hinzugefuegt? → requirements.txt/go.mod UND Docs +- [ ] Wurde die Architektur geaendert? → architecture/ aktualisieren + +## Beispiel: Vollstaendige Dokumentation einer neuen Funktion + +Wenn du z.B. `GetUserStats()` im Go Service hinzufuegst: + +1. **Code schreiben** in `internal/services/stats_service.go` +2. **API-Doc aktualisieren** in der API-Dokumentation +3. **Service-Doc aktualisieren** in der Service-README +4. **Test schreiben** (siehe [Testing](./testing.md)) + +## Dokumentations-Struktur + +Die zentrale Dokumentation befindet sich unter `docs-src/`: + +``` +docs-src/ +├── index.md # Startseite +├── getting-started/ # Erste Schritte +│ ├── environment-setup.md +│ └── mac-mini-setup.md +├── architecture/ # Architektur-Dokumentation +│ ├── system-architecture.md +│ ├── auth-system.md +│ └── ... +├── api/ # API-Dokumentation +│ └── backend-api.md +├── services/ # Service-Dokumentation +│ ├── klausur-service/ +│ ├── agent-core/ +│ └── ... +├── development/ # Entwickler-Guides +│ ├── testing.md +│ └── documentation.md +└── guides/ # Weitere Anleitungen +``` + +## MkDocs Konventionen + +Diese Dokumentation wird mit MkDocs + Material Theme generiert: + +- **Admonitions** fuer Hinweise: + ```markdown + !!! note "Hinweis" + Wichtige Information hier. + + !!! warning "Warnung" + Vorsicht bei dieser Aktion. + ``` + +- **Code-Tabs** fuer mehrere Sprachen: + ```markdown + === "Python" + ```python + print("Hello") + ``` + + === "Go" + ```go + fmt.Println("Hello") + ``` + ``` + +- **Mermaid-Diagramme** fuer Visualisierungen: + ```markdown + ```mermaid + graph LR + A --> B --> C + ``` + ``` diff --git a/docs-src/development/testing.md b/docs-src/development/testing.md new file mode 100644 index 0000000..83d5e53 --- /dev/null +++ b/docs-src/development/testing.md @@ -0,0 +1,211 @@ +# Test-Regeln + +## Automatische Test-Erweiterung + +**WICHTIG:** Bei JEDER Code-Aenderung muessen entsprechende Tests erstellt oder aktualisiert werden! + +## Wann Tests schreiben? + +### IMMER wenn du: + +1. **Neue Funktionen** erstellst → Unit Test +2. **Neue API-Endpoints** hinzufuegst → Handler Test +3. **Bugs fixst** → Regression Test (der Bug sollte nie wieder auftreten) +4. **Bestehenden Code aenderst** → Bestehende Tests anpassen + +## Test-Struktur + +### Go Tests (Consent Service) + +**Speicherort:** Im gleichen Verzeichnis wie der Code + +``` +internal/ +├── services/ +│ ├── auth_service.go +│ └── auth_service_test.go ← Test hier +├── handlers/ +│ ├── handlers.go +│ └── handlers_test.go ← Test hier +└── middleware/ + ├── auth.go + └── middleware_test.go ← Test hier +``` + +**Test-Namenskonvention:** + +```go +func TestFunctionName_Scenario_ExpectedResult(t *testing.T) + +// Beispiele: +func TestHashPassword_ValidPassword_ReturnsHash(t *testing.T) +func TestLogin_InvalidCredentials_Returns401(t *testing.T) +func TestCreateDocument_MissingTitle_ReturnsError(t *testing.T) +``` + +**Test-Template:** + +```go +func TestFunctionName(t *testing.T) { + // Arrange + service := &MyService{} + input := "test-input" + + // Act + result, err := service.DoSomething(input) + + // Assert + if err != nil { + t.Fatalf("Expected no error, got %v", err) + } + if result != expected { + t.Errorf("Expected %v, got %v", expected, result) + } +} +``` + +**Table-Driven Tests bevorzugen:** + +```go +func TestValidateEmail(t *testing.T) { + tests := []struct { + name string + email string + expected bool + }{ + {"valid email", "test@example.com", true}, + {"missing @", "testexample.com", false}, + {"empty", "", false}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result := ValidateEmail(tt.email) + if result != tt.expected { + t.Errorf("Expected %v, got %v", tt.expected, result) + } + }) + } +} +``` + +### Python Tests (Backend) + +**Speicherort:** `/backend/tests/` + +``` +backend/ +├── consent_client.py +├── gdpr_api.py +└── tests/ + ├── __init__.py + ├── test_consent_client.py ← Tests fuer consent_client.py + └── test_gdpr_api.py ← Tests fuer gdpr_api.py +``` + +**Test-Namenskonvention:** + +```python +class TestClassName: + def test_method_scenario_expected_result(self): + pass + +# Beispiele: +class TestConsentClient: + def test_check_consent_valid_token_returns_status(self): + pass + + def test_check_consent_expired_token_raises_error(self): + pass +``` + +**Test-Template:** + +```python +import pytest +from unittest.mock import AsyncMock, patch, MagicMock + +class TestMyFeature: + def test_sync_function(self): + # Arrange + input_data = "test" + + # Act + result = my_function(input_data) + + # Assert + assert result == expected + + @pytest.mark.asyncio + async def test_async_function(self): + # Arrange + client = MyClient() + + # Act + with patch("httpx.AsyncClient") as mock: + mock_instance = AsyncMock() + mock.return_value = mock_instance + result = await client.fetch_data() + + # Assert + assert result is not None +``` + +## Test-Kategorien + +### 1. Unit Tests (Hoechste Prioritaet) + +- Testen einzelne Funktionen/Methoden +- Keine externen Abhaengigkeiten (Mocks verwenden) +- Schnell ausfuehrbar + +### 2. Integration Tests + +- Testen Zusammenspiel mehrerer Komponenten +- Koennen echte DB verwenden (Test-DB) + +### 3. Security Tests + +- Auth/JWT Validierung +- Passwort-Hashing +- Berechtigungspruefung + +## Checkliste vor Abschluss + +Vor dem Abschluss einer Aufgabe: + +- [ ] Gibt es Tests fuer alle neuen Funktionen? +- [ ] Gibt es Tests fuer alle Edge Cases? +- [ ] Gibt es Tests fuer Fehlerfaelle? +- [ ] Laufen alle bestehenden Tests noch? (`go test ./...` / `pytest`) +- [ ] Ist die Test-Coverage angemessen? + +## Tests ausfuehren + +```bash +# Go - Alle Tests +cd consent-service && go test -v ./... + +# Go - Mit Coverage +cd consent-service && go test -cover ./... + +# Python - Alle Tests +cd backend && source venv/bin/activate && pytest -v + +# Python - Mit Coverage +cd backend && pytest --cov=. --cov-report=html +``` + +## Beispiel: Vollstaendiger Test-Workflow + +Wenn du z.B. eine neue `GetUserStats()` Funktion im Go Service hinzufuegst: + +1. **Funktion schreiben** in `internal/services/stats_service.go` +2. **Test erstellen** in `internal/services/stats_service_test.go`: + ```go + func TestGetUserStats_ValidUser_ReturnsStats(t *testing.T) {...} + func TestGetUserStats_InvalidUser_ReturnsError(t *testing.T) {...} + func TestGetUserStats_NoConsents_ReturnsEmptyStats(t *testing.T) {...} + ``` +3. **Tests ausfuehren**: `go test -v ./internal/services/...` +4. **Dokumentation aktualisieren** (siehe [Dokumentation](./documentation.md)) diff --git a/docs-src/index.md b/docs-src/index.md new file mode 100644 index 0000000..791409a --- /dev/null +++ b/docs-src/index.md @@ -0,0 +1,21 @@ +# BreakPilot Lehrer - Dokumentation + +Willkommen zur Dokumentation der **BreakPilot Lehrer KI-Plattform**. + +## Module + +- **Klausur-Service**: OCR, Korrektur, Vokabel-Worksheets +- **Voice-Service**: Spracheingabe und Transkription +- **Agent-Core**: Multi-Agent System +- **KI-Daten-Pipeline**: Datenverarbeitung + +## Architektur + +- [Multi-Agent System](architecture/multi-agent.md) +- [Zeugnis-System](architecture/zeugnis-system.md) + +## Entwicklung + +- [Testing](development/testing.md) +- [Dokumentation](development/documentation.md) +- [CI/CD Pipeline](development/ci-cd-pipeline.md) diff --git a/docs-src/services/agent-core/index.md b/docs-src/services/agent-core/index.md new file mode 100644 index 0000000..1a7ce6d --- /dev/null +++ b/docs-src/services/agent-core/index.md @@ -0,0 +1,420 @@ +# Breakpilot Agent Core + +Multi-Agent Architecture Infrastructure fuer Breakpilot. + +## Uebersicht + +Das `agent-core` Modul stellt die gemeinsame Infrastruktur fuer Breakpilots Multi-Agent-System bereit: + +- **Session Management**: Agent-Sessions mit Checkpoints und Recovery +- **Shared Brain**: Langzeit-Gedaechtnis und Kontext-Verwaltung +- **Orchestration**: Message Bus, Supervisor und Task-Routing + +## Architektur + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ Breakpilot Services │ +│ ┌─────────────┐ ┌─────────────┐ ┌─────────────────────────┐ │ +│ │Voice Service│ │Klausur Svc │ │ Admin-v2 / AlertAgent │ │ +│ └──────┬──────┘ └──────┬──────┘ └───────────┬─────────────┘ │ +│ │ │ │ │ +│ └────────────────┼──────────────────────┘ │ +│ │ │ +│ ┌───────────────────────▼───────────────────────────────────┐ │ +│ │ Agent Core │ │ +│ │ ┌─────────────┐ ┌─────────────┐ ┌───────────────────┐ │ │ +│ │ │ Sessions │ │Shared Brain │ │ Orchestrator │ │ │ +│ │ │ - Manager │ │ - Memory │ │ - Message Bus │ │ │ +│ │ │ - Heartbeat │ │ - Context │ │ - Supervisor │ │ │ +│ │ │ - Checkpoint│ │ - Knowledge │ │ - Task Router │ │ │ +│ │ └─────────────┘ └─────────────┘ └───────────────────┘ │ │ +│ └───────────────────────────────────────────────────────────┘ │ +│ │ │ +│ ┌───────────────────────▼───────────────────────────────────┐ │ +│ │ Infrastructure │ │ +│ │ Valkey (Redis) PostgreSQL Qdrant │ │ +│ └───────────────────────────────────────────────────────────┘ │ +└─────────────────────────────────────────────────────────────────┘ +``` + +## Verzeichnisstruktur + +``` +agent-core/ +├── __init__.py # Modul-Exports +├── README.md # Diese Datei +├── requirements.txt # Python-Abhaengigkeiten +├── pytest.ini # Test-Konfiguration +│ +├── soul/ # Agent SOUL Files (Persoenlichkeiten) +│ ├── tutor-agent.soul.md +│ ├── grader-agent.soul.md +│ ├── quality-judge.soul.md +│ ├── alert-agent.soul.md +│ └── orchestrator.soul.md +│ +├── brain/ # Shared Brain Implementation +│ ├── __init__.py +│ ├── memory_store.py # Langzeit-Gedaechtnis +│ ├── context_manager.py # Konversations-Kontext +│ └── knowledge_graph.py # Entity-Beziehungen +│ +├── sessions/ # Session Management +│ ├── __init__.py +│ ├── session_manager.py # Session-Lifecycle +│ ├── heartbeat.py # Liveness-Monitoring +│ └── checkpoint.py # Recovery-Checkpoints +│ +├── orchestrator/ # Multi-Agent Orchestration +│ ├── __init__.py +│ ├── message_bus.py # Inter-Agent Kommunikation +│ ├── supervisor.py # Agent-Ueberwachung +│ └── task_router.py # Intent-basiertes Routing +│ +└── tests/ # Unit Tests + ├── conftest.py + ├── test_session_manager.py + ├── test_heartbeat.py + ├── test_message_bus.py + ├── test_memory_store.py + └── test_task_router.py +``` + +## Komponenten + +### 1. Session Management + +Verwaltet Agent-Sessions mit State-Machine und Recovery-Faehigkeiten. + +```python +from agent_core.sessions import SessionManager, AgentSession + +# Session Manager erstellen +manager = SessionManager( + redis_client=redis, + db_pool=pg_pool, + namespace="breakpilot" +) + +# Session erstellen +session = await manager.create_session( + agent_type="tutor-agent", + user_id="user-123", + context={"subject": "math"} +) + +# Checkpoint setzen +session.checkpoint("task_started", {"task_id": "abc"}) + +# Session beenden +session.complete({"result": "success"}) +``` + +**Session States:** + +- `ACTIVE` - Session laeuft +- `PAUSED` - Session pausiert +- `COMPLETED` - Session erfolgreich beendet +- `FAILED` - Session fehlgeschlagen + +### 2. Heartbeat Monitoring + +Ueberwacht Agent-Liveness und triggert Recovery bei Timeout. + +```python +from agent_core.sessions import HeartbeatMonitor, HeartbeatClient + +# Monitor starten +monitor = HeartbeatMonitor( + timeout_seconds=30, + check_interval_seconds=5, + max_missed_beats=3 +) +await monitor.start_monitoring() + +# Agent registrieren +monitor.register("agent-1", "tutor-agent") + +# Heartbeat senden +async with HeartbeatClient("agent-1", monitor) as client: + # Agent-Arbeit... + pass +``` + +### 3. Memory Store + +Langzeit-Gedaechtnis fuer Agents mit TTL und Access-Tracking. + +```python +from agent_core.brain import MemoryStore + +store = MemoryStore(redis_client=redis, db_pool=pg_pool) + +# Erinnerung speichern +await store.remember( + key="evaluation:math:student-1", + value={"score": 85, "feedback": "Gut gemacht!"}, + agent_id="grader-agent", + ttl_days=30 +) + +# Erinnerung abrufen +result = await store.recall("evaluation:math:student-1") + +# Nach Pattern suchen +similar = await store.search("evaluation:math:*") +``` + +### 4. Context Manager + +Verwaltet Konversationskontext mit automatischer Komprimierung. + +```python +from agent_core.brain import ContextManager, MessageRole + +ctx_manager = ContextManager(redis_client=redis) + +# Kontext erstellen +context = ctx_manager.create_context( + session_id="session-123", + system_prompt="Du bist ein hilfreicher Tutor...", + max_messages=50 +) + +# Nachrichten hinzufuegen +context.add_message(MessageRole.USER, "Was ist Photosynthese?") +context.add_message(MessageRole.ASSISTANT, "Photosynthese ist...") + +# Fuer LLM API formatieren +messages = context.get_messages_for_llm() +``` + +### 5. Message Bus + +Inter-Agent Kommunikation via Redis Pub/Sub. + +```python +from agent_core.orchestrator import MessageBus, AgentMessage, MessagePriority + +bus = MessageBus(redis_client=redis) +await bus.start() + +# Handler registrieren +async def handle_message(msg): + return {"status": "processed"} + +await bus.subscribe("grader-agent", handle_message) + +# Nachricht senden +await bus.publish(AgentMessage( + sender="orchestrator", + receiver="grader-agent", + message_type="grade_request", + payload={"exam_id": "exam-1"}, + priority=MessagePriority.HIGH +)) + +# Request-Response Pattern +response = await bus.request(message, timeout=30.0) +``` + +### 6. Agent Supervisor + +Ueberwacht und koordiniert alle Agents. + +```python +from agent_core.orchestrator import AgentSupervisor, RestartPolicy + +supervisor = AgentSupervisor(message_bus=bus, heartbeat_monitor=monitor) + +# Agent registrieren +await supervisor.register_agent( + agent_id="tutor-1", + agent_type="tutor-agent", + restart_policy=RestartPolicy.ON_FAILURE, + max_restarts=3, + capacity=10 +) + +# Agent starten +await supervisor.start_agent("tutor-1") + +# Load Balancing +available = supervisor.get_available_agent("tutor-agent") +``` + +### 7. Task Router + +Intent-basiertes Routing mit Fallback-Ketten. + +```python +from agent_core.orchestrator import TaskRouter, RoutingRule, RoutingStrategy + +router = TaskRouter(supervisor=supervisor) + +# Eigene Regel hinzufuegen +router.add_rule(RoutingRule( + intent_pattern="learning_*", + agent_type="tutor-agent", + priority=10, + fallback_agent="orchestrator" +)) + +# Task routen +result = await router.route( + intent="learning_math", + context={"grade": 10}, + strategy=RoutingStrategy.LEAST_LOADED +) + +if result.success: + print(f"Routed to {result.agent_id}") +``` + +## SOUL Files + +SOUL-Dateien definieren die Persoenlichkeit und Verhaltensregeln jedes Agents. + +| Agent | SOUL File | Verantwortlichkeit | +|-------|-----------|-------------------| +| TutorAgent | tutor-agent.soul.md | Lernbegleitung, Fragen beantworten | +| GraderAgent | grader-agent.soul.md | Klausur-Korrektur, Bewertung | +| QualityJudge | quality-judge.soul.md | BQAS Qualitaetspruefung | +| AlertAgent | alert-agent.soul.md | Monitoring, Benachrichtigungen | +| Orchestrator | orchestrator.soul.md | Task-Koordination | + +## Datenbank-Schema + +### agent_sessions + +```sql +CREATE TABLE agent_sessions ( + id UUID PRIMARY KEY, + agent_type VARCHAR(50) NOT NULL, + user_id UUID REFERENCES users(id), + state VARCHAR(20) NOT NULL DEFAULT 'active', + context JSONB DEFAULT '{}', + checkpoints JSONB DEFAULT '[]', + created_at TIMESTAMPTZ DEFAULT NOW(), + updated_at TIMESTAMPTZ DEFAULT NOW(), + last_heartbeat TIMESTAMPTZ DEFAULT NOW() +); +``` + +### agent_memory + +```sql +CREATE TABLE agent_memory ( + id UUID PRIMARY KEY, + namespace VARCHAR(100) NOT NULL, + key VARCHAR(500) NOT NULL, + value JSONB NOT NULL, + agent_id VARCHAR(50) NOT NULL, + access_count INTEGER DEFAULT 0, + created_at TIMESTAMPTZ DEFAULT NOW(), + expires_at TIMESTAMPTZ, + UNIQUE(namespace, key) +); +``` + +### agent_messages + +```sql +CREATE TABLE agent_messages ( + id UUID PRIMARY KEY, + sender VARCHAR(50) NOT NULL, + receiver VARCHAR(50) NOT NULL, + message_type VARCHAR(50) NOT NULL, + payload JSONB NOT NULL, + priority INTEGER DEFAULT 1, + correlation_id UUID, + created_at TIMESTAMPTZ DEFAULT NOW() +); +``` + +## Integration + +### Mit Voice-Service + +```python +from services.enhanced_task_orchestrator import EnhancedTaskOrchestrator + +orchestrator = EnhancedTaskOrchestrator( + redis_client=redis, + db_pool=pg_pool +) + +await orchestrator.start() + +# Session fuer Voice-Interaktion +session = await orchestrator.create_session( + voice_session_id="voice-123", + user_id="teacher-1" +) + +# Task verarbeiten (nutzt Multi-Agent wenn noetig) +await orchestrator.process_task(task) +``` + +### Mit BQAS + +```python +from bqas.quality_judge_agent import QualityJudgeAgent + +judge = QualityJudgeAgent( + message_bus=bus, + memory_store=memory +) + +await judge.start() + +# Direkte Evaluation +result = await judge.evaluate( + response="Der Satz des Pythagoras...", + task_type="learning_math", + context={"user_input": "Was ist Pythagoras?"} +) + +if result["verdict"] == "production_ready": + # Response ist OK + pass +``` + +## Tests + +```bash +# In agent-core Verzeichnis +cd agent-core + +# Alle Tests ausfuehren +pytest -v + +# Mit Coverage +pytest --cov=. --cov-report=html + +# Einzelnes Test-Modul +pytest tests/test_session_manager.py -v + +# Async-Tests +pytest tests/test_message_bus.py -v +``` + +## Metriken + +Das Agent-Core exportiert folgende Metriken: + +| Metrik | Beschreibung | +|--------|--------------| +| `agent_session_duration_seconds` | Dauer von Agent-Sessions | +| `agent_heartbeat_delay_seconds` | Zeit seit letztem Heartbeat | +| `agent_message_latency_ms` | Latenz der Inter-Agent Kommunikation | +| `agent_memory_access_total` | Memory-Zugriffe pro Agent | +| `agent_error_total` | Fehler pro Agent-Typ | + +## Naechste Schritte + +1. **Migration ausfuehren**: `psql -f backend/migrations/add_agent_core_tables.sql` +2. **Voice-Service erweitern**: Enhanced Orchestrator aktivieren +3. **BQAS integrieren**: Quality Judge Agent starten +4. **Monitoring aufsetzen**: Metriken in Grafana integrieren diff --git a/docs-src/services/ki-daten-pipeline/architecture.md b/docs-src/services/ki-daten-pipeline/architecture.md new file mode 100644 index 0000000..65cf6aa --- /dev/null +++ b/docs-src/services/ki-daten-pipeline/architecture.md @@ -0,0 +1,353 @@ +# KI-Daten-Pipeline Architektur + +Diese Seite dokumentiert die technische Architektur der KI-Daten-Pipeline im Detail. + +## Systemuebersicht + +```mermaid +graph TB + subgraph Users["Benutzer"] + U1[Entwickler] + U2[Data Scientists] + U3[Lehrer] + end + + subgraph Frontend["Frontend (admin-v2)"] + direction TB + F1["OCR-Labeling
/ai/ocr-labeling"] + F2["RAG Pipeline
/ai/rag-pipeline"] + F3["Daten & RAG
/ai/rag"] + F4["Klausur-Korrektur
/ai/klausur-korrektur"] + end + + subgraph Backend["Backend Services"] + direction TB + B1["klausur-service
Port 8086"] + B2["embedding-service
Port 8087"] + end + + subgraph Storage["Persistenz"] + direction TB + D1[(PostgreSQL
Metadaten)] + D2[(Qdrant
Vektoren)] + D3[(MinIO
Bilder/PDFs)] + end + + subgraph External["Externe APIs"] + E1[OpenAI API] + E2[Ollama] + end + + U1 --> F1 + U2 --> F2 + U3 --> F4 + + F1 --> B1 + F2 --> B1 + F3 --> B1 + F4 --> B1 + + B1 --> D1 + B1 --> D2 + B1 --> D3 + B1 --> B2 + + B2 --> E1 + B1 --> E2 +``` + +## Komponenten-Details + +### OCR-Labeling Modul + +```mermaid +flowchart TB + subgraph Upload["Upload-Prozess"] + U1[Bilder hochladen] --> U2[MinIO speichern] + U2 --> U3[Session erstellen] + end + + subgraph OCR["OCR-Verarbeitung"] + O1[Bild laden] --> O2{Modell wählen} + O2 -->|llama3.2-vision| O3a[Vision LLM] + O2 -->|trocr| O3b[Transformer] + O2 -->|paddleocr| O3c[PaddleOCR] + O2 -->|donut| O3d[Document AI] + O3a --> O4[OCR-Text] + O3b --> O4 + O3c --> O4 + O3d --> O4 + end + + subgraph Labeling["Labeling-Prozess"] + L1[Queue laden] --> L2[Item anzeigen] + L2 --> L3{Entscheidung} + L3 -->|korrekt| L4[Bestaetigen] + L3 -->|falsch| L5[Korrigieren] + L3 -->|unklar| L6[Ueberspringen] + L4 --> L7[PostgreSQL] + L5 --> L7 + L6 --> L7 + end + + subgraph Export["Export"] + E1[Gelabelte Items] --> E2{Format} + E2 -->|TrOCR| E3a[Transformer Format] + E2 -->|Llama| E3b[Vision Format] + E2 -->|Generic| E3c[JSON] + end + + Upload --> OCR + OCR --> Labeling + Labeling --> Export +``` + +### RAG Pipeline Modul + +```mermaid +flowchart TB + subgraph Sources["Datenquellen"] + S1[NiBiS PDFs] + S2[Uploads] + S3[Rechtskorpus] + S4[Schulordnungen] + end + + subgraph Processing["Verarbeitung"] + direction TB + P1[PDF Parser] --> P2[OCR falls noetig] + P2 --> P3[Text Cleaning] + P3 --> P4[Chunking
1000 chars, 200 overlap] + P4 --> P5[Metadata Extraction] + end + + subgraph Embedding["Embedding"] + E1[embedding-service] --> E2[OpenAI API] + E2 --> E3[1536-dim Vektor] + end + + subgraph Indexing["Indexierung"] + I1{Collection waehlen} + I1 -->|EH| I2a[bp_nibis_eh] + I1 -->|Custom| I2b[bp_eh] + I1 -->|Legal| I2c[bp_legal_corpus] + I1 -->|Schul| I2d[bp_schulordnungen] + I2a --> I3[Qdrant upsert] + I2b --> I3 + I2c --> I3 + I2d --> I3 + end + + Sources --> Processing + Processing --> Embedding + Embedding --> Indexing +``` + +### Daten & RAG Modul + +```mermaid +flowchart TB + subgraph Query["Suchanfrage"] + Q1[User Query] --> Q2[Query Embedding] + Q2 --> Q3[1536-dim Vektor] + end + + subgraph Search["Qdrant Suche"] + S1[Collection waehlen] --> S2[Vector Search] + S2 --> S3[Top-k Results] + S3 --> S4[Score Filtering] + end + + subgraph Results["Ergebnisse"] + R1[Chunks] --> R2[Metadata anreichern] + R2 --> R3[Source URLs] + R3 --> R4[Response] + end + + Query --> Search + Search --> Results +``` + +## Datenmodelle + +### OCR-Labeling + +```typescript +interface OCRSession { + id: string + name: string + source_type: 'klausur' | 'handwriting_sample' | 'scan' + ocr_model: 'llama3.2-vision:11b' | 'trocr' | 'paddleocr' | 'donut' + total_items: number + labeled_items: number + status: 'active' | 'completed' | 'archived' + created_at: string +} + +interface OCRItem { + id: string + session_id: string + image_path: string + ocr_text: string | null + ocr_confidence: number | null + ground_truth: string | null + status: 'pending' | 'confirmed' | 'corrected' | 'skipped' + label_time_seconds: number | null +} +``` + +### RAG Pipeline + +```typescript +interface TrainingJob { + id: string + name: string + status: 'queued' | 'preparing' | 'training' | 'validating' | 'completed' | 'failed' | 'paused' + progress: number + current_epoch: number + total_epochs: number + documents_processed: number + total_documents: number + config: { + batch_size: number + bundeslaender: string[] + mixed_precision: boolean + } +} + +interface DataSource { + id: string + name: string + collection: string + document_count: number + chunk_count: number + status: 'active' | 'pending' | 'error' + last_updated: string | null +} +``` + +### Legal Corpus + +```typescript +interface RegulationStatus { + code: string + name: string + fullName: string + type: 'eu_regulation' | 'eu_directive' | 'de_law' | 'bsi_standard' + chunkCount: number + status: 'ready' | 'empty' | 'error' +} + +interface SearchResult { + text: string + regulation_code: string + regulation_name: string + article: string | null + paragraph: string | null + source_url: string + score: number +} +``` + +## Qdrant Collections + +### Konfiguration + +| Collection | Vektor-Dimension | Distanz-Metrik | Payload | +|------------|-----------------|----------------|---------| +| `bp_nibis_eh` | 1536 | COSINE | bundesland, fach, aufgabe | +| `bp_eh` | 1536 | COSINE | user_id, klausur_id | +| `bp_legal_corpus` | 1536 | COSINE | regulation, article, source_url | +| `bp_schulordnungen` | 1536 | COSINE | bundesland, typ, datum | + +### Chunk-Strategie + +``` +┌─────────────────────────────────────────────────────────────┐ +│ Originaldokument │ +│ Lorem ipsum dolor sit amet, consectetur adipiscing elit... │ +└─────────────────────────────────────────────────────────────┘ + │ + ▼ +┌──────────────────────┐ ┌──────────────────────┐ ┌──────────────────────┐ +│ Chunk 1 │ │ Chunk 2 │ │ Chunk 3 │ +│ 0-1000 chars │ │ 800-1800 chars │ │ 1600-2600 chars │ +│ │ │ (200 overlap) │ │ (200 overlap) │ +└──────────────────────┘ └──────────────────────┘ └──────────────────────┘ +``` + +## API-Authentifizierung + +Alle Endpunkte nutzen die zentrale Auth-Middleware: + +```mermaid +sequenceDiagram + participant C as Client + participant A as API Gateway + participant S as klausur-service + participant D as Datenbank + + C->>A: Request + JWT Token + A->>A: Token validieren + A->>S: Forwarded Request + S->>D: Daten abfragen + D->>S: Response + S->>C: JSON Response +``` + +## Monitoring & Metriken + +### Verfuegbare Metriken + +| Metrik | Beschreibung | Endpoint | +|--------|--------------|----------| +| `ocr_items_total` | Gesamtzahl OCR-Items | `/api/v1/ocr-label/stats` | +| `ocr_accuracy_rate` | OCR-Genauigkeit | `/api/v1/ocr-label/stats` | +| `rag_chunk_count` | Anzahl indexierter Chunks | `/api/legal-corpus/status` | +| `rag_collection_status` | Collection-Status | `/api/legal-corpus/status` | + +### Logging + +```python +# Strukturiertes Logging im klausur-service +logger.info("OCR processing started", extra={ + "session_id": session_id, + "item_count": item_count, + "model": ocr_model +}) +``` + +## Fehlerbehandlung + +### Retry-Strategien + +| Operation | Max Retries | Backoff | +|-----------|-------------|---------| +| OCR-Verarbeitung | 3 | Exponentiell (1s, 2s, 4s) | +| Embedding-API | 5 | Exponentiell mit Jitter | +| Qdrant-Upsert | 3 | Linear (1s) | + +### Fallback-Verhalten + +```mermaid +flowchart TD + A[Embedding Request] --> B{OpenAI verfuegbar?} + B -->|Ja| C[OpenAI API] + B -->|Nein| D{Lokales Modell?} + D -->|Ja| E[Ollama Embedding] + D -->|Nein| F[Error + Queue] +``` + +## Skalierung + +### Aktueller Stand + +- **Single Node**: Alle Services auf Mac Mini +- **Qdrant**: Standalone, ~50k Chunks +- **PostgreSQL**: Shared mit anderen Services + +### Geplante Erweiterungen + +1. **Qdrant Cluster**: Bei > 1M Chunks +2. **Worker Queue**: Redis-basiert fuer Batch-Jobs +3. **GPU-Offloading**: OCR auf vast.ai GPU-Instanzen diff --git a/docs-src/services/ki-daten-pipeline/index.md b/docs-src/services/ki-daten-pipeline/index.md new file mode 100644 index 0000000..d9f824b --- /dev/null +++ b/docs-src/services/ki-daten-pipeline/index.md @@ -0,0 +1,215 @@ +# KI-Daten-Pipeline + +Die KI-Daten-Pipeline ist ein zusammenhaengendes System aus drei Modulen, das den Datenfluss von der Erfassung bis zur semantischen Suche abbildet. + +## Uebersicht + +```mermaid +flowchart LR + subgraph OCR["OCR-Labeling"] + A[Klausur-Scans] --> B[OCR Erkennung] + B --> C[Ground Truth Labels] + end + + subgraph RAG["RAG Pipeline"] + D[PDF Dokumente] --> E[Text-Extraktion] + E --> F[Chunking] + F --> G[Embedding] + end + + subgraph SEARCH["Daten & RAG"] + H[Qdrant Collections] + I[Semantische Suche] + end + + C -->|Export| D + G -->|Indexierung| H + H --> I + I -->|Ergebnisse| J[Klausur-Korrektur] +``` + +## Module + +| Modul | Pfad | Funktion | Backend | +|-------|------|----------|---------| +| **OCR-Labeling** | `/ai/ocr-labeling` | Ground Truth fuer Handschrift-OCR | klausur-service:8086 | +| **RAG Pipeline** | `/ai/rag-pipeline` | Dokument-Indexierung | klausur-service:8086 | +| **Daten & RAG** | `/ai/rag` | Vektor-Suche & Collection-Mapping | klausur-service:8086 | + +## Datenfluss + +### 1. OCR-Labeling (Eingabe) + +Das OCR-Labeling-Modul erfasst Ground Truth Daten fuer das Training von Handschrift-Erkennungsmodellen: + +- **Upload**: Klausur-Scans (PDF/Bilder) werden hochgeladen +- **OCR-Verarbeitung**: Mehrere OCR-Modelle erkennen den Text + - `llama3.2-vision:11b` - Vision LLM (beste Qualitaet) + - `trocr` - Microsoft Transformer (schnell) + - `paddleocr` - PaddleOCR + LLM (4x schneller) + - `donut` - Document Understanding (strukturiert) +- **Labeling**: Manuelles Pruefen und Korrigieren der OCR-Ergebnisse +- **Export**: Gelabelte Daten koennen exportiert werden fuer: + - TrOCR Fine-Tuning + - Llama Vision Fine-Tuning + - Generic JSON + +### 2. RAG Pipeline (Verarbeitung) + +Die RAG Pipeline verarbeitet Dokumente und macht sie suchbar: + +```mermaid +flowchart TD + A[Datenquellen] --> B[OCR/Text-Extraktion] + B --> C[Chunking] + C --> D[Embedding] + D --> E[Qdrant Indexierung] + + subgraph sources["Datenquellen"] + S1[NiBiS PDFs] + S2[Eigene EH] + S3[Rechtskorpus] + S4[Schulordnungen] + end +``` + +**Verarbeitungsschritte:** + +1. **Dokumentenextraktion**: PDFs und Bilder werden per OCR in Text umgewandelt +2. **Chunking**: Lange Texte werden in Abschnitte aufgeteilt + - Chunk-Groesse: 1000 Zeichen + - Ueberlappung: 200 Zeichen +3. **Embedding**: Jeder Chunk wird in einen Vektor umgewandelt + - Modell: `text-embedding-3-small` + - Dimensionen: 1536 +4. **Indexierung**: Vektoren werden in Qdrant gespeichert + +### 3. Daten & RAG (Ausgabe) + +Das Daten & RAG Modul ermoeglicht die Verwaltung und Suche: + +- **Collection-Uebersicht**: Status aller Qdrant Collections +- **Semantische Suche**: Fragen werden in Vektoren umgewandelt und aehnliche Dokumente gefunden +- **Regulierungs-Mapping**: Zeigt welche Regulierungen indexiert sind + +## Qdrant Collections + +| Collection | Inhalt | Status | +|------------|--------|--------| +| `bp_nibis_eh` | Offizielle NiBiS Erwartungshorizonte | Aktiv | +| `bp_eh` | Benutzerdefinierte Erwartungshorizonte | Aktiv | +| `bp_schulordnungen` | Schulordnungen aller Bundeslaender | In Arbeit | +| `bp_legal_corpus` | Rechtskorpus (DSGVO, AI Act, BSI, etc.) | Aktiv | + +## Technische Architektur + +### Services + +```mermaid +graph TB + subgraph Frontend["Admin-v2 (Next.js)"] + F1["/ai/ocr-labeling"] + F2["/ai/rag-pipeline"] + F3["/ai/rag"] + end + + subgraph Backend["klausur-service (Python)"] + B1[OCR Endpoints] + B2[Indexierungs-Jobs] + B3[Such-API] + end + + subgraph Storage["Datenbanken"] + D1[(PostgreSQL)] + D2[(Qdrant)] + D3[(MinIO)] + end + + F1 --> B1 + F2 --> B2 + F3 --> B3 + + B1 --> D1 + B1 --> D3 + B2 --> D2 + B3 --> D2 +``` + +### Backend-Endpunkte + +#### OCR-Labeling (`/api/v1/ocr-label/`) + +| Endpoint | Methode | Beschreibung | +|----------|---------|--------------| +| `/sessions` | GET/POST | Session-Verwaltung | +| `/sessions/{id}/upload` | POST | Bilder hochladen | +| `/queue` | GET | Labeling-Queue | +| `/confirm` | POST | OCR bestaetigen | +| `/correct` | POST | OCR korrigieren | +| `/skip` | POST | Item ueberspringen | +| `/stats` | GET | Statistiken | +| `/export` | POST | Trainingsdaten exportieren | + +#### RAG Pipeline (`/api/ai/rag-pipeline`) + +| Action | Beschreibung | +|--------|--------------| +| `jobs` | Indexierungs-Jobs auflisten | +| `dataset-stats` | Datensatz-Statistiken | +| `create-job` | Neue Indexierung starten | +| `pause` | Job pausieren | +| `resume` | Job fortsetzen | +| `cancel` | Job abbrechen | + +#### Legal Corpus (`/api/legal-corpus/`) + +| Endpoint | Beschreibung | +|----------|--------------| +| `/status` | Collection-Status | +| `/search` | Semantische Suche | +| `/ingest` | Dokumente indexieren | + +## Integration mit Klausur-Korrektur + +Die KI-Daten-Pipeline liefert Erwartungshorizont-Vorschlaege fuer die Klausur-Korrektur: + +```mermaid +sequenceDiagram + participant L as Lehrer + participant K as Klausur-Korrektur + participant R as RAG-Suche + participant Q as Qdrant + + L->>K: Schueler-Antwort pruefen + K->>R: EH-Vorschlaege laden + R->>Q: Semantische Suche + Q->>R: Top-k Chunks + R->>K: Relevante EH-Passagen + K->>L: Bewertungsvorschlaege +``` + +## Deployment + +Die Module werden als Teil des admin-v2 Containers deployed: + +```bash +# 1. Sync +rsync -avz --delete --exclude 'node_modules' --exclude '.next' --exclude '.git' \ + /Users/benjaminadmin/Projekte/breakpilot-pwa/admin-v2/ \ + macmini:/Users/benjaminadmin/Projekte/breakpilot-pwa/admin-v2/ + +# 2. Build & Deploy +ssh macmini "/usr/local/bin/docker compose \ + -f /Users/benjaminadmin/Projekte/breakpilot-pwa/docker-compose.yml \ + build --no-cache admin-v2 && \ + /usr/local/bin/docker compose \ + -f /Users/benjaminadmin/Projekte/breakpilot-pwa/docker-compose.yml \ + up -d admin-v2" +``` + +## Verwandte Dokumentation + +- [OCR Labeling Spezifikation](../klausur-service/OCR-Labeling-Spec.md) +- [RAG Admin Spezifikation](../klausur-service/RAG-Admin-Spec.md) +- [NiBiS Ingestion Pipeline](../klausur-service/NiBiS-Ingestion-Pipeline.md) +- [Multi-Agent Architektur](../../architecture/multi-agent.md) diff --git a/docs-src/services/klausur-service/BYOEH-Architecture.md b/docs-src/services/klausur-service/BYOEH-Architecture.md new file mode 100644 index 0000000..753a8ce --- /dev/null +++ b/docs-src/services/klausur-service/BYOEH-Architecture.md @@ -0,0 +1,322 @@ +# BYOEH (Bring-Your-Own-Expectation-Horizon) - Architecture Documentation + +## Overview + +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: + +- **Tenant Isolation**: Each teacher/school has an isolated namespace +- **No Training Guarantee**: EH content is only used for RAG, never for model training +- **Operator Blindness**: Client-side encryption ensures Breakpilot cannot view plaintext +- **Rights Confirmation**: Required legal acknowledgment at upload time + +## Architecture Diagram + +``` +┌─────────────────────────────────────────────────────────────────────────┐ +│ klausur-service (Port 8086) │ +├─────────────────────────────────────────────────────────────────────────┤ +│ ┌────────────────────┐ ┌─────────────────────────────────────────┐ │ +│ │ BYOEH REST API │ │ BYOEH Service Layer │ │ +│ │ │ │ │ │ +│ │ POST /api/v1/eh │───▶│ - Upload Wizard Logic │ │ +│ │ GET /api/v1/eh │ │ - Rights Confirmation │ │ +│ │ DELETE /api/v1/eh │ │ - Chunking Pipeline │ │ +│ │ POST /rag-query │ │ - Encryption Service │ │ +│ └────────────────────┘ └────────────────────┬────────────────────┘ │ +└─────────────────────────────────────────────────┼────────────────────────┘ + │ + ┌───────────────────────────────────────┼───────────────────────┐ + │ │ │ + ▼ ▼ ▼ +┌──────────────────────┐ ┌──────────────────────────┐ ┌──────────────────────┐ +│ PostgreSQL │ │ Qdrant │ │ Encrypted Storage │ +│ (Metadata + Audit) │ │ (Vector Search) │ │ /app/eh-uploads/ │ +│ │ │ │ │ │ +│ In-Memory Storage: │ │ Collection: bp_eh │ │ {tenant}/{eh_id}/ │ +│ - erwartungshorizonte│ │ - tenant_id (filter) │ │ encrypted.bin │ +│ - eh_chunks │ │ - eh_id │ │ salt.txt │ +│ - eh_key_shares │ │ - embedding[1536] │ │ │ +│ - eh_klausur_links │ │ - encrypted_content │ └──────────────────────┘ +│ - eh_audit_log │ │ │ +└──────────────────────┘ └──────────────────────────┘ +``` + +## Data Flow + +### 1. Upload Flow + +``` +Browser Backend Storage + │ │ │ + │ 1. User selects PDF │ │ + │ 2. User enters passphrase │ │ + │ 3. PBKDF2 key derivation │ │ + │ 4. AES-256-GCM encryption │ │ + │ 5. SHA-256 key hash │ │ + │ │ │ + │──────────────────────────────▶│ │ + │ POST /api/v1/eh/upload │ │ + │ (encrypted blob + key_hash) │ │ + │ │──────────────────────────────▶│ + │ │ Store encrypted.bin + salt │ + │ │◀──────────────────────────────│ + │ │ │ + │ │ Save metadata to DB │ + │◀──────────────────────────────│ │ + │ Return EH record │ │ +``` + +### 2. Indexing Flow (RAG Preparation) + +``` +Browser Backend Qdrant + │ │ │ + │──────────────────────────────▶│ │ + │ POST /api/v1/eh/{id}/index │ │ + │ (passphrase for decryption) │ │ + │ │ │ + │ │ 1. Verify key hash │ + │ │ 2. Decrypt content │ + │ │ 3. Extract text (PDF) │ + │ │ 4. Chunk text │ + │ │ 5. Generate embeddings │ + │ │ 6. Re-encrypt each chunk │ + │ │──────────────────────────────▶│ + │ │ Index vectors + encrypted │ + │ │ chunks with tenant filter │ + │◀──────────────────────────────│ │ + │ Return chunk count │ │ +``` + +### 3. RAG Query Flow + +``` +Browser Backend Qdrant + │ │ │ + │──────────────────────────────▶│ │ + │ POST /api/v1/eh/rag-query │ │ + │ (query + passphrase) │ │ + │ │ │ + │ │ 1. Generate query embedding │ + │ │──────────────────────────────▶│ + │ │ 2. Semantic search │ + │ │ (tenant-filtered) │ + │ │◀──────────────────────────────│ + │ │ 3. Decrypt matched chunks │ + │◀──────────────────────────────│ │ + │ Return decrypted context │ │ +``` + +## Security Architecture + +### Client-Side Encryption + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ Browser (Client-Side) │ +├─────────────────────────────────────────────────────────────────┤ +│ │ +│ 1. User enters passphrase (NEVER sent to server) │ +│ │ │ +│ ▼ │ +│ 2. Key Derivation: PBKDF2-SHA256(passphrase, salt, 100k iter) │ +│ │ │ +│ ▼ │ +│ 3. Encryption: AES-256-GCM(key, iv, file_content) │ +│ │ │ +│ ▼ │ +│ 4. Key-Hash: SHA-256(derived_key) → server verification only │ +│ │ │ +│ ▼ │ +│ 5. Upload: encrypted_blob + key_hash + salt (NOT key!) │ +│ │ +└─────────────────────────────────────────────────────────────────┘ +``` + +### Security Guarantees + +| Guarantee | Implementation | +|-----------|----------------| +| **No Training** | `training_allowed: false` on all Qdrant points | +| **Operator Blindness** | Passphrase never leaves browser; server only sees key hash | +| **Tenant Isolation** | Every query filtered by `tenant_id` | +| **Audit Trail** | All actions logged with timestamps | + +## Key Sharing System + +The key sharing system enables first examiners to grant access to their EH to second examiners and supervisors. + +### Share Flow + +``` +First Examiner Backend Second Examiner + │ │ │ + │ 1. Encrypt passphrase for │ │ + │ recipient (client-side) │ │ + │ │ │ + │─────────────────────────────▶ │ + │ POST /eh/{id}/share │ │ + │ (encrypted_passphrase, role)│ │ + │ │ │ + │ │ Store EHKeyShare │ + │◀───────────────────────────── │ + │ │ │ + │ │ │ + │ │◀────────────────────────────│ + │ │ GET /eh/shared-with-me │ + │ │ │ + │ │─────────────────────────────▶ + │ │ Return shared EH list │ + │ │ │ + │ │◀────────────────────────────│ + │ │ RAG query with decrypted │ + │ │ passphrase │ +``` + +### Data Structures + +```python +@dataclass +class EHKeyShare: + id: str + eh_id: str + user_id: str # Recipient + encrypted_passphrase: str # Client-encrypted for recipient + passphrase_hint: str # Optional hint + granted_by: str # Grantor user ID + granted_at: datetime + role: str # second_examiner, third_examiner, supervisor + klausur_id: Optional[str] # Link to specific Klausur + active: bool + +@dataclass +class EHKlausurLink: + id: str + eh_id: str + klausur_id: str + linked_by: str + linked_at: datetime +``` + +## API Endpoints + +### Core EH Endpoints + +| Method | Endpoint | Description | +|--------|----------|-------------| +| POST | `/api/v1/eh/upload` | Upload encrypted EH | +| GET | `/api/v1/eh` | List user's EH | +| GET | `/api/v1/eh/{id}` | Get single EH | +| DELETE | `/api/v1/eh/{id}` | Soft delete EH | +| POST | `/api/v1/eh/{id}/index` | Index EH for RAG | +| POST | `/api/v1/eh/rag-query` | Query EH content | + +### Key Sharing Endpoints + +| Method | Endpoint | Description | +|--------|----------|-------------| +| POST | `/api/v1/eh/{id}/share` | Share EH with examiner | +| GET | `/api/v1/eh/{id}/shares` | List shares (owner) | +| DELETE | `/api/v1/eh/{id}/shares/{shareId}` | Revoke share | +| GET | `/api/v1/eh/shared-with-me` | List EH shared with user | + +### Klausur Integration Endpoints + +| Method | Endpoint | Description | +|--------|----------|-------------| +| POST | `/api/v1/eh/{id}/link-klausur` | Link EH to Klausur | +| DELETE | `/api/v1/eh/{id}/link-klausur/{klausurId}` | Unlink EH | +| GET | `/api/v1/klausuren/{id}/linked-eh` | Get linked EH for Klausur | + +### Audit & Admin Endpoints + +| Method | Endpoint | Description | +|--------|----------|-------------| +| GET | `/api/v1/eh/audit-log` | Get audit log | +| GET | `/api/v1/eh/rights-text` | Get rights confirmation text | +| GET | `/api/v1/eh/qdrant-status` | Get Qdrant status (admin) | + +## Frontend Components + +### EHUploadWizard + +5-step wizard for uploading Erwartungshorizonte: + +1. **File Selection** - Choose PDF file +2. **Metadata** - Title, Subject, Niveau, Year +3. **Rights Confirmation** - Legal acknowledgment +4. **Encryption** - Set passphrase (2x confirmation) +5. **Summary** - Review and upload + +### Integration Points + +- **KorrekturPage**: Shows EH prompt after first student upload +- **GutachtenGeneration**: Uses RAG context from linked EH +- **Sidebar Badge**: Shows linked EH count + +## File Structure + +``` +klausur-service/ +├── backend/ +│ ├── main.py # API endpoints + data structures +│ ├── qdrant_service.py # Vector database operations +│ ├── eh_pipeline.py # Chunking, embedding, encryption +│ └── requirements.txt # Python dependencies +├── frontend/ +│ └── src/ +│ ├── components/ +│ │ └── EHUploadWizard.tsx +│ ├── services/ +│ │ ├── api.ts # API client +│ │ └── encryption.ts # Client-side crypto +│ ├── pages/ +│ │ └── KorrekturPage.tsx # EH integration +│ └── styles/ +│ └── eh-wizard.css +└── docs/ + ├── BYOEH-Architecture.md + └── BYOEH-Developer-Guide.md +``` + +## Configuration + +### Environment Variables + +```env +QDRANT_URL=http://qdrant:6333 +OPENAI_API_KEY=sk-... # For embeddings +BYOEH_ENCRYPTION_ENABLED=true +EH_UPLOAD_DIR=/app/eh-uploads +``` + +### Docker Services + +```yaml +# docker-compose.yml +services: + qdrant: + image: qdrant/qdrant:v1.7.4 + ports: + - "6333:6333" + volumes: + - qdrant_data:/qdrant/storage +``` + +## Audit Events + +| Action | Description | +|--------|-------------| +| `upload` | EH uploaded | +| `index` | EH indexed for RAG | +| `rag_query` | RAG query executed | +| `delete` | EH soft deleted | +| `share` | EH shared with examiner | +| `revoke_share` | Share revoked | +| `link_klausur` | EH linked to Klausur | +| `unlink_klausur` | EH unlinked from Klausur | + +## See Also + +- [Zeugnis-System Architektur](../../architecture/zeugnis-system.md) +- [Klausur-Service Index](./index.md) diff --git a/docs-src/services/klausur-service/BYOEH-Developer-Guide.md b/docs-src/services/klausur-service/BYOEH-Developer-Guide.md new file mode 100644 index 0000000..0b70503 --- /dev/null +++ b/docs-src/services/klausur-service/BYOEH-Developer-Guide.md @@ -0,0 +1,481 @@ +# BYOEH Developer Guide + +## Quick Start + +### Prerequisites + +- Python 3.10+ +- Node.js 18+ +- Docker & Docker Compose +- OpenAI API Key (for embeddings) + +### Setup + +1. **Start services:** +```bash +docker-compose up -d qdrant +``` + +2. **Configure environment:** +```env +QDRANT_URL=http://localhost:6333 +OPENAI_API_KEY=sk-your-key +BYOEH_ENCRYPTION_ENABLED=true +``` + +3. **Run klausur-service:** +```bash +cd klausur-service/backend +pip install -r requirements.txt +uvicorn main:app --reload --port 8086 +``` + +4. **Run frontend:** +```bash +cd klausur-service/frontend +npm install +npm run dev +``` + +## Client-Side Encryption + +The encryption service (`encryption.ts`) handles all cryptographic operations in the browser: + +### Encrypting a File + +```typescript +import { encryptFile, generateSalt } from '../services/encryption' + +const file = document.getElementById('fileInput').files[0] +const passphrase = 'user-secret-password' + +const encrypted = await encryptFile(file, passphrase) +// Result: +// { +// encryptedData: ArrayBuffer, +// keyHash: string, // SHA-256 hash for verification +// salt: string, // Hex-encoded salt +// iv: string // Hex-encoded initialization vector +// } +``` + +### Decrypting Content + +```typescript +import { decryptText, verifyPassphrase } from '../services/encryption' + +// First verify the passphrase +const isValid = await verifyPassphrase(passphrase, salt, expectedKeyHash) + +if (isValid) { + const decrypted = await decryptText(encryptedBase64, passphrase, salt) +} +``` + +## Backend API Usage + +### Upload an Erwartungshorizont + +```python +# The upload endpoint accepts FormData with: +# - file: encrypted binary blob +# - metadata_json: JSON string with metadata + +POST /api/v1/eh/upload +Content-Type: multipart/form-data + +{ + "file": , + "metadata_json": { + "metadata": { + "title": "Deutsch LK 2025", + "subject": "deutsch", + "niveau": "eA", + "year": 2025, + "aufgaben_nummer": "Aufgabe 1" + }, + "encryption_key_hash": "abc123...", + "salt": "def456...", + "rights_confirmed": true, + "original_filename": "erwartungshorizont.pdf" + } +} +``` + +### Index for RAG + +```python +POST /api/v1/eh/{eh_id}/index +Content-Type: application/json + +{ + "passphrase": "user-secret-password" +} +``` + +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 + +### RAG Query + +```python +POST /api/v1/eh/rag-query +Content-Type: application/json + +{ + "query_text": "Wie sollte die Einleitung strukturiert sein?", + "passphrase": "user-secret-password", + "subject": "deutsch", # Optional filter + "limit": 5 # Max results +} +``` + +Response: +```json +{ + "context": "Die Einleitung sollte...", + "sources": [ + { + "text": "Die Einleitung sollte...", + "eh_id": "uuid", + "eh_title": "Deutsch LK 2025", + "chunk_index": 2, + "score": 0.89 + } + ], + "query": "Wie sollte die Einleitung strukturiert sein?" +} +``` + +## Key Sharing Implementation + +### Invitation Flow (Recommended) + +The invitation flow provides a two-phase sharing process: Invite -> Accept + +```typescript +import { ehApi } from '../services/api' + +// 1. First examiner sends invitation to second examiner +const invitation = await ehApi.inviteToEH(ehId, { + invitee_email: 'zweitkorrektor@school.de', + role: 'second_examiner', + klausur_id: 'klausur-uuid', // Optional: link to specific Klausur + message: 'Bitte fuer Zweitkorrektur nutzen', + expires_in_days: 14 // Default: 14 days +}) +// Returns: { invitation_id, eh_id, invitee_email, role, expires_at, eh_title } + +// 2. Second examiner sees pending invitation +const pending = await ehApi.getPendingInvitations() +// [{ invitation: {...}, eh: { id, title, subject, niveau, year } }] + +// 3. Second examiner accepts invitation +const accepted = await ehApi.acceptInvitation( + invitationId, + encryptedPassphrase // Passphrase encrypted for recipient +) +// Returns: { status: 'accepted', share_id, eh_id, role, klausur_id } +``` + +### Invitation Management + +```typescript +// Get invitations sent by current user +const sent = await ehApi.getSentInvitations() + +// Decline an invitation (as invitee) +await ehApi.declineInvitation(invitationId) + +// Revoke a pending invitation (as inviter) +await ehApi.revokeInvitation(invitationId) + +// Get complete access chain for an EH +const chain = await ehApi.getAccessChain(ehId) +// Returns: { eh_id, eh_title, owner, active_shares, pending_invitations, revoked_shares } +``` + +### Direct Sharing (Legacy) + +For immediate sharing without invitation: + +```typescript +// First examiner shares directly with second examiner +await ehApi.shareEH(ehId, { + user_id: 'second-examiner-uuid', + role: 'second_examiner', + encrypted_passphrase: encryptedPassphrase, // Encrypted for recipient + passphrase_hint: 'Das uebliche Passwort', + klausur_id: 'klausur-uuid' // Optional +}) +``` + +### Accessing Shared EH + +```typescript +// Second examiner gets shared EH +const shared = await ehApi.getSharedWithMe() +// [{ eh: {...}, share: {...} }] + +// Query using provided passphrase +const result = await ehApi.ragQuery({ + query_text: 'search query', + passphrase: decryptedPassphrase, + subject: 'deutsch' +}) +``` + +### Revoking Access + +```typescript +// List all shares for an EH +const shares = await ehApi.listShares(ehId) + +// Revoke a share +await ehApi.revokeShare(ehId, shareId) +``` + +## Klausur Integration + +### Automatic EH Prompt + +The `KorrekturPage` shows an EH upload prompt after the first student work is uploaded: + +```typescript +// In KorrekturPage.tsx +useEffect(() => { + if ( + currentKlausur?.students.length === 1 && + linkedEHs.length === 0 && + !ehPromptDismissed + ) { + setShowEHPrompt(true) + } +}, [currentKlausur?.students.length]) +``` + +### Linking EH to Klausur + +```typescript +// After EH upload, auto-link to Klausur +await ehApi.linkToKlausur(ehId, klausurId) + +// Get linked EH for a Klausur +const linked = await klausurEHApi.getLinkedEH(klausurId) +``` + +## Frontend Components + +### EHUploadWizard Props + +```typescript +interface EHUploadWizardProps { + onClose: () => void + onComplete?: (ehId: string) => void + defaultSubject?: string // Pre-fill subject + defaultYear?: number // Pre-fill year + klausurId?: string // Auto-link after upload +} + +// Usage + setShowWizard(false)} + onComplete={(ehId) => console.log('Uploaded:', ehId)} + defaultSubject={klausur.subject} + defaultYear={klausur.year} + klausurId={klausur.id} +/> +``` + +### Wizard Steps + +1. **file** - PDF file selection with drag & drop +2. **metadata** - Form for title, subject, niveau, year +3. **rights** - Rights confirmation checkbox +4. **encryption** - Passphrase input with strength meter +5. **summary** - Review and confirm upload + +## Qdrant Operations + +### Collection Schema + +```python +# Collection: bp_eh +{ + "vectors": { + "size": 1536, # OpenAI text-embedding-3-small + "distance": "Cosine" + } +} + +# Point payload +{ + "tenant_id": "school-uuid", + "eh_id": "eh-uuid", + "chunk_index": 0, + "encrypted_content": "base64...", + "training_allowed": false # ALWAYS false +} +``` + +### Tenant-Isolated Search + +```python +from qdrant_service import search_eh + +results = await search_eh( + query_embedding=embedding, + tenant_id="school-uuid", + subject="deutsch", + limit=5 +) +``` + +## Testing + +### Unit Tests + +```bash +cd klausur-service/backend +pytest tests/test_byoeh.py -v +``` + +### Test Structure + +```python +# tests/test_byoeh.py +class TestBYOEH: + def test_upload_eh(self, client, auth_headers): + """Test EH upload with encryption""" + pass + + def test_index_eh(self, client, auth_headers, uploaded_eh): + """Test EH indexing for RAG""" + pass + + def test_rag_query(self, client, auth_headers, indexed_eh): + """Test RAG query returns relevant chunks""" + pass + + def test_share_eh(self, client, auth_headers, uploaded_eh): + """Test sharing EH with another user""" + pass +``` + +### Frontend Tests + +```typescript +// EHUploadWizard.test.tsx +describe('EHUploadWizard', () => { + it('completes all steps successfully', async () => { + // ... + }) + + it('validates passphrase strength', async () => { + // ... + }) + + it('auto-links to klausur when klausurId provided', async () => { + // ... + }) +}) +``` + +## Error Handling + +### Common Errors + +| Error | Cause | Solution | +|-------|-------|----------| +| `Passphrase verification failed` | Wrong passphrase | Ask user to re-enter | +| `EH not found` | Invalid ID or deleted | Check ID, reload list | +| `Access denied` | User not owner/shared | Check permissions | +| `Qdrant connection failed` | Service unavailable | Check Qdrant container | + +### Error Response Format + +```json +{ + "detail": "Passphrase verification failed" +} +``` + +## Security Considerations + +### Do's + +- Store key hash, never the key itself +- Always filter by tenant_id +- Log all access in audit trail +- Use HTTPS in production + +### Don'ts + +- Never log passphrase or decrypted content +- Never store passphrase in localStorage +- Never send passphrase as URL parameter +- Never return decrypted content without auth + +## Performance Tips + +### Chunking Configuration + +```python +CHUNK_SIZE = 1000 # Characters per chunk +CHUNK_OVERLAP = 200 # Overlap for context continuity +``` + +### Embedding Batching + +```python +# Generate embeddings in batches of 20 +EMBEDDING_BATCH_SIZE = 20 +``` + +### Qdrant Optimization + +```python +# Use HNSW index for fast approximate search +# Collection is automatically optimized on creation +``` + +## Debugging + +### Enable Debug Logging + +```python +import logging +logging.getLogger('byoeh').setLevel(logging.DEBUG) +``` + +### Check Qdrant Status + +```bash +curl http://localhost:6333/collections/bp_eh +``` + +### Verify Encryption + +```typescript +import { isEncryptionSupported } from '../services/encryption' + +if (!isEncryptionSupported()) { + console.error('Web Crypto API not available') +} +``` + +## Migration Notes + +### From v1.0 to v1.1 + +1. Added key sharing system +2. Added Klausur linking +3. EH prompt after student upload + +No database migrations required - all data structures are additive. diff --git a/docs-src/services/klausur-service/NiBiS-Ingestion-Pipeline.md b/docs-src/services/klausur-service/NiBiS-Ingestion-Pipeline.md new file mode 100644 index 0000000..2573014 --- /dev/null +++ b/docs-src/services/klausur-service/NiBiS-Ingestion-Pipeline.md @@ -0,0 +1,227 @@ +# NiBiS Ingestion Pipeline + +## Overview + +Die NiBiS Ingestion Pipeline verarbeitet Abitur-Erwartungshorizonte aus Niedersachsen und indexiert sie in Qdrant für RAG-basierte Klausurkorrektur. + +## Unterstützte Daten + +### Verzeichnisse + +| Verzeichnis | Jahre | Namenskonvention | +|-------------|-------|------------------| +| `docs/za-download` | 2024, 2025 | `{Jahr}_{Fach}_{niveau}_{Nr}_EWH.pdf` | +| `docs/za-download-2` | 2016 | `{Jahr}{Fach}{Niveau}Lehrer/{Jahr}{Fach}{Niveau}A{Nr}L.pdf` | +| `docs/za-download-3` | 2017 | `{Jahr}{Fach}{Niveau}Lehrer/{Jahr}{Fach}{Niveau}A{Nr}L.pdf` | + +### Dokumenttypen + +- **EWH** - Erwartungshorizont (Hauptziel) +- **Aufgabe** - Prüfungsaufgaben +- **Material** - Zusatzmaterialien +- **GBU** - Gefährdungsbeurteilung (Chemie/Biologie) +- **Bewertungsbogen** - Standardisierte Bewertungsbögen + +### Fächer + +Deutsch, Englisch, Mathematik, Informatik, Biologie, Chemie, Physik, Geschichte, Erdkunde, Kunst, Musik, Sport, Latein, Griechisch, Französisch, Spanisch, Katholische Religion, Evangelische Religion, Werte und Normen, BRC, BVW, Gesundheit-Pflege + +## Architektur + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ NiBiS Ingestion Pipeline │ +├─────────────────────────────────────────────────────────────────┤ +│ │ +│ 1. ZIP Extraction │ +│ └── Entpackt 2024.zip, 2025.zip, etc. │ +│ │ +│ 2. Document Discovery │ +│ ├── Parst alte Namenskonvention (2016/2017) │ +│ └── Parst neue Namenskonvention (2024/2025) │ +│ │ +│ 3. PDF Processing │ +│ ├── Text-Extraktion (PyPDF2) │ +│ └── Chunking (1000 chars, 200 overlap) │ +│ │ +│ 4. Embedding Generation │ +│ └── OpenAI text-embedding-3-small (1536 dim) │ +│ │ +│ 5. Qdrant Indexing │ +│ └── Collection: bp_nibis_eh │ +│ │ +└─────────────────────────────────────────────────────────────────┘ +``` + +## Verwendung + +### Via API (empfohlen) + +```bash +# 1. Vorschau der verfügbaren Dokumente +curl http://localhost:8086/api/v1/admin/nibis/discover + +# 2. ZIP-Dateien entpacken +curl -X POST http://localhost:8086/api/v1/admin/nibis/extract-zips + +# 3. Ingestion starten +curl -X POST http://localhost:8086/api/v1/admin/nibis/ingest \ + -H "Content-Type: application/json" \ + -d '{"ewh_only": true}' + +# 4. Status prüfen +curl http://localhost:8086/api/v1/admin/nibis/status + +# 5. Semantische Suche testen +curl -X POST http://localhost:8086/api/v1/admin/nibis/search \ + -H "Content-Type: application/json" \ + -d '{"query": "Analyse literarischer Texte", "subject": "Deutsch", "limit": 5}' +``` + +### Via CLI + +```bash +# Dry-Run (nur analysieren) +cd klausur-service/backend +python nibis_ingestion.py --dry-run + +# Vollständige Ingestion +python nibis_ingestion.py + +# Nur bestimmtes Jahr +python nibis_ingestion.py --year 2024 + +# Nur bestimmtes Fach +python nibis_ingestion.py --subject Deutsch + +# Manifest erstellen +python nibis_ingestion.py --manifest /tmp/nibis_manifest.json +``` + +### Via Shell Script + +```bash +./klausur-service/scripts/run_nibis_ingestion.sh --dry-run +./klausur-service/scripts/run_nibis_ingestion.sh --year 2024 --subject Deutsch +``` + +## Qdrant Schema + +### Collection: `bp_nibis_eh` + +```json +{ + "id": "nibis_2024_deutsch_ea_1_abc123_chunk_0", + "vector": [1536 dimensions], + "payload": { + "doc_id": "nibis_2024_deutsch_ea_1_abc123", + "chunk_index": 0, + "text": "Der Erwartungshorizont...", + "year": 2024, + "subject": "Deutsch", + "niveau": "eA", + "task_number": 1, + "doc_type": "EWH", + "bundesland": "NI", + "variant": null, + "source": "nibis", + "training_allowed": true + } +} +``` + +## API Endpoints + +| Methode | Endpoint | Beschreibung | +|---------|----------|--------------| +| GET | `/api/v1/admin/nibis/status` | Ingestion-Status | +| POST | `/api/v1/admin/nibis/extract-zips` | ZIP-Dateien entpacken | +| GET | `/api/v1/admin/nibis/discover` | Dokumente finden | +| POST | `/api/v1/admin/nibis/ingest` | Ingestion starten | +| POST | `/api/v1/admin/nibis/search` | Semantische Suche | +| GET | `/api/v1/admin/nibis/stats` | Statistiken | +| GET | `/api/v1/admin/nibis/collections` | Qdrant Collections | +| DELETE | `/api/v1/admin/nibis/collection` | Collection löschen | + +## Erweiterung für andere Bundesländer + +Die Pipeline ist so designed, dass sie leicht erweitert werden kann: + +### 1. Neues Bundesland hinzufügen + +```python +# In nibis_ingestion.py + +# Bundesland-Code (ISO 3166-2:DE) +BUNDESLAND_CODES = { + "NI": "Niedersachsen", + "BE": "Berlin", + "BY": "Bayern", + # ... +} + +# Parsing-Funktion für neues Format +def parse_filename_berlin(filename: str, file_path: Path) -> Optional[Dict]: + # Berlin-spezifische Namenskonvention + pass +``` + +### 2. Neues Verzeichnis registrieren + +```python +# docs/za-download-berlin/ hinzufügen +ZA_DOWNLOAD_DIRS = [ + "za-download", + "za-download-2", + "za-download-3", + "za-download-berlin", # NEU +] +``` + +### 3. Dokumenttyp-Erweiterung + +Für Zeugnisgeneration oder andere Dokumenttypen: + +```python +DOC_TYPES = { + "EWH": "Erwartungshorizont", + "ZEUGNIS_VORLAGE": "Zeugnisvorlage", + "NOTENSPIEGEL": "Notenspiegel", + "BEMERKUNG": "Bemerkungstexte", +} +``` + +## Rechtliche Hinweise + +- NiBiS-Daten sind unter den [NiBiS-Nutzungsbedingungen](https://nibis.de) frei nutzbar +- `training_allowed: true` - Strukturelles Wissen darf für KI-Training genutzt werden +- Für Lehrer-eigene Erwartungshorizonte (BYOEH) gilt: `training_allowed: false` + +## Troubleshooting + +### Qdrant nicht erreichbar + +```bash +# Prüfen ob Qdrant läuft +curl http://localhost:6333/health + +# Docker starten +docker-compose up -d qdrant +``` + +### OpenAI API Fehler + +```bash +# API Key setzen +export OPENAI_API_KEY=sk-... +``` + +### PDF-Extraktion fehlgeschlagen + +Einige PDFs können problematisch sein (gescannte Dokumente ohne OCR). Diese werden übersprungen und im Error-Log protokolliert. + +## Performance + +- ~500-1000 Chunks pro Minute (abhängig von OpenAI API) +- ~2-3 GB Qdrant Storage für alle NiBiS-Daten (2016-2025) +- Embeddings werden nur einmal generiert (idempotent via Hash) diff --git a/docs-src/services/klausur-service/OCR-Compare.md b/docs-src/services/klausur-service/OCR-Compare.md new file mode 100644 index 0000000..34e093a --- /dev/null +++ b/docs-src/services/klausur-service/OCR-Compare.md @@ -0,0 +1,235 @@ +# OCR Compare - Block Review Feature + +**Status:** Produktiv +**Letzte Aktualisierung:** 2026-02-08 +**URL:** https://macmini:3002/ai/ocr-compare + +--- + +## Uebersicht + +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. + +### Hauptfunktionen + +| 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) | + +--- + +## Architektur + +``` +┌─────────────────────────────────────────────────────────────┐ +│ admin-v2 (Next.js) │ +│ /app/(admin)/ai/ocr-compare/page.tsx │ +│ - PDF Upload & Session Management │ +│ - Grid Visualization mit SVG Overlay │ +│ - Block Review Panel │ +└─────────────────────────────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────────┐ +│ klausur-service (FastAPI) │ +│ Port 8086 │ +│ - /api/v1/vocab/sessions (Session CRUD) │ +│ - /api/v1/vocab/sessions/{id}/pdf-thumbnail (Bild-Export) │ +│ - /api/v1/vocab/sessions/{id}/detect-grid (Grid-Erkennung) │ +│ - /api/v1/vocab/sessions/{id}/run-ocr (OCR-Ausfuehrung) │ +└─────────────────────────────────────────────────────────────┘ +``` + +--- + +## Komponenten + +### GridOverlay + +SVG-Overlay zur Visualisierung der erkannten Grid-Struktur. + +**Datei:** `/admin-v2/components/ocr/GridOverlay.tsx` + +```typescript +interface GridOverlayProps { + grid: GridData + imageUrl?: string + onCellClick?: (cell: GridCell) => void + selectedCell?: GridCell | null + showEmpty?: boolean // Leere Zellen anzeigen + showLabels?: boolean // Spaltenlabels (EN, DE, Ex) + showNumbers?: boolean // Block-Nummern anzeigen + highlightedBlockNumber?: number | null // Hervorgehobener Block + className?: string +} +``` + +**Zellenstatus-Farben:** + +| Status | Farbe | Bedeutung | +|--------|-------|-----------| +| `recognized` | Gruen | Text erfolgreich erkannt | +| `problematic` | Orange | Niedriger Confidence-Wert | +| `manual` | Blau | Manuell korrigiert | +| `empty` | Transparent | Keine Erkennung | + +### BlockReviewPanel + +Panel zur Block-fuer-Block Ueberpruefung der OCR-Ergebnisse. + +**Datei:** `/admin-v2/components/ocr/BlockReviewPanel.tsx` + +```typescript +interface BlockReviewPanelProps { + grid: GridData + methodResults: Record }> + currentBlockNumber: number + onBlockChange: (blockNumber: number) => void + onApprove: (blockNumber: number, methodId: string, text: string) => void + onCorrect: (blockNumber: number, correctedText: string) => void + onSkip: (blockNumber: number) => void + reviewData: Record + className?: string +} +``` + +**Review-Status:** + +| Status | Beschreibung | +|--------|--------------| +| `pending` | Noch nicht ueberprueft | +| `approved` | OCR-Ergebnis akzeptiert | +| `corrected` | Manuell korrigiert | +| `skipped` | Uebersprungen | + +### BlockReviewSummary + +Zusammenfassung aller ueberprueften Bloecke. + +```typescript +interface BlockReviewSummaryProps { + reviewData: Record + totalBlocks: number + onBlockClick: (blockNumber: number) => void + className?: string +} +``` + +--- + +## OCR-Methoden + +| ID | Name | Beschreibung | +|----|------|--------------| +| `vision_llm` | Vision LLM | Qwen VL 32B ueber Ollama | +| `tesseract` | Tesseract | Klassisches OCR (lokal) | +| `paddleocr` | PaddleOCR | PaddleOCR Engine | +| `claude_vision` | Claude Vision | Anthropic Claude Vision API | + +--- + +## API Endpoints + +### Session Management + +| Method | Endpoint | Beschreibung | +|--------|----------|--------------| +| POST | `/api/v1/vocab/upload-pdf-info` | PDF hochladen | +| GET | `/api/v1/vocab/sessions/{id}` | Session-Details | +| DELETE | `/api/v1/vocab/sessions/{id}` | Session loeschen | + +### Bildexport + +| Method | Endpoint | Beschreibung | +|--------|----------|--------------| +| GET | `/api/v1/vocab/sessions/{id}/pdf-thumbnail/{page}` | Thumbnail (zoom=0.5) | +| GET | `/api/v1/vocab/sessions/{id}/pdf-thumbnail/{page}?hires=true` | High-Res (zoom=2.0) | + +### Grid-Erkennung + +| Method | Endpoint | Beschreibung | +|--------|----------|--------------| +| POST | `/api/v1/vocab/sessions/{id}/detect-grid` | Grid-Struktur erkennen | +| POST | `/api/v1/vocab/sessions/{id}/run-ocr` | OCR auf Grid ausfuehren | + +--- + +## Session Persistence + +Die aktive Session wird im localStorage gespeichert: + +```javascript +// Speichern +localStorage.setItem('ocr-compare-active-session', sessionId) + +// Wiederherstellen beim Seitenladen +const lastSessionId = localStorage.getItem('ocr-compare-active-session') +if (lastSessionId) { + // Session-Daten laden +} +``` + +--- + +## Block Review Workflow + +1. **PDF hochladen** - Dokument in das System laden +2. **Grid erkennen** - Automatische Tabellenerkennung +3. **OCR ausfuehren** - Alle Methoden parallel ausfuehren +4. **Block Review starten** - "Block Review" Button klicken +5. **Bloecke pruefen** - Fuer jeden Block: + - Ergebnisse aller Methoden vergleichen + - Bestes Ergebnis waehlen oder manuell korrigieren +6. **Zusammenfassung** - Uebersicht der Korrekturen + +--- + +## High-Resolution Bilder + +Fuer die Anzeige werden hochaufloesende Bilder verwendet: + +```typescript +// Thumbnail URL mit High-Resolution Parameter +const imageUrl = `${KLAUSUR_API}/api/v1/vocab/sessions/${sessionId}/pdf-thumbnail/${pageNumber}?hires=true` +``` + +| Parameter | Zoom | Verwendung | +|-----------|------|------------| +| Ohne `hires` | 0.5 | Vorschau/Thumbnails | +| Mit `hires=true` | 2.0 | Anzeige/OCR | + +--- + +## Dateien + +### Frontend (admin-v2) + +| Datei | Beschreibung | +|-------|--------------| +| `app/(admin)/ai/ocr-compare/page.tsx` | Haupt-UI | +| `components/ocr/GridOverlay.tsx` | SVG Grid-Overlay | +| `components/ocr/BlockReviewPanel.tsx` | Review-Panel | +| `components/ocr/CellCorrectionDialog.tsx` | Korrektur-Dialog | +| `components/ocr/index.ts` | Exports | + +### Backend (klausur-service) + +| Datei | Beschreibung | +|-------|--------------| +| `vocab_worksheet_api.py` | API-Router | +| `hybrid_vocab_extractor.py` | OCR-Extraktion | + +--- + +## Aenderungshistorie + +| 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 | diff --git a/docs-src/services/klausur-service/OCR-Labeling-Spec.md b/docs-src/services/klausur-service/OCR-Labeling-Spec.md new file mode 100644 index 0000000..17f9754 --- /dev/null +++ b/docs-src/services/klausur-service/OCR-Labeling-Spec.md @@ -0,0 +1,445 @@ +# OCR-Labeling System Spezifikation + +**Version:** 1.1.0 +**Status:** In Produktion (Mac Mini) + +## Übersicht + +Das OCR-Labeling System ermöglicht das Erstellen von Trainingsdaten für Handschrift-OCR-Modelle aus eingescannten Klausuren. Es unterstützt folgende OCR-Modelle: + +| Modell | Beschreibung | Geschwindigkeit | Empfohlen für | +|--------|--------------|-----------------|---------------| +| **llama3.2-vision:11b** | Vision-LLM (Standard) | Langsam | Handschrift, beste Qualität | +| **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 | + +### Neue OCR-Optionen (v1.1.0) + +#### PaddleOCR + LLM (Empfohlen für Geschwindigkeit) + +PaddleOCR ist ein zweistufiger Ansatz: +1. **PaddleOCR** - Schnelle, präzise Texterkennung mit Bounding-Boxes +2. **qwen2.5:14b** - Semantische Strukturierung des erkannten Texts + +**Vorteile:** +- 4x schneller als Vision-LLM (~7-15 Sek vs 30-60 Sek pro Seite) +- Höhere Genauigkeit bei gedrucktem Text (95-99%) +- Weniger Halluzinationen (LLM korrigiert nur, erfindet nicht) +- Position-basierte Spaltenerkennung möglich + +**Dateien:** +- `/klausur-service/backend/hybrid_vocab_extractor.py` - PaddleOCR Integration + +#### Donut (Document Understanding Transformer) + +Donut ist speziell für strukturierte Dokumente optimiert: +- Tabellen und Formulare +- Rechnungen und Quittungen +- Multi-Spalten-Layouts + +**Dateien:** +- `/klausur-service/backend/services/donut_ocr_service.py` - Donut Service + +## Architektur + +``` +┌──────────────────────────────────────────────────────────────────────────┐ +│ OCR-Labeling System │ +├──────────────────────────────────────────────────────────────────────────┤ +│ │ +│ ┌─────────────┐ ┌─────────────────┐ ┌────────────────────────┐ │ +│ │ Frontend │◄──►│ Klausur-Service │◄──►│ PostgreSQL │ │ +│ │ (Next.js) │ │ (FastAPI) │ │ - ocr_labeling_sessions│ │ +│ │ Port 3000 │ │ Port 8086 │ │ - ocr_labeling_items │ │ +│ └─────────────┘ └────────┬─────────┘ │ - ocr_training_samples │ │ +│ │ └────────────────────────┘ │ +│ │ │ +│ ┌──────────┼──────────┐ │ +│ ▼ ▼ ▼ │ +│ ┌───────────┐ ┌─────────┐ ┌───────────────┐ │ +│ │ MinIO │ │ Ollama │ │ Export Service │ │ +│ │ (Images) │ │ (OCR) │ │ (Training) │ │ +│ │ Port 9000 │ │ :11434 │ │ │ │ +│ └───────────┘ └─────────┘ └───────────────┘ │ +│ │ +└──────────────────────────────────────────────────────────────────────────┘ +``` + +## Datenmodell + +### PostgreSQL Tabellen + +```sql +-- Labeling Sessions (gruppiert zusammengehörige Bilder) +CREATE TABLE ocr_labeling_sessions ( + id VARCHAR(36) PRIMARY KEY, + name VARCHAR(255) NOT NULL, + source_type VARCHAR(50) NOT NULL, -- 'klausur', 'handwriting_sample', 'scan' + description TEXT, + ocr_model VARCHAR(100), -- z.B. 'llama3.2-vision:11b' + total_items INTEGER DEFAULT 0, + labeled_items INTEGER DEFAULT 0, + confirmed_items INTEGER DEFAULT 0, + corrected_items INTEGER DEFAULT 0, + skipped_items INTEGER DEFAULT 0, + teacher_id VARCHAR(100), + created_at TIMESTAMP DEFAULT NOW() +); + +-- Einzelne Labeling Items (Bild + OCR + Ground Truth) +CREATE TABLE ocr_labeling_items ( + id VARCHAR(36) PRIMARY KEY, + session_id VARCHAR(36) REFERENCES ocr_labeling_sessions(id), + image_path TEXT NOT NULL, -- MinIO Pfad oder lokaler Pfad + image_hash VARCHAR(64), -- SHA256 für Deduplizierung + ocr_text TEXT, -- Von LLM erkannter Text + ocr_confidence FLOAT, -- Konfidenz (0-1) + ocr_model VARCHAR(100), + ground_truth TEXT, -- Korrigierter/bestätigter Text + status VARCHAR(20) DEFAULT 'pending', -- pending/confirmed/corrected/skipped + labeled_by VARCHAR(100), + labeled_at TIMESTAMP, + label_time_seconds INTEGER, + metadata JSONB, + created_at TIMESTAMP DEFAULT NOW() +); + +-- Exportierte Training Samples +CREATE TABLE ocr_training_samples ( + id VARCHAR(36) PRIMARY KEY, + item_id VARCHAR(36) REFERENCES ocr_labeling_items(id), + image_path TEXT NOT NULL, + ground_truth TEXT NOT NULL, + export_format VARCHAR(50) NOT NULL, -- 'generic', 'trocr', 'llama_vision' + exported_at TIMESTAMP DEFAULT NOW(), + training_batch VARCHAR(100), + used_in_training BOOLEAN DEFAULT FALSE +); +``` + +## API Referenz + +Base URL: `http://macmini:8086/api/v1/ocr-label` + +### Sessions + +#### POST /sessions +Neue Labeling-Session erstellen. + +**Request:** +```json +{ + "name": "Klausur Deutsch 12a Q1", + "source_type": "klausur", + "description": "Gedichtanalyse Expressionismus", + "ocr_model": "llama3.2-vision:11b" +} +``` + +**Response:** +```json +{ + "id": "abc-123-def", + "name": "Klausur Deutsch 12a Q1", + "source_type": "klausur", + "total_items": 0, + "labeled_items": 0, + "created_at": "2026-01-21T10:30:00Z" +} +``` + +#### GET /sessions +Sessions auflisten. + +**Query Parameter:** +- `limit` (int, default: 50) - Maximale Anzahl + +#### GET /sessions/{session_id} +Einzelne Session abrufen. + +### Upload + +#### POST /sessions/{session_id}/upload +Bilder zu einer Session hochladen. + +**Request:** Multipart Form Data +- `files` (File[]) - PNG/JPG/PDF Dateien +- `run_ocr` (bool, default: true) - OCR direkt ausführen +- `metadata` (JSON string) - Optional: Metadaten + +**Response:** +```json +{ + "session_id": "abc-123-def", + "uploaded_count": 5, + "items": [ + { + "id": "item-1", + "filename": "scan_001.png", + "image_path": "ocr-labeling/abc-123/item-1.png", + "ocr_text": "Die Lösung der Aufgabe...", + "ocr_confidence": 0.87, + "status": "pending" + } + ] +} +``` + +### Labeling Queue + +#### GET /queue +Nächste zu labelnde Items abrufen. + +**Query Parameter:** +- `session_id` (str, optional) - Nach Session filtern +- `status` (str, default: "pending") - Status-Filter +- `limit` (int, default: 10) - Maximale Anzahl + +**Response:** +```json +[ + { + "id": "item-456", + "session_id": "abc-123", + "session_name": "Klausur Deutsch", + "image_path": "/app/ocr-labeling/abc-123/item-456.png", + "image_url": "/api/v1/ocr-label/images/abc-123/item-456.png", + "ocr_text": "Erkannter Text...", + "ocr_confidence": 0.87, + "ground_truth": null, + "status": "pending", + "metadata": {"page": 1} + } +] +``` + +### Labeling Actions + +#### POST /confirm +OCR-Text als korrekt bestätigen. + +**Request:** +```json +{ + "item_id": "item-456", + "label_time_seconds": 5 +} +``` + +**Effect:** `ground_truth = ocr_text`, `status = 'confirmed'` + +#### POST /correct +Ground Truth korrigieren. + +**Request:** +```json +{ + "item_id": "item-456", + "ground_truth": "Korrigierter Text hier", + "label_time_seconds": 15 +} +``` + +**Effect:** `ground_truth = `, `status = 'corrected'` + +#### POST /skip +Item überspringen (unbrauchbar). + +**Request:** +```json +{ + "item_id": "item-456" +} +``` + +**Effect:** `status = 'skipped'` (wird nicht exportiert) + +### Statistiken + +#### GET /stats +Labeling-Statistiken abrufen. + +**Query Parameter:** +- `session_id` (str, optional) - Für Session-spezifische Stats + +**Response:** +```json +{ + "total_items": 100, + "labeled_items": 75, + "confirmed_items": 60, + "corrected_items": 15, + "pending_items": 25, + "accuracy_rate": 0.80, + "avg_label_time_seconds": 8.5 +} +``` + +### Training Export + +#### POST /export +Trainingsdaten exportieren. + +**Request:** +```json +{ + "export_format": "trocr", + "session_id": "abc-123", + "batch_id": "batch_20260121" +} +``` + +**Export Formate:** + +| Format | Beschreibung | Output | +|--------|--------------|--------| +| `generic` | Allgemeines JSONL | `{"id", "image_path", "ground_truth", ...}` | +| `trocr` | Microsoft TrOCR | `{"file_name", "text", "id"}` | +| `llama_vision` | Llama 3.2 Vision | OpenAI-style Messages mit image_url | + +**Response:** +```json +{ + "export_format": "trocr", + "batch_id": "batch_20260121", + "exported_count": 75, + "export_path": "/app/ocr-exports/trocr/batch_20260121", + "manifest_path": "/app/ocr-exports/trocr/batch_20260121/manifest.json", + "samples": [...] +} +``` + +#### GET /exports +Verfügbare Exports auflisten. + +**Query Parameter:** +- `export_format` (str, optional) - Nach Format filtern + +## Export Formate im Detail + +### TrOCR Format + +``` +batch_20260121/ +├── manifest.json +├── train.jsonl +└── images/ + ├── item-1.png + └── item-2.png +``` + +**train.jsonl:** +```jsonl +{"file_name": "images/item-1.png", "text": "Ground truth text", "id": "item-1"} +{"file_name": "images/item-2.png", "text": "Another text", "id": "item-2"} +``` + +### Llama Vision Format + +```jsonl +{ + "id": "item-1", + "messages": [ + {"role": "system", "content": "Du bist ein OCR-Experte für deutsche Handschrift..."}, + {"role": "user", "content": [ + {"type": "image_url", "image_url": {"url": "images/item-1.png"}}, + {"type": "text", "text": "Lies den handgeschriebenen Text in diesem Bild."} + ]}, + {"role": "assistant", "content": "Ground truth text"} + ] +} +``` + +### Generic Format + +```jsonl +{ + "id": "item-1", + "image_path": "images/item-1.png", + "ground_truth": "Ground truth text", + "ocr_text": "OCR recognized text", + "ocr_confidence": 0.87, + "metadata": {"page": 1, "session": "Deutsch 12a"} +} +``` + +## Frontend Integration + +Die OCR-Labeling UI ist unter `/admin/ocr-labeling` verfügbar. + +### Keyboard Shortcuts + +| Taste | Aktion | +|-------|--------| +| `Enter` | Bestätigen (OCR korrekt) | +| `Tab` | Ins Korrekturfeld springen | +| `Escape` | Überspringen | +| `←` / `→` | Navigation (Prev/Next) | + +### Workflow + +1. **Session erstellen** - Name, Typ, OCR-Modell wählen +2. **Bilder hochladen** - Drag & Drop oder File-Browser +3. **Labeling durchführen** - Bild + OCR-Text vergleichen + - Korrekt → Bestätigen (Enter) + - Falsch → Korrigieren + Speichern + - Unbrauchbar → Überspringen +4. **Export** - Format wählen (TrOCR, Llama Vision, Generic) +5. **Training starten** - Export-Ordner für Fine-Tuning nutzen + +## Umgebungsvariablen + +```bash +# PostgreSQL +DATABASE_URL=postgres://user:pass@postgres:5432/breakpilot_db + +# MinIO (S3-kompatibel) +MINIO_ENDPOINT=minio:9000 +MINIO_ACCESS_KEY=breakpilot +MINIO_SECRET_KEY=breakpilot123 +MINIO_BUCKET=breakpilot-rag +MINIO_SECURE=false + +# Ollama (Vision-LLM) +OLLAMA_BASE_URL=http://host.docker.internal:11434 +OLLAMA_VISION_MODEL=llama3.2-vision:11b +OLLAMA_CORRECTION_MODEL=qwen2.5:14b + +# Export +OCR_EXPORT_PATH=/app/ocr-exports +OCR_STORAGE_PATH=/app/ocr-labeling +``` + +## Sicherheit & Datenschutz + +- **100% Lokale Verarbeitung** - Alle Daten bleiben auf dem Mac Mini +- **Keine Cloud-Uploads** - Ollama läuft vollständig offline +- **DSGVO-konform** - Keine Schülerdaten verlassen das Schulnetzwerk +- **Deduplizierung** - SHA256-Hash verhindert doppelte Bilder + +## Dateien + +| Datei | Beschreibung | +|-------|--------------| +| `klausur-service/backend/ocr_labeling_api.py` | FastAPI Router mit OCR Model Dispatcher | +| `klausur-service/backend/training_export_service.py` | Export-Service für TrOCR/Llama | +| `klausur-service/backend/metrics_db.py` | PostgreSQL CRUD Funktionen | +| `klausur-service/backend/minio_storage.py` | MinIO OCR-Image Storage | +| `klausur-service/backend/hybrid_vocab_extractor.py` | PaddleOCR Integration | +| `klausur-service/backend/services/donut_ocr_service.py` | Donut OCR Service (NEU) | +| `klausur-service/backend/services/trocr_service.py` | TrOCR Service (NEU) | +| `website/app/admin/ocr-labeling/page.tsx` | Frontend UI mit Model-Auswahl | +| `website/app/admin/ocr-labeling/types.ts` | TypeScript Interfaces inkl. OCRModel Type | + +## Tests + +```bash +# Backend-Tests ausführen +cd klausur-service/backend +pytest tests/test_ocr_labeling.py -v + +# Mit Coverage +pytest tests/test_ocr_labeling.py --cov=. --cov-report=html +``` diff --git a/docs-src/services/klausur-service/RAG-Admin-Spec.md b/docs-src/services/klausur-service/RAG-Admin-Spec.md new file mode 100644 index 0000000..76e4eb7 --- /dev/null +++ b/docs-src/services/klausur-service/RAG-Admin-Spec.md @@ -0,0 +1,472 @@ +# RAG & Daten-Management Spezifikation + +## Übersicht + +Admin-Frontend für die Verwaltung von Trainingsdaten und RAG-Systemen in BreakPilot. + +**Location**: `/admin/docs` → Tab "Daten & RAG" +**Backend**: `klausur-service` (Port 8086) +**Storage**: MinIO (persistentes Docker Volume `minio_data`) +**Vector DB**: Qdrant (Port 6333) + +## Datenmodell + +### Zwei Datentypen mit unterschiedlichen Regeln + +| Typ | Quelle | Training erlaubt | Isolation | Collection | +|-----|--------|------------------|-----------|------------| +| **Landes-Daten** | NiBiS, andere Bundesländer | ✅ Ja | Pro Bundesland | `bp_{bundesland}_{usecase}` | +| **Lehrer-Daten** | Lehrer-Upload (BYOEH) | ❌ Nein | Pro Tenant (Schule/Lehrer) | `bp_eh` (verschlüsselt) | + +### Bundesland-Codes (ISO 3166-2:DE) + +``` +NI = Niedersachsen BY = Bayern BW = Baden-Württemberg +NW = Nordrhein-Westf. HE = Hessen SN = Sachsen +BE = Berlin HH = Hamburg SH = Schleswig-Holstein +BB = Brandenburg MV = Meckl.-Vorp. ST = Sachsen-Anhalt +TH = Thüringen RP = Rheinland-Pfalz SL = Saarland +HB = Bremen +``` + +### Use Cases (RAG-Sammlungen) + +| Use Case | Collection Pattern | Beschreibung | +|----------|-------------------|--------------| +| Klausurkorrektur | `bp_{bl}_klausur` | Erwartungshorizonte für Abitur | +| Zeugnisgenerator | `bp_{bl}_zeugnis` | Textbausteine für Zeugnisse | +| Lehrplan | `bp_{bl}_lehrplan` | Kerncurricula, Rahmenrichtlinien | + +Beispiel: `bp_ni_klausur` = Niedersachsen Klausurkorrektur + +## MinIO Bucket-Struktur + +``` +breakpilot-rag/ +├── landes-daten/ +│ ├── ni/ # Niedersachsen +│ │ ├── klausur/ +│ │ │ ├── 2016/ +│ │ │ │ ├── manifest.json +│ │ │ │ └── *.pdf +│ │ │ ├── 2017/ +│ │ │ ├── ... +│ │ │ └── 2025/ +│ │ └── zeugnis/ +│ ├── by/ # Bayern +│ └── .../ +│ +└── lehrer-daten/ # BYOEH - verschlüsselt + └── {tenant_id}/ + └── {lehrer_id}/ + └── *.pdf.enc +``` + +## Qdrant Schema + +### Landes-Daten Collection (z.B. `bp_ni_klausur`) + +```json +{ + "id": "uuid-v5-from-string", + "vector": [384 dimensions], + "payload": { + "original_id": "nibis_2024_deutsch_ea_1_abc123_chunk_0", + "doc_id": "nibis_2024_deutsch_ea_1_abc123", + "chunk_index": 0, + "text": "Der Erwartungshorizont...", + "year": 2024, + "subject": "Deutsch", + "niveau": "eA", + "task_number": 1, + "doc_type": "EWH", + "bundesland": "NI", + "source": "nibis", + "training_allowed": true, + "minio_path": "landes-daten/ni/klausur/2024/2024_Deutsch_eA_I_EWH.pdf" + } +} +``` + +### Lehrer-Daten Collection (`bp_eh`) + +```json +{ + "id": "uuid", + "vector": [384 dimensions], + "payload": { + "tenant_id": "schule_123", + "eh_id": "eh_abc", + "chunk_index": 0, + "subject": "deutsch", + "encrypted_content": "base64...", + "training_allowed": false + } +} +``` + +## Frontend-Komponenten + +### 1. Sammlungen-Übersicht (`/admin/rag/collections`) + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ Daten & RAG │ +├─────────────────────────────────────────────────────────────────┤ +│ │ +│ Sammlungen [+ Neu] │ +│ ───────────────────────────────────────────────────────────── │ +│ │ +│ ┌─────────────────────────────────────────────────────────┐ │ +│ │ 📚 Niedersachsen - Klausurkorrektur │ │ +│ │ bp_ni_klausur | 630 Docs | 4.521 Chunks | 2016-2025 │ │ +│ │ [Suchen] [Indexieren] [Details] │ │ +│ └─────────────────────────────────────────────────────────┘ │ +│ │ +│ ┌─────────────────────────────────────────────────────────┐ │ +│ │ 📚 Niedersachsen - Zeugnisgenerator │ │ +│ │ bp_ni_zeugnis | 0 Docs | Leer │ │ +│ │ [Suchen] [Indexieren] [Details] │ │ +│ └─────────────────────────────────────────────────────────┘ │ +│ │ +└─────────────────────────────────────────────────────────────────┘ +``` + +### 2. Upload-Bereich (`/admin/rag/upload`) + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ Dokumente hochladen │ +├─────────────────────────────────────────────────────────────────┤ +│ │ +│ Ziel-Sammlung: [Niedersachsen - Klausurkorrektur ▼] │ +│ │ +│ ┌─────────────────────────────────────────────────────────┐ │ +│ │ │ │ +│ │ 📁 ZIP-Datei oder Ordner hierher ziehen │ │ +│ │ │ │ +│ │ oder [Dateien auswählen] │ │ +│ │ │ │ +│ │ Unterstützt: .zip, .pdf, Ordner │ │ +│ │ │ │ +│ └─────────────────────────────────────────────────────────┘ │ +│ │ +│ Upload-Queue: │ +│ ┌─────────────────────────────────────────────────────────┐ │ +│ │ ✅ 2018.zip - 45 PDFs erkannt │ │ +│ │ ⏳ 2019.zip - Wird analysiert... │ │ +│ └─────────────────────────────────────────────────────────┘ │ +│ │ +│ [Hochladen & Indexieren] │ +│ │ +└─────────────────────────────────────────────────────────────────┘ +``` + +### 3. Ingestion-Status (`/admin/rag/ingestion`) + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ Ingestion Status │ +├─────────────────────────────────────────────────────────────────┤ +│ │ +│ Aktueller Job: Niedersachsen Klausur 2024 │ +│ ████████████████████░░░░░░░░░░ 65% (412/630 Docs) │ +│ Chunks: 2.891 | Fehler: 3 | ETA: 4:32 │ +│ [Pausieren] [Abbrechen] │ +│ │ +│ ───────────────────────────────────────────────────────────── │ +│ │ +│ Letzte Jobs: │ +│ ┌─────────────────────────────────────────────────────────┐ │ +│ │ ✅ 09.01.2025 15:30 - NI Klausur 2024 - 128 Chunks │ │ +│ │ ✅ 09.01.2025 14:00 - NI Klausur 2017 - 890 Chunks │ │ +│ │ ❌ 08.01.2025 10:15 - BY Klausur - Fehler: Timeout │ │ +│ └─────────────────────────────────────────────────────────┘ │ +│ │ +└─────────────────────────────────────────────────────────────────┘ +``` + +### 4. Suche & Qualitätstest (`/admin/rag/search`) + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ RAG Suche & Qualitätstest │ +├─────────────────────────────────────────────────────────────────┤ +│ │ +│ Sammlung: [Niedersachsen - Klausurkorrektur ▼] │ +│ │ +│ Query: [Analyse eines Gedichts von Rilke ] │ +│ │ +│ Filter: │ +│ Jahr: [Alle ▼] Fach: [Deutsch ▼] Niveau: [eA ▼] │ +│ │ +│ [🔍 Suchen] │ +│ │ +│ ───────────────────────────────────────────────────────────── │ +│ │ +│ Ergebnisse (3): Latenz: 45ms │ +│ │ +│ ┌─────────────────────────────────────────────────────────┐ │ +│ │ #1 | Score: 0.847 | 2024 Deutsch eA Aufgabe 2 │ │ +│ │ │ │ +│ │ "...Die Analyse des Rilke-Gedichts soll folgende │ │ +│ │ Aspekte berücksichtigen: Aufbau, Bildsprache..." │ │ +│ │ │ │ +│ │ Relevanz: [⭐⭐⭐⭐⭐] [⭐⭐⭐⭐] [⭐⭐⭐] [⭐⭐] [⭐] │ │ +│ │ Notizen: [Optional: Warum relevant/nicht relevant? ] │ │ +│ └─────────────────────────────────────────────────────────┘ │ +│ │ +└─────────────────────────────────────────────────────────────────┘ +``` + +### 5. Metriken-Dashboard (`/admin/rag/metrics`) + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ RAG Qualitätsmetriken │ +├─────────────────────────────────────────────────────────────────┤ +│ │ +│ Zeitraum: [Letzte 7 Tage ▼] Sammlung: [Alle ▼] │ +│ │ +│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ +│ │ Precision@5 │ │ Recall@10 │ │ MRR │ │ +│ │ 0.78 │ │ 0.85 │ │ 0.72 │ │ +│ │ ↑ +5% │ │ ↑ +3% │ │ ↓ -2% │ │ +│ └──────────────┘ └──────────────┘ └──────────────┘ │ +│ │ +│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ +│ │ Avg Latency │ │ Bewertungen │ │ Fehlerrate │ │ +│ │ 52ms │ │ 127 │ │ 0.3% │ │ +│ └──────────────┘ └──────────────┘ └──────────────┘ │ +│ │ +│ ───────────────────────────────────────────────────────────── │ +│ │ +│ Score-Verteilung: │ +│ 0.9+ ████████████████ 23% │ +│ 0.7+ ████████████████████████████ 41% │ +│ 0.5+ ████████████████████ 28% │ +│ <0.5 ██████ 8% │ +│ │ +│ [Export CSV] [Detailbericht] │ +│ │ +└─────────────────────────────────────────────────────────────────┘ +``` + +## API Endpoints + +### Collections API + +``` +GET /api/v1/admin/rag/collections +POST /api/v1/admin/rag/collections +GET /api/v1/admin/rag/collections/{id} +DELETE /api/v1/admin/rag/collections/{id} +GET /api/v1/admin/rag/collections/{id}/stats +``` + +### Upload API + +``` +POST /api/v1/admin/rag/upload + Content-Type: multipart/form-data + - file: ZIP oder PDF + - collection_id: string + - metadata: JSON (optional) + +POST /api/v1/admin/rag/upload/folder + - Für Ordner-Upload (WebKitDirectory) +``` + +### Ingestion API + +``` +POST /api/v1/admin/rag/ingest + - collection_id: string + - filters: {year?, subject?, doc_type?} + +GET /api/v1/admin/rag/ingest/status +GET /api/v1/admin/rag/ingest/history +POST /api/v1/admin/rag/ingest/cancel +``` + +### Search API + +``` +POST /api/v1/admin/rag/search + - query: string + - collection_id: string + - filters: {year?, subject?, niveau?} + - limit: int + +POST /api/v1/admin/rag/search/feedback + - result_id: string + - rating: 1-5 + - notes: string (optional) +``` + +### Metrics API + +``` +GET /api/v1/admin/rag/metrics + - collection_id?: string + - from_date?: date + - to_date?: date + +GET /api/v1/admin/rag/metrics/export + - format: csv|json +``` + +## Embedding-Konfiguration + +```python +# Default: Lokale Embeddings (kein API-Key nötig) +EMBEDDING_BACKEND = "local" +LOCAL_EMBEDDING_MODEL = "all-MiniLM-L6-v2" +VECTOR_DIMENSIONS = 384 + +# Optional: OpenAI (für Produktion) +EMBEDDING_BACKEND = "openai" +EMBEDDING_MODEL = "text-embedding-3-small" +VECTOR_DIMENSIONS = 1536 +``` + +## Datenpersistenz + +### Docker Volumes (WICHTIG - nicht löschen!) + +```yaml +volumes: + minio_data: # Alle hochgeladenen Dokumente + qdrant_data: # Alle Vektoren und Embeddings + postgres_data: # Metadaten, Bewertungen, History +``` + +### Backup-Strategie + +```bash +# MinIO Backup +docker exec breakpilot-pwa-minio mc mirror /data /backup + +# Qdrant Backup +curl -X POST http://localhost:6333/collections/bp_ni_klausur/snapshots + +# Postgres Backup (bereits implementiert) +# Läuft automatisch täglich um 2 Uhr +``` + +## Implementierungsreihenfolge + +1. ✅ Backend: Basis-Ingestion (nibis_ingestion.py) +2. ✅ Backend: Lokale Embeddings (sentence-transformers) +3. ✅ Backend: MinIO-Integration (minio_storage.py) +4. ✅ Backend: Collections API (admin_api.py) +5. ✅ Backend: Upload API mit ZIP-Support +6. ✅ Backend: Metrics API mit PostgreSQL (metrics_db.py) +7. ✅ Frontend: Sammlungen-Übersicht +8. ✅ Frontend: Upload-Bereich (Drag & Drop) +9. ✅ Frontend: Ingestion-Status +10. ✅ Frontend: Suche & Qualitätstest (mit Stern-Bewertungen) +11. ✅ Frontend: Metriken-Dashboard + +## Technologie-Stack + +- **Frontend**: Next.js 15 (`/website/app/admin/rag/page.tsx`) +- **Backend**: FastAPI (`klausur-service/backend/`) +- **Vector DB**: Qdrant v1.7.4 (384-dim Vektoren) +- **Object Storage**: MinIO (S3-kompatibel) +- **Embeddings**: sentence-transformers `all-MiniLM-L6-v2` +- **Metrics DB**: PostgreSQL 16 + +## Entwickler-Dokumentation + +### Projektstruktur + +``` +klausur-service/ +├── backend/ +│ ├── main.py # FastAPI App + BYOEH Endpoints +│ ├── admin_api.py # RAG Admin API (Upload, Search, Metrics) +│ ├── nibis_ingestion.py # NiBiS Dokument-Ingestion Pipeline +│ ├── eh_pipeline.py # Chunking, Embeddings, Encryption +│ ├── qdrant_service.py # Qdrant Client + Search +│ ├── minio_storage.py # MinIO S3 Storage +│ ├── metrics_db.py # PostgreSQL Metrics +│ ├── requirements.txt # Python Dependencies +│ └── tests/ +│ └── test_rag_admin.py +└── docs/ + └── RAG-Admin-Spec.md # Diese Datei +``` + +### Schnellstart für Entwickler + +```bash +# 1. Services starten +cd /path/to/breakpilot-pwa +docker-compose up -d qdrant minio postgres + +# 2. Dependencies installieren +cd klausur-service/backend +pip install -r requirements.txt + +# 3. Service starten +python -m uvicorn main:app --port 8086 --reload + +# 4. RAG-Services initialisieren (erstellt Bucket + Tabellen) +curl -X POST http://localhost:8086/api/v1/admin/rag/init +``` + +### API-Referenz (Implementiert) + +#### NiBiS Ingestion +``` +GET /api/v1/admin/nibis/discover # Dokumente finden +POST /api/v1/admin/nibis/ingest # Indexierung starten +GET /api/v1/admin/nibis/status # Status abfragen +GET /api/v1/admin/nibis/stats # Statistiken +POST /api/v1/admin/nibis/search # Semantische Suche +GET /api/v1/admin/nibis/collections # Qdrant Collections +``` + +#### RAG Upload & Storage +``` +POST /api/v1/admin/rag/upload # ZIP/PDF hochladen +GET /api/v1/admin/rag/upload/history # Upload-Verlauf +GET /api/v1/admin/rag/storage/stats # MinIO Statistiken +``` + +#### Metrics & Feedback +``` +GET /api/v1/admin/rag/metrics # Qualitätsmetriken +POST /api/v1/admin/rag/search/feedback # Bewertung abgeben +POST /api/v1/admin/rag/init # Services initialisieren +``` + +### Umgebungsvariablen + +```bash +# Qdrant +QDRANT_URL=http://localhost:6333 + +# MinIO +MINIO_ENDPOINT=localhost:9000 +MINIO_ACCESS_KEY=breakpilot +MINIO_SECRET_KEY=breakpilot123 +MINIO_BUCKET=breakpilot-rag + +# PostgreSQL +DATABASE_URL=postgres://breakpilot:breakpilot123@localhost:5432/breakpilot_db + +# Embeddings +EMBEDDING_BACKEND=local +LOCAL_EMBEDDING_MODEL=all-MiniLM-L6-v2 +``` + +### Aktuelle Indexierungs-Statistik + +- **Dokumente**: 579 Erwartungshorizonte (NiBiS) +- **Chunks**: 7.352 +- **Jahre**: 2016, 2017, 2024, 2025 +- **Fächer**: Deutsch, Englisch, Mathematik, Physik, Chemie, Biologie, Geschichte, Politik-Wirtschaft, Erdkunde, Sport, Kunst, Musik, Latein, Informatik, Ev. Religion, Kath. Religion, Werte und Normen, etc. +- **Collection**: `bp_nibis_eh` +- **Vektor-Dimensionen**: 384 diff --git a/docs-src/services/klausur-service/Worksheet-Editor-Architecture.md b/docs-src/services/klausur-service/Worksheet-Editor-Architecture.md new file mode 100644 index 0000000..6d7fed8 --- /dev/null +++ b/docs-src/services/klausur-service/Worksheet-Editor-Architecture.md @@ -0,0 +1,409 @@ +# Visual Worksheet Editor - Architecture Documentation + +**Version:** 1.0 +**Status:** Implementiert + +## 1. Übersicht + +Der Visual Worksheet Editor ist ein Canvas-basierter Editor für die Erstellung und Bearbeitung von Arbeitsblättern. Er ermöglicht Lehrern, eingescannte Arbeitsblätter originalgetreu zu rekonstruieren oder neue Arbeitsblätter visuell zu gestalten. + +### 1.1 Hauptfunktionen + +- **Canvas-basiertes Editieren** mit Fabric.js +- **Freie Positionierung** von Text, Bildern und Formen +- **Typografie-Steuerung** (Schriftarten, Größen, Stile) +- **Bilder & Grafiken** hochladen und einfügen +- **KI-generierte Bilder** via Ollama/Stable Diffusion +- **PDF/Bild-Export** für Druck und digitale Nutzung +- **Mehrseitige Dokumente** mit Seitennavigation + +### 1.2 Technologie-Stack + +| 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 | + +## 2. Architektur + +``` +┌──────────────────────────────────────────────────────────────────────┐ +│ Frontend (studio-v2 / Next.js) │ +│ /studio-v2/app/worksheet-editor/page.tsx │ +│ │ +│ ┌─────────────┐ ┌────────────────────────────┐ ┌────────────────┐ │ +│ │ Toolbar │ │ Fabric.js Canvas │ │ Properties │ │ +│ │ (Links) │ │ (Mitte - 60%) │ │ Panel │ │ +│ │ │ │ │ │ (Rechts) │ │ +│ │ - Select │ │ ┌──────────────────────┐ │ │ │ │ +│ │ - Text │ │ │ │ │ │ - Schriftart │ │ +│ │ - Formen │ │ │ A4 Arbeitsfläche │ │ │ - Größe │ │ +│ │ - Bilder │ │ │ mit Grid │ │ │ - Farbe │ │ +│ │ - KI-Bild │ │ │ │ │ │ - Position │ │ +│ │ - Tabelle │ │ └──────────────────────┘ │ │ - Ebene │ │ +│ └─────────────┘ └────────────────────────────┘ └────────────────┘ │ +│ │ +│ ┌────────────────────────────────────────────────────────────────┐ │ +│ │ Seiten-Navigation | Zoom | Grid | Export PDF │ │ +│ └────────────────────────────────────────────────────────────────┘ │ +└──────────────────────────────────────────────────────────────────────┘ + │ + ▼ +┌──────────────────────────────────────────────────────────────────────┐ +│ klausur-service (FastAPI - Port 8086) │ +│ POST /api/v1/worksheet/ai-image → Bild via Ollama generieren │ +│ POST /api/v1/worksheet/save → Worksheet speichern │ +│ GET /api/v1/worksheet/{id} → Worksheet laden │ +│ POST /api/v1/worksheet/export-pdf → PDF generieren │ +└──────────────────────────────────────────────────────────────────────┘ + │ + ▼ +┌──────────────────────────────────────────────────────────────────────┐ +│ Ollama (Port 11434) │ +│ Model: stable-diffusion oder kompatibles Text-to-Image Modell │ +│ Text-to-Image für KI-generierte Grafiken │ +└──────────────────────────────────────────────────────────────────────┘ +``` + +## 3. Dateistruktur + +### 3.1 Frontend (studio-v2) + +``` +/studio-v2/ +├── app/ +│ └── worksheet-editor/ +│ ├── page.tsx # Haupt-Editor-Seite +│ └── types.ts # TypeScript Interfaces +│ +├── components/ +│ └── worksheet-editor/ +│ ├── index.ts # Exports +│ ├── FabricCanvas.tsx # Fabric.js Canvas Wrapper +│ ├── EditorToolbar.tsx # Werkzeugleiste (links) +│ ├── PropertiesPanel.tsx # Eigenschaften-Panel (rechts) +│ ├── AIImageGenerator.tsx # KI-Bild Generator Modal +│ ├── CanvasControls.tsx # Zoom, Grid, Seiten +│ ├── ExportPanel.tsx # PDF/Bild Export +│ └── PageNavigator.tsx # Mehrseitige Dokumente +│ +├── lib/ +│ └── worksheet-editor/ +│ ├── index.ts # Exports +│ └── WorksheetContext.tsx # State Management +``` + +### 3.2 Backend (klausur-service) + +``` +/klausur-service/backend/ +├── worksheet_editor_api.py # API Endpoints +└── main.py # Router-Registrierung +``` + +## 4. API Endpoints + +### 4.1 KI-Bild generieren + +```http +POST /api/v1/worksheet/ai-image +Content-Type: application/json + +{ + "prompt": "Ein freundlicher Cartoon-Hund der ein Buch liest", + "style": "cartoon", + "width": 512, + "height": 512 +} +``` + +**Response:** +```json +{ + "image_base64": "data:image/png;base64,...", + "prompt_used": "...", + "error": null +} +``` + +**Styles:** +- `realistic` - Fotorealistisch +- `cartoon` - Cartoon/Comic +- `sketch` - Handgezeichnete Skizze +- `clipart` - Einfache Clipart-Grafiken +- `educational` - Bildungs-Illustrationen + +### 4.2 Worksheet speichern + +```http +POST /api/v1/worksheet/save +Content-Type: application/json + +{ + "id": "optional-existing-id", + "title": "Englisch Vokabeln Unit 3", + "pages": [ + { "id": "page_1", "index": 0, "canvasJSON": "{...}" } + ], + "pageFormat": { + "width": 210, + "height": 297, + "orientation": "portrait" + } +} +``` + +### 4.3 Worksheet laden + +```http +GET /api/v1/worksheet/{id} +``` + +### 4.4 PDF exportieren + +```http +POST /api/v1/worksheet/{id}/export-pdf +``` + +**Response:** PDF-Datei als Download + +### 4.5 Worksheets auflisten + +```http +GET /api/v1/worksheet/list/all +``` + +## 5. Komponenten + +### 5.1 FabricCanvas + +Die Kernkomponente für den Canvas-Bereich: + +- **A4-Format**: 794 x 1123 Pixel (96 DPI) +- **Grid-Overlay**: Optionales Raster mit Snap-Funktion +- **Zoom/Pan**: Mausrad und Controls +- **Selection**: Einzel- und Mehrfachauswahl +- **Keyboard Shortcuts**: Del, Ctrl+C/V/Z/D + +### 5.2 EditorToolbar + +Werkzeuge für die Bearbeitung: + +| Icon | Tool | Beschreibung | +|------|------|--------------| +| 🖱️ | Select | Elemente auswählen/verschieben | +| T | Text | Text hinzufügen (IText) | +| ▭ | Rechteck | Rechteck zeichnen | +| ○ | Kreis | Kreis/Ellipse zeichnen | +| ― | Linie | Linie zeichnen | +| → | Pfeil | Pfeil zeichnen | +| 🖼️ | Bild | Bild hochladen | +| ✨ | KI-Bild | Bild mit KI generieren | +| ⊞ | Tabelle | Tabelle einfügen | + +### 5.3 PropertiesPanel + +Eigenschaften-Editor für ausgewählte Objekte: + +**Text-Eigenschaften:** +- Schriftart (Arial, Times, Georgia, OpenDyslexic, Schulschrift) +- Schriftgröße (8-120pt) +- Schriftstil (Normal, Fett, Kursiv) +- Zeilenhöhe, Zeichenabstand +- Textausrichtung +- Textfarbe + +**Form-Eigenschaften:** +- Füllfarbe +- Rahmenfarbe und -stärke +- Eckenradius + +**Allgemein:** +- Deckkraft +- Löschen-Button + +### 5.4 WorksheetContext + +React Context für globalen State: + +```typescript +interface WorksheetContextType { + canvas: Canvas | null + document: WorksheetDocument | null + activeTool: EditorTool + selectedObjects: FabricObject[] + zoom: number + showGrid: boolean + snapToGrid: boolean + currentPageIndex: number + canUndo: boolean + canRedo: boolean + isDirty: boolean + // ... Methoden +} +``` + +## 6. Datenmodelle + +### 6.1 WorksheetDocument + +```typescript +interface WorksheetDocument { + id: string + title: string + description?: string + pages: WorksheetPage[] + pageFormat: PageFormat + createdAt: string + updatedAt: string +} +``` + +### 6.2 WorksheetPage + +```typescript +interface WorksheetPage { + id: string + index: number + canvasJSON: string // Serialisierter Fabric.js Canvas + thumbnail?: string +} +``` + +### 6.3 PageFormat + +```typescript +interface PageFormat { + width: number // in mm (Standard: 210) + height: number // in mm (Standard: 297) + orientation: 'portrait' | 'landscape' + margins: { top, right, bottom, left: number } +} +``` + +## 7. Features + +### 7.1 Undo/Redo + +- History-Stack mit max. 50 Einträgen +- Automatische Speicherung bei jeder Änderung +- Keyboard: Ctrl+Z (Undo), Ctrl+Y (Redo) + +### 7.2 Grid & Snap + +- Konfigurierbares Raster (5mm, 10mm, 15mm, 20mm) +- Snap-to-Grid beim Verschieben +- Ein-/Ausblendbar + +### 7.3 Export + +- **PDF**: Mehrseitig, A4-Format +- **PNG**: Hochauflösend (2x Multiplier) +- **JPG**: Mit Qualitätseinstellung + +### 7.4 Speicherung + +- **Backend**: REST API mit JSON-Persistierung +- **Fallback**: localStorage bei Offline-Betrieb + +## 8. KI-Bildgenerierung + +### 8.1 Ollama Integration + +Der Editor nutzt Ollama für die KI-Bildgenerierung: + +```python +OLLAMA_URL = "http://host.docker.internal:11434" +``` + +### 8.2 Placeholder-System + +Falls Ollama nicht verfügbar ist, wird ein Placeholder-Bild generiert: +- Farbcodiert nach Stil +- Prompt-Text als Beschreibung +- "KI-Bild (Platzhalter)"-Badge + +### 8.3 Stil-Prompts + +Jeder Stil fügt automatisch Modifikatoren zum Prompt hinzu: + +```python +STYLE_PROMPTS = { + "realistic": "photorealistic, high detail", + "cartoon": "cartoon style, colorful, child-friendly", + "sketch": "pencil sketch, hand-drawn", + "clipart": "clipart style, flat design", + "educational": "educational illustration, textbook style" +} +``` + +## 9. Glassmorphism Design + +Der Editor folgt dem Glassmorphism-Design des Studio v2: + +```typescript +// Dark Theme +'backdrop-blur-xl bg-white/10 border border-white/20' + +// Light Theme +'backdrop-blur-xl bg-white/70 border border-black/10 shadow-xl' +``` + +## 10. Internationalisierung + +Unterstützte Sprachen: +- 🇩🇪 Deutsch +- 🇬🇧 English +- 🇹🇷 Türkçe +- 🇸🇦 العربية (RTL) +- 🇷🇺 Русский +- 🇺🇦 Українська +- 🇵🇱 Polski + +Translation Key: `nav_worksheet_editor` + +## 11. Sicherheit + +### 11.1 Bild-Upload + +- Nur Bildformate (image/*) +- Client-seitige Validierung +- Base64-Konvertierung + +### 11.2 CORS + +Aktiviert für lokale Entwicklung und Docker-Umgebung. + +## 12. Deployment + +### 12.1 Frontend + +```bash +cd studio-v2 +npm install +npm run dev # Port 3001 +``` + +### 12.2 Backend + +Der klausur-service läuft auf Port 8086: + +```bash +cd klausur-service/backend +python main.py +``` + +### 12.3 Docker + +Der Service ist Teil des docker-compose.yml. + +## 13. Zukünftige Erweiterungen + +- [ ] Tabellen-Tool mit Zellbearbeitung +- [ ] Vorlagen-Bibliothek +- [ ] Kollaboratives Editieren +- [ ] Drag & Drop aus Dokumentenbibliothek +- [ ] Integration mit Vocab-Worksheet diff --git a/docs-src/services/klausur-service/index.md b/docs-src/services/klausur-service/index.md new file mode 100644 index 0000000..22e50df --- /dev/null +++ b/docs-src/services/klausur-service/index.md @@ -0,0 +1,173 @@ +# Klausur-Service + +Der Klausur-Service ist ein FastAPI-basierter Microservice fuer KI-gestuetzte Abitur-Klausurkorrektur. + +## Uebersicht + +| Eigenschaft | Wert | +|-------------|------| +| **Port** | 8086 | +| **Framework** | FastAPI (Python) | +| **Datenbank** | PostgreSQL + Qdrant (Vektor-DB) | +| **Speicher** | MinIO (Datei-Storage) | + +## Features + +- **OCR-Erkennung**: Automatische Texterkennung aus gescannten Klausuren +- **KI-Bewertung**: Automatische Bewertungsvorschlaege basierend auf Erwartungshorizont +- **BYOEH**: Bring-Your-Own-Expectation-Horizon mit Client-seitiger Verschluesselung +- **Fairness-Analyse**: Statistische Analyse der Bewertungskonsistenz +- **PDF-Export**: Gutachten und Notenuebersichten als PDF +- **Zweitkorrektur**: Vollstaendiger Workflow fuer Erst-, Zweit- und Drittkorrektur + +## Architektur + +``` +┌─────────────────────────────────────────────────────────────┐ +│ Frontend (Next.js) │ +│ /website/app/admin/klausur-korrektur/ │ +│ - Klausur-Liste │ +│ - Studenten-Liste │ +│ - Korrektur-Workspace (2/3-1/3 Layout) │ +│ - Fairness-Dashboard │ +└─────────────────────────────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────────┐ +│ klausur-service (FastAPI) │ +│ Port 8086 - /klausur-service/backend/main.py │ +│ - Klausur CRUD (/api/v1/klausuren) │ +│ - Student Work (/api/v1/students) │ +│ - Annotations (/api/v1/annotations) │ +│ - BYOEH (/api/v1/eh) │ +│ - PDF Export │ +└─────────────────────────────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────────┐ +│ Infrastruktur │ +│ - Qdrant (Vektor-DB fuer RAG) │ +│ - MinIO (Datei-Storage) │ +│ - PostgreSQL (Metadaten) │ +│ - Embedding-Service (Port 8087) │ +└─────────────────────────────────────────────────────────────┘ +``` + +## API Endpoints + +### Klausur-Verwaltung + +| Method | Endpoint | Beschreibung | +|--------|----------|--------------| +| GET | `/api/v1/klausuren` | Liste aller Klausuren | +| POST | `/api/v1/klausuren` | Neue Klausur erstellen | +| GET | `/api/v1/klausuren/{id}` | Klausur-Details | +| DELETE | `/api/v1/klausuren/{id}` | Klausur loeschen | + +### Studenten-Arbeiten + +| Method | Endpoint | Beschreibung | +|--------|----------|--------------| +| POST | `/api/v1/klausuren/{id}/students` | Arbeit hochladen | +| GET | `/api/v1/klausuren/{id}/students` | Studenten-Liste | +| GET | `/api/v1/students/{id}` | Einzelne Arbeit | +| PUT | `/api/v1/students/{id}/criteria` | Kriterien bewerten | +| PUT | `/api/v1/students/{id}/gutachten` | Gutachten speichern | + +### KI-Funktionen + +| Method | Endpoint | Beschreibung | +|--------|----------|--------------| +| POST | `/api/v1/students/{id}/gutachten/generate` | Gutachten generieren | +| GET | `/api/v1/klausuren/{id}/fairness` | Fairness-Analyse | +| POST | `/api/v1/students/{id}/eh-suggestions` | EH-Vorschlaege via RAG | + +### PDF-Export + +| Method | Endpoint | Beschreibung | +|--------|----------|--------------| +| GET | `/api/v1/students/{id}/export/gutachten` | Einzelgutachten PDF | +| GET | `/api/v1/students/{id}/export/annotations` | Anmerkungen PDF | +| GET | `/api/v1/klausuren/{id}/export/overview` | Notenuebersicht PDF | +| GET | `/api/v1/klausuren/{id}/export/all-gutachten` | Alle Gutachten PDF | + +## Notensystem + +Das System verwendet das deutsche 15-Punkte-System fuer Abiturklausuren: + +| Punkte | Prozent | Note | +|--------|---------|------| +| 15 | >= 95% | 1+ | +| 14 | >= 90% | 1 | +| 13 | >= 85% | 1- | +| 12 | >= 80% | 2+ | +| 11 | >= 75% | 2 | +| 10 | >= 70% | 2- | +| 9 | >= 65% | 3+ | +| 8 | >= 60% | 3 | +| 7 | >= 55% | 3- | +| 6 | >= 50% | 4+ | +| 5 | >= 45% | 4 | +| 4 | >= 40% | 4- | +| 3 | >= 33% | 5+ | +| 2 | >= 27% | 5 | +| 1 | >= 20% | 5- | +| 0 | < 20% | 6 | + +## Bewertungskriterien + +| Kriterium | Gewicht | Beschreibung | +|-----------|---------|--------------| +| Rechtschreibung | 15% | Orthografie | +| Grammatik | 15% | Grammatik & Syntax | +| Inhalt | 40% | Inhaltliche Qualitaet | +| Struktur | 15% | Aufbau & Gliederung | +| Stil | 15% | Ausdruck & Stil | + +## Verzeichnisstruktur + +``` +klausur-service/ +├── backend/ +│ ├── main.py # API Endpoints + Datenmodelle +│ ├── qdrant_service.py # Vektor-Datenbank Operationen +│ ├── eh_pipeline.py # BYOEH Verarbeitung +│ ├── hybrid_search.py # Hybrid Search (BM25 + Semantic) +│ └── requirements.txt # Python Dependencies +├── frontend/ +│ └── src/ +│ ├── components/ # React Komponenten +│ ├── pages/ # Seiten +│ └── services/ # API Client +└── docs/ + ├── BYOEH-Architecture.md + └── BYOEH-Developer-Guide.md +``` + +## Konfiguration + +### Umgebungsvariablen + +```env +# Klausur-Service +KLAUSUR_SERVICE_PORT=8086 +QDRANT_URL=http://qdrant:6333 +MINIO_ENDPOINT=minio:9000 +MINIO_ACCESS_KEY=... +MINIO_SECRET_KEY=... + +# Embedding-Service +EMBEDDING_SERVICE_URL=http://embedding:8087 +OPENAI_API_KEY=sk-... + +# BYOEH +BYOEH_ENCRYPTION_ENABLED=true +EH_UPLOAD_DIR=/app/eh-uploads +``` + +## Weiterführende Dokumentation + +- [BYOEH Architektur](./BYOEH-Architecture.md) - Client-seitige Verschluesselung +- [OCR Compare](./OCR-Compare.md) - Block Review Feature fuer OCR-Vergleich +- [Zeugnis-System](../../architecture/zeugnis-system.md) - Zeugniserstellung +- [Backend API](../../api/backend-api.md) - Allgemeine API-Dokumentation diff --git a/docs-src/services/voice-service/index.md b/docs-src/services/voice-service/index.md new file mode 100644 index 0000000..7ffa502 --- /dev/null +++ b/docs-src/services/voice-service/index.md @@ -0,0 +1,160 @@ +# Voice Service + +Der Voice Service ist eine Voice-First Interface für die Breakpilot-Plattform mit DSGVO-konformem Design. + +## Übersicht + +| Eigenschaft | Wert | +|-------------|------| +| **Port** | 8082 | +| **Framework** | FastAPI (Python) | +| **Streaming** | WebSocket | +| **DSGVO** | Privacy-by-Design | + +## Architektur + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ Voice Service (Port 8082) │ +├─────────────────────────────────────────────────────────────────┤ +│ │ +│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ +│ │ Sessions │───>│ Task │───>│ BQAS │ │ +│ │ API │ │ Orchestrator │ │ (Quality) │ │ +│ └──────────────┘ └──────────────┘ └──────────────┘ │ +│ │ │ +│ ┌────────────────────┼────────────────────┐ │ +│ │ │ │ │ +│ ▼ ▼ ▼ │ +│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ +│ │ WebSocket │ │ Encryption │ │ Logging │ │ +│ │ Streaming │ │ Service │ │ (structlog) │ │ +│ └──────────────┘ └──────────────┘ └──────────────┘ │ +│ │ +└─────────────────────────────────────────────────────────────────┘ +``` + +## Kernkomponenten + +### PersonaPlex + TaskOrchestrator + +- Voice-first Interface für Breakpilot +- Real-time Voice Processing +- Multi-Agent Integration + +### DSGVO-Compliance (Privacy-by-Design) + +| Feature | Beschreibung | +|---------|--------------| +| **Keine Audio-Persistenz** | Nur RAM-basiert, keine dauerhafte Speicherung | +| **Namespace-Verschlüsselung** | Schlüssel nur auf Lehrer-Gerät | +| **TTL-basierte Löschung** | Automatische Datenlöschung nach Zeitablauf | +| **Transcript-Verschlüsselung** | Verschlüsselte Transkripte | + +## API-Endpunkte + +### Sessions + +| Method | Endpoint | Beschreibung | +|--------|----------|--------------| +| POST | `/api/v1/sessions` | Session erstellen | +| GET | `/api/v1/sessions/:id` | Session abrufen | +| DELETE | `/api/v1/sessions/:id` | Session beenden | + +### Task Orchestration + +| Method | Endpoint | Beschreibung | +|--------|----------|--------------| +| POST | `/api/v1/tasks` | Task erstellen | +| GET | `/api/v1/tasks/:id` | Task-Status abrufen | + +### BQAS (Quality Assessment) + +| Method | Endpoint | Beschreibung | +|--------|----------|--------------| +| POST | `/api/v1/bqas/evaluate` | Qualitätsbewertung | +| GET | `/api/v1/bqas/metrics` | Metriken abrufen | + +### WebSocket + +| Endpoint | Beschreibung | +|----------|--------------| +| `/ws/voice` | Real-time Voice Streaming | + +### Health + +| Method | Endpoint | Beschreibung | +|--------|----------|--------------| +| GET | `/health` | Health Check | +| GET | `/ready` | Readiness Check | + +## Verzeichnisstruktur + +``` +voice-service/ +├── main.py # FastAPI Application +├── config.py # Konfiguration +├── pyproject.toml # Projekt-Metadaten +├── requirements.txt # Dependencies +├── api/ +│ ├── sessions.py # Session-Management +│ ├── streaming.py # WebSocket Voice Streaming +│ ├── tasks.py # Task Orchestration +│ └── bqas.py # Quality Assessment +├── services/ +│ ├── task_orchestrator.py # Task-Routing +│ └── encryption.py # Verschlüsselung +├── bqas/ +│ ├── judge.py # LLM Judge +│ └── quality_judge_agent.py # Agent-Integration +├── models/ # Datenmodelle +├── scripts/ # Utility-Scripts +└── tests/ # Test-Suite +``` + +## Konfiguration + +```env +# .env +VOICE_SERVICE_PORT=8082 +REDIS_URL=redis://localhost:6379 +DATABASE_URL=postgresql://... +ENCRYPTION_KEY=... +TTL_MINUTES=60 +``` + +## Entwicklung + +```bash +# Dependencies installieren +cd voice-service +pip install -r requirements.txt + +# Server starten +uvicorn main:app --reload --port 8082 + +# Tests ausführen +pytest -v +``` + +## Docker + +Der Service läuft als Teil von docker-compose.yml: + +```yaml +voice-service: + build: + context: ./voice-service + ports: + - "8082:8082" + environment: + - REDIS_URL=redis://valkey:6379 + depends_on: + - valkey + - postgres +``` + +## Weiterführende Dokumentation + +- [Multi-Agent Architektur](../../architecture/multi-agent.md) +- [BQAS Quality System](../../architecture/bqas.md) diff --git a/mkdocs.yml b/mkdocs.yml new file mode 100644 index 0000000..82af606 --- /dev/null +++ b/mkdocs.yml @@ -0,0 +1,81 @@ +site_name: BreakPilot Lehrer - Dokumentation +site_url: https://macmini:8010 +docs_dir: docs-src +site_dir: docs-site + +theme: + name: material + language: de + palette: + - scheme: default + primary: blue + accent: blue + toggle: + icon: material/brightness-7 + name: Dark Mode + - scheme: slate + primary: blue + accent: blue + toggle: + icon: material/brightness-4 + name: Light Mode + features: + - search.highlight + - search.suggest + - navigation.tabs + - navigation.sections + - navigation.expand + - navigation.top + - content.code.copy + - toc.follow + +plugins: + - search: + lang: de + +markdown_extensions: + - admonition + - pymdownx.details + - pymdownx.superfences: + custom_fences: + - name: mermaid + class: mermaid + format: !!python/name:pymdownx.superfences.fence_code_format + - pymdownx.tabbed: + alternate_style: true + - pymdownx.highlight: + anchor_linenums: true + - pymdownx.inlinehilite + - pymdownx.snippets + - tables + - attr_list + - md_in_html + - toc: + permalink: true + +nav: + - Start: index.md + - Services: + - KI-Daten-Pipeline: + - Uebersicht: services/ki-daten-pipeline/index.md + - Architektur: services/ki-daten-pipeline/architecture.md + - Klausur-Service: + - Uebersicht: services/klausur-service/index.md + - BYOEH Architektur: services/klausur-service/BYOEH-Architecture.md + - BYOEH Developer Guide: services/klausur-service/BYOEH-Developer-Guide.md + - NiBiS Pipeline: services/klausur-service/NiBiS-Ingestion-Pipeline.md + - OCR Labeling: services/klausur-service/OCR-Labeling-Spec.md + - OCR Vergleich: services/klausur-service/OCR-Compare.md + - RAG Admin: services/klausur-service/RAG-Admin-Spec.md + - Worksheet Editor: services/klausur-service/Worksheet-Editor-Architecture.md + - Voice-Service: + - Uebersicht: services/voice-service/index.md + - Agent-Core: + - Uebersicht: services/agent-core/index.md + - Architektur: + - Multi-Agent System: architecture/multi-agent.md + - Zeugnis-System: architecture/zeugnis-system.md + - Entwicklung: + - Testing: development/testing.md + - Dokumentation: development/documentation.md + - CI/CD Pipeline: development/ci-cd-pipeline.md