Add CLAUDE.md, MkDocs docs, .claude/rules

- CLAUDE.md: Comprehensive documentation for Lehrer KI platform
- docs-src: Klausur, Voice, Agent-Core, KI-Pipeline docs
- mkdocs.yml: Lehrer-specific nav with blue theme
- docker-compose: Added docs service (port 8010, profile: docs)
- .claude/rules: testing, docs, open-source, abiturkorrektur, vocab-worksheet, multi-agent, experimental-dashboard

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Benjamin Boenisch
2026-02-12 00:49:25 +01:00
parent 5a31f52310
commit e22019b2d5
29 changed files with 7288 additions and 25 deletions

View File

@@ -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 && <cmd>"
```
---
## 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 <service>"
# Logs
ssh macmini "/usr/local/bin/docker logs -f bp-lehrer-<service>"
# 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 |

View File

@@ -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

View File

@@ -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)

View File

@@ -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 |

View File

@@ -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 |

View File

@@ -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 <package> license
# Python Package
pip show <package> | grep License
# Go Module
go-licenses check <module>
```
### 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

202
.claude/rules/testing.md Normal file
View File

@@ -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)

View File

@@ -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 |

View File

@@ -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

48
docs-src/Dockerfile Normal file
View File

@@ -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;"]

View File

@@ -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/`

View File

@@ -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

View File

@@ -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 <service-name>"
# 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 <service-name>"
```
### 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-name>"
```
## 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-<service>-1"
# 2. Container manuell starten für Debug-Output
ssh macmini "docker compose -f .../docker-compose.yml run --rm <service>"
# 3. In Container einloggen
ssh macmini "docker exec -it breakpilot-pwa-<service>-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 <service>"
```
## 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=<client_id>
WOODPECKER_GITEA_SECRET=<client_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
```

View File

@@ -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
```
```

View File

@@ -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))

21
docs-src/index.md Normal file
View File

@@ -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)

View File

@@ -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

View File

@@ -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<br/>/ai/ocr-labeling"]
F2["RAG Pipeline<br/>/ai/rag-pipeline"]
F3["Daten & RAG<br/>/ai/rag"]
F4["Klausur-Korrektur<br/>/ai/klausur-korrektur"]
end
subgraph Backend["Backend Services"]
direction TB
B1["klausur-service<br/>Port 8086"]
B2["embedding-service<br/>Port 8087"]
end
subgraph Storage["Persistenz"]
direction TB
D1[(PostgreSQL<br/>Metadaten)]
D2[(Qdrant<br/>Vektoren)]
D3[(MinIO<br/>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<br/>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

View File

@@ -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)

View File

@@ -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)

View File

@@ -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": <encrypted_blob>,
"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
<EHUploadWizard
onClose={() => 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.

View File

@@ -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)

View File

@@ -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<string, { vocabulary: Array<...> }>
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<number, BlockReviewData>
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<number, BlockReviewData>
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 |

View File

@@ -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 = <input>`, `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
```

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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)

81
mkdocs.yml Normal file
View File

@@ -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