Files
breakpilot-compliance/developer-portal/app/api/training/page.tsx
Benjamin Admin 4f6bc8f6f6
Some checks failed
CI/CD / go-lint (push) Has been skipped
CI/CD / python-lint (push) Has been skipped
CI/CD / nodejs-lint (push) Has been skipped
CI/CD / test-go-ai-compliance (push) Failing after 37s
CI/CD / test-python-backend-compliance (push) Successful in 39s
CI/CD / test-python-document-crawler (push) Successful in 26s
CI/CD / test-python-dsms-gateway (push) Successful in 23s
CI/CD / validate-canonical-controls (push) Successful in 12s
CI/CD / Deploy (push) Has been skipped
feat(training+controls): interactive video pipeline, training blocks, control generator, CE libraries
Interactive Training Videos (CP-TRAIN):
- DB migration 022: training_checkpoints + checkpoint_progress tables
- NarratorScript generation via Anthropic (AI Teacher persona, German)
- TTS batch synthesis + interactive video pipeline (slides + checkpoint slides + FFmpeg)
- 4 new API endpoints: generate-interactive, interactive-manifest, checkpoint submit, checkpoint progress
- InteractiveVideoPlayer component (HTML5 Video, quiz overlay, seek protection, progress tracking)
- Learner portal integration with automatic completion on all checkpoints passed
- 30 new tests (handler validation + grading logic + manifest/progress + seek protection)

Training Blocks:
- Block generator, block store, block config CRUD + preview/generate endpoints
- Migration 021: training_blocks schema

Control Generator + Canonical Library:
- Control generator routes + service enhancements
- Canonical control library helpers, sidebar entry
- Citation backfill service + tests
- CE libraries data (hazard, protection, evidence, lifecycle, components)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-16 21:41:48 +01:00

