[split-required] Split 58 monoliths across Python, Go, TypeScript (Phases 1-3)

Phase 1 — Python (klausur-service): 5 monoliths → 36 files
- dsfa_corpus_ingestion.py (1,828 LOC → 5 files)
- cv_ocr_engines.py (2,102 LOC → 7 files)
- cv_layout.py (3,653 LOC → 10 files)
- vocab_worksheet_api.py (2,783 LOC → 8 files)
- grid_build_core.py (1,958 LOC → 6 files)

Phase 2 — Go (edu-search-service, school-service): 8 monoliths → 19 files
- staff_crawler.go (1,402 → 4), policy/store.go (1,168 → 3)
- policy_handlers.go (700 → 2), repository.go (684 → 2)
- search.go (592 → 2), ai_extraction_handlers.go (554 → 2)
- seed_data.go (591 → 2), grade_service.go (646 → 2)

Phase 3 — TypeScript (admin-lehrer): 45 monoliths → 220+ files
- sdk/types.ts (2,108 → 16 domain files)
- ai/rag/page.tsx (2,686 → 14 files)
- 22 page.tsx files split into _components/ + _hooks/
- 11 component files split into sub-components
- 10 SDK data catalogs added to loc-exceptions
- Deleted dead backup index_original.ts (4,899 LOC)

All original public APIs preserved via re-export facades.
Zero new errors: Python imports verified, Go builds clean,
TypeScript tsc --noEmit shows only pre-existing errors.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Benjamin Admin
2026-04-24 17:28:57 +02:00
parent 9ba420fa91
commit b681ddb131
251 changed files with 30016 additions and 25037 deletions

View File

