This repository has been archived on 2026-02-15. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
breakpilot-pwa/backend/frontend/components/admin_klausur_docs.py
Benjamin Admin 21a844cb8a fix: Restore all files lost during destructive rebase
A previous `git pull --rebase origin main` dropped 177 local commits,
losing 3400+ files across admin-v2, backend, studio-v2, website,
klausur-service, and many other services. The partial restore attempt
(660295e2) only recovered some files.

This commit restores all missing files from pre-rebase ref 98933f5e
while preserving post-rebase additions (night-scheduler, night-mode UI,
NightModeWidget dashboard integration).

Restored features include:
- AI Module Sidebar (FAB), OCR Labeling, OCR Compare
- GPU Dashboard, RAG Pipeline, Magic Help
- Klausur-Korrektur (8 files), Abitur-Archiv (5+ files)
- Companion, Zeugnisse-Crawler, Screen Flow
- Full backend, studio-v2, website, klausur-service
- All compliance SDKs, agent-core, voice-service
- CI/CD configs, documentation, scripts

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-09 09:51:32 +01:00

630 lines
22 KiB
Python

"""
Admin Klausurkorrektur Documentation Component.
Provides audit-ready documentation for education ministries and data protection officers.
Written in non-technical language for compliance review.
This component explains:
- Privacy-by-Design architecture
- DSGVO compliance measures
- Data flow and processing
- Security guarantees
"""
def get_admin_klausur_docs_css() -> str:
"""CSS for Klausur Documentation Panel."""
return """
/* ==========================================
KLAUSUR DOCUMENTATION STYLES (Audit-Ready)
========================================== */
.klausur-docs-panel {
background: var(--bp-surface-elevated);
border-radius: 12px;
padding: 24px;
margin-bottom: 20px;
border: 1px solid var(--bp-border);
}
.klausur-docs-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 24px;
padding-bottom: 16px;
border-bottom: 1px solid var(--bp-border);
}
.klausur-docs-header h2 {
margin: 0;
font-size: 20px;
color: var(--bp-text);
display: flex;
align-items: center;
gap: 12px;
}
.audit-badge {
background: #065f46;
color: #6ee7b7;
font-size: 11px;
padding: 4px 10px;
border-radius: 4px;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.5px;
}
.doc-section {
margin-bottom: 32px;
}
.doc-section h3 {
color: var(--bp-text);
font-size: 16px;
margin: 0 0 16px 0;
padding-bottom: 8px;
border-bottom: 1px solid var(--bp-border-subtle);
display: flex;
align-items: center;
gap: 8px;
}
.doc-section h3 .section-number {
background: var(--bp-primary);
color: white;
width: 24px;
height: 24px;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
font-size: 12px;
font-weight: 600;
}
.doc-content {
color: var(--bp-text-muted);
font-size: 14px;
line-height: 1.8;
}
.doc-content p {
margin: 0 0 12px 0;
}
.doc-content ul, .doc-content ol {
margin: 12px 0;
padding-left: 24px;
}
.doc-content li {
margin-bottom: 8px;
}
.highlight-box {
background: rgba(6, 95, 70, 0.15);
border: 1px solid #065f46;
border-radius: 8px;
padding: 16px;
margin: 16px 0;
}
.highlight-box.green {
background: rgba(6, 95, 70, 0.15);
border-color: #065f46;
}
.highlight-box.blue {
background: rgba(59, 130, 246, 0.1);
border-color: #3b82f6;
}
.highlight-box.yellow {
background: rgba(251, 191, 36, 0.1);
border-color: #fbbf24;
}
.highlight-box h4 {
color: inherit;
margin: 0 0 8px 0;
font-size: 14px;
}
.highlight-box p, .highlight-box ul {
margin: 0;
color: inherit;
}
.highlight-box.green { color: #6ee7b7; }
.highlight-box.blue { color: #60a5fa; }
.highlight-box.yellow { color: #fbbf24; }
.data-flow-diagram {
background: var(--bp-surface);
border: 1px solid var(--bp-border);
border-radius: 8px;
padding: 20px;
margin: 16px 0;
font-family: monospace;
font-size: 12px;
overflow-x: auto;
white-space: pre;
color: var(--bp-text);
line-height: 1.6;
}
.legal-reference {
background: var(--bp-surface);
border-left: 3px solid var(--bp-primary);
padding: 12px 16px;
margin: 16px 0;
font-style: italic;
color: var(--bp-text-muted);
}
.legal-reference cite {
display: block;
margin-top: 8px;
font-style: normal;
font-weight: 600;
color: var(--bp-text);
}
.comparison-table {
width: 100%;
border-collapse: collapse;
margin: 16px 0;
font-size: 13px;
}
.comparison-table th,
.comparison-table td {
padding: 12px;
text-align: left;
border: 1px solid var(--bp-border);
}
.comparison-table th {
background: var(--bp-surface);
color: var(--bp-text);
font-weight: 600;
}
.comparison-table td {
color: var(--bp-text-muted);
}
.comparison-table .good {
color: #22c55e;
}
.comparison-table .bad {
color: #ef4444;
}
.tech-specs {
background: var(--bp-surface);
border-radius: 8px;
padding: 16px;
margin: 16px 0;
}
.tech-specs h4 {
margin: 0 0 12px 0;
color: var(--bp-text);
font-size: 14px;
}
.tech-specs table {
width: 100%;
font-size: 12px;
}
.tech-specs td {
padding: 6px 0;
color: var(--bp-text-muted);
}
.tech-specs td:first-child {
color: var(--bp-text);
font-weight: 500;
width: 40%;
}
.print-button {
background: var(--bp-surface);
border: 1px solid var(--bp-border);
color: var(--bp-text);
padding: 10px 20px;
border-radius: 8px;
cursor: pointer;
font-size: 13px;
display: flex;
align-items: center;
gap: 8px;
}
.print-button:hover {
background: var(--bp-border);
}
@media print {
.klausur-docs-panel {
background: white;
color: black;
border: none;
}
.doc-content, .highlight-box, .tech-specs td {
color: black !important;
}
.print-button {
display: none;
}
}
"""
def get_admin_klausur_docs_html() -> str:
"""HTML for Klausur Documentation (Audit-Ready)."""
return """
<!-- Klausur Documentation Tab Content (Audit-Ready) -->
<div id="admin-content-klausur-docs" class="admin-content">
<div class="klausur-docs-panel">
<div class="klausur-docs-header">
<h2>
Datenschutz-Dokumentation Klausurkorrektur
<span class="audit-badge">Audit-Ready</span>
</h2>
<button class="print-button" onclick="window.print()">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M6 9V2h12v7M6 18H4a2 2 0 0 1-2-2v-5a2 2 0 0 1 2-2h16a2 2 0 0 1 2 2v5a2 2 0 0 1-2 2h-2"/>
<rect x="6" y="14" width="12" height="8"/>
</svg>
Drucken / PDF
</button>
</div>
<!-- Section 1: Overview -->
<div class="doc-section">
<h3>
<span class="section-number">1</span>
Zusammenfassung fuer Entscheidungstraeger
</h3>
<div class="doc-content">
<div class="highlight-box green">
<h4>Kernaussage</h4>
<p>
Die KI-gestuetzte Klausurkorrektur verarbeitet <strong>keine personenbezogenen Daten</strong>
ausserhalb des Geraets der Lehrkraft. Die Verarbeitung ist datenschutzrechtlich
vergleichbar mit einer Korrektur auf dem eigenen PC der Lehrkraft.
</p>
</div>
<p>
Dieses System wurde nach dem Prinzip <strong>"Privacy by Design"</strong> entwickelt.
Schueler-Namen werden niemals an Server oder KI-Systeme uebermittelt.
Stattdessen werden zufaellige Dokumenten-Tokens (Pseudonyme) verwendet,
die nur die Lehrkraft lokal wieder aufloesen kann.
</p>
</div>
</div>
<!-- Section 2: Legal Basis -->
<div class="doc-section">
<h3>
<span class="section-number">2</span>
Rechtsgrundlage und DSGVO-Konformitaet
</h3>
<div class="doc-content">
<div class="legal-reference">
"Pseudonymisierung bezeichnet die Verarbeitung personenbezogener Daten in einer Weise,
dass die personenbezogenen Daten ohne Hinzuziehung zusaetzlicher Informationen nicht
mehr einer spezifischen betroffenen Person zugeordnet werden koennen."
<cite>— Art. 4 Nr. 5 DSGVO (Begriffsbestimmung Pseudonymisierung)</cite>
</div>
<p><strong>Anwendung auf unser System:</strong></p>
<ul>
<li>
<strong>Pseudonymisierung:</strong> Jedes Klausur-Dokument erhaelt einen
zufaelligen 128-Bit Token (UUID), der keinerlei Beziehung zur Schueleridentitaet hat.
</li>
<li>
<strong>Getrennte Speicherung:</strong> Die Zuordnung Token → Name wird
ausschliesslich lokal beim Lehrer gespeichert (verschluesselt mit AES-256).
</li>
<li>
<strong>Kein Zugriff:</strong> Der Server und die KI haben keinen Zugang
zur Zuordnungstabelle und koennen somit keine Re-Identifizierung durchfuehren.
</li>
</ul>
<div class="highlight-box blue">
<h4>Rechtliche Einordnung</h4>
<p>
Da die KI nur pseudonymisierte Texte ohne jeglichen Personenbezug verarbeitet,
handelt es sich aus Sicht der KI-Verarbeitung um <strong>anonyme Daten</strong>.
Die DSGVO gilt nicht fuer anonyme Daten (Erwaegungsgrund 26).
</p>
</div>
</div>
</div>
<!-- Section 3: Data Flow -->
<div class="doc-section">
<h3>
<span class="section-number">3</span>
Datenfluss und Verarbeitungsschritte
</h3>
<div class="doc-content">
<div class="data-flow-diagram">
┌─────────────────────────────────────────────────────────────────────────────────┐
│ DATENFLUSS KLAUSURKORREKTUR │
├─────────────────────────────────────────────────────────────────────────────────┤
│ │
│ LEHRER-GERAET (Browser) SERVER (BreakPilot) │
│ ──────────────────────── ───────────────────── │
│ │
│ 1. Schuelerliste eingeben │
│ [Max, Anna, Tim, ...] │
│ │ │
│ ▼ │
│ 2. Lokale Verschluesselung ─────► Verschluesselte Zuordnung │
│ (AES-256, Passwort) (Server kann nicht lesen) │
│ │ │
│ ▼ │
│ 3. QR-Codes generieren ◄───── Zufaellige doc_tokens │
│ [abc123..., def456..., ...] (128-bit UUID) │
│ │ │
│ ▼ │
│ 4. QR-Bogen drucken │
│ │ │
│ ══════════╪══════════════════════════════════════════════════════════════ │
│ │ (Physisch: Klausur mit QR) │
│ ══════════╪══════════════════════════════════════════════════════════════ │
│ │ │
│ 5. Scan hochladen ─────► 6. QR erkennen │
│ (Bild der Klausur) │ │
│ ▼ │
│ 7. Kopfzeile entfernen │
│ (Name/Klasse redacted) │
│ │ │
│ ▼ │
│ 8. OCR + KI-Korrektur │
│ (Nur Token + Text) │
│ │ │
│ ▼ │
│ 10. Lokal entschluesseln ◄───── 9. Pseudonymisierte Ergebnisse │
│ + Namen zuordnen [abc123: Note 2+, ...] │
│ │ │
│ ▼ │
│ 11. Ergebnis: Max = 2+ │
│ │
└─────────────────────────────────────────────────────────────────────────────────┘
LEGENDE:
─────► Verschluesselte oder pseudonymisierte Daten
═══════ Physischer Medienbruch (Papier)
Server kann NIEMALS: Schuelernamen sehen, Zuordnung aufloesen, Identitaet bestimmen
</div>
<p><strong>Erklaerung der Schritte:</strong></p>
<ol>
<li><strong>Schuelerliste:</strong> Der Lehrer gibt die Namen seiner Schueler ein. Diese verlassen das Geraet nicht.</li>
<li><strong>Verschluesselung:</strong> Die Zuordnung wird mit dem Passwort des Lehrers verschluesselt (AES-256-GCM).</li>
<li><strong>QR-Codes:</strong> Fuer jeden Schueler wird ein zufaelliger Token generiert. Kein Zusammenhang zum Namen.</li>
<li><strong>Drucken:</strong> Der QR-Bogen wird ausgedruckt. Schueler kleben ihren QR auf die Klausur.</li>
<li><strong>Scan:</strong> Die korrigierten Klausuren werden gescannt.</li>
<li><strong>QR-Erkennung:</strong> Der QR-Code wird automatisch erkannt, um das Dokument zuzuordnen.</li>
<li><strong>Redaction:</strong> Die Kopfzeile mit Name/Klasse wird automatisch geschwärzt.</li>
<li><strong>KI-Korrektur:</strong> Die KI sieht nur den anonymen Text und den Token - niemals einen Namen.</li>
<li><strong>Ergebnis:</strong> Das Ergebnis wird mit dem Token gespeichert (z.B. "abc123: 85 Punkte").</li>
<li><strong>Entschluesselung:</strong> Nur der Lehrer kann mit seinem Passwort die Zuordnung wiederherstellen.</li>
</ol>
</div>
</div>
<!-- Section 4: Comparison -->
<div class="doc-section">
<h3>
<span class="section-number">4</span>
Vergleich mit anderen Loesungen
</h3>
<div class="doc-content">
<table class="comparison-table">
<thead>
<tr>
<th>Kriterium</th>
<th>BreakPilot (diese Loesung)</th>
<th>Typische Cloud-KI (z.B. NovaGrade)</th>
</tr>
</thead>
<tbody>
<tr>
<td>Schuelernamen an Server</td>
<td class="good">Nein (nur Tokens)</td>
<td class="bad">Ja</td>
</tr>
<tr>
<td>Schuelernamen an KI</td>
<td class="good">Nein</td>
<td class="bad">Ja (OpenAI/Claude API)</td>
</tr>
<tr>
<td>Datenspeicherung</td>
<td class="good">Self-Hosted (SysEleven, Deutschland)</td>
<td class="bad">US-Cloud (OpenAI, AWS)</td>
</tr>
<tr>
<td>Zuordnung abrufbar durch</td>
<td class="good">Nur Lehrer (verschluesselt)</td>
<td class="bad">Anbieter, evtl. Dritte</td>
</tr>
<tr>
<td>DSGVO-Risiko</td>
<td class="good">Minimal (pseudonymisiert)</td>
<td class="bad">Hoch (personenbezogen)</td>
</tr>
<tr>
<td>Vergleichbar mit</td>
<td class="good">Lokale PC-Korrektur</td>
<td class="bad">Cloud-Datenuebermittlung</td>
</tr>
</tbody>
</table>
</div>
</div>
<!-- Section 5: Technical Security -->
<div class="doc-section">
<h3>
<span class="section-number">5</span>
Technische Sicherheitsmassnahmen
</h3>
<div class="doc-content">
<div class="tech-specs">
<h4>Kryptographische Parameter</h4>
<table>
<tr><td>Token-Generierung</td><td>UUID v4 (128-bit kryptographisch zufaellig)</td></tr>
<tr><td>Verschluesselung</td><td>AES-256-GCM (authentifizierte Verschluesselung)</td></tr>
<tr><td>Schluesselableitung</td><td>PBKDF2-SHA256, 100.000 Iterationen</td></tr>
<tr><td>Salt</td><td>128-bit zufaellig pro Sitzung</td></tr>
<tr><td>IV (Initialisierungsvektor)</td><td>96-bit zufaellig pro Verschluesselung</td></tr>
</table>
</div>
<div class="tech-specs">
<h4>Infrastruktur</h4>
<table>
<tr><td>LLM-Hosting</td><td>SysEleven, Berlin (DE)</td></tr>
<tr><td>Datenbank</td><td>PostgreSQL mit Verschluesselung at rest</td></tr>
<tr><td>Netzwerk</td><td>TLS 1.3, kein Datenverkehr zu US-Servern</td></tr>
<tr><td>Datenloeschung</td><td>Automatisch nach 30 Tagen</td></tr>
</table>
</div>
<div class="tech-specs">
<h4>Zugangskontrolle</h4>
<table>
<tr><td>Lehrer-Isolation</td><td>Strikte Mandantentrennung (teacher_id Filter)</td></tr>
<tr><td>Kein Admin-Zugriff auf Zuordnung</td><td>Zero-Knowledge-Design</td></tr>
<tr><td>Audit-Log</td><td>Alle Zugriffe protokolliert (ohne PII)</td></tr>
</table>
</div>
</div>
</div>
<!-- Section 6: Risk Assessment -->
<div class="doc-section">
<h3>
<span class="section-number">6</span>
Risikobewertung
</h3>
<div class="doc-content">
<p><strong>Potenzielle Risiken und Gegenmassnahmen:</strong></p>
<table class="comparison-table">
<thead>
<tr>
<th>Risiko</th>
<th>Bewertung</th>
<th>Gegenmassnahme</th>
</tr>
</thead>
<tbody>
<tr>
<td>Re-Identifizierung durch Server</td>
<td class="good">Technisch unmoeglich</td>
<td>Server hat keinen Zugang zur Zuordnung (Zero-Knowledge)</td>
</tr>
<tr>
<td>Datenverlust</td>
<td class="good">Kein Personenbezug</td>
<td>Gestohlene Daten enthalten nur Tokens, keine Namen</td>
</tr>
<tr>
<td>Passwort-Verlust durch Lehrer</td>
<td style="color: #fbbf24;">Mittel</td>
<td>Lokale Backup-Kopie im Browser (localStorage), Neustart moeglich</td>
</tr>
<tr>
<td>KI-Halluzination</td>
<td class="good">Kein Datenschutzrisiko</td>
<td>Lehrer prueft und korrigiert Ergebnisse manuell</td>
</tr>
</tbody>
</table>
<div class="highlight-box yellow">
<h4>Wichtiger Hinweis</h4>
<p>
Bei Verlust des Vault-Passworts kann die Zuordnung Token → Name nicht wiederhergestellt werden.
Die Lehrkraft sollte das Passwort sicher aufbewahren oder eine lokale Sicherung erstellen.
</p>
</div>
</div>
</div>
<!-- Section 7: Conclusion -->
<div class="doc-section">
<h3>
<span class="section-number">7</span>
Fazit und Empfehlung
</h3>
<div class="doc-content">
<div class="highlight-box green">
<h4>Bewertung: Datenschutzkonform</h4>
<p>
Die Klausurkorrektur mit BreakPilot ist <strong>vergleichbar mit einer lokalen Verarbeitung
auf dem PC der Lehrkraft</strong>. Personenbezogene Daten verlassen das Geraet der Lehrkraft
nicht. Die KI-Verarbeitung erfolgt ausschliesslich auf pseudonymisierten Daten.
</p>
<ul>
<li>Keine Uebermittlung personenbezogener Daten an Dritte</li>
<li>Kein US-Cloud-Transfer (Schrems II konform)</li>
<li>Volle Kontrolle der Lehrkraft ueber die Identitaets-Zuordnung</li>
<li>Automatische Datenloeschung nach 30 Tagen</li>
</ul>
</div>
<p>
<strong>Empfehlung:</strong> Das System kann ohne zusaetzliche Genehmigung oder
Datenschutz-Folgenabschaetzung (DSFA) eingesetzt werden, da keine hohen Risiken
fuer die Rechte und Freiheiten der Betroffenen bestehen.
</p>
</div>
</div>
<!-- Version Info -->
<div style="margin-top: 32px; padding-top: 16px; border-top: 1px solid var(--bp-border); color: var(--bp-text-muted); font-size: 12px;">
<p>
<strong>Dokumentversion:</strong> 1.0 |
<strong>Stand:</strong> <span id="doc-date"></span> |
<strong>System:</strong> BreakPilot Klausurkorrektur |
<strong>Kontakt:</strong> datenschutz@breakpilot.de
</p>
</div>
</div>
</div>
<script>
// Set current date
document.getElementById('doc-date').textContent = new Date().toLocaleDateString('de-DE');
</script>
"""
def get_admin_klausur_docs_js() -> str:
"""JavaScript for Klausur Documentation Panel."""
return """
// Klausur Documentation Panel
// No interactive JS needed - documentation is static
// Print functionality uses native window.print()
console.log('Klausur Documentation loaded - Audit-ready version');
"""