440 lines
23 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
'use client'
import { DevPortalLayout, ApiEndpoint, CodeBlock, ParameterTable, InfoBox } from '@/components/DevPortalLayout'
export default function TrainingAPIPage() {
return (
<DevPortalLayout
title="Training API"
description="Compliance-Schulungssystem (CP-TRAIN) — Module, Zuweisungen, Quiz, Zertifikate, KI-Generierung"
>
{/* ================================================================= */}
{/* OVERVIEW */}
{/* ================================================================= */}
<h2>Uebersicht</h2>
<p>
Das Training-Modul bietet ein vollstaendiges Compliance-Schulungssystem mit:
</p>
<ul>
<li>Modulverwaltung mit Regulierungsbereichen (DSGVO, NIS2, ISO 27001, AI Act, GeschGehG, HinSchG)</li>
<li>Compliance Training Matrix (CTM) rollenbasierte Zuweisung</li>
<li>KI-gestuetzte Content- und Quiz-Generierung</li>
<li>Audio/Video-Schulungsinhalte via TTS</li>
<li>Quiz-Engine mit Bestehens-Schwelle</li>
<li>Eskalationsstufen (7/14/30/45 Tage)</li>
<li>PDF-Zertifikate nach Schulungsabschluss</li>
<li>Training Blocks automatische Modul-Erstellung aus Canonical Controls</li>
</ul>
<InfoBox type="info" title="Basis-URL">
Alle Endpoints nutzen den Prefix <code>/sdk/v1/training</code>.
Authentifizierung via <code>X-Tenant-ID</code> und <code>X-User-ID</code> Header.
</InfoBox>
{/* ================================================================= */}
{/* MODULES */}
{/* ================================================================= */}
<h2 id="modules">1. Module</h2>
<p>Schulungsmodule sind die zentrale Einheit des Training-Systems.</p>
<ApiEndpoint method="GET" path="/sdk/v1/training/modules" description="Alle Module auflisten (mit optionalen Filtern)" />
<ParameterTable parameters={[
{ name: 'regulation_area', type: 'string', description: 'Filter: dsgvo, nis2, iso27001, ai_act, geschgehg, hinschg' },
{ name: 'frequency_type', type: 'string', description: 'Filter: onboarding, annual, event_trigger, micro' },
{ name: 'search', type: 'string', description: 'Volltextsuche in Titel und Beschreibung' },
]} />
<ApiEndpoint method="GET" path="/sdk/v1/training/modules/:id" description="Einzelnes Modul mit Content und Quiz-Fragen laden" />
<ApiEndpoint method="POST" path="/sdk/v1/training/modules" description="Neues Schulungsmodul erstellen" />
<ParameterTable parameters={[
{ name: 'module_code', type: 'string', required: true, description: 'Eindeutiger Modulcode (z.B. CP-TRAIN-001)' },
{ name: 'title', type: 'string', required: true, description: 'Titel des Moduls' },
{ name: 'description', type: 'string', description: 'Beschreibung' },
{ name: 'regulation_area', type: 'string', required: true, description: 'Regulierungsbereich' },
{ name: 'frequency_type', type: 'string', required: true, description: 'Schulungsfrequenz' },
{ name: 'duration_minutes', type: 'integer', description: 'Dauer in Minuten (Standard: 30)' },
{ name: 'pass_threshold', type: 'integer', description: 'Quiz-Bestehensgrenze in Prozent (Standard: 70)' },
]} />
<ApiEndpoint method="PUT" path="/sdk/v1/training/modules/:id" description="Modul aktualisieren" />
<ApiEndpoint method="DELETE" path="/sdk/v1/training/modules/:id" description="Modul loeschen" />
<CodeBlock language="json">{`// POST /sdk/v1/training/modules — Beispiel
{
"module_code": "CP-DSGVO-001",
"title": "DSGVO Grundlagen fuer Mitarbeiter",
"description": "Einfuehrung in die Datenschutz-Grundverordnung",
"regulation_area": "dsgvo",
"frequency_type": "annual",
"duration_minutes": 30,
"pass_threshold": 70
}`}</CodeBlock>
{/* ================================================================= */}
{/* MATRIX */}
{/* ================================================================= */}
<h2 id="matrix">2. Compliance Training Matrix (CTM)</h2>
<p>Die CTM ordnet Rollen zu Schulungsmodulen zu. 10 vordefinierte Rollen (R1R10).</p>
<ApiEndpoint method="GET" path="/sdk/v1/training/matrix" description="Vollstaendige Training-Matrix abrufen (alle Rollen → Module)" />
<ApiEndpoint method="GET" path="/sdk/v1/training/matrix/:role" description="Module fuer eine bestimmte Rolle abrufen" />
<ApiEndpoint method="POST" path="/sdk/v1/training/matrix" description="Matrix-Eintrag setzen (Rolle → Modul)" />
<ParameterTable parameters={[
{ name: 'role_code', type: 'string', required: true, description: 'Rollencode (R1R10)' },
{ name: 'module_id', type: 'uuid', required: true, description: 'Modul-UUID' },
{ name: 'is_mandatory', type: 'boolean', description: 'Pflichtschulung (Standard: false)' },
{ name: 'priority', type: 'integer', description: 'Prioritaet (1 = hoechste)' },
]} />
<ApiEndpoint method="DELETE" path="/sdk/v1/training/matrix/:role/:moduleId" description="Matrix-Eintrag entfernen" />
<InfoBox type="info" title="Rollen">
R1: Geschaeftsfuehrung, R2: IT-Leitung, R3: DSB, R4: ISB, R5: HR,
R6: Einkauf, R7: Fachabteilung, R8: IT-Admin, R9: Alle Mitarbeiter, R10: Behoerden
</InfoBox>
{/* ================================================================= */}
{/* ASSIGNMENTS */}
{/* ================================================================= */}
<h2 id="assignments">3. Zuweisungen</h2>
<p>Zuweisungen verbinden Mitarbeiter mit Schulungsmodulen und tracken den Fortschritt.</p>
<ApiEndpoint method="POST" path="/sdk/v1/training/assignments/compute" description="Zuweisungen fuer einen Benutzer berechnen (basierend auf Rollen + CTM)" />
<ParameterTable parameters={[
{ name: 'user_id', type: 'uuid', required: true, description: 'Benutzer-UUID' },
{ name: 'user_name', type: 'string', required: true, description: 'Name des Benutzers' },
{ name: 'user_email', type: 'string', required: true, description: 'E-Mail' },
{ name: 'roles', type: 'string[]', required: true, description: 'Rollencodes des Benutzers' },
{ name: 'trigger', type: 'string', description: 'Ausloeser: onboarding, annual, event, manual' },
]} />
<ApiEndpoint method="GET" path="/sdk/v1/training/assignments" description="Zuweisungen auflisten" />
<ParameterTable parameters={[
{ name: 'user_id', type: 'uuid', description: 'Filter nach Benutzer' },
{ name: 'module_id', type: 'uuid', description: 'Filter nach Modul' },
{ name: 'role', type: 'string', description: 'Filter nach Rolle' },
{ name: 'status', type: 'string', description: 'Filter: pending, in_progress, completed, overdue, expired' },
{ name: 'limit', type: 'integer', description: 'Pagination (Standard: 50)' },
{ name: 'offset', type: 'integer', description: 'Pagination Offset' },
]} />
<ApiEndpoint method="GET" path="/sdk/v1/training/assignments/:id" description="Einzelne Zuweisung laden" />
<ApiEndpoint method="PUT" path="/sdk/v1/training/assignments/:id" description="Zuweisung aktualisieren (z.B. Deadline aendern)" />
<ApiEndpoint method="POST" path="/sdk/v1/training/assignments/:id/start" description="Schulung starten (Status → in_progress)" />
<ApiEndpoint method="POST" path="/sdk/v1/training/assignments/:id/progress" description="Fortschritt aktualisieren (0100%)" />
<ApiEndpoint method="POST" path="/sdk/v1/training/assignments/:id/complete" description="Schulung abschliessen (Status → completed)" />
<CodeBlock language="json">{`// POST /sdk/v1/training/assignments/compute — Response
{
"assignments": [
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"module_id": "...",
"user_id": "...",
"status": "pending",
"progress_percent": 0,
"deadline": "2026-04-15T00:00:00Z",
"escalation_level": 0
}
],
"created": 5
}`}</CodeBlock>
{/* ================================================================= */}
{/* QUIZ */}
{/* ================================================================= */}
<h2 id="quiz">4. Quiz-Engine</h2>
<p>Multiple-Choice-Quiz mit automatischer Bewertung und Bestehensgrenze.</p>
<ApiEndpoint method="GET" path="/sdk/v1/training/quiz/:moduleId" description="Quiz-Fragen fuer ein Modul abrufen" />
<ApiEndpoint method="POST" path="/sdk/v1/training/quiz/:moduleId/submit" description="Quiz-Antworten einreichen" />
<ParameterTable parameters={[
{ name: 'assignment_id', type: 'uuid', required: true, description: 'Zuweisungs-UUID' },
{ name: 'answers', type: 'QuizAnswer[]', required: true, description: 'Array von {question_id, selected_index}' },
{ name: 'duration_seconds', type: 'integer', description: 'Bearbeitungsdauer in Sekunden' },
]} />
<ApiEndpoint method="GET" path="/sdk/v1/training/quiz/attempts/:assignmentId" description="Quiz-Versuche fuer eine Zuweisung anzeigen" />
<CodeBlock language="json">{`// POST /sdk/v1/training/quiz/:moduleId/submit — Response
{
"attempt_id": "...",
"score": 80.0,
"passed": true,
"correct_count": 4,
"total_count": 5,
"threshold": 70
}`}</CodeBlock>
{/* ================================================================= */}
{/* CONTENT GENERATION */}
{/* ================================================================= */}
<h2 id="content">5. KI-Content-Generierung</h2>
<p>LLM-basierte Erstellung von Schulungsinhalten und Quiz-Fragen.</p>
<ApiEndpoint method="POST" path="/sdk/v1/training/content/generate" description="Schulungsinhalt fuer ein Modul generieren (Markdown)" />
<ParameterTable parameters={[
{ name: 'module_id', type: 'uuid', required: true, description: 'Modul-UUID' },
{ name: 'language', type: 'string', description: 'Sprache: de (Standard) oder en' },
]} />
<ApiEndpoint method="POST" path="/sdk/v1/training/content/generate-quiz" description="Quiz-Fragen fuer ein Modul generieren" />
<ParameterTable parameters={[
{ name: 'module_id', type: 'uuid', required: true, description: 'Modul-UUID' },
{ name: 'count', type: 'integer', description: 'Anzahl Fragen (Standard: 5)' },
]} />
<ApiEndpoint method="GET" path="/sdk/v1/training/content/:moduleId" description="Veroeffentlichten Content eines Moduls abrufen" />
<ApiEndpoint method="POST" path="/sdk/v1/training/content/:contentId/publish" description="Content veroeffentlichen (Freigabe)" />
<ApiEndpoint method="POST" path="/sdk/v1/training/content/generate-all" description="Content fuer alle Module ohne Content generieren (Bulk)" />
<ApiEndpoint method="POST" path="/sdk/v1/training/content/generate-all-quiz" description="Quiz fuer alle Module ohne Fragen generieren (Bulk)" />
<InfoBox type="warning" title="LLM-Kosten">
Content- und Quiz-Generierung nutzt LLM-APIs (Ollama/Anthropic). Bulk-Generierung kann
signifikante Token-Kosten verursachen. PII-Detektion ist aktiv personenbezogene Daten
werden automatisch redaktiert.
</InfoBox>
{/* ================================================================= */}
{/* MEDIA */}
{/* ================================================================= */}
<h2 id="media">6. Media (Audio/Video)</h2>
<p>TTS-basierte Audio- und Videogenerierung fuer Schulungsmodule.</p>
<ApiEndpoint method="POST" path="/sdk/v1/training/content/:moduleId/generate-audio" description="Audio-Datei aus Schulungsinhalt generieren (Piper TTS)" />
<ApiEndpoint method="POST" path="/sdk/v1/training/content/:moduleId/generate-video" description="Praesentationsvideo generieren (TTS + Folien)" />
<ApiEndpoint method="POST" path="/sdk/v1/training/content/:moduleId/preview-script" description="Video-Script als JSON-Vorschau generieren" />
<ApiEndpoint method="GET" path="/sdk/v1/training/media/module/:moduleId" description="Alle Medien eines Moduls auflisten" />
<ApiEndpoint method="GET" path="/sdk/v1/training/media/:mediaId/url" description="Metadaten (Bucket, Object Key) fuer eine Media-Datei" />
<ApiEndpoint method="POST" path="/sdk/v1/training/media/:mediaId/publish" description="Media veroeffentlichen/zurueckziehen" />
<ApiEndpoint method="GET" path="/sdk/v1/training/media/:mediaId/stream" description="Media streamen (307-Redirect zu Presigned URL)" />
<InfoBox type="info" title="Streaming">
Der <code>/stream</code>-Endpoint liefert einen <code>307 Temporary Redirect</code> zu einer
zeitlich begrenzten Presigned URL (MinIO/S3). Browser und Audio/Video-Player folgen dem
Redirect automatisch.
</InfoBox>
<CodeBlock language="json">{`// POST /sdk/v1/training/content/:moduleId/preview-script — Response
{
"title": "DSGVO Grundlagen",
"sections": [
{
"heading": "Was ist die DSGVO?",
"text": "Die DSGVO regelt den Umgang mit personenbezogenen Daten.",
"bullet_points": [
"Gilt seit 25. Mai 2018",
"EU-weit verbindlich",
"Hohe Bussgelder bei Verstoessen"
]
}
]
}`}</CodeBlock>
{/* ================================================================= */}
{/* DEADLINES & ESCALATION */}
{/* ================================================================= */}
<h2 id="deadlines">7. Deadlines & Eskalation</h2>
<p>Automatisches Eskalationssystem mit 4 Stufen.</p>
<ApiEndpoint method="GET" path="/sdk/v1/training/deadlines" description="Anstehende Deadlines auflisten" />
<ParameterTable parameters={[
{ name: 'limit', type: 'integer', description: 'Maximale Anzahl (Standard: 50)' },
]} />
<ApiEndpoint method="GET" path="/sdk/v1/training/deadlines/overdue" description="Ueberfaellige Zuweisungen auflisten" />
<ApiEndpoint method="POST" path="/sdk/v1/training/escalation/check" description="Eskalationspruefung ausfuehren" />
<CodeBlock language="json">{`// POST /sdk/v1/training/escalation/check — Response
{
"results": [
{
"assignment_id": "...",
"user_name": "Max Mustermann",
"module_title": "DSGVO Grundlagen",
"previous_level": 1,
"new_level": 2,
"days_overdue": 15,
"escalation_label": "Benachrichtigung Teamleitung"
}
],
"total_checked": 42,
"escalated": 3
}`}</CodeBlock>
<ParameterTable parameters={[
{ name: 'Stufe 1 (7 Tage)', type: '-', description: 'Erinnerung an Mitarbeiter' },
{ name: 'Stufe 2 (14 Tage)', type: '-', description: 'Benachrichtigung Teamleitung' },
{ name: 'Stufe 3 (30 Tage)', type: '-', description: 'Benachrichtigung Management' },
{ name: 'Stufe 4 (45 Tage)', type: '-', description: 'Benachrichtigung Compliance Officer' },
]} />
{/* ================================================================= */}
{/* CERTIFICATES */}
{/* ================================================================= */}
<h2 id="certificates">8. Zertifikate</h2>
<p>PDF-Zertifikate nach erfolgreichem Schulungsabschluss.</p>
<ApiEndpoint method="POST" path="/sdk/v1/training/certificates/generate/:assignmentId" description="Zertifikat fuer eine abgeschlossene Zuweisung generieren" />
<ApiEndpoint method="GET" path="/sdk/v1/training/certificates" description="Alle Zertifikate des Tenants auflisten" />
<ApiEndpoint method="GET" path="/sdk/v1/training/certificates/:id/pdf" description="Zertifikat als PDF herunterladen" />
<ApiEndpoint method="GET" path="/sdk/v1/training/certificates/:id/verify" description="Zertifikat verifizieren (z.B. fuer Audit)" />
<InfoBox type="warning" title="Voraussetzungen">
Zertifikate koennen nur generiert werden, wenn die Zuweisung den Status <code>completed</code> hat
UND das Quiz bestanden wurde (<code>quiz_passed = true</code>).
</InfoBox>
<CodeBlock language="json">{`// POST /sdk/v1/training/certificates/generate/:assignmentId — Response
{
"certificate_id": "a1b2c3d4-...",
"assignment": {
"id": "...",
"status": "completed",
"quiz_passed": true,
"certificate_id": "a1b2c3d4-...",
"module_title": "DSGVO Grundlagen"
}
}
// GET /sdk/v1/training/certificates/:id/verify — Response
{
"valid": true,
"assignment": { ... }
}`}</CodeBlock>
{/* ================================================================= */}
{/* AUDIT & STATS */}
{/* ================================================================= */}
<h2 id="audit">9. Audit & Statistiken</h2>
<p>Compliance-konformes Audit-Logging aller Schulungsaktivitaeten.</p>
<ApiEndpoint method="GET" path="/sdk/v1/training/audit-log" description="Audit-Log abrufen" />
<ParameterTable parameters={[
{ name: 'action', type: 'string', description: 'Filter: assigned, started, completed, quiz_submitted, escalated, certificate_issued, content_generated' },
{ name: 'entity_type', type: 'string', description: 'Filter: assignment, module, quiz, certificate' },
{ name: 'limit', type: 'integer', description: 'Pagination (Standard: 50)' },
{ name: 'offset', type: 'integer', description: 'Pagination Offset' },
]} />
<ApiEndpoint method="GET" path="/sdk/v1/training/stats" description="Aggregierte Schulungsstatistiken" />
<CodeBlock language="json">{`// GET /sdk/v1/training/stats — Response
{
"total_modules": 28,
"total_assignments": 156,
"completion_rate": 72.5,
"overdue_count": 8,
"pending_count": 23,
"in_progress_count": 14,
"completed_count": 111,
"avg_quiz_score": 81.3,
"avg_completion_days": 4.2,
"upcoming_deadlines": 12
}`}</CodeBlock>
{/* ================================================================= */}
{/* TRAINING BLOCKS */}
{/* ================================================================= */}
<h2 id="blocks">10. Training Blocks (Controls Module)</h2>
<p>
Training Blocks automatisieren die Erstellung von Schulungsmodulen aus Canonical Controls.
Ein Block definiert Filter (Domain, Kategorie, Severity, Zielgruppe) und generiert
automatisch Module, Content und CTM-Eintraege.
</p>
<ApiEndpoint method="GET" path="/sdk/v1/training/blocks" description="Alle Block-Konfigurationen auflisten" />
<ApiEndpoint method="POST" path="/sdk/v1/training/blocks" description="Neue Block-Konfiguration erstellen" />
<ParameterTable parameters={[
{ name: 'name', type: 'string', required: true, description: 'Name des Blocks' },
{ name: 'description', type: 'string', description: 'Beschreibung' },
{ name: 'domain_filter', type: 'string', description: 'Domain-Filter (z.B. AUTH, CRYP, NET)' },
{ name: 'category_filter', type: 'string', description: 'Kategorie-Filter (z.B. authentication, encryption)' },
{ name: 'severity_filter', type: 'string', description: 'Severity-Filter (high, critical)' },
{ name: 'target_audience_filter', type: 'string', description: 'Zielgruppe: enterprise, authority, provider, all' },
{ name: 'regulation_area', type: 'string', required: true, description: 'Regulierungsbereich' },
{ name: 'module_code_prefix', type: 'string', required: true, description: 'Prefix fuer generierte Modulcodes' },
{ name: 'frequency_type', type: 'string', description: 'Schulungsfrequenz' },
{ name: 'duration_minutes', type: 'integer', description: 'Dauer pro Modul' },
{ name: 'pass_threshold', type: 'integer', description: 'Quiz-Bestehensgrenze' },
{ name: 'max_controls_per_module', type: 'integer', description: 'Max. Controls pro Modul (Standard: 10)' },
]} />
<ApiEndpoint method="GET" path="/sdk/v1/training/blocks/:id" description="Block-Konfiguration laden" />
<ApiEndpoint method="PUT" path="/sdk/v1/training/blocks/:id" description="Block-Konfiguration aktualisieren" />
<ApiEndpoint method="DELETE" path="/sdk/v1/training/blocks/:id" description="Block-Konfiguration loeschen" />
<ApiEndpoint method="POST" path="/sdk/v1/training/blocks/:id/preview" description="Vorschau: Welche Controls und Module wuerden generiert?" />
<ApiEndpoint method="POST" path="/sdk/v1/training/blocks/:id/generate" description="Module aus Block generieren (Content + CTM)" />
<ParameterTable parameters={[
{ name: 'language', type: 'string', description: 'Sprache: de (Standard) oder en' },
{ name: 'auto_matrix', type: 'boolean', description: 'Automatisch CTM-Eintraege erstellen (Standard: true)' },
]} />
<ApiEndpoint method="GET" path="/sdk/v1/training/blocks/:id/controls" description="Verlinkte Controls eines Blocks anzeigen" />
<CodeBlock language="json">{`// POST /sdk/v1/training/blocks/:id/generate — Response
{
"modules_created": 3,
"controls_linked": 24,
"matrix_entries_created": 15,
"content_generated": 3,
"errors": []
}`}</CodeBlock>
{/* ================================================================= */}
{/* CANONICAL CONTROLS */}
{/* ================================================================= */}
<h2 id="canonical">11. Canonical Controls</h2>
<p>Referenz-Datenbank mit standardisierten Sicherheitskontrollen.</p>
<ApiEndpoint method="GET" path="/sdk/v1/training/canonical/controls" description="Canonical Controls auflisten (mit Filtern)" />
<ParameterTable parameters={[
{ name: 'domain', type: 'string', description: 'Domain-Filter (z.B. AUTH, CRYP)' },
{ name: 'category', type: 'string', description: 'Kategorie-Filter' },
{ name: 'severity', type: 'string', description: 'Severity-Filter' },
{ name: 'target_audience', type: 'string', description: 'Zielgruppen-Filter' },
]} />
<ApiEndpoint method="GET" path="/sdk/v1/training/canonical/meta" description="Aggregierte Metadaten (Domains, Kategorien, Audiences mit Counts)" />
<CodeBlock language="json">{`// GET /sdk/v1/training/canonical/meta — Response
{
"domains": [
{ "domain": "AUTH", "count": 12 },
{ "domain": "CRYP", "count": 8 }
],
"categories": [
{ "category": "authentication", "count": 12 },
{ "category": "encryption", "count": 8 }
],
"audiences": [
{ "audience": "enterprise", "count": 45 },
{ "audience": "all", "count": 30 }
],
"total": 102
}`}</CodeBlock>
{/* ================================================================= */}
{/* WORKFLOW */}
{/* ================================================================= */}
<h2 id="workflow">Typischer Workflow</h2>
<ol>
<li><strong>Module erstellen</strong> via POST /modules oder Training Blocks</li>
<li><strong>Content generieren</strong> POST /content/generate (LLM)</li>
<li><strong>Content freigeben</strong> POST /content/:id/publish</li>
<li><strong>Quiz generieren</strong> POST /content/generate-quiz</li>
<li><strong>Audio/Video</strong> POST /content/:id/generate-audio, generate-video</li>
<li><strong>CTM konfigurieren</strong> POST /matrix (Rolle Modul)</li>
<li><strong>Zuweisungen berechnen</strong> POST /assignments/compute</li>
<li><strong>Mitarbeiter absolviert</strong> start progress Quiz complete</li>
<li><strong>Zertifikat</strong> POST /certificates/generate/:assignmentId</li>
<li><strong>Audit</strong> GET /audit-log + GET /stats</li>
</ol>
</DevPortalLayout>
)
}