@@ -0,0 +1,491 @@
import type React from 'react'
import type {
VendorComplianceAction,
VendorComplianceState,
ProcessingActivity,
Vendor,
ContractDocument,
Finding,
ControlInstance,
ExportFormat,
} from './types'
type Dispatch = React.Dispatch<VendorComplianceAction>
const API_BASE = '/api/sdk/v1/vendor-compliance'
// ==========================================
// DATA LOADING
// ==========================================
export async function loadAllData(dispatch: Dispatch): Promise<void> {
dispatch({ type: 'SET_LOADING', payload: true })
dispatch({ type: 'SET_ERROR', payload: null })
try {
const [
activitiesRes,
vendorsRes,
contractsRes,
findingsRes,
controlsRes,
controlInstancesRes,
] = await Promise.all([
fetch(`${API_BASE}/processing-activities`),
fetch(`${API_BASE}/vendors`),
fetch(`${API_BASE}/contracts`),
fetch(`${API_BASE}/findings`),
fetch(`${API_BASE}/controls`),
fetch(`${API_BASE}/control-instances`),
])
if (activitiesRes.ok) {
const data = await activitiesRes.json()
dispatch({ type: 'SET_PROCESSING_ACTIVITIES', payload: data.data || [] })
}
if (vendorsRes.ok) {
const data = await vendorsRes.json()
dispatch({ type: 'SET_VENDORS', payload: data.data || [] })
}
if (contractsRes.ok) {
const data = await contractsRes.json()
dispatch({ type: 'SET_CONTRACTS', payload: data.data || [] })
}
if (findingsRes.ok) {
const data = await findingsRes.json()
dispatch({ type: 'SET_FINDINGS', payload: data.data || [] })
}
if (controlsRes.ok) {
const data = await controlsRes.json()
dispatch({ type: 'SET_CONTROLS', payload: data.data || [] })
}
if (controlInstancesRes.ok) {
const data = await controlInstancesRes.json()
dispatch({ type: 'SET_CONTROL_INSTANCES', payload: data.data || [] })
}
} catch (error) {
console.error('Failed to load vendor compliance data:', error)
dispatch({
type: 'SET_ERROR',
payload: 'Fehler beim Laden der Daten',
})
} finally {
dispatch({ type: 'SET_LOADING', payload: false })
}
}
// ==========================================
// PROCESSING ACTIVITIES ACTIONS
// ==========================================
export async function apiCreateProcessingActivity(
dispatch: Dispatch,
data: Omit<ProcessingActivity, 'id' | 'tenantId' | 'createdAt' | 'updatedAt'>
): Promise<ProcessingActivity> {
const response = await fetch(`${API_BASE}/processing-activities`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(data),
})
if (!response.ok) {
const error = await response.json()
throw new Error(error.error || 'Fehler beim Erstellen der Verarbeitungstaetigkeit')
}
const result = await response.json()
const activity = result.data
dispatch({ type: 'ADD_PROCESSING_ACTIVITY', payload: activity })
return activity
}
export async function apiUpdateProcessingActivity(
dispatch: Dispatch,
id: string,
data: Partial<ProcessingActivity>
): Promise<void> {
const response = await fetch(`${API_BASE}/processing-activities/${id}`, {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(data),
})
if (!response.ok) {
const error = await response.json()
throw new Error(error.error || 'Fehler beim Aktualisieren der Verarbeitungstaetigkeit')
}
dispatch({ type: 'UPDATE_PROCESSING_ACTIVITY', payload: { id, data } })
}
export async function apiDeleteProcessingActivity(
dispatch: Dispatch,
id: string
): Promise<void> {
const response = await fetch(`${API_BASE}/processing-activities/${id}`, {
method: 'DELETE',
})
if (!response.ok) {
const error = await response.json()
throw new Error(error.error || 'Fehler beim Loeschen der Verarbeitungstaetigkeit')
}
dispatch({ type: 'DELETE_PROCESSING_ACTIVITY', payload: id })
}
export async function apiDuplicateProcessingActivity(
dispatch: Dispatch,
state: VendorComplianceState,
id: string
): Promise<ProcessingActivity> {
const original = state.processingActivities.find((a) => a.id === id)
if (!original) {
throw new Error('Verarbeitungstaetigkeit nicht gefunden')
}
const { id: _id, vvtId: _vvtId, createdAt: _createdAt, updatedAt: _updatedAt, tenantId: _tenantId, ...rest } = original
const newActivity = await apiCreateProcessingActivity(dispatch, {
...rest,
vvtId: '', // Will be generated by backend
name: {
de: `${original.name.de} (Kopie)`,
en: `${original.name.en} (Copy)`,
},
status: 'DRAFT',
})
return newActivity
}
// ==========================================
// VENDOR ACTIONS
// ==========================================
export async function apiCreateVendor(
dispatch: Dispatch,
data: Omit<Vendor, 'id' | 'tenantId' | 'createdAt' | 'updatedAt'>
): Promise<Vendor> {
const response = await fetch(`${API_BASE}/vendors`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(data),
})
if (!response.ok) {
const error = await response.json()
throw new Error(error.error || 'Fehler beim Erstellen des Vendors')
}
const result = await response.json()
const vendor = result.data
dispatch({ type: 'ADD_VENDOR', payload: vendor })
return vendor
}
export async function apiUpdateVendor(
dispatch: Dispatch,
id: string,
data: Partial<Vendor>
): Promise<void> {
const response = await fetch(`${API_BASE}/vendors/${id}`, {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(data),
})
if (!response.ok) {
const error = await response.json()
throw new Error(error.error || 'Fehler beim Aktualisieren des Vendors')
}
dispatch({ type: 'UPDATE_VENDOR', payload: { id, data } })
}
export async function apiDeleteVendor(
dispatch: Dispatch,
id: string
): Promise<void> {
const response = await fetch(`${API_BASE}/vendors/${id}`, {
method: 'DELETE',
})
if (!response.ok) {
const error = await response.json()
throw new Error(error.error || 'Fehler beim Loeschen des Vendors')
}
dispatch({ type: 'DELETE_VENDOR', payload: id })
}
// ==========================================
// CONTRACT ACTIONS
// ==========================================
export async function apiUploadContract(
dispatch: Dispatch,
state: VendorComplianceState,
vendorId: string,
file: File,
metadata: Partial<ContractDocument>
): Promise<ContractDocument> {
const formData = new FormData()
formData.append('file', file)
formData.append('vendorId', vendorId)
formData.append('metadata', JSON.stringify(metadata))
const response = await fetch(`${API_BASE}/contracts`, {
method: 'POST',
body: formData,
})
if (!response.ok) {
const error = await response.json()
throw new Error(error.error || 'Fehler beim Hochladen des Vertrags')
}
const result = await response.json()
const contract = result.data
dispatch({ type: 'ADD_CONTRACT', payload: contract })
// Update vendor's contracts list
const vendor = state.vendors.find((v) => v.id === vendorId)
if (vendor) {
dispatch({
type: 'UPDATE_VENDOR',
payload: {
id: vendorId,
data: { contracts: [...vendor.contracts, contract.id] },
},
})
}
return contract
}
export async function apiUpdateContract(
dispatch: Dispatch,
id: string,
data: Partial<ContractDocument>
): Promise<void> {
const response = await fetch(`${API_BASE}/contracts/${id}`, {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(data),
})
if (!response.ok) {
const error = await response.json()
throw new Error(error.error || 'Fehler beim Aktualisieren des Vertrags')
}
dispatch({ type: 'UPDATE_CONTRACT', payload: { id, data } })
}
export async function apiDeleteContract(
dispatch: Dispatch,
state: VendorComplianceState,
id: string
): Promise<void> {
const contract = state.contracts.find((c) => c.id === id)
const response = await fetch(`${API_BASE}/contracts/${id}`, {
method: 'DELETE',
})
if (!response.ok) {
const error = await response.json()
throw new Error(error.error || 'Fehler beim Loeschen des Vertrags')
}
dispatch({ type: 'DELETE_CONTRACT', payload: id })
// Update vendor's contracts list
if (contract) {
const vendor = state.vendors.find((v) => v.id === contract.vendorId)
if (vendor) {
dispatch({
type: 'UPDATE_VENDOR',
payload: {
id: vendor.id,
data: { contracts: vendor.contracts.filter((cId) => cId !== id) },
},
})
}
}
}
export async function apiStartContractReview(
dispatch: Dispatch,
contractId: string
): Promise<void> {
dispatch({
type: 'UPDATE_CONTRACT',
payload: { id: contractId, data: { reviewStatus: 'IN_PROGRESS' } },
})
const response = await fetch(`${API_BASE}/contracts/${contractId}/review`, {
method: 'POST',
})
if (!response.ok) {
dispatch({
type: 'UPDATE_CONTRACT',
payload: { id: contractId, data: { reviewStatus: 'FAILED' } },
})
const error = await response.json()
throw new Error(error.error || 'Fehler beim Starten der Vertragspruefung')
}
const result = await response.json()
// Update contract with review results
dispatch({
type: 'UPDATE_CONTRACT',
payload: {
id: contractId,
data: {
reviewStatus: 'COMPLETED',
reviewCompletedAt: new Date(),
complianceScore: result.data.complianceScore,
},
},
})
// Add findings
if (result.data.findings && result.data.findings.length > 0) {
dispatch({ type: 'ADD_FINDINGS', payload: result.data.findings })
}
}
// ==========================================
// FINDINGS ACTIONS
// ==========================================
export async function apiUpdateFinding(
dispatch: Dispatch,
id: string,
data: Partial<Finding>
): Promise<void> {
const response = await fetch(`${API_BASE}/findings/${id}`, {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(data),
})
if (!response.ok) {
const error = await response.json()
throw new Error(error.error || 'Fehler beim Aktualisieren des Findings')
}
dispatch({ type: 'UPDATE_FINDING', payload: { id, data } })
}
export async function apiResolveFinding(
dispatch: Dispatch,
id: string,
resolution: string
): Promise<void> {
await apiUpdateFinding(dispatch, id, {
status: 'RESOLVED',
resolution,
resolvedAt: new Date(),
})
}
// ==========================================
// CONTROL ACTIONS
// ==========================================
export async function apiUpdateControlInstance(
dispatch: Dispatch,
id: string,
data: Partial<ControlInstance>
): Promise<void> {
const response = await fetch(`${API_BASE}/control-instances/${id}`, {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(data),
})
if (!response.ok) {
const error = await response.json()
throw new Error(error.error || 'Fehler beim Aktualisieren des Control-Status')
}
dispatch({ type: 'UPDATE_CONTROL_INSTANCE', payload: { id, data } })
}
// ==========================================
// EXPORT ACTIONS
// ==========================================
export async function apiExportVVT(
format: ExportFormat,
activityIds?: string[]
): Promise<string> {
const params = new URLSearchParams({ format })
if (activityIds && activityIds.length > 0) {
params.append('activityIds', activityIds.join(','))
}
const response = await fetch(`${API_BASE}/export/vvt?${params}`)
if (!response.ok) {
const error = await response.json()
throw new Error(error.error || 'Fehler beim Exportieren des VVT')
}
const blob = await response.blob()
const url = URL.createObjectURL(blob)
return url
}
export async function apiExportVendorAuditPack(
vendorId: string,
format: ExportFormat
): Promise<string> {
const params = new URLSearchParams({ format, vendorId })
const response = await fetch(`${API_BASE}/export/vendor-audit?${params}`)
if (!response.ok) {
const error = await response.json()
throw new Error(error.error || 'Fehler beim Exportieren des Vendor Audit Packs')
}
const blob = await response.blob()
const url = URL.createObjectURL(blob)
return url
}
export async function apiExportRoPA(
format: ExportFormat
): Promise<string> {
const params = new URLSearchParams({ format })
const response = await fetch(`${API_BASE}/export/ropa?${params}`)
if (!response.ok) {
const error = await response.json()
throw new Error(error.error || 'Fehler beim Exportieren des RoPA')
}
const blob = await response.blob()
const url = URL.createObjectURL(blob)
return url
}