[split-required] Split final 43 files (500-668 LOC) to complete refactoring

klausur-service (11 files):
- cv_gutter_repair, ocr_pipeline_regression, upload_api
- ocr_pipeline_sessions, smart_spell, nru_worksheet_generator
- ocr_pipeline_overlays, mail/aggregator, zeugnis_api
- cv_syllable_detect, self_rag

backend-lehrer (17 files):
- classroom_engine/suggestions, generators/quiz_generator
- worksheets_api, llm_gateway/comparison, state_engine_api
- classroom/models (→ 4 submodules), services/file_processor
- alerts_agent/api/wizard+digests+routes, content_generators/pdf
- classroom/routes/sessions, llm_gateway/inference
- classroom_engine/analytics, auth/keycloak_auth
- alerts_agent/processing/rule_engine, ai_processor/print_versions

agent-core (5 files):
- brain/memory_store, brain/knowledge_graph, brain/context_manager
- orchestrator/supervisor, sessions/session_manager

admin-lehrer (5 components):
- GridOverlay, StepGridReview, DevOpsPipelineSidebar
- DataFlowDiagram, sbom/wizard/page

website (2 files):
- DependencyMap, lehrer/abitur-archiv

Other: nibis_ingestion, grid_detection_service, export-doclayout-onnx

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Benjamin Admin
2026-04-25 09:41:42 +02:00
parent 451365a312
commit bd4b956e3c
113 changed files with 13790 additions and 14148 deletions

View File

