Services: Admin-Lehrer, Backend-Lehrer, Studio v2, Website, Klausur-Service, School-Service, Voice-Service, Geo-Service, BreakPilot Drive, Agent-Core Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
317 lines
13 KiB
TypeScript
317 lines
13 KiB
TypeScript
'use client'
|
|
|
|
/**
|
|
* DSMS (Data Protection Management System) Admin Page
|
|
*
|
|
* Central hub for data protection compliance management
|
|
*/
|
|
|
|
import AdminLayout from '@/components/admin/AdminLayout'
|
|
import Link from 'next/link'
|
|
|
|
interface ComplianceModule {
|
|
id: string
|
|
title: string
|
|
description: string
|
|
status: 'active' | 'pending' | 'inactive'
|
|
href?: string
|
|
items: {
|
|
name: string
|
|
status: 'complete' | 'in_progress' | 'pending'
|
|
lastUpdated?: string
|
|
}[]
|
|
}
|
|
|
|
export default function DSMSPage() {
|
|
const modules: ComplianceModule[] = [
|
|
{
|
|
id: 'legal-docs',
|
|
title: 'Rechtliche Dokumente',
|
|
description: 'AGB, Datenschutzerklärung, Cookie-Richtlinie',
|
|
status: 'active',
|
|
href: '/admin/consent',
|
|
items: [
|
|
{ name: 'AGB', status: 'complete', lastUpdated: '2024-12-01' },
|
|
{ name: 'Datenschutzerklärung', status: 'complete', lastUpdated: '2024-12-01' },
|
|
{ name: 'Cookie-Richtlinie', status: 'complete', lastUpdated: '2024-12-01' },
|
|
{ name: 'Impressum', status: 'complete', lastUpdated: '2024-12-01' },
|
|
],
|
|
},
|
|
{
|
|
id: 'dsr',
|
|
title: 'Betroffenenanfragen (DSR)',
|
|
description: 'Art. 15-21 DSGVO Anfragen-Management',
|
|
status: 'active',
|
|
href: '/admin/dsr',
|
|
items: [
|
|
{ name: 'Auskunftsprozess (Art. 15)', status: 'complete' },
|
|
{ name: 'Berichtigung (Art. 16)', status: 'complete' },
|
|
{ name: 'Löschung (Art. 17)', status: 'complete' },
|
|
{ name: 'Datenübertragbarkeit (Art. 20)', status: 'complete' },
|
|
],
|
|
},
|
|
{
|
|
id: 'consent',
|
|
title: 'Einwilligungsverwaltung',
|
|
description: 'Consent-Tracking und -Nachweis',
|
|
status: 'active',
|
|
href: '/admin/consent',
|
|
items: [
|
|
{ name: 'Consent-Datenbank', status: 'complete' },
|
|
{ name: 'Widerrufsprozess', status: 'complete' },
|
|
{ name: 'Audit-Trail', status: 'complete' },
|
|
{ name: 'Export-Funktion', status: 'complete' },
|
|
],
|
|
},
|
|
{
|
|
id: 'tom',
|
|
title: 'Technische & Organisatorische Maßnahmen',
|
|
description: 'Art. 32 DSGVO Sicherheitsmaßnahmen',
|
|
status: 'active',
|
|
items: [
|
|
{ name: 'Verschlüsselung (TLS/Ruhe)', status: 'complete' },
|
|
{ name: 'Zugriffskontrolle', status: 'complete' },
|
|
{ name: 'Backup & Recovery', status: 'in_progress' },
|
|
{ name: 'Logging & Monitoring', status: 'complete' },
|
|
],
|
|
},
|
|
{
|
|
id: 'vvt',
|
|
title: 'Verarbeitungsverzeichnis',
|
|
description: 'Art. 30 DSGVO Dokumentation',
|
|
status: 'pending',
|
|
items: [
|
|
{ name: 'Verarbeitungstätigkeiten', status: 'pending' },
|
|
{ name: 'Rechtsgrundlagen', status: 'pending' },
|
|
{ name: 'Löschfristen', status: 'in_progress' },
|
|
{ name: 'Auftragsverarbeiter', status: 'pending' },
|
|
],
|
|
},
|
|
{
|
|
id: 'dpia',
|
|
title: 'Datenschutz-Folgenabschätzung',
|
|
description: 'Art. 35 DSGVO Risikoanalyse',
|
|
status: 'pending',
|
|
items: [
|
|
{ name: 'KI-Verarbeitung', status: 'pending' },
|
|
{ name: 'Profiling-Risiken', status: 'pending' },
|
|
{ name: 'Automatisierte Entscheidungen', status: 'pending' },
|
|
],
|
|
},
|
|
]
|
|
|
|
// Get status badge
|
|
const getStatusBadge = (status: string) => {
|
|
switch (status) {
|
|
case 'active':
|
|
case 'complete':
|
|
return <span className="px-2 py-1 rounded-full text-xs font-medium bg-green-100 text-green-800">Aktiv</span>
|
|
case 'in_progress':
|
|
return <span className="px-2 py-1 rounded-full text-xs font-medium bg-yellow-100 text-yellow-800">In Arbeit</span>
|
|
case 'pending':
|
|
case 'inactive':
|
|
return <span className="px-2 py-1 rounded-full text-xs font-medium bg-slate-100 text-slate-600">Ausstehend</span>
|
|
default:
|
|
return null
|
|
}
|
|
}
|
|
|
|
// Calculate overall compliance score
|
|
const calculateScore = () => {
|
|
let complete = 0
|
|
let total = 0
|
|
modules.forEach((m) => {
|
|
m.items.forEach((item) => {
|
|
total++
|
|
if (item.status === 'complete') complete++
|
|
})
|
|
})
|
|
return Math.round((complete / total) * 100)
|
|
}
|
|
|
|
const complianceScore = calculateScore()
|
|
|
|
return (
|
|
<AdminLayout title="DSMS" description="Datenschutz-Management-System">
|
|
{/* Compliance Score */}
|
|
<div className="bg-white rounded-xl border border-slate-200 p-6 mb-6">
|
|
<div className="flex items-center justify-between">
|
|
<div>
|
|
<h2 className="text-lg font-semibold text-slate-900">DSGVO-Compliance Score</h2>
|
|
<p className="text-sm text-slate-500 mt-1">Gesamtfortschritt der Datenschutz-Maßnahmen</p>
|
|
</div>
|
|
<div className="text-right">
|
|
<div className={`text-4xl font-bold ${complianceScore >= 80 ? 'text-green-600' : complianceScore >= 50 ? 'text-yellow-600' : 'text-red-600'}`}>
|
|
{complianceScore}%
|
|
</div>
|
|
<div className="text-sm text-slate-500">Compliance</div>
|
|
</div>
|
|
</div>
|
|
<div className="mt-4 h-3 bg-slate-100 rounded-full overflow-hidden">
|
|
<div
|
|
className={`h-full transition-all ${complianceScore >= 80 ? 'bg-green-500' : complianceScore >= 50 ? 'bg-yellow-500' : 'bg-red-500'}`}
|
|
style={{ width: `${complianceScore}%` }}
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Quick Actions */}
|
|
<div className="grid grid-cols-1 md:grid-cols-4 gap-4 mb-6">
|
|
<Link
|
|
href="/admin/dsr"
|
|
className="bg-white rounded-xl border border-slate-200 p-4 hover:border-primary-300 transition-colors"
|
|
>
|
|
<div className="flex items-center gap-3">
|
|
<div className="w-10 h-10 rounded-lg bg-orange-100 flex items-center justify-center">
|
|
<svg className="w-5 h-5 text-orange-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 15v2m-6 4h12a2 2 0 002-2v-6a2 2 0 00-2-2H6a2 2 0 00-2 2v6a2 2 0 002 2zm10-10V7a4 4 0 00-8 0v4h8z" />
|
|
</svg>
|
|
</div>
|
|
<div>
|
|
<div className="font-medium text-slate-900">DSR bearbeiten</div>
|
|
<div className="text-xs text-slate-500">Anfragen verwalten</div>
|
|
</div>
|
|
</div>
|
|
</Link>
|
|
|
|
<Link
|
|
href="/admin/consent"
|
|
className="bg-white rounded-xl border border-slate-200 p-4 hover:border-primary-300 transition-colors"
|
|
>
|
|
<div className="flex items-center gap-3">
|
|
<div className="w-10 h-10 rounded-lg bg-green-100 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="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z" />
|
|
</svg>
|
|
</div>
|
|
<div>
|
|
<div className="font-medium text-slate-900">Consents</div>
|
|
<div className="text-xs text-slate-500">Einwilligungen prüfen</div>
|
|
</div>
|
|
</div>
|
|
</Link>
|
|
|
|
<button className="bg-white rounded-xl border border-slate-200 p-4 hover:border-primary-300 transition-colors text-left">
|
|
<div className="flex items-center gap-3">
|
|
<div className="w-10 h-10 rounded-lg bg-blue-100 flex items-center justify-center">
|
|
<svg className="w-5 h-5 text-blue-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 17v-2m3 2v-4m3 4v-6m2 10H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z" />
|
|
</svg>
|
|
</div>
|
|
<div>
|
|
<div className="font-medium text-slate-900">Audit-Report</div>
|
|
<div className="text-xs text-slate-500">PDF generieren</div>
|
|
</div>
|
|
</div>
|
|
</button>
|
|
|
|
<button className="bg-white rounded-xl border border-slate-200 p-4 hover:border-primary-300 transition-colors text-left">
|
|
<div className="flex items-center gap-3">
|
|
<div className="w-10 h-10 rounded-lg bg-purple-100 flex items-center justify-center">
|
|
<svg className="w-5 h-5 text-purple-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z" />
|
|
</svg>
|
|
</div>
|
|
<div>
|
|
<div className="font-medium text-slate-900">Löschfristen</div>
|
|
<div className="text-xs text-slate-500">Prüfen & durchführen</div>
|
|
</div>
|
|
</div>
|
|
</button>
|
|
</div>
|
|
|
|
{/* Compliance Modules */}
|
|
<h2 className="text-lg font-semibold text-slate-900 mb-4">Compliance-Module</h2>
|
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
|
|
{modules.map((module) => (
|
|
<div key={module.id} className="bg-white rounded-xl border border-slate-200">
|
|
<div className="px-4 py-3 border-b border-slate-100 flex items-center justify-between">
|
|
<div>
|
|
<h3 className="font-semibold text-slate-900">{module.title}</h3>
|
|
<p className="text-xs text-slate-500">{module.description}</p>
|
|
</div>
|
|
{getStatusBadge(module.status)}
|
|
</div>
|
|
<div className="p-4">
|
|
<ul className="space-y-2">
|
|
{module.items.map((item, idx) => (
|
|
<li key={idx} className="flex items-center justify-between text-sm">
|
|
<div className="flex items-center gap-2">
|
|
{item.status === 'complete' ? (
|
|
<svg className="w-4 h-4 text-green-500" fill="currentColor" viewBox="0 0 20 20">
|
|
<path fillRule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z" clipRule="evenodd" />
|
|
</svg>
|
|
) : item.status === 'in_progress' ? (
|
|
<svg className="w-4 h-4 text-yellow-500" fill="currentColor" viewBox="0 0 20 20">
|
|
<path fillRule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm1-12a1 1 0 10-2 0v4a1 1 0 00.293.707l2.828 2.829a1 1 0 101.415-1.415L11 9.586V6z" clipRule="evenodd" />
|
|
</svg>
|
|
) : (
|
|
<svg className="w-4 h-4 text-slate-300" fill="currentColor" viewBox="0 0 20 20">
|
|
<path fillRule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zM7 9a1 1 0 000 2h6a1 1 0 100-2H7z" clipRule="evenodd" />
|
|
</svg>
|
|
)}
|
|
<span className={item.status === 'pending' ? 'text-slate-400' : 'text-slate-700'}>
|
|
{item.name}
|
|
</span>
|
|
</div>
|
|
{item.lastUpdated && (
|
|
<span className="text-xs text-slate-400">{item.lastUpdated}</span>
|
|
)}
|
|
</li>
|
|
))}
|
|
</ul>
|
|
{module.href && (
|
|
<Link
|
|
href={module.href}
|
|
className="mt-3 block text-center py-2 text-sm text-primary-600 hover:text-primary-700 font-medium"
|
|
>
|
|
Verwalten →
|
|
</Link>
|
|
)}
|
|
</div>
|
|
</div>
|
|
))}
|
|
</div>
|
|
|
|
{/* GDPR Rights Overview */}
|
|
<div className="mt-6 bg-slate-50 rounded-xl p-6">
|
|
<h3 className="font-semibold text-slate-900 mb-4">DSGVO Betroffenenrechte (Art. 12-22)</h3>
|
|
<div className="grid grid-cols-2 md:grid-cols-4 gap-4 text-sm">
|
|
<div>
|
|
<div className="font-medium text-slate-700">Art. 15</div>
|
|
<div className="text-slate-500">Auskunftsrecht</div>
|
|
</div>
|
|
<div>
|
|
<div className="font-medium text-slate-700">Art. 16</div>
|
|
<div className="text-slate-500">Recht auf Berichtigung</div>
|
|
</div>
|
|
<div>
|
|
<div className="font-medium text-slate-700">Art. 17</div>
|
|
<div className="text-slate-500">Recht auf Löschung</div>
|
|
</div>
|
|
<div>
|
|
<div className="font-medium text-slate-700">Art. 18</div>
|
|
<div className="text-slate-500">Recht auf Einschränkung</div>
|
|
</div>
|
|
<div>
|
|
<div className="font-medium text-slate-700">Art. 19</div>
|
|
<div className="text-slate-500">Mitteilungspflicht</div>
|
|
</div>
|
|
<div>
|
|
<div className="font-medium text-slate-700">Art. 20</div>
|
|
<div className="text-slate-500">Datenübertragbarkeit</div>
|
|
</div>
|
|
<div>
|
|
<div className="font-medium text-slate-700">Art. 21</div>
|
|
<div className="text-slate-500">Widerspruchsrecht</div>
|
|
</div>
|
|
<div>
|
|
<div className="font-medium text-slate-700">Art. 22</div>
|
|
<div className="text-slate-500">Automatisierte Entscheidungen</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</AdminLayout>
|
|
)
|
|
}
|