fix(admin-v2): Restore complete admin-v2 application
The admin-v2 application was incomplete in the repository. This commit restores all missing components: - Admin pages (76 pages): dashboard, ai, compliance, dsgvo, education, infrastructure, communication, development, onboarding, rbac - SDK pages (45 pages): tom, dsfa, vvt, loeschfristen, einwilligungen, vendor-compliance, tom-generator, dsr, and more - Developer portal (25 pages): API docs, SDK guides, frameworks - All components, lib files, hooks, and types - Updated package.json with all dependencies The issue was caused by incomplete initial repository state - the full admin-v2 codebase existed in backend/admin-v2 and docs-src/admin-v2 but was never fully synced to the main admin-v2 directory. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
691
admin-v2/app/(admin)/compliance/dsfa/page.tsx
Normal file
691
admin-v2/app/(admin)/compliance/dsfa/page.tsx
Normal file
@@ -0,0 +1,691 @@
|
||||
'use client'
|
||||
|
||||
/**
|
||||
* DSFA - Datenschutz-Folgenabschaetzung
|
||||
*
|
||||
* Art. 35 DSGVO - Datenschutz-Folgenabschaetzung
|
||||
*/
|
||||
|
||||
import { useState } from 'react'
|
||||
import { PagePurpose } from '@/components/common/PagePurpose'
|
||||
|
||||
interface DSFAProject {
|
||||
id: string
|
||||
name: string
|
||||
description: string
|
||||
status: 'draft' | 'in_progress' | 'completed' | 'review_needed'
|
||||
riskLevel: 'low' | 'medium' | 'high' | 'critical'
|
||||
createdAt: string
|
||||
lastUpdated: string
|
||||
dpoApproval?: boolean
|
||||
phases: {
|
||||
description: boolean
|
||||
necessity: boolean
|
||||
risks: boolean
|
||||
measures: boolean
|
||||
consultation: boolean
|
||||
}
|
||||
}
|
||||
|
||||
interface RiskAssessment {
|
||||
id: string
|
||||
category: string
|
||||
risk: string
|
||||
likelihood: 'rare' | 'unlikely' | 'possible' | 'likely' | 'certain'
|
||||
impact: 'negligible' | 'minor' | 'moderate' | 'major' | 'severe'
|
||||
riskScore: number
|
||||
mitigations: string[]
|
||||
residualRisk: 'acceptable' | 'tolerable' | 'unacceptable'
|
||||
}
|
||||
|
||||
export default function DSFAPage() {
|
||||
const [activeTab, setActiveTab] = useState<'overview' | 'projects' | 'methodology' | 'templates'>('overview')
|
||||
const [expandedProject, setExpandedProject] = useState<string | null>('ai_processing')
|
||||
|
||||
const dsfaProjects: DSFAProject[] = [
|
||||
{
|
||||
id: 'ai_processing',
|
||||
name: 'KI-gestuetzte Korrektur und Bewertung',
|
||||
description: 'Automatische Korrektur von Schuelerarbeiten mittels KI (Ollama/OpenAI)',
|
||||
status: 'in_progress',
|
||||
riskLevel: 'high',
|
||||
createdAt: '2024-10-01',
|
||||
lastUpdated: '2024-12-01',
|
||||
dpoApproval: false,
|
||||
phases: {
|
||||
description: true,
|
||||
necessity: true,
|
||||
risks: true,
|
||||
measures: false,
|
||||
consultation: false
|
||||
}
|
||||
},
|
||||
{
|
||||
id: 'learning_analytics',
|
||||
name: 'Lernfortschrittsanalyse',
|
||||
description: 'Systematische Analyse des Lernverhaltens zur Personalisierung',
|
||||
status: 'completed',
|
||||
riskLevel: 'medium',
|
||||
createdAt: '2024-06-15',
|
||||
lastUpdated: '2024-11-15',
|
||||
dpoApproval: true,
|
||||
phases: {
|
||||
description: true,
|
||||
necessity: true,
|
||||
risks: true,
|
||||
measures: true,
|
||||
consultation: true
|
||||
}
|
||||
},
|
||||
{
|
||||
id: 'biometric_voice',
|
||||
name: 'Voice-Service Spracherkennung',
|
||||
description: 'Sprachbasierte Interaktion mit potentieller Stimmerkennung',
|
||||
status: 'draft',
|
||||
riskLevel: 'high',
|
||||
createdAt: '2024-11-01',
|
||||
lastUpdated: '2024-11-01',
|
||||
dpoApproval: false,
|
||||
phases: {
|
||||
description: true,
|
||||
necessity: false,
|
||||
risks: false,
|
||||
measures: false,
|
||||
consultation: false
|
||||
}
|
||||
},
|
||||
]
|
||||
|
||||
const riskAssessments: RiskAssessment[] = [
|
||||
{
|
||||
id: 'r1',
|
||||
category: 'Vertraulichkeit',
|
||||
risk: 'Unbefugter Zugriff auf Schuelerdaten durch Drittanbieter-KI',
|
||||
likelihood: 'unlikely',
|
||||
impact: 'major',
|
||||
riskScore: 12,
|
||||
mitigations: [
|
||||
'Lokale Verarbeitung mit Ollama priorisieren',
|
||||
'Anonymisierung vor Cloud-Verarbeitung',
|
||||
'Standardvertragsklauseln mit OpenAI'
|
||||
],
|
||||
residualRisk: 'tolerable'
|
||||
},
|
||||
{
|
||||
id: 'r2',
|
||||
category: 'Integritaet',
|
||||
risk: 'Fehlerhafte KI-Bewertungen fuehren zu falschen Noten',
|
||||
likelihood: 'possible',
|
||||
impact: 'moderate',
|
||||
riskScore: 9,
|
||||
mitigations: [
|
||||
'Menschliche Ueberpruefung aller KI-Bewertungen',
|
||||
'Transparente Darstellung als "Vorschlag"',
|
||||
'Feedback-Mechanismus fuer Korrekturen'
|
||||
],
|
||||
residualRisk: 'acceptable'
|
||||
},
|
||||
{
|
||||
id: 'r3',
|
||||
category: 'Verfuegbarkeit',
|
||||
risk: 'Systemausfall verhindert Zugriff auf Lernmaterialien',
|
||||
likelihood: 'rare',
|
||||
impact: 'minor',
|
||||
riskScore: 2,
|
||||
mitigations: [
|
||||
'Offline-Faehigkeit der App',
|
||||
'Redundante Datenhaltung',
|
||||
'Automatische Backups'
|
||||
],
|
||||
residualRisk: 'acceptable'
|
||||
},
|
||||
{
|
||||
id: 'r4',
|
||||
category: 'Rechte der Betroffenen',
|
||||
risk: 'Automatisierte Entscheidungen ohne menschliche Intervention',
|
||||
likelihood: 'possible',
|
||||
impact: 'major',
|
||||
riskScore: 12,
|
||||
mitigations: [
|
||||
'KI nur als Unterstuetzung, finale Entscheidung beim Lehrer',
|
||||
'Recht auf menschliche Ueberpruefung dokumentiert',
|
||||
'Transparente Information ueber KI-Einsatz'
|
||||
],
|
||||
residualRisk: 'tolerable'
|
||||
},
|
||||
]
|
||||
|
||||
const getStatusBadge = (status: string) => {
|
||||
switch (status) {
|
||||
case 'completed':
|
||||
return <span className="px-2 py-1 rounded-full text-xs font-medium bg-green-100 text-green-800">Abgeschlossen</span>
|
||||
case 'in_progress':
|
||||
return <span className="px-2 py-1 rounded-full text-xs font-medium bg-blue-100 text-blue-800">In Bearbeitung</span>
|
||||
case 'draft':
|
||||
return <span className="px-2 py-1 rounded-full text-xs font-medium bg-slate-100 text-slate-600">Entwurf</span>
|
||||
case 'review_needed':
|
||||
return <span className="px-2 py-1 rounded-full text-xs font-medium bg-yellow-100 text-yellow-800">Pruefung erforderlich</span>
|
||||
default:
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
const getRiskBadge = (level: string) => {
|
||||
switch (level) {
|
||||
case 'critical':
|
||||
return <span className="px-2 py-1 rounded-full text-xs font-medium bg-red-100 text-red-800">Kritisch</span>
|
||||
case 'high':
|
||||
return <span className="px-2 py-1 rounded-full text-xs font-medium bg-orange-100 text-orange-800">Hoch</span>
|
||||
case 'medium':
|
||||
return <span className="px-2 py-1 rounded-full text-xs font-medium bg-yellow-100 text-yellow-800">Mittel</span>
|
||||
case 'low':
|
||||
return <span className="px-2 py-1 rounded-full text-xs font-medium bg-green-100 text-green-800">Niedrig</span>
|
||||
default:
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
const getResidualRiskBadge = (risk: string) => {
|
||||
switch (risk) {
|
||||
case 'acceptable':
|
||||
return <span className="px-2 py-1 rounded-full text-xs font-medium bg-green-100 text-green-800">Akzeptabel</span>
|
||||
case 'tolerable':
|
||||
return <span className="px-2 py-1 rounded-full text-xs font-medium bg-yellow-100 text-yellow-800">Tolerierbar</span>
|
||||
case 'unacceptable':
|
||||
return <span className="px-2 py-1 rounded-full text-xs font-medium bg-red-100 text-red-800">Nicht akzeptabel</span>
|
||||
default:
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
const calculatePhaseProgress = (phases: DSFAProject['phases']) => {
|
||||
const total = Object.keys(phases).length
|
||||
const completed = Object.values(phases).filter(Boolean).length
|
||||
return Math.round((completed / total) * 100)
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<PagePurpose
|
||||
title="Datenschutz-Folgenabschaetzung (DSFA)"
|
||||
purpose="Systematische Risikoanalyse fuer Verarbeitungen mit hohem Risiko gemaess Art. 35 DSGVO. Dokumentiert Risiken, Massnahmen und DSB-Freigaben."
|
||||
audience={['DSB', 'Projektleiter', 'Entwickler', 'Geschaeftsfuehrung']}
|
||||
gdprArticles={['Art. 35 (Datenschutz-Folgenabschaetzung)', 'Art. 36 (Vorherige Konsultation)']}
|
||||
architecture={{
|
||||
services: ['consent-service (Go)', 'backend (Python)'],
|
||||
databases: ['PostgreSQL'],
|
||||
}}
|
||||
relatedPages={[
|
||||
{ name: 'VVT', href: '/compliance/vvt', description: 'Verarbeitungsverzeichnis' },
|
||||
{ name: 'TOMs', href: '/compliance/tom', description: 'Technische Massnahmen' },
|
||||
{ name: 'DSMS', href: '/compliance/dsms', description: 'Datenschutz-Management-System' },
|
||||
]}
|
||||
collapsible={true}
|
||||
defaultCollapsed={true}
|
||||
/>
|
||||
|
||||
{/* Tabs */}
|
||||
<div className="bg-white rounded-xl border border-slate-200 p-4 mb-6">
|
||||
<div className="flex gap-2">
|
||||
{[
|
||||
{ id: 'overview', label: 'Uebersicht' },
|
||||
{ id: 'projects', label: 'DSFA-Projekte' },
|
||||
{ id: 'methodology', label: 'Methodik' },
|
||||
{ id: 'templates', label: 'Vorlagen' },
|
||||
].map(tab => (
|
||||
<button
|
||||
key={tab.id}
|
||||
onClick={() => setActiveTab(tab.id as typeof activeTab)}
|
||||
className={`px-4 py-2 rounded-lg text-sm font-medium transition-colors ${
|
||||
activeTab === tab.id
|
||||
? 'bg-purple-600 text-white'
|
||||
: 'bg-slate-100 text-slate-700 hover:bg-slate-200'
|
||||
}`}
|
||||
>
|
||||
{tab.label}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Overview Tab */}
|
||||
{activeTab === 'overview' && (
|
||||
<div className="space-y-6">
|
||||
{/* Statistics */}
|
||||
<div className="grid grid-cols-1 md:grid-cols-4 gap-4">
|
||||
<div className="bg-white rounded-xl border border-slate-200 p-4">
|
||||
<div className="text-2xl font-bold text-slate-900">{dsfaProjects.length}</div>
|
||||
<div className="text-sm text-slate-500">DSFA-Projekte</div>
|
||||
</div>
|
||||
<div className="bg-white rounded-xl border border-slate-200 p-4">
|
||||
<div className="text-2xl font-bold text-green-600">
|
||||
{dsfaProjects.filter(p => p.status === 'completed').length}
|
||||
</div>
|
||||
<div className="text-sm text-slate-500">Abgeschlossen</div>
|
||||
</div>
|
||||
<div className="bg-white rounded-xl border border-slate-200 p-4">
|
||||
<div className="text-2xl font-bold text-blue-600">
|
||||
{dsfaProjects.filter(p => p.status === 'in_progress').length}
|
||||
</div>
|
||||
<div className="text-sm text-slate-500">In Bearbeitung</div>
|
||||
</div>
|
||||
<div className="bg-white rounded-xl border border-slate-200 p-4">
|
||||
<div className="text-2xl font-bold text-orange-600">
|
||||
{dsfaProjects.filter(p => p.riskLevel === 'high' || p.riskLevel === 'critical').length}
|
||||
</div>
|
||||
<div className="text-sm text-slate-500">Hohes Risiko</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* When is DSFA required */}
|
||||
<div className="bg-white rounded-xl border border-slate-200 p-6">
|
||||
<h2 className="text-lg font-semibold text-slate-900 mb-4">Wann ist eine DSFA erforderlich?</h2>
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||
<div className="space-y-3">
|
||||
<h3 className="font-medium text-slate-700">Art. 35 Abs. 3 - Pflichtfaelle:</h3>
|
||||
<ul className="space-y-2 text-sm text-slate-600">
|
||||
<li className="flex items-start gap-2">
|
||||
<span className="text-red-500 mt-0.5">●</span>
|
||||
Systematische Bewertung persoenlicher Aspekte (Profiling)
|
||||
</li>
|
||||
<li className="flex items-start gap-2">
|
||||
<span className="text-red-500 mt-0.5">●</span>
|
||||
Umfangreiche Verarbeitung besonderer Kategorien (Art. 9)
|
||||
</li>
|
||||
<li className="flex items-start gap-2">
|
||||
<span className="text-red-500 mt-0.5">●</span>
|
||||
Systematische Ueberwachung oeffentlicher Bereiche
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div className="space-y-3">
|
||||
<h3 className="font-medium text-slate-700">Zusaetzliche Kriterien (DSK-Liste):</h3>
|
||||
<ul className="space-y-2 text-sm text-slate-600">
|
||||
<li className="flex items-start gap-2">
|
||||
<span className="text-orange-500 mt-0.5">●</span>
|
||||
Verarbeitung von Daten Minderjaehriger
|
||||
</li>
|
||||
<li className="flex items-start gap-2">
|
||||
<span className="text-orange-500 mt-0.5">●</span>
|
||||
Einsatz neuer Technologien (z.B. KI)
|
||||
</li>
|
||||
<li className="flex items-start gap-2">
|
||||
<span className="text-orange-500 mt-0.5">●</span>
|
||||
Zusammenfuehrung von Datensaetzen
|
||||
</li>
|
||||
<li className="flex items-start gap-2">
|
||||
<span className="text-orange-500 mt-0.5">●</span>
|
||||
Automatisierte Entscheidungsfindung
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Risk Matrix */}
|
||||
<div className="bg-white rounded-xl border border-slate-200 p-6">
|
||||
<h2 className="text-lg font-semibold text-slate-900 mb-4">Risiko-Matrix (KI-Verarbeitung)</h2>
|
||||
<div className="overflow-x-auto">
|
||||
<table className="w-full text-sm">
|
||||
<thead>
|
||||
<tr className="border-b border-slate-200">
|
||||
<th className="text-left py-3 px-4 font-medium text-slate-500">Kategorie</th>
|
||||
<th className="text-left py-3 px-4 font-medium text-slate-500">Risiko</th>
|
||||
<th className="text-left py-3 px-4 font-medium text-slate-500">Score</th>
|
||||
<th className="text-left py-3 px-4 font-medium text-slate-500">Massnahmen</th>
|
||||
<th className="text-left py-3 px-4 font-medium text-slate-500">Restrisiko</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{riskAssessments.map(risk => (
|
||||
<tr key={risk.id} className="border-b border-slate-100 hover:bg-slate-50">
|
||||
<td className="py-3 px-4 font-medium text-slate-900">{risk.category}</td>
|
||||
<td className="py-3 px-4 text-slate-600">{risk.risk}</td>
|
||||
<td className="py-3 px-4">
|
||||
<span className={`px-2 py-1 rounded text-xs font-medium ${
|
||||
risk.riskScore >= 12 ? 'bg-red-100 text-red-800' :
|
||||
risk.riskScore >= 6 ? 'bg-yellow-100 text-yellow-800' :
|
||||
'bg-green-100 text-green-800'
|
||||
}`}>
|
||||
{risk.riskScore}
|
||||
</span>
|
||||
</td>
|
||||
<td className="py-3 px-4">
|
||||
<ul className="text-xs text-slate-600 space-y-1">
|
||||
{risk.mitigations.slice(0, 2).map((m, i) => (
|
||||
<li key={i}>• {m}</li>
|
||||
))}
|
||||
{risk.mitigations.length > 2 && (
|
||||
<li className="text-slate-400">+{risk.mitigations.length - 2} weitere</li>
|
||||
)}
|
||||
</ul>
|
||||
</td>
|
||||
<td className="py-3 px-4">{getResidualRiskBadge(risk.residualRisk)}</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Projects Tab */}
|
||||
{activeTab === 'projects' && (
|
||||
<div className="space-y-4">
|
||||
<div className="bg-white rounded-xl border border-slate-200 p-4 flex items-center justify-between">
|
||||
<div>
|
||||
<h2 className="font-semibold text-slate-900">DSFA-Projekte</h2>
|
||||
<p className="text-sm text-slate-500">{dsfaProjects.length} dokumentierte Folgenabschaetzungen</p>
|
||||
</div>
|
||||
<button className="px-4 py-2 bg-purple-600 text-white rounded-lg text-sm font-medium hover:bg-purple-700">
|
||||
+ Neue DSFA
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{dsfaProjects.map(project => (
|
||||
<div key={project.id} className="bg-white rounded-xl border border-slate-200 overflow-hidden">
|
||||
<button
|
||||
onClick={() => setExpandedProject(expandedProject === project.id ? null : project.id)}
|
||||
className="w-full px-6 py-4 flex items-center justify-between hover:bg-slate-50 transition-colors"
|
||||
>
|
||||
<div className="flex items-center gap-4">
|
||||
<div className="text-left">
|
||||
<div className="flex items-center gap-3">
|
||||
<h3 className="font-semibold text-slate-900">{project.name}</h3>
|
||||
{getStatusBadge(project.status)}
|
||||
{getRiskBadge(project.riskLevel)}
|
||||
{project.dpoApproval && (
|
||||
<span className="px-2 py-1 rounded-full text-xs font-medium bg-green-100 text-green-800">
|
||||
DSB-Freigabe
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
<p className="text-sm text-slate-500 mt-1">{project.description}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex items-center gap-4">
|
||||
<div className="text-right text-sm text-slate-500">
|
||||
<div>{calculatePhaseProgress(project.phases)}% abgeschlossen</div>
|
||||
</div>
|
||||
<svg
|
||||
className={`w-5 h-5 text-slate-400 transition-transform ${expandedProject === project.id ? 'rotate-180' : ''}`}
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 9l-7 7-7-7" />
|
||||
</svg>
|
||||
</div>
|
||||
</button>
|
||||
|
||||
{expandedProject === project.id && (
|
||||
<div className="px-6 pb-6 border-t border-slate-100">
|
||||
<div className="mt-4 grid grid-cols-1 md:grid-cols-2 gap-6">
|
||||
{/* Phases */}
|
||||
<div>
|
||||
<h4 className="text-sm font-medium text-slate-500 mb-3">DSFA-Phasen</h4>
|
||||
<div className="space-y-2">
|
||||
{[
|
||||
{ key: 'description', label: 'Beschreibung der Verarbeitung' },
|
||||
{ key: 'necessity', label: 'Notwendigkeit & Verhaeltnismaessigkeit' },
|
||||
{ key: 'risks', label: 'Risikobewertung' },
|
||||
{ key: 'measures', label: 'Abhilfemassnahmen' },
|
||||
{ key: 'consultation', label: 'DSB-Konsultation' },
|
||||
].map(phase => (
|
||||
<div key={phase.key} className="flex items-center gap-3">
|
||||
<div className={`w-5 h-5 rounded-full flex items-center justify-center ${
|
||||
project.phases[phase.key as keyof typeof project.phases]
|
||||
? 'bg-green-100 text-green-600'
|
||||
: 'bg-slate-100 text-slate-400'
|
||||
}`}>
|
||||
{project.phases[phase.key as keyof typeof project.phases] ? (
|
||||
<svg className="w-3 h-3" fill="currentColor" viewBox="0 0 20 20">
|
||||
<path fillRule="evenodd" d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z" clipRule="evenodd" />
|
||||
</svg>
|
||||
) : (
|
||||
<span className="w-2 h-2 rounded-full bg-slate-300" />
|
||||
)}
|
||||
</div>
|
||||
<span className={project.phases[phase.key as keyof typeof project.phases] ? 'text-slate-900' : 'text-slate-500'}>
|
||||
{phase.label}
|
||||
</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Meta Info */}
|
||||
<div className="space-y-4">
|
||||
<div>
|
||||
<h4 className="text-sm font-medium text-slate-500 mb-1">Erstellt</h4>
|
||||
<p className="text-slate-700">{project.createdAt}</p>
|
||||
</div>
|
||||
<div>
|
||||
<h4 className="text-sm font-medium text-slate-500 mb-1">Letzte Aktualisierung</h4>
|
||||
<p className="text-slate-700">{project.lastUpdated}</p>
|
||||
</div>
|
||||
<div>
|
||||
<h4 className="text-sm font-medium text-slate-500 mb-1">DSB-Freigabe</h4>
|
||||
<p className={project.dpoApproval ? 'text-green-600 font-medium' : 'text-yellow-600'}>
|
||||
{project.dpoApproval ? 'Erteilt' : 'Ausstehend'}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="mt-4 pt-4 border-t border-slate-100 flex gap-2">
|
||||
<button className="px-3 py-1.5 text-sm text-purple-600 hover:text-purple-700 font-medium">
|
||||
Bearbeiten
|
||||
</button>
|
||||
<button className="px-3 py-1.5 text-sm text-slate-600 hover:text-slate-700">
|
||||
PDF exportieren
|
||||
</button>
|
||||
{!project.dpoApproval && (
|
||||
<button className="px-3 py-1.5 text-sm text-green-600 hover:text-green-700">
|
||||
Zur DSB-Freigabe einreichen
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Methodology Tab */}
|
||||
{activeTab === 'methodology' && (
|
||||
<div className="space-y-6">
|
||||
<div className="bg-white rounded-xl border border-slate-200 p-6">
|
||||
<h2 className="text-lg font-semibold text-slate-900 mb-4">DSFA-Prozess nach Art. 35 DSGVO</h2>
|
||||
|
||||
<div className="space-y-6">
|
||||
{[
|
||||
{
|
||||
step: 1,
|
||||
title: 'Schwellwertanalyse',
|
||||
description: 'Pruefung ob eine DSFA erforderlich ist anhand der Kriterien aus Art. 35 Abs. 3 und der DSK-Positivliste.',
|
||||
details: [
|
||||
'Verarbeitung besonderer Kategorien (Art. 9)?',
|
||||
'Systematisches Profiling?',
|
||||
'Neue Technologien im Einsatz?',
|
||||
'Daten von Minderjaehrigen?'
|
||||
]
|
||||
},
|
||||
{
|
||||
step: 2,
|
||||
title: 'Beschreibung der Verarbeitung',
|
||||
description: 'Systematische Beschreibung der geplanten Verarbeitungsvorgaenge und Zwecke.',
|
||||
details: [
|
||||
'Art, Umfang, Umstaende der Verarbeitung',
|
||||
'Zweck der Verarbeitung',
|
||||
'Betroffene Personengruppen',
|
||||
'Verantwortlichkeiten'
|
||||
]
|
||||
},
|
||||
{
|
||||
step: 3,
|
||||
title: 'Notwendigkeit & Verhaeltnismaessigkeit',
|
||||
description: 'Bewertung ob die Verarbeitung notwendig und verhaeltnismaessig ist.',
|
||||
details: [
|
||||
'Rechtsgrundlage vorhanden?',
|
||||
'Zweckbindung eingehalten?',
|
||||
'Datenminimierung beachtet?',
|
||||
'Speicherbegrenzung definiert?'
|
||||
]
|
||||
},
|
||||
{
|
||||
step: 4,
|
||||
title: 'Risikobewertung',
|
||||
description: 'Systematische Bewertung der Risiken fuer Rechte und Freiheiten der Betroffenen.',
|
||||
details: [
|
||||
'Risiken identifizieren',
|
||||
'Eintrittswahrscheinlichkeit bewerten',
|
||||
'Schwere der Auswirkungen bewerten',
|
||||
'Risiko-Score berechnen'
|
||||
]
|
||||
},
|
||||
{
|
||||
step: 5,
|
||||
title: 'Abhilfemassnahmen',
|
||||
description: 'Definition von Massnahmen zur Eindaemmung der identifizierten Risiken.',
|
||||
details: [
|
||||
'Technische Massnahmen (TOMs)',
|
||||
'Organisatorische Massnahmen',
|
||||
'Restrisiko-Bewertung',
|
||||
'Implementierungsplan'
|
||||
]
|
||||
},
|
||||
{
|
||||
step: 6,
|
||||
title: 'DSB-Konsultation',
|
||||
description: 'Einholung der Stellungnahme des Datenschutzbeauftragten.',
|
||||
details: [
|
||||
'DSFA dem DSB vorlegen',
|
||||
'Stellungnahme dokumentieren',
|
||||
'Ggf. Anpassungen vornehmen',
|
||||
'Freigabe erteilen'
|
||||
]
|
||||
},
|
||||
{
|
||||
step: 7,
|
||||
title: 'Vorherige Konsultation (Art. 36)',
|
||||
description: 'Bei verbleibendem hohen Risiko: Konsultation der Aufsichtsbehoerde.',
|
||||
details: [
|
||||
'Nur bei hohem Restrisiko erforderlich',
|
||||
'Aufsichtsbehoerde hat 8 Wochen zur Pruefung',
|
||||
'Dokumentation der Konsultation',
|
||||
'Umsetzung der Auflagen'
|
||||
]
|
||||
}
|
||||
].map(item => (
|
||||
<div key={item.step} className="flex gap-4">
|
||||
<div className="flex-shrink-0 w-8 h-8 rounded-full bg-purple-100 text-purple-700 flex items-center justify-center font-bold">
|
||||
{item.step}
|
||||
</div>
|
||||
<div className="flex-grow">
|
||||
<h3 className="font-semibold text-slate-900">{item.title}</h3>
|
||||
<p className="text-sm text-slate-600 mt-1">{item.description}</p>
|
||||
<ul className="mt-2 grid grid-cols-2 gap-x-4 gap-y-1 text-xs text-slate-500">
|
||||
{item.details.map((detail, idx) => (
|
||||
<li key={idx} className="flex items-center gap-1">
|
||||
<span className="text-purple-400">→</span> {detail}
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Templates Tab */}
|
||||
{activeTab === 'templates' && (
|
||||
<div className="space-y-4">
|
||||
<div className="bg-white rounded-xl border border-slate-200 p-6">
|
||||
<h2 className="text-lg font-semibold text-slate-900 mb-4">DSFA-Vorlagen</h2>
|
||||
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||
{[
|
||||
{
|
||||
name: 'Standard DSFA-Vorlage',
|
||||
description: 'Vollstaendige Vorlage nach Art. 35 DSGVO',
|
||||
format: 'DOCX',
|
||||
size: '45 KB'
|
||||
},
|
||||
{
|
||||
name: 'KI-Verarbeitung Template',
|
||||
description: 'Spezialvorlage fuer KI/ML-Anwendungen',
|
||||
format: 'DOCX',
|
||||
size: '52 KB'
|
||||
},
|
||||
{
|
||||
name: 'Risikobewertungs-Matrix',
|
||||
description: 'Excel-Vorlage fuer systematische Risikobewertung',
|
||||
format: 'XLSX',
|
||||
size: '28 KB'
|
||||
},
|
||||
{
|
||||
name: 'Schwellwert-Checkliste',
|
||||
description: 'Checkliste zur Pruefung ob DSFA erforderlich',
|
||||
format: 'PDF',
|
||||
size: '120 KB'
|
||||
},
|
||||
{
|
||||
name: 'DSB-Konsultationsformular',
|
||||
description: 'Formular zur internen DSB-Freigabe',
|
||||
format: 'DOCX',
|
||||
size: '32 KB'
|
||||
},
|
||||
{
|
||||
name: 'Aufsichtsbehoerden-Vorlage',
|
||||
description: 'Vorlage fuer Art. 36 Konsultation',
|
||||
format: 'DOCX',
|
||||
size: '38 KB'
|
||||
}
|
||||
].map(template => (
|
||||
<div key={template.name} className="p-4 border border-slate-200 rounded-lg hover:border-purple-300 transition-colors">
|
||||
<div className="flex items-start justify-between">
|
||||
<div>
|
||||
<h3 className="font-medium text-slate-900">{template.name}</h3>
|
||||
<p className="text-sm text-slate-500 mt-1">{template.description}</p>
|
||||
</div>
|
||||
<span className="px-2 py-1 bg-slate-100 text-slate-600 rounded text-xs font-medium">
|
||||
{template.format}
|
||||
</span>
|
||||
</div>
|
||||
<div className="mt-3 flex items-center justify-between">
|
||||
<span className="text-xs text-slate-400">{template.size}</span>
|
||||
<button className="text-sm text-purple-600 hover:text-purple-700 font-medium">
|
||||
Herunterladen
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Info */}
|
||||
<div className="mt-6 bg-yellow-50 border border-yellow-200 rounded-xl p-4">
|
||||
<div className="flex gap-3">
|
||||
<svg className="w-5 h-5 text-yellow-600 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>
|
||||
<div>
|
||||
<h4 className="font-semibold text-yellow-900">Wichtiger Hinweis</h4>
|
||||
<p className="text-sm text-yellow-800 mt-1">
|
||||
Eine DSFA ist <strong>vor</strong> Beginn der Verarbeitung durchzufuehren. Bei wesentlichen Aenderungen
|
||||
an bestehenden Verarbeitungen muss die DSFA aktualisiert werden. Die Dokumentation muss
|
||||
der Aufsichtsbehoerde auf Anfrage vorgelegt werden koennen.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user