'use client' /** * VVT - Verarbeitungsverzeichnis * * Art. 30 DSGVO - Verzeichnis von Verarbeitungstaetigkeiten * Integriert mit AI Compliance SDK */ import { useState, useEffect } from 'react' import { PagePurpose } from '@/components/common/PagePurpose' interface ProcessingActivity { id: string tenant_id: string name: string description: string purpose: string legal_basis: string legal_basis_details: string data_categories: string[] data_subject_categories: string[] recipients: string[] third_country_transfer: boolean transfer_safeguards: string retention_period: string dsfa_required: boolean responsible_person: string responsible_department: string systems: string[] status: string created_at: string updated_at: string } const LEGAL_BASES = [ { value: 'consent', label: 'Art. 6 Abs. 1 lit. a - Einwilligung' }, { value: 'contract', label: 'Art. 6 Abs. 1 lit. b - Vertragserfüllung' }, { value: 'legal_obligation', label: 'Art. 6 Abs. 1 lit. c - Rechtliche Verpflichtung' }, { value: 'vital_interests', label: 'Art. 6 Abs. 1 lit. d - Lebenswichtige Interessen' }, { value: 'public_interest', label: 'Art. 6 Abs. 1 lit. e - Öffentliches Interesse' }, { value: 'legitimate_interests', label: 'Art. 6 Abs. 1 lit. f - Berechtigtes Interesse' }, ] export default function VVTPage() { const [activities, setActivities] = useState([]) const [loading, setLoading] = useState(true) const [error, setError] = useState(null) const [expandedActivity, setExpandedActivity] = useState(null) const [filterStatus, setFilterStatus] = useState('all') const [showCreateModal, setShowCreateModal] = useState(false) const [newActivity, setNewActivity] = useState>({ name: '', purpose: '', legal_basis: 'contract', legal_basis_details: '', data_categories: [], data_subject_categories: [], recipients: [], third_country_transfer: false, retention_period: '', responsible_person: '', responsible_department: '', systems: [], status: 'draft', }) useEffect(() => { loadActivities() }, []) async function loadActivities() { setLoading(true) setError(null) try { const res = await fetch('/sdk/v1/dsgvo/processing-activities', { headers: { 'X-Tenant-ID': localStorage.getItem('bp_tenant_id') || '', 'X-User-ID': localStorage.getItem('bp_user_id') || '', } }) if (res.ok) { const data = await res.json() setActivities(data.processing_activities || []) } else { const errorData = await res.json().catch(() => ({})) setError(errorData.error || 'Fehler beim Laden') } } catch (err) { setError('Verbindungsfehler zum SDK') } finally { setLoading(false) } } async function createActivity() { try { const res = await fetch('/sdk/v1/dsgvo/processing-activities', { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-Tenant-ID': localStorage.getItem('bp_tenant_id') || '', 'X-User-ID': localStorage.getItem('bp_user_id') || '', }, body: JSON.stringify(newActivity), }) if (res.ok) { setShowCreateModal(false) setNewActivity({ name: '', purpose: '', legal_basis: 'contract', data_categories: [], status: 'draft', }) loadActivities() } else { const errorData = await res.json().catch(() => ({})) alert(errorData.error || 'Fehler beim Erstellen') } } catch (err) { alert('Verbindungsfehler') } } async function deleteActivity(id: string) { if (!confirm('Verarbeitungstätigkeit wirklich löschen?')) return try { const res = await fetch(`/sdk/v1/dsgvo/processing-activities/${id}`, { method: 'DELETE', headers: { 'X-Tenant-ID': localStorage.getItem('bp_tenant_id') || '', 'X-User-ID': localStorage.getItem('bp_user_id') || '', }, }) if (res.ok) { loadActivities() } } catch (err) { alert('Fehler beim Löschen') } } async function exportVVT(format: 'csv' | 'json') { window.open(`/sdk/v1/dsgvo/export/vvt?format=${format}`, '_blank') } const getStatusBadge = (status: string) => { switch (status) { case 'active': return Aktiv case 'draft': return Entwurf case 'under_review': return In Prüfung case 'archived': return Archiviert default: return {status} } } const getLegalBasisLabel = (value: string) => { const basis = LEGAL_BASES.find(b => b.value === value) return basis?.label || value } const filteredActivities = filterStatus === 'all' ? activities : activities.filter(a => a.status === filterStatus) return (
{/* Header */}

Verarbeitungstätigkeiten

{activities.length} dokumentierte Tätigkeiten

{/* Filter */}
{[ { value: 'all', label: 'Alle' }, { value: 'active', label: 'Aktiv' }, { value: 'draft', label: 'Entwurf' }, { value: 'under_review', label: 'In Prüfung' }, { value: 'archived', label: 'Archiviert' }, ].map(filter => ( ))}
{/* Loading / Error */} {loading && (

Lade Verarbeitungstätigkeiten...

)} {error && (

{error}

)} {/* Activities List */} {!loading && !error && (
{filteredActivities.length === 0 ? (

Keine Verarbeitungstätigkeiten gefunden.

) : ( filteredActivities.map((activity) => (
{expandedActivity === activity.id && (
{/* Left Column */}

Rechtsgrundlage

{getLegalBasisLabel(activity.legal_basis)}

{activity.legal_basis_details && (

{activity.legal_basis_details}

)}

Datenkategorien

{(activity.data_categories || []).map((cat, idx) => ( {cat} ))} {(!activity.data_categories || activity.data_categories.length === 0) && ( Keine angegeben )}

Betroffene Kategorien

{(activity.data_subject_categories || []).map((cat, idx) => ( {cat} ))} {(!activity.data_subject_categories || activity.data_subject_categories.length === 0) && ( Keine angegeben )}

Empfänger

{activity.recipients && activity.recipients.length > 0 ? (
    {activity.recipients.map((rec, idx) => (
  • {rec}
  • ))}
) : ( Keine externen Empfänger )}
{/* Right Column */}

Löschfrist

{activity.retention_period || 'Nicht definiert'}

{activity.third_country_transfer && activity.transfer_safeguards && (

Drittland-Schutzmaßnahmen

{activity.transfer_safeguards}

)}

Verantwortlich

{activity.responsible_person || 'k.A.'} {activity.responsible_department && ` (${activity.responsible_department})`}

Systeme

{(activity.systems || []).map((sys, idx) => ( {sys} ))} {(!activity.systems || activity.systems.length === 0) && ( Keine angegeben )}

Erstellt / Aktualisiert

{new Date(activity.created_at).toLocaleDateString('de-DE')} / {new Date(activity.updated_at).toLocaleDateString('de-DE')}

)}
)) )}
)} {/* Create Modal */} {showCreateModal && (

Neue Verarbeitungstätigkeit

setNewActivity({ ...newActivity, name: e.target.value })} className="w-full px-3 py-2 border border-slate-300 rounded-lg text-sm" placeholder="z.B. Benutzerverwaltung" />