[split-required] Split remaining 500-680 LOC files (final batch)

website (17 pages + 3 components):
- multiplayer/wizard, middleware/wizard+test-wizard, communication
- builds/wizard, staff-search, voice, sbom/wizard
- foerderantrag, mail/tasks, tools/communication, sbom
- compliance/evidence, uni-crawler, brandbook (already done)
- CollectionsTab, IngestionTab, RiskHeatmap

backend-lehrer (5 files):
- letters_api (641 → 2), certificates_api (636 → 2)
- alerts_agent/db/models (636 → 3)
- llm_gateway/communication_service (614 → 2)
- game/database already done in prior batch

klausur-service (2 files):
- hybrid_vocab_extractor (664 → 2)
- klausur-service/frontend: api.ts (620 → 3), EHUploadWizard (591 → 2)

voice-service (3 files):
- bqas/rag_judge (618 → 3), runner (529 → 2)
- enhanced_task_orchestrator (519 → 2)

studio-v2 (6 files):
- korrektur/[klausurId] (578 → 4), fairness (569 → 2)
- AlertsWizard (552 → 2), OnboardingWizard (513 → 2)
- korrektur/api.ts (506 → 3), geo-lernwelt (501 → 2)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Benjamin Admin
2026-04-25 08:56:45 +02:00
parent b4613e26f3
commit 451365a312
115 changed files with 10694 additions and 13839 deletions

View File

@@ -0,0 +1,100 @@
export function CategoryDemo({ stepId }: { stepId: string }) {
if (stepId === 'categories') {
const categories = [
{ name: 'infrastructure', color: 'blue', count: 45 },
{ name: 'security-tools', color: 'red', count: 12 },
{ name: 'python', color: 'yellow', count: 35 },
{ name: 'go', color: 'cyan', count: 18 },
{ name: 'nodejs', color: 'green', count: 55 },
{ name: 'unity', color: 'amber', count: 7, isNew: true },
{ name: 'csharp', color: 'fuchsia', count: 3, isNew: true },
{ name: 'game', color: 'rose', count: 1, isNew: true },
]
return (
<div className="bg-white border border-slate-200 rounded-lg p-4 mb-4">
<h4 className="font-semibold text-slate-800 mb-3">Live-Vorschau: Kategorien</h4>
<div className="grid grid-cols-4 gap-2">
{categories.map((cat) => (
<div
key={cat.name}
className={`bg-${cat.color}-100 text-${cat.color}-800 px-3 py-2 rounded-lg text-center text-sm relative`}
>
<p className="font-medium">{cat.name}</p>
<p className="text-xs opacity-70">{cat.count} Komponenten</p>
{cat.isNew && (
<span className="absolute -top-1 -right-1 bg-amber-500 text-white text-xs px-1 rounded">NEU</span>
)}
</div>
))}
</div>
</div>
)
}
if (stepId === 'unity-game') {
const unityComponents = [
{ name: 'Unity Engine', version: '6000.0', license: 'Unity EULA' },
{ name: 'URP', version: '17.x', license: 'Unity Companion' },
{ name: 'TextMeshPro', version: '3.2', license: 'Unity Companion' },
{ name: 'Mathematics', version: '1.3', license: 'Unity Companion' },
{ name: 'Newtonsoft.Json', version: '3.2', license: 'MIT' },
]
return (
<div className="bg-white border border-slate-200 rounded-lg p-4 mb-4">
<h4 className="font-semibold text-slate-800 mb-3">Unity Packages (Breakpilot Drive)</h4>
<div className="space-y-2">
{unityComponents.map((comp) => (
<div key={comp.name} className="flex items-center justify-between py-2 border-b border-slate-100 last:border-0">
<div className="flex items-center gap-2">
<span className="bg-amber-100 text-amber-800 text-xs px-2 py-0.5 rounded">unity</span>
<span className="font-medium">{comp.name}</span>
</div>
<div className="flex items-center gap-4 text-sm text-slate-600">
<span>{comp.version}</span>
<span className="bg-slate-100 px-2 py-0.5 rounded text-xs">{comp.license}</span>
</div>
</div>
))}
</div>
</div>
)
}
if (stepId === 'licenses') {
const licenses = [
{ name: 'MIT', count: 85, color: 'green', risk: 'Niedrig' },
{ name: 'Apache 2.0', count: 45, color: 'green', risk: 'Niedrig' },
{ name: 'BSD', count: 12, color: 'green', risk: 'Niedrig' },
{ name: 'Unity EULA', count: 1, color: 'yellow', risk: 'Mittel' },
{ name: 'Unity Companion', count: 6, color: 'yellow', risk: 'Mittel' },
{ name: 'AGPL', count: 2, color: 'orange', risk: 'Hoch' },
]
return (
<div className="bg-white border border-slate-200 rounded-lg p-4 mb-4">
<h4 className="font-semibold text-slate-800 mb-3">Lizenz-Uebersicht</h4>
<div className="space-y-2">
{licenses.map((lic) => (
<div key={lic.name} className="flex items-center justify-between py-2">
<div className="flex items-center gap-2">
<span className="font-medium">{lic.name}</span>
<span className="text-sm text-slate-500">({lic.count})</span>
</div>
<span className={`text-xs px-2 py-1 rounded ${
lic.risk === 'Niedrig' ? 'bg-green-100 text-green-700' :
lic.risk === 'Mittel' ? 'bg-yellow-100 text-yellow-700' :
'bg-orange-100 text-orange-700'
}`}>
Risiko: {lic.risk}
</span>
</div>
))}
</div>
</div>
)
}
return null
}

