feat: V1 Control Enrichment — Eigenentwicklung-Label, regulatorisches Matching & Vergleichsansicht
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 39s
CI/CD / test-python-backend-compliance (push) Successful in 32s
CI/CD / test-python-document-crawler (push) Successful in 20s
CI/CD / test-python-dsms-gateway (push) Successful in 16s
CI/CD / validate-canonical-controls (push) Successful in 9s
CI/CD / Deploy (push) Successful in 4s
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 39s
CI/CD / test-python-backend-compliance (push) Successful in 32s
CI/CD / test-python-document-crawler (push) Successful in 20s
CI/CD / test-python-dsms-gateway (push) Successful in 16s
CI/CD / validate-canonical-controls (push) Successful in 9s
CI/CD / Deploy (push) Successful in 4s
863 v1-Controls (manuell geschrieben, ohne Rechtsgrundlage) werden als "Eigenentwicklung" gekennzeichnet und automatisch mit regulatorischen Controls (DSGVO, NIS2, OWASP etc.) per Embedding-Similarity abgeglichen. Backend: - Migration 080: v1_control_matches Tabelle (Cross-Reference) - v1_enrichment.py: Batch-Matching via BGE-M3 + Qdrant (Threshold 0.75) - 3 neue API-Endpoints: enrich-v1-matches, v1-matches, v1-enrichment-stats - 6 Tests (dry-run, execution, matches, pagination, detection) Frontend: - Orange "Eigenentwicklung"-Badge statt grauem "v1" (wenn kein Source) - "Regulatorische Abdeckung"-Sektion im ControlDetail mit Match-Karten - Side-by-Side V1CompareView (Eigenentwicklung vs. regulatorisch gedeckt) - Prev/Next Navigation durch alle Matches Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -52,6 +52,7 @@ export interface CanonicalControl {
|
||||
parent_control_id?: string | null
|
||||
parent_control_title?: string | null
|
||||
decomposition_method?: string | null
|
||||
pipeline_version?: number | string | null
|
||||
created_at: string
|
||||
updated_at: string
|
||||
}
|
||||
@@ -293,7 +294,29 @@ export function TargetAudienceBadge({ audience }: { audience: string | string[]
|
||||
)
|
||||
}
|
||||
|
||||
export function GenerationStrategyBadge({ strategy }: { strategy: string | null | undefined }) {
|
||||
export interface CanonicalControlPipelineInfo {
|
||||
pipeline_version?: number | string | null
|
||||
source_citation?: Record<string, string> | null
|
||||
parent_control_uuid?: string | null
|
||||
}
|
||||
|
||||
export function isEigenentwicklung(ctrl: CanonicalControlPipelineInfo & { generation_strategy?: string | null }): boolean {
|
||||
return (
|
||||
(!ctrl.generation_strategy || ctrl.generation_strategy === 'ungrouped') &&
|
||||
(!ctrl.pipeline_version || String(ctrl.pipeline_version) === '1') &&
|
||||
!ctrl.source_citation &&
|
||||
!ctrl.parent_control_uuid
|
||||
)
|
||||
}
|
||||
|
||||
export function GenerationStrategyBadge({ strategy, pipelineInfo }: {
|
||||
strategy: string | null | undefined
|
||||
pipelineInfo?: CanonicalControlPipelineInfo & { generation_strategy?: string | null }
|
||||
}) {
|
||||
// Eigenentwicklung detection: v1 + no source + no parent
|
||||
if (pipelineInfo && isEigenentwicklung(pipelineInfo)) {
|
||||
return <span className="inline-flex items-center px-1.5 py-0.5 rounded text-xs font-medium bg-orange-100 text-orange-700">Eigenentwicklung</span>
|
||||
}
|
||||
if (!strategy || strategy === 'ungrouped') {
|
||||
return <span className="inline-flex items-center px-1.5 py-0.5 rounded text-xs font-medium bg-gray-100 text-gray-500">v1</span>
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user