Use-Case-Mapping-Filter für Master Controls + Mapper-Präzisionsfix
CI / detect-changes (push) Successful in 14s
CI / branch-name (push) Has been skipped
CI / guardrail-integrity (push) Has been skipped
CI / secret-scan (push) Has been skipped
CI / dep-audit (push) Has been skipped
CI / sbom-scan (push) Has been skipped
CI / build-sha-integrity (push) Failing after 7s
CI / validate-canonical-controls (push) Successful in 13s
CI / loc-budget (push) Failing after 15s
CI / go-lint (push) Has been skipped
CI / test-go (push) Has been skipped
CI / python-lint (push) Has been skipped
CI / nodejs-lint (push) Has been skipped
CI / nodejs-build (push) Successful in 2m23s
CI / iace-gt-coverage (push) Has been skipped
CI / test-python-backend (push) Successful in 34s
CI / test-python-document-crawler (push) Has been skipped
CI / test-python-dsms-gateway (push) Has been skipped

Phase 2: Live-Filter an /sdk/master-controls (Use Case, Quell-Regulierung,
Verifikations-Methode, Coverage, Primärzweck-Toggle, category via Member-EXISTS).
API mit EXISTS-Filtern + gecachten Meta-Counts in master-controls/route.ts.

Phase A: neue UseCase telekommunikation + Fix der Impressum-Fehlrouten im
Register (TKG/AT-TKG->telekommunikation, telemedien->dse, GewO->handelsrecht);
echte Impressum-Quellen (TMG/Mediengesetz) bleiben impressum. Deterministischer
Seed aus source_regulation; Tests grün.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Benjamin Admin
2026-06-09 23:19:56 +02:00
parent c4d9b1426f
commit 372e1fe9e9
10 changed files with 434 additions and 45 deletions
@@ -14,6 +14,11 @@ export interface ControlsMeta {
category_counts?: Record<string, number>
evidence_type_counts?: Record<string, number>
release_state_counts?: Record<string, number>
// Master-control mapping dimensions (only returned by the MC endpoint)
use_case_counts?: Record<string, number>
regulations?: Array<{ source_regulation: string; count: number }>
mapped_total?: number
unmapped_count?: number
}
const PAGE_SIZE = 50
@@ -35,6 +40,10 @@ export function useControlLibraryState(backendUrlOverride?: string) {
const [domainFilter, setDomainFilter] = useState<string>('')
const [stateFilter, setStateFilter] = useState<string>('')
const [verificationFilter, setVerificationFilter] = useState<string>('')
const [useCaseFilter, setUseCaseFilter] = useState<string>('')
const [primaryOnly, setPrimaryOnly] = useState<boolean>(false)
const [regulationFilter, setRegulationFilter] = useState<string>('')
const [mappedFilter, setMappedFilter] = useState<string>('')
const [categoryFilter, setCategoryFilter] = useState<string>('')
const [evidenceTypeFilter, setEvidenceTypeFilter] = useState<string>('')
const [audienceFilter, setAudienceFilter] = useState<string>('')
@@ -88,6 +97,10 @@ export function useControlLibraryState(backendUrlOverride?: string) {
if (domainFilter) p.set('domain', domainFilter)
if (stateFilter) p.set('release_state', stateFilter)
if (verificationFilter) p.set('verification_method', verificationFilter)
if (useCaseFilter) p.set('use_case', useCaseFilter)
if (primaryOnly) p.set('primary', '1')
if (regulationFilter) p.set('source_regulation', regulationFilter)
if (mappedFilter) p.set('mapped', mappedFilter)
if (categoryFilter) p.set('category', categoryFilter)
if (evidenceTypeFilter) p.set('evidence_type', evidenceTypeFilter)
if (audienceFilter) p.set('target_audience', audienceFilter)
@@ -97,7 +110,7 @@ export function useControlLibraryState(backendUrlOverride?: string) {
if (debouncedSearch) p.set('search', debouncedSearch)
if (extra) for (const [k, v] of Object.entries(extra)) p.set(k, v)
return p.toString()
}, [severityFilter, domainFilter, stateFilter, verificationFilter, categoryFilter, evidenceTypeFilter, audienceFilter, sourceFilter, typeFilter, hideDuplicates, debouncedSearch])
}, [severityFilter, domainFilter, stateFilter, verificationFilter, useCaseFilter, primaryOnly, regulationFilter, mappedFilter, categoryFilter, evidenceTypeFilter, audienceFilter, sourceFilter, typeFilter, hideDuplicates, debouncedSearch])
const loadFrameworks = useCallback(async () => {
try {
@@ -156,7 +169,7 @@ export function useControlLibraryState(backendUrlOverride?: string) {
useEffect(() => { loadFrameworks(); loadReviewCount() }, [loadFrameworks, loadReviewCount])
useEffect(() => { loadMeta() }, [loadMeta])
useEffect(() => { loadControls() }, [loadControls])
useEffect(() => { setCurrentPage(1) }, [severityFilter, domainFilter, stateFilter, verificationFilter, categoryFilter, evidenceTypeFilter, audienceFilter, sourceFilter, typeFilter, hideDuplicates, debouncedSearch, sortBy])
useEffect(() => { setCurrentPage(1) }, [severityFilter, domainFilter, stateFilter, verificationFilter, useCaseFilter, primaryOnly, regulationFilter, mappedFilter, categoryFilter, evidenceTypeFilter, audienceFilter, sourceFilter, typeFilter, hideDuplicates, debouncedSearch, sortBy])
const totalPages = Math.max(1, Math.ceil(totalCount / PAGE_SIZE))
@@ -212,6 +225,10 @@ export function useControlLibraryState(backendUrlOverride?: string) {
domainFilter, setDomainFilter,
stateFilter, setStateFilter,
verificationFilter, setVerificationFilter,
useCaseFilter, setUseCaseFilter,
primaryOnly, setPrimaryOnly,
regulationFilter, setRegulationFilter,
mappedFilter, setMappedFilter,
categoryFilter, setCategoryFilter,
evidenceTypeFilter, setEvidenceTypeFilter,
audienceFilter, setAudienceFilter,