View File

@@ -0,0 +1,75 @@
import { WizardStep, EDUCATION_CONTENT } from './types'
export function WizardStepper({
steps,
currentStep,
onStepClick
}: {
steps: WizardStep[]
currentStep: number
onStepClick: (index: number) => void
}) {
return (
<div className="flex items-center justify-between mb-8 overflow-x-auto pb-4">
{steps.map((step, index) => (
<div key={step.id} className="flex items-center">
<button
onClick={() => onStepClick(index)}
className={`flex flex-col items-center min-w-[80px] p-2 rounded-lg transition-colors ${
index === currentStep
? 'bg-primary-100 text-primary-700'
: step.status === 'completed'
? 'bg-green-100 text-green-700 cursor-pointer hover:bg-green-200'
: 'text-slate-400 hover:bg-slate-100'
}`}
>
<span className="text-2xl mb-1">{step.icon}</span>
<span className="text-xs font-medium text-center">{step.name}</span>
{step.status === 'completed' && <span className="text-xs text-green-600"></span>}
</button>
{index < steps.length - 1 && (
<div className={`h-0.5 w-8 mx-1 ${
index < currentStep ? 'bg-green-400' : 'bg-slate-200'
}`} />
)}
</div>
))}
</div>
)
}
export function EducationCard({ stepId }: { stepId: string }) {
const content = EDUCATION_CONTENT[stepId]
if (!content) return null
return (
<div className="bg-primary-50 border border-primary-200 rounded-lg p-6 mb-6">
<h3 className="text-lg font-semibold text-primary-800 mb-4 flex items-center">
<span className="mr-2">📖</span>
{content.title}
</h3>
<div className="space-y-2 text-primary-900">
{content.content.map((line, index) => (
<p
key={index}
className={`${line.startsWith('•') ? 'ml-4' : ''} ${line.startsWith('**') ? 'font-semibold mt-3' : ''}`}
dangerouslySetInnerHTML={{
__html: line
.replace(/\*\*(.*?)\*\*/g, '<strong>$1</strong>')
.replace(/→/g, '<span class="text-primary-600">→</span>')
.replace(/← NEU!/g, '<span class="bg-amber-200 text-amber-800 px-1 rounded text-sm font-bold">← NEU!</span>')
}}
/>
))}
</div>
{content.tips && content.tips.length > 0 && (
<div className="mt-4 pt-4 border-t border-primary-200">
<p className="text-sm font-semibold text-primary-700 mb-2">💡 Tipps:</p>
{content.tips.map((tip, index) => (
<p key={index} className="text-sm text-primary-700 ml-4"> {tip}</p>
))}
</div>
)}
</div>
)
}

View File

