feat: Control-Detail Provenance + Atomare Controls Seite
All checks were successful
CI/CD / go-lint (push) Has been skipped
CI/CD / python-lint (push) Has been skipped
CI/CD / nodejs-lint (push) Has been skipped
CI/CD / test-go-ai-compliance (push) Successful in 41s
CI/CD / test-python-backend-compliance (push) Successful in 40s
CI/CD / test-python-document-crawler (push) Successful in 23s
CI/CD / test-python-dsms-gateway (push) Successful in 18s
CI/CD / validate-canonical-controls (push) Successful in 11s
CI/CD / Deploy (push) Successful in 4s

Backend: provenance endpoint (obligations, doc refs, merged duplicates,
regulations summary) + atomic-stats aggregation endpoint.
Frontend: ControlDetail mit Provenance-Sektionen, klickbare Navigation,
neue /sdk/atomic-controls Seite mit Stats-Bar und gefilterer Liste.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Benjamin Admin
2026-03-24 10:38:34 +01:00
parent 200facda6a
commit 6d3bdf8e74
8 changed files with 1210 additions and 5 deletions

View File

@@ -304,3 +304,61 @@ export function ObligationTypeBadge({ type }: { type: string | null | undefined
export function getDomain(controlId: string): string {
return controlId.split('-')[0] || ''
}
// =============================================================================
// PROVENANCE TYPES
// =============================================================================
export interface ObligationInfo {
candidate_id: string
obligation_text: string
action: string | null
object: string | null
normative_strength: string
release_state: string
}
export interface DocumentReference {
regulation_code: string
article: string | null
paragraph: string | null
extraction_method: string
confidence: number | null
}
export interface MergedDuplicate {
control_id: string
title: string
source_regulation: string | null
}
export interface RegulationSummary {
regulation_code: string
articles: string[]
link_types: string[]
}
// =============================================================================
// PROVENANCE BADGES
// =============================================================================
const EXTRACTION_METHOD_CONFIG: Record<string, { bg: string; label: string }> = {
exact_match: { bg: 'bg-green-100 text-green-700', label: 'Exakt' },
embedding_match: { bg: 'bg-blue-100 text-blue-700', label: 'Embedding' },
llm_extracted: { bg: 'bg-violet-100 text-violet-700', label: 'LLM' },
inferred: { bg: 'bg-gray-100 text-gray-600', label: 'Abgeleitet' },
}
export function ExtractionMethodBadge({ method }: { method: string }) {
const config = EXTRACTION_METHOD_CONFIG[method] || EXTRACTION_METHOD_CONFIG.inferred
return <span className={`inline-flex items-center px-1.5 py-0.5 rounded text-xs font-medium ${config.bg}`}>{config.label}</span>
}
export function RegulationCountBadge({ count }: { count: number }) {
if (count <= 0) return null
return (
<span className="inline-flex items-center px-1.5 py-0.5 rounded text-xs font-medium bg-violet-100 text-violet-700">
{count} {count === 1 ? 'Regulierung' : 'Regulierungen'}
</span>
)
}