feat(regulations): Automatische Ableitung anwendbarer Gesetze & Aufsichtsbehoerden
Some checks failed
CI / go-lint (push) Has been skipped
CI / python-lint (push) Has been skipped
CI / nodejs-lint (push) Has been skipped
CI / test-go-ai-compliance (push) Failing after 35s
CI / test-python-backend-compliance (push) Successful in 37s
CI / test-python-document-crawler (push) Successful in 27s
CI / test-python-dsms-gateway (push) Successful in 21s
Some checks failed
CI / go-lint (push) Has been skipped
CI / python-lint (push) Has been skipped
CI / nodejs-lint (push) Has been skipped
CI / test-go-ai-compliance (push) Failing after 35s
CI / test-python-backend-compliance (push) Successful in 37s
CI / test-python-document-crawler (push) Successful in 27s
CI / test-python-dsms-gateway (push) Successful in 21s
Nach Abschluss von Profil + Scope werden jetzt automatisch die anwendbaren Regulierungen (DSGVO, NIS2, AI Act, DORA) ermittelt und die zustaendigen Aufsichtsbehoerden (Landes-DSB, BSI, BaFin) aus Bundesland + Branche abgeleitet. - Neues scope-to-facts.ts: Mapping CompanyProfile+Scope → Go SDK Payload - Neues supervisory-authority-resolver.ts: 16 Landes-DSB + nationale Behoerden - ScopeDecisionTab: Regulierungs-Report mit Aufsichtsbehoerden-Karten - Obligations-Seite: Echte Daten statt Dummy in handleAutoProfiling() - Neue Types: ApplicableRegulation, RegulationAssessmentResult, SupervisoryAuthorityInfo Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
'use client'
|
||||
import React, { useState } from 'react'
|
||||
import type { ScopeDecision, ComplianceDepthLevel } from '@/lib/sdk/compliance-scope-types'
|
||||
import type { ScopeDecision, ComplianceDepthLevel, ApplicableRegulation, SupervisoryAuthorityInfo } from '@/lib/sdk/compliance-scope-types'
|
||||
import { DEPTH_LEVEL_LABELS, DEPTH_LEVEL_DESCRIPTIONS, DEPTH_LEVEL_COLORS, DOCUMENT_TYPE_LABELS } from '@/lib/sdk/compliance-scope-types'
|
||||
|
||||
interface ScopeDecisionTabProps {
|
||||
@@ -11,6 +11,10 @@ interface ScopeDecisionTabProps {
|
||||
canEvaluate?: boolean
|
||||
onEvaluate?: () => void
|
||||
isEvaluating?: boolean
|
||||
applicableRegulations?: ApplicableRegulation[]
|
||||
supervisoryAuthorities?: SupervisoryAuthorityInfo[]
|
||||
regulationAssessmentLoading?: boolean
|
||||
onGoToObligations?: () => void
|
||||
}
|
||||
|
||||
export function ScopeDecisionTab({
|
||||
@@ -20,6 +24,10 @@ export function ScopeDecisionTab({
|
||||
canEvaluate,
|
||||
onEvaluate,
|
||||
isEvaluating,
|
||||
applicableRegulations,
|
||||
supervisoryAuthorities,
|
||||
regulationAssessmentLoading,
|
||||
onGoToObligations,
|
||||
}: ScopeDecisionTabProps) {
|
||||
const [expandedTrigger, setExpandedTrigger] = useState<number | null>(null)
|
||||
const [showAuditTrail, setShowAuditTrail] = useState(false)
|
||||
@@ -125,6 +133,103 @@ export function ScopeDecisionTab({
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Applicable Regulations */}
|
||||
{(applicableRegulations || regulationAssessmentLoading) && (
|
||||
<div className="bg-white rounded-xl border border-gray-200 p-6">
|
||||
<h3 className="text-lg font-semibold text-gray-900 mb-4">Anwendbare Regulierungen</h3>
|
||||
{regulationAssessmentLoading ? (
|
||||
<div className="flex items-center gap-3 text-gray-500">
|
||||
<svg className="animate-spin h-5 w-5" viewBox="0 0 24 24">
|
||||
<circle className="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" strokeWidth="4" fill="none" />
|
||||
<path className="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z" />
|
||||
</svg>
|
||||
<span>Regulierungen werden geprueft...</span>
|
||||
</div>
|
||||
) : applicableRegulations && applicableRegulations.length > 0 ? (
|
||||
<div className="space-y-3">
|
||||
{applicableRegulations.map((reg) => (
|
||||
<div
|
||||
key={reg.id}
|
||||
className="flex items-center justify-between border border-gray-200 rounded-lg p-4 hover:bg-gray-50 transition-colors"
|
||||
>
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="flex-shrink-0 w-8 h-8 bg-green-100 rounded-full flex items-center justify-center">
|
||||
<svg className="w-5 h-5 text-green-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M5 13l4 4L19 7" />
|
||||
</svg>
|
||||
</div>
|
||||
<div>
|
||||
<span className="font-semibold text-gray-900">{reg.name}</span>
|
||||
{reg.classification && (
|
||||
<span className="ml-2 inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-purple-100 text-purple-800">
|
||||
{reg.classification}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<div className="text-right text-sm text-gray-600">
|
||||
<span>{reg.obligation_count} Pflichten</span>
|
||||
{reg.control_count > 0 && (
|
||||
<span className="ml-2">{reg.control_count} Controls</span>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
|
||||
{/* Supervisory Authorities */}
|
||||
{supervisoryAuthorities && supervisoryAuthorities.length > 0 && (
|
||||
<div className="mt-4 pt-4 border-t border-gray-200">
|
||||
<h4 className="text-sm font-semibold text-gray-700 mb-3">Zustaendige Aufsichtsbehoerden</h4>
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-3">
|
||||
{supervisoryAuthorities.map((sa, idx) => (
|
||||
<div key={idx} className="flex items-start gap-3 bg-gray-50 rounded-lg p-3">
|
||||
<div className="flex-shrink-0 w-6 h-6 bg-blue-100 rounded flex items-center justify-center mt-0.5">
|
||||
<svg className="w-4 h-4 text-blue-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 21V5a2 2 0 00-2-2H7a2 2 0 00-2 2v16m14 0h2m-2 0h-5m-9 0H3m2 0h5M9 7h1m-1 4h1m4-4h1m-1 4h1m-5 10v-5a1 1 0 011-1h2a1 1 0 011 1v5m-4 0h4" />
|
||||
</svg>
|
||||
</div>
|
||||
<div>
|
||||
<span className="text-sm font-medium text-gray-900">{sa.authority.abbreviation}</span>
|
||||
<span className="text-xs text-gray-500 ml-1">({sa.domain})</span>
|
||||
<p className="text-xs text-gray-600 mt-0.5">{sa.authority.name}</p>
|
||||
{sa.authority.url && (
|
||||
<a
|
||||
href={sa.authority.url}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="text-xs text-purple-600 hover:text-purple-700"
|
||||
>
|
||||
Website →
|
||||
</a>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Link to Obligations */}
|
||||
{onGoToObligations && (
|
||||
<div className="mt-4 pt-4 border-t border-gray-200">
|
||||
<button
|
||||
onClick={onGoToObligations}
|
||||
className="inline-flex items-center gap-2 px-4 py-2 text-sm bg-purple-600 text-white rounded-lg hover:bg-purple-700 transition-colors"
|
||||
>
|
||||
Pflichten anzeigen
|
||||
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M13 7l5 5m0 0l-5 5m5-5H6" />
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
) : (
|
||||
<p className="text-gray-500 text-sm">Keine anwendbaren Regulierungen ermittelt.</p>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Hard Triggers */}
|
||||
{decision.hardTriggers && decision.hardTriggers.length > 0 && (
|
||||
<div className="bg-white rounded-xl border border-gray-200 p-6">
|
||||
|
||||
Reference in New Issue
Block a user