feat: DSFA Section 8 KI-Anwendungsfälle + Bundesland RAG-Ingest
All checks were successful
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) Successful in 38s
CI / test-python-backend-compliance (push) Successful in 33s
CI / test-python-document-crawler (push) Successful in 24s
CI / test-python-dsms-gateway (push) Successful in 19s

- Migration 028: ai_use_case_modules JSONB + section_8_complete auf compliance_dsfas
- Neues ai-use-case-types.ts: AIUseCaseModule Interface, 8 Typen, Art22Assessment,
  AI Act Risikoklassen, WP248-Kriterien, Privacy by Design, createEmptyModule() Helper
- types.ts: Section 8 in DSFA_SECTIONS, ai_use_case_modules im DSFA Interface,
  section_8_complete in DSFASectionProgress
- api.ts: addAIUseCaseModule, updateAIUseCaseModule, removeAIUseCaseModule
- 5 neue UI-Komponenten: AIUseCaseTypeSelector, Art22AssessmentPanel,
  AIRiskCriteriaChecklist, AIUseCaseModuleEditor (7 Tabs), AIUseCaseSection
- DSFASidebar: Section 8 Eintrag + calculateSectionProgress case 8
- ReviewScheduleSection: ai_use_case_module Trigger-Typ ergänzt
- page.tsx: Section 8 Rendering + Weiter-Button auf activeSection < 8 + KI-Module Counter
- scripts/ingest-dsfa-bundesland.sh: WP248 + alle 17 Behörden → bp_dsfa_corpus
- Docs: dsfa.md Section 8 + RAG-Corpus, Developer Portal DSFA mit AI-Modul-Code-Beispielen

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Benjamin Admin
2026-03-05 09:20:27 +01:00
parent 274dc68e24
commit 308d559c85
17 changed files with 2541 additions and 3 deletions

View File

@@ -0,0 +1,149 @@
'use client'
import React from 'react'
import { Art22Assessment, Art22ExceptionType } from '@/lib/sdk/dsfa/ai-use-case-types'
interface Art22AssessmentPanelProps {
assessment: Art22Assessment
onChange: (updated: Art22Assessment) => void
readonly?: boolean
}
const EXCEPTION_OPTIONS: { value: Art22ExceptionType; label: string; description: string }[] = [
{
value: 'contract',
label: 'Art. 22 Abs. 2 lit. a Vertragserfüllung',
description: 'Die Entscheidung ist für den Abschluss oder die Erfüllung eines Vertrags erforderlich',
},
{
value: 'legal',
label: 'Art. 22 Abs. 2 lit. b Rechtliche Verpflichtung',
description: 'Die Entscheidung ist durch Unionsrecht oder mitgliedstaatliches Recht zugelassen',
},
{
value: 'consent',
label: 'Art. 22 Abs. 2 lit. c Ausdrückliche Einwilligung',
description: 'Die betroffene Person hat ausdrücklich eingewilligt',
},
]
export function Art22AssessmentPanel({ assessment, onChange, readonly }: Art22AssessmentPanelProps) {
const missingRequiredSafeguards = assessment.applies &&
!assessment.safeguards.some(s => s.id === 'human_review' && s.implemented)
return (
<div className="space-y-4">
{/* Art. 22 Toggle */}
<div className="flex items-start gap-3 p-4 rounded-xl border border-gray-200 bg-gray-50">
<input
type="checkbox"
id="art22_applies"
checked={assessment.applies}
onChange={e => onChange({ ...assessment, applies: e.target.checked })}
disabled={readonly}
className="mt-1 h-4 w-4 rounded border-gray-300 text-purple-600 focus:ring-purple-500"
/>
<label htmlFor="art22_applies" className="flex-1">
<div className="font-medium text-gray-900">
Automatisierte Einzelentscheidung mit Rechtswirkung (Art. 22 DSGVO)
</div>
<p className="text-xs text-gray-500 mt-0.5">
Das KI-System trifft Entscheidungen, die rechtliche Wirkung oder ähnlich erhebliche
Auswirkungen auf Personen haben, ohne maßgebliche menschliche Beteiligung.
</p>
</label>
</div>
{/* Warning if applies without safeguards */}
{missingRequiredSafeguards && (
<div className="flex items-start gap-2 p-3 bg-red-50 border border-red-200 rounded-lg">
<svg className="w-4 h-4 text-red-500 flex-shrink-0 mt-0.5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z" />
</svg>
<p className="text-sm text-red-700">
Art. 22 gilt als anwendbar, aber die erforderliche Schutzmaßnahme Recht auf menschliche Überprüfung" ist nicht implementiert.
</p>
</div>
)}
{assessment.applies && (
<>
{/* Justification */}
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">
Begründung der Ausnahme (Art. 22 Abs. 2)
</label>
<textarea
value={assessment.justification || ''}
onChange={e => onChange({ ...assessment, justification: e.target.value })}
disabled={readonly}
rows={3}
placeholder="Begründen Sie, auf welcher Rechtsgrundlage die automatisierte Entscheidung zulässig ist..."
className="w-full px-3 py-2 text-sm border border-gray-300 rounded-lg focus:ring-2 focus:ring-purple-500 focus:border-purple-500 resize-none"
/>
</div>
{/* Exception Type */}
<div>
<label className="block text-sm font-medium text-gray-700 mb-2">Ausnahmetatbestand</label>
<div className="space-y-2">
{EXCEPTION_OPTIONS.map(opt => (
<label key={opt.value} className="flex items-start gap-3 p-3 rounded-lg border border-gray-200 hover:bg-gray-50 cursor-pointer">
<input
type="radio"
name="art22_exception"
value={opt.value}
checked={assessment.exception_type === opt.value}
onChange={() => onChange({ ...assessment, exception_type: opt.value })}
disabled={readonly}
className="mt-0.5 h-4 w-4 text-purple-600"
/>
<div>
<div className="text-sm font-medium text-gray-900">{opt.label}</div>
<p className="text-xs text-gray-500 mt-0.5">{opt.description}</p>
</div>
</label>
))}
</div>
</div>
{/* Safeguards */}
<div>
<label className="block text-sm font-medium text-gray-700 mb-2">
Schutzmaßnahmen (Art. 22 Abs. 3 DSGVO)
</label>
<div className="space-y-2">
{assessment.safeguards.map((safeguard, idx) => (
<label key={safeguard.id} className="flex items-start gap-3 p-3 rounded-lg border border-gray-200 hover:bg-gray-50 cursor-pointer">
<input
type="checkbox"
checked={safeguard.implemented}
onChange={e => {
const updated = assessment.safeguards.map((s, i) =>
i === idx ? { ...s, implemented: e.target.checked } : s
)
onChange({ ...assessment, safeguards: updated })
}}
disabled={readonly}
className="mt-0.5 h-4 w-4 rounded border-gray-300 text-purple-600"
/>
<div>
<div className={`text-sm font-medium ${safeguard.id === 'human_review' && !safeguard.implemented ? 'text-red-700' : 'text-gray-900'}`}>
{safeguard.label}
{safeguard.id === 'human_review' && (
<span className="ml-1 text-xs text-red-500">*Pflicht</span>
)}
</div>
{safeguard.description && (
<p className="text-xs text-gray-500 mt-0.5">{safeguard.description}</p>
)}
</div>
</label>
))}
</div>
</div>
</>
)}
</div>
)
}