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>
116 lines
3.2 KiB
TypeScript
116 lines
3.2 KiB
TypeScript
/**
|
|
* Controls Library - Helper Functions
|
|
*
|
|
* Query, filter, and analysis utilities for the controls library.
|
|
*/
|
|
|
|
import { Control, ControlDomain, ReviewFrequency, LocalizedText } from '../types'
|
|
import { CONTROLS_LIBRARY } from './controls-all'
|
|
|
|
/**
|
|
* Get all controls
|
|
*/
|
|
export function getAllControls(): Control[] {
|
|
return CONTROLS_LIBRARY
|
|
}
|
|
|
|
/**
|
|
* Get controls by domain
|
|
*/
|
|
export function getControlsByDomain(domain: ControlDomain): Control[] {
|
|
return CONTROLS_LIBRARY.filter((c) => c.domain === domain)
|
|
}
|
|
|
|
/**
|
|
* Get control by ID
|
|
*/
|
|
export function getControlById(id: string): Control | undefined {
|
|
return CONTROLS_LIBRARY.find((c) => c.id === id)
|
|
}
|
|
|
|
/**
|
|
* Get required controls
|
|
*/
|
|
export function getRequiredControls(): Control[] {
|
|
return CONTROLS_LIBRARY.filter((c) => c.isRequired)
|
|
}
|
|
|
|
/**
|
|
* Get controls by frequency
|
|
*/
|
|
export function getControlsByFrequency(frequency: ReviewFrequency): Control[] {
|
|
return CONTROLS_LIBRARY.filter((c) => c.defaultFrequency === frequency)
|
|
}
|
|
|
|
/**
|
|
* Get controls applicable to vendors
|
|
*/
|
|
export function getVendorControls(): Control[] {
|
|
return CONTROLS_LIBRARY.filter((c) =>
|
|
['TRANSFER', 'AUDIT', 'DELETION', 'INCIDENT', 'SUBPROCESSOR', 'TOM', 'CONTRACT', 'DATA_SUBJECT', 'SECURITY', 'GOVERNANCE'].includes(c.domain)
|
|
)
|
|
}
|
|
|
|
/**
|
|
* Get controls applicable to processing activities
|
|
*/
|
|
export function getProcessingActivityControls(): Control[] {
|
|
return CONTROLS_LIBRARY.filter((c) =>
|
|
['TOM', 'DATA_SUBJECT', 'GOVERNANCE', 'SECURITY'].includes(c.domain)
|
|
)
|
|
}
|
|
|
|
/**
|
|
* Group controls by domain
|
|
*/
|
|
export function getControlsGroupedByDomain(): Map<ControlDomain, Control[]> {
|
|
const grouped = new Map<ControlDomain, Control[]>()
|
|
|
|
for (const control of CONTROLS_LIBRARY) {
|
|
const existing = grouped.get(control.domain) || []
|
|
grouped.set(control.domain, [...existing, control])
|
|
}
|
|
|
|
return grouped
|
|
}
|
|
|
|
/**
|
|
* Get domain metadata
|
|
*/
|
|
export function getControlDomainMeta(domain: ControlDomain): LocalizedText {
|
|
const meta: Record<ControlDomain, LocalizedText> = {
|
|
TRANSFER: { de: 'Drittlandtransfer', en: 'Third Country Transfer' },
|
|
AUDIT: { de: 'Audit & Prüfung', en: 'Audit & Review' },
|
|
DELETION: { de: 'Löschung', en: 'Deletion' },
|
|
INCIDENT: { de: 'Incident Response', en: 'Incident Response' },
|
|
SUBPROCESSOR: { de: 'Unterauftragnehmer', en: 'Sub-Processors' },
|
|
TOM: { de: 'Technische/Org. Maßnahmen', en: 'Technical/Org. Measures' },
|
|
CONTRACT: { de: 'Vertragliche Grundlagen', en: 'Contractual Basics' },
|
|
DATA_SUBJECT: { de: 'Betroffenenrechte', en: 'Data Subject Rights' },
|
|
SECURITY: { de: 'Sicherheit', en: 'Security' },
|
|
GOVERNANCE: { de: 'Governance', en: 'Governance' },
|
|
}
|
|
|
|
return meta[domain]
|
|
}
|
|
|
|
/**
|
|
* Calculate control coverage
|
|
*/
|
|
export function calculateControlCoverage(
|
|
controlIds: string[],
|
|
domain?: ControlDomain
|
|
): { covered: number; total: number; percentage: number } {
|
|
const targetControls = domain
|
|
? getControlsByDomain(domain)
|
|
: getRequiredControls()
|
|
|
|
const covered = targetControls.filter((c) => controlIds.includes(c.id)).length
|
|
|
|
return {
|
|
covered,
|
|
total: targetControls.length,
|
|
percentage: targetControls.length > 0 ? Math.round((covered / targetControls.length) * 100) : 0,
|
|
}
|
|
}
|