@@ -0,0 +1,190 @@
'use client'
/**
* DependencyMap Sankey/Connection View
*
* Extracted from DependencyMap to keep each file under 500 LOC.
*/
import type { Language } from '@/lib/compliance-i18n'
import type { Requirement, Control, Mapping } from './DependencyMapTypes'
import { DOMAIN_COLORS, COVERAGE_COLORS } from './DependencyMapTypes'
interface DependencyMapSankeyProps {
filteredControls: Control[]
filteredRequirements: Requirement[]
requirements: Requirement[]
controls: Control[]
mappingLookup: Record<string, Record<string, Mapping>>
selectedControl: string | null
selectedRequirement: string | null
onControlClick: (control: Control) => void
onRequirementClick: (requirement: Requirement) => void
lang: Language
}
export function DependencyMapSankey({
filteredControls,
filteredRequirements,
requirements,
controls,
mappingLookup,
selectedControl,
selectedRequirement,
onControlClick,
onRequirementClick,
lang,
}: DependencyMapSankeyProps) {
const getConnectedRequirements = (controlId: string) => {
return Object.keys(mappingLookup[controlId] || {})
}
const getConnectedControls = (requirementId: string) => {
return Object.keys(mappingLookup)
.filter((controlId) => mappingLookup[controlId][requirementId])
.map((controlId) => ({
controlId,
coverage: mappingLookup[controlId][requirementId].coverage_level,
}))
}
return (
<div className="bg-white rounded-xl shadow-sm border p-6">
<div className="flex gap-8">
{/* Controls Column */}
<div className="w-1/3 space-y-2">
<h4 className="text-sm font-medium text-slate-700 mb-3">
Controls ({filteredControls.length})
</h4>
{filteredControls.map((control) => {
const connectedReqs = getConnectedRequirements(control.control_id)
const isSelected = selectedControl === control.control_id
return (
<button
key={control.control_id}
onClick={() => onControlClick(control)}
className={`
w-full text-left p-3 rounded-lg border transition-all
${isSelected ? 'border-primary-500 bg-primary-50 shadow' : 'border-slate-200 hover:border-slate-300'}
`}
>
<div className="flex items-center gap-2">
<div
className="w-3 h-3 rounded-full flex-shrink-0"
style={{ backgroundColor: DOMAIN_COLORS[control.domain] || '#94a3b8' }}
/>
<span className="font-mono text-sm font-medium">{control.control_id}</span>
<span className="text-xs text-slate-400 ml-auto">{connectedReqs.length}</span>
</div>
<p className="text-xs text-slate-500 mt-1 truncate">{control.title}</p>
</button>
)
})}
</div>
{/* Connection Lines (simplified) */}
<div className="w-1/3 flex items-center justify-center">
<div className="relative w-full h-full min-h-[200px]">
{selectedControl && (
<div className="absolute inset-0 flex flex-col items-center justify-center gap-2">
{getConnectedRequirements(selectedControl).slice(0, 10).map((reqId) => {
const req = requirements.find((r) => r.id === reqId)
const mapping = mappingLookup[selectedControl][reqId]
if (!req) return null
return (
<div
key={reqId}
className={`
px-3 py-1.5 rounded-full text-xs font-medium
${COVERAGE_COLORS[mapping.coverage_level].bg}
${COVERAGE_COLORS[mapping.coverage_level].text}
border ${COVERAGE_COLORS[mapping.coverage_level].border}
`}
>
{req.regulation_code} {req.article}
</div>
)
})}
{getConnectedRequirements(selectedControl).length > 10 && (
<span className="text-xs text-slate-400">
+{getConnectedRequirements(selectedControl).length - 10} {lang === 'de' ? 'weitere' : 'more'}
</span>
)}
</div>
)}
{selectedRequirement && (
<div className="absolute inset-0 flex flex-col items-center justify-center gap-2">
{getConnectedControls(selectedRequirement).slice(0, 10).map(({ controlId, coverage }) => {
const control = controls.find((c) => c.control_id === controlId)
if (!control) return null
return (
<div
key={controlId}
className={`
px-3 py-1.5 rounded-full text-xs font-medium
${COVERAGE_COLORS[coverage].bg}
${COVERAGE_COLORS[coverage].text}
border ${COVERAGE_COLORS[coverage].border}
`}
>
{control.control_id}
</div>
)
})}
</div>
)}
{!selectedControl && !selectedRequirement && (
<div className="absolute inset-0 flex items-center justify-center">
<p className="text-sm text-slate-400 text-center">
{lang === 'de'
? 'Waehlen Sie ein Control oder eine Anforderung aus'
: 'Select a control or requirement'}
</p>
</div>
)}
</div>
</div>
{/* Requirements Column */}
<div className="w-1/3 space-y-2">
<h4 className="text-sm font-medium text-slate-700 mb-3">
{lang === 'de' ? 'Anforderungen' : 'Requirements'} ({filteredRequirements.length})
</h4>
{filteredRequirements.slice(0, 15).map((req) => {
const connectedCtrls = getConnectedControls(req.id)
const isSelected = selectedRequirement === req.id
const isHighlighted = selectedControl && connectedCtrls.some((c) => c.controlId === selectedControl)
return (
<button
key={req.id}
onClick={() => onRequirementClick(req)}
className={`
w-full text-left p-3 rounded-lg border transition-all
${isSelected ? 'border-primary-500 bg-primary-50 shadow' : ''}
${isHighlighted && !isSelected ? 'border-primary-300 bg-primary-25' : ''}
${!isSelected && !isHighlighted ? 'border-slate-200 hover:border-slate-300' : ''}
`}
>
<div className="flex items-center gap-2">
<span className="text-xs font-medium text-slate-600">{req.regulation_code}</span>
<span className="font-mono text-sm">{req.article}</span>
<span className="text-xs text-slate-400 ml-auto">{connectedCtrls.length}</span>
</div>
<p className="text-xs text-slate-500 mt-1 truncate">{req.title}</p>
</button>
)
})}
{filteredRequirements.length > 15 && (
<p className="text-xs text-slate-400 text-center py-2">
+{filteredRequirements.length - 15} {lang === 'de' ? 'weitere' : 'more'}
</p>
)}
</div>
</div>
</div>
)
}