@@ -0,0 +1,124 @@
export type StepStatus = 'pending' | 'active' | 'completed'
export interface WizardStep {
id: string
name: string
icon: string
status: StepStatus
}
export const INITIAL_STEPS: WizardStep[] = [
{ id: 'welcome', name: 'Willkommen', icon: '📋', status: 'pending' },
{ id: 'what-is-sbom', name: 'Was ist SBOM?', icon: '❓', status: 'pending' },
{ id: 'why-important', name: 'Warum wichtig?', icon: '⚠️', status: 'pending' },
{ id: 'categories', name: 'Kategorien', icon: '📁', status: 'pending' },
{ id: 'infrastructure', name: 'Infrastruktur', icon: '🏗️', status: 'pending' },
{ id: 'unity-game', name: 'Unity & Game', icon: '🎮', status: 'pending' },
{ id: 'licenses', name: 'Lizenzen', icon: '📜', status: 'pending' },
{ id: 'summary', name: 'Zusammenfassung', icon: '✅', status: 'pending' },
]
export const EDUCATION_CONTENT: Record<string, { title: string; content: string[]; tips?: string[] }> = {
'welcome': {
title: 'Willkommen zum SBOM-Wizard!',
content: [
'Eine **Software Bill of Materials (SBOM)** ist wie ein Zutaten-Etikett fuer Software.',
'Sie listet alle Komponenten auf, aus denen eine Anwendung besteht:',
'• Open-Source-Bibliotheken',
'• Frameworks und Engines',
'• Infrastruktur-Dienste',
'• Entwicklungs-Tools',
'In diesem Wizard lernst du, warum SBOMs wichtig sind und welche Komponenten BreakPilot verwendet - inklusive der neuen **Breakpilot Drive** (Unity) Komponenten.',
],
tips: ['SBOMs sind seit 2021 fuer US-Regierungsauftraege Pflicht', 'Die EU plant aehnliche Vorschriften im Cyber Resilience Act'],
},
'what-is-sbom': {
title: 'Was ist eine SBOM?',
content: [
'**SBOM = Software Bill of Materials**',
'Eine SBOM ist eine vollstaendige Liste aller Software-Komponenten:',
'**Enthaltene Informationen:**',
'• Name der Komponente', '• Version', '• Lizenz (MIT, Apache, GPL, etc.)', '• Herkunft (Source URL)', '• Typ (Library, Service, Tool)',
'**Formate:**',
'• SPDX (Linux Foundation Standard)', '• CycloneDX (OWASP Standard)', '• SWID Tags (ISO Standard)',
'BreakPilot verwendet eine eigene Darstellung im Admin-Panel, die alle relevanten Infos zeigt.',
],
tips: ['Eine SBOM ist wie ein Beipackzettel fuer Medikamente', 'Sie ermoeglicht schnelle Reaktion bei Sicherheitsluecken'],
},
'why-important': {
title: 'Warum sind SBOMs wichtig?',
content: [
'**1. Sicherheit (Security)**',
'Wenn eine Sicherheitsluecke in einer Bibliothek entdeckt wird (z.B. Log4j), kannst du sofort pruefen ob du betroffen bist.',
'**2. Compliance (Lizenz-Einhaltung)**',
'Verschiedene Lizenzen haben verschiedene Anforderungen:',
'• MIT: Fast keine Einschraenkungen', '• GPL: Copyleft - abgeleitete Werke muessen auch GPL sein', '• Proprietary: Kommerzielle Nutzung eingeschraenkt',
'**3. Supply Chain Security**',
'Moderne Software besteht aus hunderten Abhaengigkeiten. Eine SBOM macht diese Kette transparent.',
'**4. Regulatorische Anforderungen**',
'US Executive Order 14028 verlangt SBOMs fuer Regierungssoftware.',
],
tips: ['Log4Shell (2021) betraf Millionen von Systemen', 'Mit SBOM: Betroffenheit in Minuten geprueft'],
},
'categories': {
title: 'SBOM-Kategorien in BreakPilot',
content: [
'Die BreakPilot SBOM ist in Kategorien unterteilt:',
'**infrastructure** (Blau)', '→ Kern-Infrastruktur: PostgreSQL, Valkey, Keycloak, Docker',
'**security-tools** (Rot)', '→ Sicherheits-Tools: Trivy, Gitleaks, Semgrep',
'**python** (Gelb)', '→ Python-Backend: FastAPI, Pydantic, httpx',
'**go** (Cyan)', '→ Go-Services: Gin, GORM, JWT',
'**nodejs** (Gruen)', '→ Frontend: Next.js, React, Tailwind',
'**unity** (Amber) ← NEU!', '→ Game Engine: Unity 6, URP, TextMeshPro',
'**csharp** (Fuchsia) ← NEU!', '→ C#/.NET: .NET Standard, UnityWebRequest',
'**game** (Rose) ← NEU!', '→ Breakpilot Drive Service',
],
tips: ['Klicke auf eine Kategorie um zu filtern', 'Die neuen Unity/Game-Kategorien wurden fuer Breakpilot Drive hinzugefuegt'],
},
'infrastructure': {
title: 'Infrastruktur-Komponenten',
content: [
'BreakPilot basiert auf robuster Infrastruktur:',
'**Datenbanken:**', '• PostgreSQL 16 - Relationale Datenbank', '• Valkey 8 - In-Memory Cache (Redis-Fork)', '• ChromaDB - Vector Store fuer RAG',
'**Auth & Security:**', '• Keycloak 23 - Identity & Access Management', '• HashiCorp Vault - Secrets Management',
'**Container & Orchestrierung:**', '• Docker - Container Runtime', '• Traefik - Reverse Proxy',
'**Kommunikation:**', '• Matrix Synapse - Chat/Messaging', '• Jitsi Meet - Video-Konferenzen',
],
tips: ['Alle Services laufen in Docker-Containern', 'Ports sind in docker-compose.yml definiert'],
},
'unity-game': {
title: 'Unity & Breakpilot Drive',
content: [
'**Neu hinzugefuegt fuer Breakpilot Drive:**',
'**Unity Engine (6000.0)**', '→ Die Game Engine fuer das Lernspiel', '→ Lizenz: Unity EULA (kostenlos bis 100k Revenue)',
'**Universal Render Pipeline (17.x)**', '→ Optimierte Grafik-Pipeline fuer WebGL', '→ Lizenz: Unity Companion License',
'**TextMeshPro (3.2)**', '→ Fortgeschrittenes Text-Rendering',
'**Unity Mathematics (1.3)**', '→ SIMD-optimierte Mathe-Bibliothek',
'**Newtonsoft.Json (3.2)**', '→ JSON-Serialisierung fuer API-Kommunikation',
'**C# Abhängigkeiten:**', '• .NET Standard 2.1', '• UnityWebRequest (HTTP Client)', '• System.Text.Json',
],
tips: ['Unity 6 ist die neueste LTS-Version', 'WebGL-Builds sind ~30-50 MB gross'],
},
'licenses': {
title: 'Lizenz-Compliance',
content: [
'**Lizenz-Typen in BreakPilot:**',
'**Permissive (Unkompliziert):**', '• MIT - Die meisten JS/Python Libs', '• Apache 2.0 - FastAPI, Keycloak', '• BSD - PostgreSQL',
'**Copyleft (Vorsicht bei Aenderungen):**', '• GPL - Wenige Komponenten', '• AGPL - Jitsi (Server-Side OK)',
'**Proprietary:**', '• Unity EULA - Kostenlos bis 100k Revenue', '• Unity Companion - Packages an Engine gebunden',
'**Wichtig:**', 'Alle verwendeten Lizenzen sind mit kommerziellem Einsatz kompatibel. Bei Fragen: Rechtsabteilung konsultieren.',
],
tips: ['MIT und Apache 2.0 sind am unproblematischsten', 'AGPL erfordert Source-Code-Freigabe bei Modifikation'],
},
'summary': {
title: 'Zusammenfassung',
content: [
'Du hast die SBOM von BreakPilot kennengelernt:',
'✅ Was eine SBOM ist und warum sie wichtig ist', '✅ Die verschiedenen Kategorien (8 Stueck)',
'✅ Infrastruktur-Komponenten', '✅ Die neuen Unity/Game-Komponenten fuer Breakpilot Drive', '✅ Lizenz-Typen und Compliance',
'**Im SBOM-Dashboard kannst du:**', '• Nach Kategorie filtern', '• Nach Namen suchen', '• Lizenzen pruefen', '• Komponenten-Details ansehen',
'**180+ Komponenten** sind dokumentiert und nachverfolgbar.',
],
tips: ['Pruefe regelmaessig auf veraltete Komponenten', 'Bei neuen Abhaengigkeiten: SBOM aktualisieren'],
},
}