refactor(admin): split lib document generators and data catalogs into domain barrels

obligations-document, tom-document, loeschfristen-document, compliance-scope-triggers,
sdk-flow/flow-data, processing-activities, loeschfristen-baseline-catalog,
catalog-registry, dsfa mitigation-library + risk-catalog, vvt-baseline-catalog,
vendor contract-review checklists + findings, demo-data, tom-compliance.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Sharang Parnerkar
2026-04-18 00:07:03 +02:00
parent b00fe6cb73
commit 91063f09b8
65 changed files with 9514 additions and 9544 deletions

View File

@@ -1,897 +1,28 @@
/** /**
* SDK Flow Visualization - Step-Definitionen mit Datenfluss * SDK Flow Visualization - Step-Definitionen mit Datenfluss
* * Barrel re-export — implementation split into sdk-flow/ subdirectory files
* Beschreibt alle SDK-Steps mit:
* - Inputs/Outputs (SDKState-Properties)
* - DB-Tabellen und Modus
* - RAG-Collections und Verwendungszweck
* - Checkpoint-Informationen
* - Detaillierte Beschreibungen
*/ */
export interface SDKFlowStep { export type { SDKFlowStep } from './types'
id: string export { FLOW_PACKAGES } from './types'
name: string
nameShort: string
package: 'vorbereitung' | 'analyse' | 'dokumentation' | 'rechtliche-texte' | 'betrieb'
seq: number
checkpointId?: string
checkpointType?: 'REQUIRED' | 'RECOMMENDED'
checkpointReviewer?: 'NONE' | 'DSB' | 'LEGAL'
// Beschreibung export { STEPS_VORBEREITUNG } from './steps-vorbereitung'
description: string export { STEPS_ANALYSE } from './steps-analyse'
descriptionLong: string export { STEPS_DOKUMENTATION, STEPS_RECHTLICHE_TEXTE } from './steps-dokumentation'
legalBasis?: string export { STEPS_BETRIEB } from './steps-betrieb'
// Datenfluss import { STEPS_VORBEREITUNG } from './steps-vorbereitung'
inputs: string[] import { STEPS_ANALYSE } from './steps-analyse'
outputs: string[] import { STEPS_DOKUMENTATION, STEPS_RECHTLICHE_TEXTE } from './steps-dokumentation'
prerequisiteSteps: string[] import { STEPS_BETRIEB } from './steps-betrieb'
import type { SDKFlowStep } from './types'
// Infrastruktur
dbTables: string[]
dbMode: 'read' | 'write' | 'read/write' | 'none'
ragCollections: string[]
ragPurpose?: string
// Generierung
generates?: string[]
isOptional?: boolean
url: string
/**
* Fertigstellungsgrad in Prozent (0100).
* Nur für Betrieb-Module gesetzt (außer academy/training).
* Berechnung: Frontend-Reifegrad + Backend-Persistenz + API-Abdeckung.
*/
completion?: number
}
// =============================================================================
// PACKAGE METADATA
// =============================================================================
export const FLOW_PACKAGES = {
vorbereitung: {
name: 'Vorbereitung',
nameShort: 'Vorb.',
icon: '🎯',
color: { bg: '#dbeafe', border: '#3b82f6', text: '#1e40af' },
},
analyse: {
name: 'Analyse',
nameShort: 'Analyse',
icon: '🔍',
color: { bg: '#fef3c7', border: '#f59e0b', text: '#92400e' },
},
dokumentation: {
name: 'Dokumentation',
nameShort: 'Doku',
icon: '📋',
color: { bg: '#ede9fe', border: '#7c3aed', text: '#5b21b6' },
},
'rechtliche-texte': {
name: 'Rechtliche Texte',
nameShort: 'Legal',
icon: '📝',
color: { bg: '#d1fae5', border: '#10b981', text: '#065f46' },
},
betrieb: {
name: 'Betrieb',
nameShort: 'Betrieb',
icon: '⚙️',
color: { bg: '#f1f5f9', border: '#64748b', text: '#334155' },
},
} as const
// =============================================================================
// ALL SDK FLOW STEPS
// =============================================================================
export const SDK_FLOW_STEPS: SDKFlowStep[] = [ export const SDK_FLOW_STEPS: SDKFlowStep[] = [
// ========================================================================= ...STEPS_VORBEREITUNG,
// PAKET 1: VORBEREITUNG (seq 100-700) ...STEPS_ANALYSE,
// ========================================================================= ...STEPS_DOKUMENTATION,
{ ...STEPS_RECHTLICHE_TEXTE,
id: 'company-profile', ...STEPS_BETRIEB,
name: 'Unternehmensprofil',
nameShort: 'Profil',
package: 'vorbereitung',
seq: 100,
checkpointId: 'CP-PROF',
checkpointType: 'REQUIRED',
checkpointReviewer: 'NONE',
description: 'Erfassung aller Stammdaten des Unternehmens als Grundlage fuer die Compliance-Analyse.',
descriptionLong: 'Hier werden alle relevanten Unternehmensdaten erfasst: Firmenname, Rechtsform, Branche, Mitarbeiterzahl, Standorte, Datenschutzbeauftragter und Verantwortlicher. Diese Daten bilden die Basis fuer alle nachfolgenden Compliance-Schritte, da sie bestimmen, welche Regulierungen anwendbar sind (z.B. DSGVO, NIS2, AI Act). Nach Abschluss zeigt eine Summary-Seite alle erfassten Daten auf einen Blick. Ohne ein vollstaendiges Unternehmensprofil koennen keine weiteren Schritte durchgefuehrt werden.',
inputs: [],
outputs: ['companyProfile', 'complianceScope'],
prerequisiteSteps: [],
dbTables: ['sdk_states', 'compliance_company_profiles', 'compliance_company_profile_audit'],
dbMode: 'read/write',
ragCollections: [],
isOptional: false,
url: '/sdk/company-profile',
},
{
id: 'compliance-scope',
name: 'Compliance Scope',
nameShort: 'Scope',
package: 'vorbereitung',
seq: 200,
checkpointId: 'CP-SCOPE',
checkpointType: 'REQUIRED',
checkpointReviewer: 'NONE',
description: 'Bestimmung der Compliance-Tiefe und des Umfangs basierend auf Unternehmensprofil.',
descriptionLong: 'Basierend auf dem Unternehmensprofil wird automatisch ermittelt, wie tiefgehend die Compliance-Analyse sein muss. Kleine Unternehmen mit wenig Datenverarbeitung erhalten eine "BASIS"-Tiefe, waehrend grosse Unternehmen mit sensiblen Daten oder KI-Systemen eine "ERWEITERT" oder "VOLLSTAENDIG"-Tiefe erhalten. Der Compliance-Scope bestimmt, welche Module aktiviert werden und wie detailliert die Dokumentation sein muss. Zusaetzlich werden anwendbare Regulierungen (DSGVO, AI Act, NIS2 etc.) und zustaendige Aufsichtsbehoerden automatisch abgeleitet.',
inputs: ['companyProfile'],
outputs: ['complianceDepthLevel', 'applicableRegulations', 'supervisoryAuthorities'],
prerequisiteSteps: ['company-profile'],
dbTables: ['sdk_states'],
dbMode: 'read/write',
ragCollections: [],
isOptional: false,
url: '/sdk/compliance-scope',
},
{
id: 'use-case-assessment',
name: 'Anwendungsfall-Erfassung',
nameShort: 'Anwendung',
package: 'vorbereitung',
seq: 300,
checkpointId: 'CP-UC',
checkpointType: 'REQUIRED',
checkpointReviewer: 'NONE',
description: 'Systematische Erfassung aller Datenverarbeitungs- und KI-Anwendungsfaelle ueber einen 8-Schritte-Wizard mit Kachel-Auswahl.',
descriptionLong: 'In einem 8-Schritte-Wizard werden alle Use Cases erfasst: (1) Grundlegendes — Titel, Beschreibung, KI-Kategorie (21 Kacheln), Branche wird automatisch aus dem Profil abgeleitet. (2) Datenkategorien — ~60 Kategorien in 10 Gruppen als Kacheln (inkl. Art. 9 hervorgehoben). (3) Verarbeitungszweck — 16 Zweck-Kacheln, Rechtsgrundlage wird vom SDK automatisch ermittelt. (4) Automatisierungsgrad — assistiv/teilautomatisiert/vollautomatisiert. (5) Hosting & Modell — Provider, Region, Modellnutzung (Inferenz/RAG/Fine-Tuning/Training). (6) Datentransfer — Transferziele und Schutzmechanismen. (7) Datenhaltung — Aufbewahrungsfristen. (8) Vertraege — vorhandene Compliance-Dokumente. Die RAG-Collection bp_compliance_ce wird verwendet, um relevante CE-Regulierungen automatisch den Use Cases zuzuordnen (UCCA).',
legalBasis: 'Art. 30 DSGVO (Verzeichnis von Verarbeitungstaetigkeiten)',
inputs: ['companyProfile'],
outputs: ['useCases'],
prerequisiteSteps: ['company-profile'],
dbTables: ['ucca_assessments', 'ucca_findings', 'ucca_controls'],
dbMode: 'read/write',
ragCollections: ['bp_compliance_ce'],
ragPurpose: 'CE-Regulierungen fuer Use-Case Matching',
isOptional: false,
url: '/sdk/use-cases',
},
{
id: 'import',
name: 'Dokument-Import',
nameShort: 'Import',
package: 'vorbereitung',
seq: 400,
description: 'Import bestehender Compliance-Dokumente (Datenschutzerklaerungen, TOMs, VVTs).',
descriptionLong: 'Optionaler Schritt zum Import bereits vorhandener Compliance-Dokumente. Der Document Crawler analysiert hochgeladene PDFs, Word-Dokumente oder bestehende Datenschutzerklaerungen und extrahiert automatisch relevante Informationen wie bestehende TOMs, Verarbeitungsverzeichnisse oder Risikoanalysen. Diese importierten Daten werden als Grundlage fuer die nachfolgenden Schritte verwendet, damit nicht alles von Null aufgebaut werden muss.',
inputs: ['useCases'],
outputs: ['importedDocuments'],
prerequisiteSteps: ['use-case-assessment'],
dbTables: ['compliance_imported_documents', 'compliance_gap_analyses'],
dbMode: 'read/write',
ragCollections: [],
isOptional: true,
url: '/sdk/import',
},
{
id: 'screening',
name: 'System Screening',
nameShort: 'Screening',
package: 'vorbereitung',
seq: 500,
checkpointId: 'CP-SCAN',
checkpointType: 'REQUIRED',
checkpointReviewer: 'NONE',
description: 'Technische Analyse der eingesetzten Software, Dienste und deren Abhaengigkeiten.',
descriptionLong: 'Das System Screening analysiert die technische Infrastruktur des Unternehmens. Es werden alle eingesetzten Software-Systeme, Cloud-Dienste, APIs und deren Abhaengigkeiten erfasst. Dabei wird auch eine SBOM (Software Bill of Materials) erstellt, die alle Drittanbieter-Komponenten und deren Lizenzen dokumentiert. Das Screening identifiziert potenzielle Compliance-Risiken wie Datentransfers in Drittlaender, unsichere Abhaengigkeiten oder fehlende Verschluesselung.',
inputs: ['useCases'],
outputs: ['screening', 'sbom'],
prerequisiteSteps: ['use-case-assessment'],
dbTables: ['compliance_screenings', 'compliance_security_issues'],
dbMode: 'read/write',
ragCollections: [],
isOptional: false,
url: '/sdk/screening',
},
{
id: 'modules',
name: 'Compliance Modules',
nameShort: 'Module',
package: 'vorbereitung',
seq: 600,
checkpointId: 'CP-MOD',
checkpointType: 'REQUIRED',
checkpointReviewer: 'NONE',
description: 'Aktivierung der relevanten Compliance-Module basierend auf Screening-Ergebnissen.',
descriptionLong: 'Basierend auf dem Unternehmensprofil und den Screening-Ergebnissen werden die relevanten Compliance-Module aktiviert. Module umfassen z.B. DSGVO-Grundschutz, AI Act, NIS2, ePrivacy, Whistleblower-Richtlinie usw. Die RAG-Collection bp_compliance_gesetze wird verwendet, um aktuelle Gesetzestexte den Modulen zuzuordnen. Nur aktivierte Module erzeugen in den nachfolgenden Schritten Anforderungen, Controls und Dokumentation.',
inputs: ['companyProfile', 'screening'],
outputs: ['modules'],
prerequisiteSteps: ['screening'],
dbTables: ['compliance_service_modules', 'sdk_states'],
dbMode: 'read/write',
ragCollections: ['bp_compliance_gesetze'],
ragPurpose: 'Regulierungen den Modulen zuordnen',
isOptional: false,
url: '/sdk/modules',
},
{
id: 'source-policy',
name: 'Source Policy',
nameShort: 'Quellen',
package: 'vorbereitung',
seq: 700,
checkpointId: 'CP-SPOL',
checkpointType: 'REQUIRED',
checkpointReviewer: 'NONE',
description: 'Festlegung der Rechtsquellen und Normen fuer die Compliance-Analyse.',
descriptionLong: 'Die Source Policy definiert, welche Rechtsquellen und Normen fuer die Compliance-Analyse herangezogen werden. Dies umfasst EU-Verordnungen (DSGVO, AI Act, NIS2), nationale Gesetze (BDSG, TTDSG), Branchenstandards (ISO 27001, BSI Grundschutz) und interne Richtlinien. Die Source Policy stellt sicher, dass alle nachfolgenden Schritte konsistent auf denselben Rechtsgrundlagen basieren.',
inputs: ['modules'],
outputs: ['sourcePolicy'],
prerequisiteSteps: ['modules'],
dbTables: ['compliance_allowed_sources', 'compliance_pii_rules', 'compliance_source_operations', 'compliance_source_policy_audit'],
dbMode: 'read/write',
ragCollections: [],
isOptional: false,
url: '/sdk/source-policy',
},
// =========================================================================
// PAKET 2: ANALYSE (seq 1000-1600)
// =========================================================================
{
id: 'requirements',
name: 'Requirements',
nameShort: 'Anforderungen',
package: 'analyse',
seq: 1000,
checkpointId: 'CP-REQ',
checkpointType: 'REQUIRED',
checkpointReviewer: 'NONE',
description: 'Ableitung konkreter Compliance-Anforderungen aus den aktivierten Modulen, mit RAG-Anreicherung.',
descriptionLong: 'Aus den aktivierten Modulen und der Source Policy werden konkrete, umsetzbare Compliance-Anforderungen abgeleitet. Vollstaendige CRUD-Operationen (Erstellen, Lesen, Aktualisieren, Loeschen) mit Backend-Persistenz. Die RAG-Collections bp_compliance_recht (DE-Gesetze) und bp_compliance_ce (EU-Verordnungen) liefern aktuelle Rechtstexte, aus denen spezifische Pflichten extrahiert werden. Die KI-gestuetzte Interpretation (interpret_requirement) und Control-Vorschlaege (suggest_controls) werden mit RAG-Kontext angereichert — die Collection wird automatisch anhand des Regulation-Codes gewaehlt (EU → bp_compliance_ce, DE → bp_compliance_recht). Status-Workflow: NOT_STARTED → IN_PROGRESS → IMPLEMENTED → VERIFIED mit automatischem Rollback bei Backend-Fehler. Filterung, Volltextsuche und Paginierung fuer grosse Datensaetze (500+ Anforderungen).',
legalBasis: 'Art. 5, 24, 25 DSGVO (Rechenschaftspflicht)',
inputs: ['modules', 'sourcePolicy'],
outputs: ['requirements'],
prerequisiteSteps: ['source-policy'],
dbTables: ['compliance_requirements'],
dbMode: 'read/write',
ragCollections: ['bp_compliance_recht', 'bp_compliance_ce'],
ragPurpose: 'Rechtliche Anforderungen ableiten + AI-Interpretation mit Rechtskontext anreichern (Collection-Routing: EU→ce, DE→recht)',
isOptional: false,
url: '/sdk/requirements',
},
{
id: 'controls',
name: 'Controls',
nameShort: 'Controls',
package: 'analyse',
seq: 1100,
checkpointId: 'CP-CTRL',
checkpointType: 'REQUIRED',
checkpointReviewer: 'DSB',
description: 'Definition technischer und organisatorischer Kontrollen zur Erfuellung der Anforderungen.',
descriptionLong: 'Fuer jede Compliance-Anforderung werden konkrete Controls (Kontrollmassnahmen) definiert. Controls sind technische oder organisatorische Massnahmen, die sicherstellen, dass eine Anforderung erfuellt wird. Beispiele: Zugriffskontrolle (RBAC), Verschluesselung (AES-256), Logging, Schulungspflichten. Evidence-Linking: Jeder Control zeigt verknuepfte Nachweise mit Gueltigkeits-Badge an. Navigation zur Evidence-Seite mit vorausgewaehltem Control. Domaenen-basierte Gruppierung (gov, priv, iam, crypto, sdlc, ops, ai, cra, aud). Review-Workflow mit Verantwortlichem und naechstem Review-Datum. Der DSB muss diesen Schritt freigeben.',
legalBasis: 'Art. 32 DSGVO (Sicherheit der Verarbeitung)',
inputs: ['requirements'],
outputs: ['controls'],
prerequisiteSteps: ['requirements'],
dbTables: ['compliance_controls'],
dbMode: 'read/write',
ragCollections: [],
isOptional: false,
url: '/sdk/controls',
},
{
id: 'evidence',
name: 'Evidence',
nameShort: 'Nachweise',
package: 'analyse',
seq: 1200,
checkpointId: 'CP-EVI',
checkpointType: 'RECOMMENDED',
checkpointReviewer: 'NONE',
description: 'Sammlung und Verwaltung von Nachweisen fuer die Umsetzung der Controls.',
descriptionLong: 'Fuer jeden Control wird dokumentiert, wie und wann er umgesetzt wurde. Evidence (Nachweise) koennen Screenshots, Konfigurationsdateien, Audit-Logs, Schulungszertifikate oder Testprotokolle sein. Server-seitige Pagination (page, limit Query-Parameter) fuer grosse Nachweis-Sammlungen. Gueltigkeits-Tracking (valid_from, valid_until) mit Status: valid, expired, pending, failed. Verknuepfung mit Controls und Upload von Dateien als Nachweise. Essentiell fuer Audits und Zertifizierungen.',
legalBasis: 'Art. 5 Abs. 2 DSGVO (Rechenschaftspflicht)',
inputs: ['controls'],
outputs: ['evidence'],
prerequisiteSteps: ['controls'],
dbTables: ['compliance_evidence'],
dbMode: 'write',
ragCollections: [],
isOptional: false,
url: '/sdk/evidence',
},
{
id: 'risks',
name: 'Risk Matrix',
nameShort: 'Risiken',
package: 'analyse',
seq: 1300,
checkpointId: 'CP-RISK',
checkpointType: 'REQUIRED',
checkpointReviewer: 'DSB',
description: 'Bewertung aller Datenschutz- und Compliance-Risiken in einer Risikomatrix.',
descriptionLong: 'Die 5x5 Risikomatrix bewertet jedes Risiko nach Eintrittswahrscheinlichkeit und Schadenshoehe. Inherent Risk vs. Residual Risk mit visuellem Vergleich. Status-Workflow: IDENTIFIED → ASSESSED → MITIGATED → ACCEPTED → CLOSED. Expandierbare Mitigations-Sektion pro Risiko mit verknuepften Controls (Name, Status, Effectiveness). Automatische Risiko-Level-Berechnung: Score = Likelihood × Impact (LOW <6, MEDIUM 6-11, HIGH 12-19, CRITICAL ≥20). Der DSB muss die Risikobewertung freigeben.',
legalBasis: 'Art. 35 DSGVO (Datenschutz-Folgenabschaetzung)',
inputs: ['controls', 'modules'],
outputs: ['risks'],
prerequisiteSteps: ['evidence'],
dbTables: ['compliance_risks'],
dbMode: 'write',
ragCollections: [],
isOptional: false,
url: '/sdk/risks',
},
{
id: 'ai-act',
name: 'AI Act Klassifizierung',
nameShort: 'AI Act',
package: 'analyse',
seq: 1400,
checkpointId: 'CP-AI',
checkpointType: 'REQUIRED',
checkpointReviewer: 'LEGAL',
description: 'Klassifizierung aller KI-Systeme nach EU AI Act Risikokategorien.',
descriptionLong: 'KI-System-Registrierung mit vollstaendiger Backend-Persistenz (CRUD). Risikopyramide: Minimal → Begrenzt → Hoch → Verboten. KI-gestuetzte Risikobewertung mit Rule-Based-Fallback: Der Assess-Endpoint analysiert Zweck, Sektor und Beschreibung und leitet Klassifizierung + Pflichten automatisch ab. Fuer Hochrisiko-Systeme werden 8 AI Act Pflichten abgeleitet (Risikomanagement, Daten-Governance, Dokumentation, Transparenz, menschliche Aufsicht, Genauigkeit, Robustheit, Cybersicherheit). Filterung nach Klassifizierung, Status und Sektor. Die Rechtsabteilung (LEGAL) muss die Klassifizierung freigeben.',
legalBasis: 'EU AI Act Art. 6-9 (Risikokategorien)',
inputs: ['useCases', 'companyProfile'],
outputs: ['aiActClassification', 'obligations'],
prerequisiteSteps: ['risks'],
dbTables: ['compliance_ai_systems'],
dbMode: 'read/write',
ragCollections: ['bp_compliance_ce'],
ragPurpose: 'EU AI Act Regulierungstexte',
isOptional: false,
url: '/sdk/ai-act',
},
{
id: 'audit-checklist',
name: 'Audit Checklist',
nameShort: 'Checklist',
package: 'analyse',
seq: 1500,
checkpointId: 'CP-CHK',
checkpointType: 'RECOMMENDED',
checkpointReviewer: 'NONE',
description: 'Erstellung einer pruefbaren Checkliste fuer interne und externe Audits.',
descriptionLong: 'Aus den Requirements und Controls wird eine strukturierte Audit-Checkliste generiert. Session-Management: Draft → In Progress → Completed → Archived. Interaktiver Sign-Off-Workflow mit digitalem Signatur-Hash (SHA-256). PDF-Download in Deutsch oder Englisch. Session-History: Anzeige vergangener Audit-Sitzungen mit Status-Badges. JSON-Export der Checkliste. Die Checkliste kann fuer interne Self-Assessments oder als Vorbereitung auf externe Audits (ISO 27001, BSI Grundschutz) verwendet werden.',
inputs: ['requirements', 'controls'],
outputs: ['checklist'],
prerequisiteSteps: ['ai-act'],
dbTables: ['compliance_audit_sessions', 'compliance_audit_signoffs'],
dbMode: 'read/write',
ragCollections: [],
isOptional: false,
url: '/sdk/audit-checklist',
},
{
id: 'audit-report',
name: 'Audit Report',
nameShort: 'Report',
package: 'analyse',
seq: 1600,
checkpointId: 'CP-AREP',
checkpointType: 'REQUIRED',
checkpointReviewer: 'NONE',
description: 'Generierung eines vollstaendigen Audit-Reports mit Findings und Empfehlungen.',
descriptionLong: 'Der Audit Report fasst alle Ergebnisse der Analyse-Phase zusammen. Uebersicht aller Audit-Sitzungen mit Status-Badges. Detail-Seite pro Sitzung mit Session-Metadaten (Auditor, Zeitraum, Status), Fortschrittsbalken (konform/nicht konform/ausstehend), interaktiven Checklist-Items mit Sign-Off, Notizen-Bearbeitung pro Pruefpunkt und PDF-Download mit Sprachauswahl (DE/EN). Click-Navigation von der Uebersicht zur Detail-Seite. Dient als Nachweis gegenueber Aufsichtsbehoerden.',
inputs: ['checklist', 'controls', 'evidence'],
outputs: ['auditReport'],
prerequisiteSteps: ['audit-checklist'],
dbTables: ['compliance_audit_sessions'],
dbMode: 'write',
ragCollections: [],
generates: ['Audit-Report (PDF)'],
isOptional: false,
url: '/sdk/audit-report',
},
// =========================================================================
// PAKET 3: DOKUMENTATION (seq 2000-2400)
// =========================================================================
{
id: 'obligations',
name: 'Pflichtenuebersicht',
nameShort: 'Pflichten',
package: 'dokumentation',
seq: 2000,
checkpointId: 'CP-OBL',
checkpointType: 'REQUIRED',
checkpointReviewer: 'NONE',
description: 'Zusammenfassung aller gesetzlichen Pflichten aus DSGVO, AI Act, NIS2.',
descriptionLong: 'Die Pflichtenuebersicht konsolidiert alle gesetzlichen Pflichten, die sich aus den Requirements, der AI-Act-Klassifizierung und den aktivierten Modulen ergeben. Wenn applicableRegulations aus dem Scope-Profiling vorliegen, werden diese direkt als Vorfilter verwendet. Fuer jede Pflicht wird angegeben: Welches Gesetz (DSGVO, AI Act, NIS2), welcher Artikel, welche Frist, wer verantwortlich ist und welche Massnahmen erforderlich sind. Die RAG-Collection bp_compliance_recht liefert aktuelle Pflichtentexte und Auslegungshinweise.',
legalBasis: 'Art. 5 Abs. 2 DSGVO, Art. 9 AI Act',
inputs: ['requirements', 'aiActClassification', 'modules', 'applicableRegulations'],
outputs: ['obligationsOverview'],
prerequisiteSteps: ['audit-report'],
dbTables: ['compliance_obligations'],
dbMode: 'read/write',
ragCollections: ['bp_compliance_recht'],
ragPurpose: 'NIS2, DSGVO, AI Act Pflichtentexte',
isOptional: false,
url: '/sdk/obligations',
},
{
id: 'dsfa',
name: 'DSFA',
nameShort: 'DSFA',
package: 'dokumentation',
seq: 2100,
checkpointId: 'CP-DSFA',
checkpointType: 'REQUIRED',
checkpointReviewer: 'DSB',
description: 'Datenschutz-Folgenabschaetzung fuer Hochrisiko-Verarbeitungen. Draft-Modus (v1 + v2) nutzt RAG fuer rechtliche Praezision.',
descriptionLong: 'Die Datenschutz-Folgenabschaetzung (DSFA) ist nach Art. 35 DSGVO fuer Verarbeitungen mit hohem Risiko vorgeschrieben. Sie bewertet systematisch die Notwendigkeit, Verhaeltnismaessigkeit und Risiken der Datenverarbeitung. Die DSFA enthaelt: Beschreibung der Verarbeitung, Bewertung der Notwendigkeit, Risikobewertung fuer die Betroffenen, geplante Abhilfemassnahmen. Der DSB muss die DSFA freigeben. Bei verbleibendem Hochrisiko muss die Aufsichtsbehoerde konsultiert werden. Sowohl der v1- als auch der v2-Draft-Modus werden mit rechtlichem Kontext aus dem RAG-Corpus (bp_dsfa_corpus) angereichert. Die shared queryRAG-Utility (rag-query.ts) wird von Chat- und Draft-Pipelines gemeinsam genutzt.',
legalBasis: 'Art. 35, 36 DSGVO (DSFA und vorherige Konsultation)',
inputs: ['risks', 'aiActClassification', 'modules'],
outputs: ['dsfa'],
prerequisiteSteps: ['obligations'],
dbTables: [],
dbMode: 'none',
ragCollections: ['bp_dsfa_corpus'],
ragPurpose: 'DSFA-Vorlagen, Bewertungskriterien und Art. 35 DSGVO Rechtstexte. v1-Pipeline haengt RAG-Kontext an System-Prompt an, v2-Pipeline injiziert ihn pro Block als RECHTSKONTEXT-Referenz.',
generates: ['DSFA-Report'],
isOptional: true,
url: '/sdk/dsfa',
},
{
id: 'tom',
name: 'TOMs',
nameShort: 'TOMs',
package: 'dokumentation',
seq: 2200,
checkpointId: 'CP-TOM',
checkpointType: 'REQUIRED',
checkpointReviewer: 'NONE',
description: 'Dokumentation aller Technisch-Organisatorischen Massnahmen nach Art. 32 DSGVO.',
descriptionLong: 'Die Technisch-Organisatorischen Massnahmen (TOMs) dokumentieren alle Sicherheitsmassnahmen, die zum Schutz personenbezogener Daten implementiert sind. TOMs umfassen: Zutrittskontrolle, Zugangskontrolle, Zugriffskontrolle, Weitergabekontrolle, Eingabekontrolle, Auftragskontrolle, Verfuegbarkeitskontrolle und Trennungsgebot. Jede Massnahme wird mit Implementierungsstatus, Verantwortlichem und Pruefintervall dokumentiert. Die bestehenden Controls werden als Basis verwendet.',
legalBasis: 'Art. 32 DSGVO (Sicherheit der Verarbeitung)',
inputs: ['dsfa', 'controls', 'risks'],
outputs: ['toms'],
prerequisiteSteps: ['obligations'],
dbTables: ['compliance_controls'],
dbMode: 'read',
ragCollections: ['bp_compliance_datenschutz'],
ragPurpose: 'TOM-Massnahmenkataloge',
isOptional: false,
url: '/sdk/tom',
},
{
id: 'loeschfristen',
name: 'Loeschfristen',
nameShort: 'Loeschfristen',
package: 'dokumentation',
seq: 2300,
checkpointId: 'CP-RET',
checkpointType: 'REQUIRED',
checkpointReviewer: 'NONE',
description: 'Festlegung von Aufbewahrungs- und Loeschfristen fuer alle Datenkategorien.',
descriptionLong: 'Fuer jede Datenkategorie werden gesetzliche Aufbewahrungsfristen und Loeschzeitpunkte definiert. Dabei werden gesetzliche Mindestaufbewahrungsfristen (z.B. 10 Jahre Steuerrecht, 6 Jahre Handelsrecht, 3 Jahre Verjaehrung) mit dem Grundsatz der Datenminimierung abgewogen. Das Loeschkonzept definiert: Welche Daten, wann geloescht, wie geloescht (Anonymisierung vs. physische Loeschung) und wer verantwortlich ist.',
legalBasis: 'Art. 5 Abs. 1e DSGVO (Speicherbegrenzung), Art. 17 DSGVO (Recht auf Loeschung)',
inputs: ['vvt', 'dataMapping'],
outputs: ['retentionPolicies'],
prerequisiteSteps: ['tom'],
dbTables: ['compliance_loeschfristen'],
dbMode: 'read/write',
ragCollections: ['bp_compliance_recht'],
ragPurpose: 'Aufbewahrungsfristen nach Gesetz',
isOptional: false,
url: '/sdk/loeschfristen',
},
{
id: 'vvt',
name: 'Verarbeitungsverzeichnis',
nameShort: 'VVT',
package: 'dokumentation',
seq: 2400,
checkpointId: 'CP-VVT',
checkpointType: 'REQUIRED',
checkpointReviewer: 'DSB',
description: 'Erstellung des Verzeichnisses aller Verarbeitungstaetigkeiten nach Art. 30 DSGVO — vollstaendig backend-persistent.',
descriptionLong: 'Das VVT (Verzeichnis von Verarbeitungstaetigkeiten) ist eine gesetzliche Pflichtdokumentation nach Art. 30 DSGVO. Fuer jede Verarbeitungstaetigkeit wird dokumentiert: Zweck, Rechtsgrundlage, Kategorien betroffener Personen, Datenkategorien, Empfaenger, Drittlandtransfers, Loeschfristen und TOMs. Jede Aktivitaet wird mit einem eindeutigen VVT-ID versehen und in der Datenbank gespeichert (compliance_vvt_activities). Organisationsweite Metadaten (DSB-Kontakt, Branche, Standorte) werden separat verwaltet (compliance_vvt_organization). Alle Aenderungen werden in einem Audit-Log protokolliert (compliance_vvt_audit_log). Das VVT wird via FastAPI-Backend (backend-compliance:8002) persistent gespeichert. Der DSB muss das VVT freigeben.',
legalBasis: 'Art. 30 DSGVO (Verzeichnis von Verarbeitungstaetigkeiten)',
inputs: ['modules', 'toms', 'dataMapping'],
outputs: ['vvt'],
prerequisiteSteps: ['loeschfristen'],
dbTables: ['compliance_vvt_organization', 'compliance_vvt_activities', 'compliance_vvt_audit_log'],
dbMode: 'read/write',
ragCollections: ['bp_compliance_gesetze'],
ragPurpose: 'Art. 30 DSGVO Vorlage',
isOptional: false,
url: '/sdk/vvt',
},
// =========================================================================
// PAKET 4: RECHTLICHE TEXTE (seq 3000-3400)
// =========================================================================
{
id: 'einwilligungen',
name: 'Einwilligungen',
nameShort: 'Einwilligungen',
package: 'rechtliche-texte',
seq: 3000,
checkpointId: 'CP-CONS',
checkpointType: 'REQUIRED',
checkpointReviewer: 'NONE',
description: 'Definition aller Einwilligungserklaerungen — vollstaendig backend-persistent mit Nachweis-Tracking.',
descriptionLong: 'Basierend auf dem VVT und den aktivierten Modulen werden alle Verarbeitungen identifiziert, die eine Einwilligung erfordern (Art. 6 Abs. 1a DSGVO). Der Datenkatalog definiert einwilligungspflichtige Datenpunkte. Erteilte und widerrufene Einwilligungen werden mit vollstaendigem Audit-Trail gespeichert: Zeitpunkt, Version, IP-Adresse, User-Agent, Quelle. Widerruf setzt `revoked_at` ohne den urspruenglichen Eintrag zu loeschen (Nachweispflicht). Cookie-Banner-Konfiguration ist ebenfalls hier zentral verwaltet.',
legalBasis: 'Art. 6 Abs. 1a, Art. 7 DSGVO (Einwilligung)',
inputs: ['vvt', 'modules'],
outputs: ['consents'],
prerequisiteSteps: ['vvt'],
dbTables: ['compliance_einwilligungen_catalog', 'compliance_einwilligungen_company', 'compliance_einwilligungen_consents', 'compliance_einwilligungen_cookies'],
dbMode: 'read/write',
ragCollections: ['bp_compliance_datenschutz'],
ragPurpose: 'Einwilligungsvorlagen DSGVO',
isOptional: false,
url: '/sdk/einwilligungen',
completion: 100,
},
{
id: 'consent',
name: 'Rechtliche Vorlagen',
nameShort: 'Vorlagen',
package: 'rechtliche-texte',
seq: 3100,
checkpointId: 'CP-DOC',
checkpointType: 'REQUIRED',
checkpointReviewer: 'NONE',
description: 'Verwaltung von Datenschutzerklaerung, AGB und Nutzungsbedingungen — vollstaendig backend-persistent.',
descriptionLong: 'In diesem Schritt werden die zentralen rechtlichen Dokumente verwaltet: Datenschutzerklaerung (Art. 13/14 DSGVO), AGB, Cookie-Richtlinie, Impressum und AVV. Jedes Dokument wird in `compliance_legal_documents` gespeichert. Ueber den Vorschau-Button kann die aktuell veroffentlichte HTML-Version im Browser angezeigt werden. Per Bearbeiten-Button gelangt man direkt in den Document Workflow. Schnellaktionen navigieren zum Dokumentengenerator fuer KI-gestuetzte Template-Generierung.',
legalBasis: 'Art. 13, 14 DSGVO (Informationspflichten)',
inputs: ['companyProfile', 'vvt', 'consents'],
outputs: ['documents'],
prerequisiteSteps: ['einwilligungen'],
dbTables: ['compliance_legal_documents', 'compliance_legal_document_versions'],
dbMode: 'read/write',
ragCollections: ['bp_legal_templates'],
ragPurpose: 'AGB, DSE, Nutzungsbedingungen Templates',
generates: ['Datenschutzerklaerung', 'AGB', 'Nutzungsbedingungen'],
isOptional: false,
url: '/sdk/consent',
completion: 100,
},
{
id: 'cookie-banner',
name: 'Cookie Banner',
nameShort: 'Cookies',
package: 'rechtliche-texte',
seq: 3200,
checkpointId: 'CP-COOK',
checkpointType: 'REQUIRED',
checkpointReviewer: 'NONE',
description: 'Konfiguration eines rechtskonformen Cookie-Banners — Texte und Kategorien persistent in DB.',
descriptionLong: 'Der Cookie-Banner wird basierend auf den definierten Einwilligungen konfiguriert. Alle Einstellungen (Position, Stil, Farbe, Texte) und Kategorien werden in `compliance_einwilligungen_cookies` gespeichert. Banner-Texte (Ueberschrift, Beschreibung, Datenschutz-Link) sind Controlled Inputs und werden beim Speichern persistiert. Die Live-Vorschau aktualisiert sich in Echtzeit. Der Embed-Code wird beim Export aus der DB-Konfiguration generiert — kein In-Memory-Speicher, kein Datenverlust bei Neustart. Implementiert "Privacy by Default": nur notwendige Cookies sind vorausgewaehlt.',
legalBasis: 'Art. 5 Abs. 3 ePrivacy-RL, TTDSG § 25',
inputs: ['consents', 'companyProfile'],
outputs: ['cookieBanner'],
prerequisiteSteps: ['consent'],
dbTables: ['compliance_einwilligungen_cookies'],
dbMode: 'read/write',
ragCollections: ['bp_compliance_datenschutz'],
ragPurpose: 'Cookie-Consent Richtlinien',
isOptional: false,
url: '/sdk/cookie-banner',
completion: 100,
},
{
id: 'document-generator',
name: 'Dokumentengenerator',
nameShort: 'Generator',
package: 'rechtliche-texte',
seq: 3300,
checkpointId: 'CP-DOCGEN',
checkpointType: 'RECOMMENDED',
checkpointReviewer: 'NONE',
description: 'Generierung weiterer rechtlicher Dokumente (Impressum, AVV, Auftragsverarbeitung) mit PDF-Export.',
descriptionLong: 'Der Dokumentengenerator erstellt zusaetzliche rechtliche Dokumente, die ueber die Pflichtdokumente hinausgehen: Impressum (nach TMG/DDG), Auftragsverarbeitungsvertraege (AVV nach Art. 28 DSGVO), Vertraulichkeitsvereinbarungen, Betriebsvereinbarungen zum Datenschutz und Datenschutz-Folgenabschaetzungs-Berichte. Die Templates werden aus bp_legal_templates geladen und mit den unternehmensspezifischen Daten befuellt. PDF-Export ist direkt im Browser via window.print() moeglich. Steht der Template-Service (breakpilot-core) nicht bereit, erscheint ein Fallback-Banner mit Hinweis.',
legalBasis: 'Art. 28 DSGVO (Auftragsverarbeitung), DDG § 5 (Impressum)',
inputs: ['companyProfile', 'toms', 'vvt'],
outputs: ['generatedDocuments'],
prerequisiteSteps: ['cookie-banner'],
dbTables: [],
dbMode: 'none',
ragCollections: ['bp_legal_templates'],
ragPurpose: 'Dokumenten-Templates',
generates: ['Impressum', 'Auftragsverarbeitungsvertrag'],
isOptional: true,
url: '/sdk/document-generator',
completion: 100,
},
{
id: 'workflow',
name: 'Document Workflow',
nameShort: 'Workflow',
package: 'rechtliche-texte',
seq: 3400,
checkpointId: 'CP-WRKF',
checkpointType: 'REQUIRED',
checkpointReviewer: 'NONE',
description: 'Freigabe-Workflow fuer alle rechtlichen Dokumente — vollstaendig backend-persistent mit Versionierung.',
descriptionLong: 'Der Document Workflow steuert den Freigabeprozess fuer alle rechtlichen Dokumente. Split-View-Editor: linkes Panel zeigt die veroffentlichte Version, rechtes Panel den Entwurf. Status-Workflow: draft → review → approved → published (oder rejected). Alle Versionen werden in `compliance_legal_document_versions` gespeichert. Der Versions-Endpoint gibt ein direktes JSON-Array zurueck. DOCX-Import via multipart/form-data moeglich. Freigabe-Historie wird in `compliance_legal_document_approvals` protokolliert (Zeitstempel, Benutzer, Kommentar). Veroeffentlichte Versionen sind unveraenderlich — Aenderungen erzeugen stets eine neue Version.',
inputs: ['documents', 'generatedDocuments'],
outputs: ['approvedDocuments'],
prerequisiteSteps: ['cookie-banner'],
dbTables: ['compliance_legal_documents', 'compliance_legal_document_versions', 'compliance_legal_document_approvals'],
dbMode: 'read/write',
ragCollections: [],
isOptional: false,
url: '/sdk/workflow',
completion: 100,
},
// =========================================================================
// PAKET 5: BETRIEB (seq 4000+)
// =========================================================================
{
id: 'dsr',
name: 'DSR Portal',
nameShort: 'DSR',
package: 'betrieb',
seq: 4000,
checkpointId: 'CP-DSR',
checkpointType: 'REQUIRED',
checkpointReviewer: 'NONE',
description: 'Einrichtung des Portals fuer Betroffenenrechte (Auskunft, Loeschung, Widerspruch).',
descriptionLong: 'Das DSR-Portal (Data Subject Rights) ermoeglicht es betroffenen Personen, ihre Rechte nach Art. 15-22 DSGVO auszuueben: Auskunftsrecht, Berichtigungsrecht, Loeschungsrecht ("Recht auf Vergessenwerden"), Einschraenkung der Verarbeitung, Datenportabilitaet und Widerspruchsrecht. Das Portal generiert automatisch Formulare, verwaltet Fristen (30 Tage) und dokumentiert die Bearbeitung jeder Anfrage fuer die Nachweispflicht.',
legalBasis: 'Art. 15-22 DSGVO (Betroffenenrechte)',
inputs: ['vvt', 'consents'],
outputs: ['dsrConfig'],
prerequisiteSteps: ['workflow'],
dbTables: [],
dbMode: 'none',
ragCollections: ['bp_compliance_recht'],
ragPurpose: 'Art. 15-21 DSGVO Betroffenenrechte',
isOptional: false,
url: '/sdk/dsr',
completion: 100,
},
{
id: 'escalations',
name: 'Escalations',
nameShort: 'Eskalationen',
package: 'betrieb',
seq: 4100,
checkpointId: 'CP-ESC',
checkpointType: 'REQUIRED',
checkpointReviewer: 'NONE',
description: 'Definition von Eskalationspfaden bei Compliance-Verstoessen und Datenpannen — vollstaendig backend-persistent.',
descriptionLong: 'Das Eskalationsmanagement definiert klare Eskalationspfade fuer verschiedene Szenarien: Datenschutzverletzungen (Art. 33/34 DSGVO), Compliance-Verstoesse, Betroffenen-Beschwerden und Aufsichtsbehoerden-Anfragen. Fuer jedes Szenario werden Verantwortliche, Fristen (72h bei Datenpannen), Kommunikationswege und Massnahmen festgelegt. Eskalationen koennen aus DSR, Incidents und Whistleblower-Modulen heraus erstellt werden. Alle Daten werden in compliance_escalations gespeichert.',
legalBasis: 'Art. 33, 34 DSGVO (Meldepflichten bei Datenpannen)',
inputs: ['risks', 'controls'],
outputs: ['escalationWorkflows'],
prerequisiteSteps: ['dsr'],
dbTables: ['compliance_escalations'],
dbMode: 'read/write',
ragCollections: [],
isOptional: false,
url: '/sdk/escalations',
completion: 100,
},
{
id: 'vendor-compliance',
name: 'Vendor Compliance',
nameShort: 'Vendor',
package: 'dokumentation',
seq: 2500,
checkpointId: 'CP-VEND',
checkpointType: 'REQUIRED',
checkpointReviewer: 'NONE',
description: 'Pruefung und Verwaltung aller Auftragsverarbeiter und Drittanbieter — Cross-Modul-Integration mit VVT, Obligations, TOM und Loeschfristen.',
descriptionLong: 'Vendor Compliance verwaltet alle externen Dienstleister, die im Auftrag personenbezogene Daten verarbeiten (Auftragsverarbeiter nach Art. 28 DSGVO). Fuer jeden Vendor wird geprueft: Gibt es einen AVV? Wo werden Daten gespeichert (EU/Drittland)? Welche TOMs hat der Vendor? Gibt es Subunternehmer? Cross-Modul-Integration: VVT-Processor-Tab liest Vendors mit role=PROCESSOR direkt aus der Vendor-API, Obligations und Loeschfristen verknuepfen Vendors ueber linked_vendor_ids (JSONB), TOM zeigt Vendor-Controls als Querverweis.',
legalBasis: 'Art. 28 DSGVO (Auftragsverarbeiter), Art. 44-49 (Drittlandtransfer)',
inputs: ['modules', 'vvt'],
outputs: ['vendorAssessments', 'vendorControlInstances'],
prerequisiteSteps: ['vvt'],
dbTables: ['vendor_vendors', 'vendor_contracts', 'vendor_findings', 'vendor_control_instances', 'compliance_templates'],
dbMode: 'read/write',
ragCollections: ['bp_compliance_recht'],
ragPurpose: 'AVV-Vorlagen und Pruefkataloge',
isOptional: false,
url: '/sdk/vendor-compliance',
completion: 100,
},
{
id: 'consent-management',
name: 'Consent Verwaltung',
nameShort: 'Consent Mgmt',
package: 'betrieb',
seq: 4300,
checkpointId: 'CP-CMGMT',
checkpointType: 'REQUIRED',
checkpointReviewer: 'NONE',
description: 'Laufende Verwaltung aller erteilten und widerrufenen Einwilligungen — E-Mail-Templates + DSGVO-Prozesse aus DB.',
descriptionLong: 'Das Consent Management System verwaltet im laufenden Betrieb alle erteilten Einwilligungen. E-Mail-Templates (Bestaetigungen, DSR-Antworten, etc.) und DSGVO-Prozesse (Art. 15-21) werden in der Datenbank gespeichert und koennen inline bearbeitet werden. Das System stellt sicher, dass Einwilligungen nachweisbar sind (Art. 7 Abs. 1 DSGVO), Widerrufe sofort wirksam werden und bei geaenderten Zwecken neue Einwilligungen eingeholt werden.',
legalBasis: 'Art. 7 DSGVO (Bedingungen fuer die Einwilligung)',
inputs: ['consents', 'documents'],
outputs: ['consentManagement'],
prerequisiteSteps: ['vendor-compliance'],
dbTables: ['compliance_consent_email_templates', 'compliance_consent_gdpr_processes'],
dbMode: 'read/write',
ragCollections: [],
isOptional: false,
url: '/sdk/consent-management',
completion: 100,
},
{
id: 'notfallplan',
name: 'Notfallplan & Breach Response',
nameShort: 'Notfallplan',
package: 'betrieb',
seq: 4400,
checkpointId: 'CP-NOTF',
checkpointType: 'REQUIRED',
checkpointReviewer: 'NONE',
description: 'Erstellung eines Notfallplans fuer Datenpannen und Sicherheitsvorfaelle — vollstaendig backend-persistent.',
descriptionLong: 'Der Notfallplan definiert das Vorgehen bei Datenschutzverletzungen (Data Breaches). Er enthaelt: Sofortmassnahmen zur Schadensbegrenzung, Meldeprozess an die Aufsichtsbehoerde (innerhalb 72h nach Art. 33 DSGVO), Benachrichtigung betroffener Personen (Art. 34 DSGVO), Dokumentation des Vorfalls und Massnahmen zur Verhinderung kuenftiger Vorfaelle. Alle Szenarien, Notfallkontakte, Checklisten und Uebungen werden in der Datenbank gespeichert — kein Mock-Data mehr.',
legalBasis: 'Art. 33, 34 DSGVO (Meldung von Datenpannen)',
inputs: ['risks', 'controls'],
outputs: ['incidentResponsePlan'],
prerequisiteSteps: ['consent-management'],
dbTables: ['compliance_notfallplan_scenarios', 'compliance_notfallplan_contacts', 'compliance_notfallplan_checklists', 'compliance_notfallplan_exercises'],
dbMode: 'read/write',
ragCollections: [],
generates: ['Notfallplan (PDF)'],
isOptional: false,
url: '/sdk/notfallplan',
completion: 100,
},
{
id: 'incidents',
name: 'Incident Management',
nameShort: 'Incidents',
package: 'betrieb',
seq: 4500,
checkpointId: 'CP-INC',
checkpointType: 'REQUIRED',
checkpointReviewer: 'NONE',
description: 'Verwaltung und Dokumentation von Datenschutz-Vorfaellen und Sicherheitsereignissen.',
descriptionLong: 'Das Incident Management System ermoeglicht die strukturierte Erfassung, Bewertung und Bearbeitung von Datenschutzvorfaellen. Jeder Vorfall wird klassifiziert (Schweregrad, betroffene Daten, Anzahl Betroffener), der Notfallplan wird aktiviert und alle Massnahmen werden protokolliert. Das System berechnet automatisch, ob eine Meldepflicht an die Aufsichtsbehoerde oder eine Benachrichtigung der Betroffenen erforderlich ist. Historische Vorfaelle werden im Incident Registry archiviert.',
legalBasis: 'Art. 33 DSGVO (Meldung an Aufsichtsbehoerde)',
inputs: ['incidentResponsePlan'],
outputs: ['incidentRegistry'],
prerequisiteSteps: ['notfallplan'],
dbTables: [],
dbMode: 'none',
ragCollections: [],
isOptional: false,
url: '/sdk/incidents',
completion: 100,
},
{
id: 'whistleblower',
name: 'Hinweisgebersystem',
nameShort: 'Whistleblower',
package: 'betrieb',
seq: 4600,
checkpointId: 'CP-WB',
checkpointType: 'REQUIRED',
checkpointReviewer: 'NONE',
description: 'Einrichtung eines anonymen Meldekanals nach HinSchG.',
descriptionLong: 'Das Hinweisgebersystem erfuellt die Anforderungen des Hinweisgeberschutzgesetzes (HinSchG). Es bietet Mitarbeitern und externen Personen einen sicheren, anonymen Kanal zur Meldung von Verstoessen gegen Compliance-Regeln, Datenschutzrecht oder andere Vorschriften. Das System schuetzt die Identitaet des Hinweisgebers, dokumentiert den Bearbeitungsprozess und stellt die Einhaltung der gesetzlichen Fristen (7 Tage Eingangsbestaetigung, 3 Monate Rueckmeldung) sicher.',
legalBasis: 'HinSchG (Hinweisgeberschutzgesetz)',
inputs: ['companyProfile'],
outputs: ['whistleblowerConfig'],
prerequisiteSteps: ['incidents'],
dbTables: [],
dbMode: 'none',
ragCollections: [],
isOptional: false,
url: '/sdk/whistleblower',
completion: 100,
},
{
id: 'academy',
name: 'Compliance Academy',
nameShort: 'Academy',
package: 'betrieb',
seq: 4700,
checkpointId: 'CP-ACAD',
checkpointType: 'REQUIRED',
checkpointReviewer: 'NONE',
description: 'Erstellung eines Schulungsplans fuer Mitarbeiter zu Datenschutz und Compliance.',
descriptionLong: 'Die Compliance Academy erstellt basierend auf dem Unternehmensprofil und den aktivierten Modulen einen massgeschneiderten Schulungsplan. Verschiedene Mitarbeitergruppen erhalten unterschiedliche Schulungsinhalte: Grundlagen-Datenschutz fuer alle, vertiefte DSGVO-Schulung fuer die IT, AI-Act-Schulung fuer KI-Entwickler, Fuehrungskraefte-Schulung fuer das Management. Der Plan definiert Schulungsintervalle, Pflicht- und Wahlmodule und Erfolgskontrolle.',
inputs: ['companyProfile', 'modules'],
outputs: ['trainingPlan'],
prerequisiteSteps: ['whistleblower'],
dbTables: [],
dbMode: 'none',
ragCollections: [],
isOptional: false,
url: '/sdk/academy',
},
{
id: 'training',
name: 'Training Engine',
nameShort: 'Training',
package: 'betrieb',
seq: 4800,
checkpointId: 'CP-TRAIN',
checkpointType: 'REQUIRED',
checkpointReviewer: 'NONE',
description: 'Durchfuehrung und Tracking von Compliance-Schulungen mit Quizzes und Zertifikaten — vollstaendig backend-persistent.',
descriptionLong: 'Die Training Engine setzt den Schulungsplan der Academy um. Sie bietet interaktive Schulungsmodule (DSGVO, AI Act, ISO 27001 etc.) mit Quizzes, automatisch generierten Inhalten und Zertifikaten. 28 vordefinierte Schulungsmodule sind hinterlegt. Jede abgeschlossene Schulung wird dokumentiert (Teilnehmer, Datum, Ergebnis, Quiz-Versuch) und dient als Evidence fuer Audits. Die Engine ueberwacht Faelligkeiten, sendet Erinnerungen bei ausstehenden Pflichtschulungen und generiert Compliance-Reports ueber den Schulungsstand aller Mitarbeiter. Backend: ai-compliance-sdk (Go, Port 8093) via /sdk/v1/training/*. Schulungsmatrix ordnet Rollen Pflichtmodulen zu.',
inputs: ['trainingPlan', 'modules'],
outputs: ['trainingContent'],
prerequisiteSteps: ['academy'],
dbTables: ['training_modules', 'training_assignments', 'training_quiz_questions', 'training_quiz_attempts', 'training_matrix_entries', 'training_audit_log'],
dbMode: 'read/write',
ragCollections: [],
isOptional: false,
url: '/sdk/training',
},
{
id: 'security-backlog',
name: 'Security Backlog',
nameShort: 'Sec-Backlog',
package: 'betrieb',
seq: 4900,
checkpointId: 'CP-SEC',
checkpointType: 'RECOMMENDED',
checkpointReviewer: 'NONE',
description: 'Verwaltung offener Sicherheits-Findings: Schwachstellen, Fehlkonfigurationen und Haertungsmassnahmen.',
descriptionLong: 'Der Security Backlog erfasst alle identifizierten IT-Sicherheitsprobleme: CVE-Schwachstellen, Fehlkonfigurationen, Compliance-Luecken und Haertungsmassnahmen. Jeder Befund wird nach Schweregrad (critical/high/medium/low) klassifiziert, CVSS-Scores und betroffene Assets werden dokumentiert.',
legalBasis: 'Art. 32 DSGVO (Sicherheit der Verarbeitung), BSIG / IT-SiG 2.0',
inputs: ['risks', 'controls'],
outputs: ['securityBacklog'],
prerequisiteSteps: ['training'],
dbTables: ['compliance_security_backlog'],
dbMode: 'read/write',
ragCollections: [],
isOptional: true,
url: '/sdk/security-backlog',
completion: 100,
},
{
id: 'quality',
name: 'KI-Qualitaetsmanagement',
nameShort: 'Quality',
package: 'betrieb',
seq: 5000,
checkpointId: 'CP-QUAL',
checkpointType: 'RECOMMENDED',
checkpointReviewer: 'NONE',
description: 'Kontinuierliches Monitoring von KI-Qualitaetsmetriken: Genauigkeit, Fairness, Erklaerbarkeit und Tests.',
descriptionLong: 'Das KI-Qualitaetsmanagement ueberwacht alle KI-Systeme auf Qualitaetsmetriken. Fuer jede Metrik wird ein Schwellenwert definiert; Ueberschreitungen loesen Warnungen aus. Qualitaetstests werden dokumentiert. Liefert Evidence fuer AI-Act High-Risk Anforderungen (Art. 9, Art. 15).',
legalBasis: 'Art. 9 AI Act (Risikomanagementsystem), Art. 15 AI Act (Genauigkeit)',
inputs: ['aiActClassification'],
outputs: ['qualityMetrics'],
prerequisiteSteps: ['security-backlog'],
dbTables: ['compliance_quality_metrics', 'compliance_quality_tests'],
dbMode: 'read/write',
ragCollections: [],
isOptional: true,
url: '/sdk/quality',
completion: 100,
},
{
id: 'isms',
name: 'ISMS (ISO 27001)',
nameShort: 'ISMS',
package: 'betrieb',
seq: 5100,
checkpointId: 'CP-ISMS',
checkpointType: 'RECOMMENDED',
checkpointReviewer: 'DSB',
description: 'Informationssicherheits-Managementsystem: Scope, Policies, SoA, Audits, CAPA, Management-Reviews und Readiness-Check.',
descriptionLong: 'ISO 27001 Zertifizierungsvorbereitung. Verwaltet den ISMS-Scope (Kap. 4.3), Kontextanalyse (4.1/4.2), Sicherheitspolicies (5.2), Security Objectives mit SMART-KPIs (6.2), Statement of Applicability fuer alle 93 Annex-A-Controls, interne Audits (9.2), Management-Reviews (9.3), Audit-Findings mit CAPA-Workflow und einen automatischen Readiness-Check der potenzielle Major/Minor-Findings vor der externen Zertifizierung identifiziert.',
legalBasis: 'ISO/IEC 27001:2022, Art. 32 DSGVO (Sicherheit der Verarbeitung)',
inputs: ['risks', 'controls', 'requirements'],
outputs: ['ismsReadiness'],
prerequisiteSteps: ['quality'],
dbTables: [
'compliance_isms_scope', 'compliance_isms_context', 'compliance_isms_policy',
'compliance_security_objectives', 'compliance_soa',
'compliance_audit_findings', 'compliance_corrective_actions',
'compliance_management_reviews', 'compliance_internal_audits',
'compliance_audit_trail', 'compliance_isms_readiness_checks',
],
dbMode: 'read/write',
ragCollections: [],
isOptional: true,
url: '/sdk/isms',
completion: 100,
},
] ]
// ============================================================================= // =============================================================================

View File

@@ -0,0 +1,155 @@
/**
* SDK Flow Steps — Paket 2: Analyse (seq 10001600)
*/
import type { SDKFlowStep } from './types'
export const STEPS_ANALYSE: SDKFlowStep[] = [
{
id: 'requirements',
name: 'Requirements',
nameShort: 'Anforderungen',
package: 'analyse',
seq: 1000,
checkpointId: 'CP-REQ',
checkpointType: 'REQUIRED',
checkpointReviewer: 'NONE',
description: 'Ableitung konkreter Compliance-Anforderungen aus den aktivierten Modulen, mit RAG-Anreicherung.',
descriptionLong: 'Aus den aktivierten Modulen und der Source Policy werden konkrete, umsetzbare Compliance-Anforderungen abgeleitet. Vollstaendige CRUD-Operationen (Erstellen, Lesen, Aktualisieren, Loeschen) mit Backend-Persistenz. Die RAG-Collections bp_compliance_recht (DE-Gesetze) und bp_compliance_ce (EU-Verordnungen) liefern aktuelle Rechtstexte, aus denen spezifische Pflichten extrahiert werden. Die KI-gestuetzte Interpretation (interpret_requirement) und Control-Vorschlaege (suggest_controls) werden mit RAG-Kontext angereichert — die Collection wird automatisch anhand des Regulation-Codes gewaehlt (EU → bp_compliance_ce, DE → bp_compliance_recht). Status-Workflow: NOT_STARTED → IN_PROGRESS → IMPLEMENTED → VERIFIED mit automatischem Rollback bei Backend-Fehler. Filterung, Volltextsuche und Paginierung fuer grosse Datensaetze (500+ Anforderungen).',
legalBasis: 'Art. 5, 24, 25 DSGVO (Rechenschaftspflicht)',
inputs: ['modules', 'sourcePolicy'],
outputs: ['requirements'],
prerequisiteSteps: ['source-policy'],
dbTables: ['compliance_requirements'],
dbMode: 'read/write',
ragCollections: ['bp_compliance_recht', 'bp_compliance_ce'],
ragPurpose: 'Rechtliche Anforderungen ableiten + AI-Interpretation mit Rechtskontext anreichern (Collection-Routing: EU→ce, DE→recht)',
isOptional: false,
url: '/sdk/requirements',
},
{
id: 'controls',
name: 'Controls',
nameShort: 'Controls',
package: 'analyse',
seq: 1100,
checkpointId: 'CP-CTRL',
checkpointType: 'REQUIRED',
checkpointReviewer: 'DSB',
description: 'Definition technischer und organisatorischer Kontrollen zur Erfuellung der Anforderungen.',
descriptionLong: 'Fuer jede Compliance-Anforderung werden konkrete Controls (Kontrollmassnahmen) definiert. Controls sind technische oder organisatorische Massnahmen, die sicherstellen, dass eine Anforderung erfuellt wird. Beispiele: Zugriffskontrolle (RBAC), Verschluesselung (AES-256), Logging, Schulungspflichten. Evidence-Linking: Jeder Control zeigt verknuepfte Nachweise mit Gueltigkeits-Badge an. Navigation zur Evidence-Seite mit vorausgewaehltem Control. Domaenen-basierte Gruppierung (gov, priv, iam, crypto, sdlc, ops, ai, cra, aud). Review-Workflow mit Verantwortlichem und naechstem Review-Datum. Der DSB muss diesen Schritt freigeben.',
legalBasis: 'Art. 32 DSGVO (Sicherheit der Verarbeitung)',
inputs: ['requirements'],
outputs: ['controls'],
prerequisiteSteps: ['requirements'],
dbTables: ['compliance_controls'],
dbMode: 'read/write',
ragCollections: [],
isOptional: false,
url: '/sdk/controls',
},
{
id: 'evidence',
name: 'Evidence',
nameShort: 'Nachweise',
package: 'analyse',
seq: 1200,
checkpointId: 'CP-EVI',
checkpointType: 'RECOMMENDED',
checkpointReviewer: 'NONE',
description: 'Sammlung und Verwaltung von Nachweisen fuer die Umsetzung der Controls.',
descriptionLong: 'Fuer jeden Control wird dokumentiert, wie und wann er umgesetzt wurde. Evidence (Nachweise) koennen Screenshots, Konfigurationsdateien, Audit-Logs, Schulungszertifikate oder Testprotokolle sein. Server-seitige Pagination (page, limit Query-Parameter) fuer grosse Nachweis-Sammlungen. Gueltigkeits-Tracking (valid_from, valid_until) mit Status: valid, expired, pending, failed. Verknuepfung mit Controls und Upload von Dateien als Nachweise. Essentiell fuer Audits und Zertifizierungen.',
legalBasis: 'Art. 5 Abs. 2 DSGVO (Rechenschaftspflicht)',
inputs: ['controls'],
outputs: ['evidence'],
prerequisiteSteps: ['controls'],
dbTables: ['compliance_evidence'],
dbMode: 'write',
ragCollections: [],
isOptional: false,
url: '/sdk/evidence',
},
{
id: 'risks',
name: 'Risk Matrix',
nameShort: 'Risiken',
package: 'analyse',
seq: 1300,
checkpointId: 'CP-RISK',
checkpointType: 'REQUIRED',
checkpointReviewer: 'DSB',
description: 'Bewertung aller Datenschutz- und Compliance-Risiken in einer Risikomatrix.',
descriptionLong: 'Die 5x5 Risikomatrix bewertet jedes Risiko nach Eintrittswahrscheinlichkeit und Schadenshoehe. Inherent Risk vs. Residual Risk mit visuellem Vergleich. Status-Workflow: IDENTIFIED → ASSESSED → MITIGATED → ACCEPTED → CLOSED. Expandierbare Mitigations-Sektion pro Risiko mit verknuepften Controls (Name, Status, Effectiveness). Automatische Risiko-Level-Berechnung: Score = Likelihood × Impact (LOW <6, MEDIUM 6-11, HIGH 12-19, CRITICAL ≥20). Der DSB muss die Risikobewertung freigeben.',
legalBasis: 'Art. 35 DSGVO (Datenschutz-Folgenabschaetzung)',
inputs: ['controls', 'modules'],
outputs: ['risks'],
prerequisiteSteps: ['evidence'],
dbTables: ['compliance_risks'],
dbMode: 'write',
ragCollections: [],
isOptional: false,
url: '/sdk/risks',
},
{
id: 'ai-act',
name: 'AI Act Klassifizierung',
nameShort: 'AI Act',
package: 'analyse',
seq: 1400,
checkpointId: 'CP-AI',
checkpointType: 'REQUIRED',
checkpointReviewer: 'LEGAL',
description: 'Klassifizierung aller KI-Systeme nach EU AI Act Risikokategorien.',
descriptionLong: 'KI-System-Registrierung mit vollstaendiger Backend-Persistenz (CRUD). Risikopyramide: Minimal → Begrenzt → Hoch → Verboten. KI-gestuetzte Risikobewertung mit Rule-Based-Fallback: Der Assess-Endpoint analysiert Zweck, Sektor und Beschreibung und leitet Klassifizierung + Pflichten automatisch ab. Fuer Hochrisiko-Systeme werden 8 AI Act Pflichten abgeleitet (Risikomanagement, Daten-Governance, Dokumentation, Transparenz, menschliche Aufsicht, Genauigkeit, Robustheit, Cybersicherheit). Filterung nach Klassifizierung, Status und Sektor. Die Rechtsabteilung (LEGAL) muss die Klassifizierung freigeben.',
legalBasis: 'EU AI Act Art. 6-9 (Risikokategorien)',
inputs: ['useCases', 'companyProfile'],
outputs: ['aiActClassification', 'obligations'],
prerequisiteSteps: ['risks'],
dbTables: ['compliance_ai_systems'],
dbMode: 'read/write',
ragCollections: ['bp_compliance_ce'],
ragPurpose: 'EU AI Act Regulierungstexte',
isOptional: false,
url: '/sdk/ai-act',
},
{
id: 'audit-checklist',
name: 'Audit Checklist',
nameShort: 'Checklist',
package: 'analyse',
seq: 1500,
checkpointId: 'CP-CHK',
checkpointType: 'RECOMMENDED',
checkpointReviewer: 'NONE',
description: 'Erstellung einer pruefbaren Checkliste fuer interne und externe Audits.',
descriptionLong: 'Aus den Requirements und Controls wird eine strukturierte Audit-Checkliste generiert. Session-Management: Draft → In Progress → Completed → Archived. Interaktiver Sign-Off-Workflow mit digitalem Signatur-Hash (SHA-256). PDF-Download in Deutsch oder Englisch. Session-History: Anzeige vergangener Audit-Sitzungen mit Status-Badges. JSON-Export der Checkliste. Die Checkliste kann fuer interne Self-Assessments oder als Vorbereitung auf externe Audits (ISO 27001, BSI Grundschutz) verwendet werden.',
inputs: ['requirements', 'controls'],
outputs: ['checklist'],
prerequisiteSteps: ['ai-act'],
dbTables: ['compliance_audit_sessions', 'compliance_audit_signoffs'],
dbMode: 'read/write',
ragCollections: [],
isOptional: false,
url: '/sdk/audit-checklist',
},
{
id: 'audit-report',
name: 'Audit Report',
nameShort: 'Report',
package: 'analyse',
seq: 1600,
checkpointId: 'CP-AREP',
checkpointType: 'REQUIRED',
checkpointReviewer: 'NONE',
description: 'Generierung eines vollstaendigen Audit-Reports mit Findings und Empfehlungen.',
descriptionLong: 'Der Audit Report fasst alle Ergebnisse der Analyse-Phase zusammen. Uebersicht aller Audit-Sitzungen mit Status-Badges. Detail-Seite pro Sitzung mit Session-Metadaten (Auditor, Zeitraum, Status), Fortschrittsbalken (konform/nicht konform/ausstehend), interaktiven Checklist-Items mit Sign-Off, Notizen-Bearbeitung pro Pruefpunkt und PDF-Download mit Sprachauswahl (DE/EN). Click-Navigation von der Uebersicht zur Detail-Seite. Dient als Nachweis gegenueber Aufsichtsbehoerden.',
inputs: ['checklist', 'controls', 'evidence'],
outputs: ['auditReport'],
prerequisiteSteps: ['audit-checklist'],
dbTables: ['compliance_audit_sessions'],
dbMode: 'write',
ragCollections: [],
generates: ['Audit-Report (PDF)'],
isOptional: false,
url: '/sdk/audit-report',
},
]

View File

@@ -0,0 +1,253 @@
/**
* SDK Flow Steps — Paket 5: Betrieb (seq 4000+)
*/
import type { SDKFlowStep } from './types'
export const STEPS_BETRIEB: SDKFlowStep[] = [
{
id: 'dsr',
name: 'DSR Portal',
nameShort: 'DSR',
package: 'betrieb',
seq: 4000,
checkpointId: 'CP-DSR',
checkpointType: 'REQUIRED',
checkpointReviewer: 'NONE',
description: 'Einrichtung des Portals fuer Betroffenenrechte (Auskunft, Loeschung, Widerspruch).',
descriptionLong: 'Das DSR-Portal (Data Subject Rights) ermoeglicht es betroffenen Personen, ihre Rechte nach Art. 15-22 DSGVO auszuueben: Auskunftsrecht, Berichtigungsrecht, Loeschungsrecht ("Recht auf Vergessenwerden"), Einschraenkung der Verarbeitung, Datenportabilitaet und Widerspruchsrecht. Das Portal generiert automatisch Formulare, verwaltet Fristen (30 Tage) und dokumentiert die Bearbeitung jeder Anfrage fuer die Nachweispflicht.',
legalBasis: 'Art. 15-22 DSGVO (Betroffenenrechte)',
inputs: ['vvt', 'consents'],
outputs: ['dsrConfig'],
prerequisiteSteps: ['workflow'],
dbTables: [],
dbMode: 'none',
ragCollections: ['bp_compliance_recht'],
ragPurpose: 'Art. 15-21 DSGVO Betroffenenrechte',
isOptional: false,
url: '/sdk/dsr',
completion: 100,
},
{
id: 'escalations',
name: 'Escalations',
nameShort: 'Eskalationen',
package: 'betrieb',
seq: 4100,
checkpointId: 'CP-ESC',
checkpointType: 'REQUIRED',
checkpointReviewer: 'NONE',
description: 'Definition von Eskalationspfaden bei Compliance-Verstoessen und Datenpannen — vollstaendig backend-persistent.',
descriptionLong: 'Das Eskalationsmanagement definiert klare Eskalationspfade fuer verschiedene Szenarien: Datenschutzverletzungen (Art. 33/34 DSGVO), Compliance-Verstoesse, Betroffenen-Beschwerden und Aufsichtsbehoerden-Anfragen. Fuer jedes Szenario werden Verantwortliche, Fristen (72h bei Datenpannen), Kommunikationswege und Massnahmen festgelegt. Eskalationen koennen aus DSR, Incidents und Whistleblower-Modulen heraus erstellt werden. Alle Daten werden in compliance_escalations gespeichert.',
legalBasis: 'Art. 33, 34 DSGVO (Meldepflichten bei Datenpannen)',
inputs: ['risks', 'controls'],
outputs: ['escalationWorkflows'],
prerequisiteSteps: ['dsr'],
dbTables: ['compliance_escalations'],
dbMode: 'read/write',
ragCollections: [],
isOptional: false,
url: '/sdk/escalations',
completion: 100,
},
{
id: 'consent-management',
name: 'Consent Verwaltung',
nameShort: 'Consent Mgmt',
package: 'betrieb',
seq: 4300,
checkpointId: 'CP-CMGMT',
checkpointType: 'REQUIRED',
checkpointReviewer: 'NONE',
description: 'Laufende Verwaltung aller erteilten und widerrufenen Einwilligungen — E-Mail-Templates + DSGVO-Prozesse aus DB.',
descriptionLong: 'Das Consent Management System verwaltet im laufenden Betrieb alle erteilten Einwilligungen. E-Mail-Templates (Bestaetigungen, DSR-Antworten, etc.) und DSGVO-Prozesse (Art. 15-21) werden in der Datenbank gespeichert und koennen inline bearbeitet werden. Das System stellt sicher, dass Einwilligungen nachweisbar sind (Art. 7 Abs. 1 DSGVO), Widerrufe sofort wirksam werden und bei geaenderten Zwecken neue Einwilligungen eingeholt werden.',
legalBasis: 'Art. 7 DSGVO (Bedingungen fuer die Einwilligung)',
inputs: ['consents', 'documents'],
outputs: ['consentManagement'],
prerequisiteSteps: ['vendor-compliance'],
dbTables: ['compliance_consent_email_templates', 'compliance_consent_gdpr_processes'],
dbMode: 'read/write',
ragCollections: [],
isOptional: false,
url: '/sdk/consent-management',
completion: 100,
},
{
id: 'notfallplan',
name: 'Notfallplan & Breach Response',
nameShort: 'Notfallplan',
package: 'betrieb',
seq: 4400,
checkpointId: 'CP-NOTF',
checkpointType: 'REQUIRED',
checkpointReviewer: 'NONE',
description: 'Erstellung eines Notfallplans fuer Datenpannen und Sicherheitsvorfaelle — vollstaendig backend-persistent.',
descriptionLong: 'Der Notfallplan definiert das Vorgehen bei Datenschutzverletzungen (Data Breaches). Er enthaelt: Sofortmassnahmen zur Schadensbegrenzung, Meldeprozess an die Aufsichtsbehoerde (innerhalb 72h nach Art. 33 DSGVO), Benachrichtigung betroffener Personen (Art. 34 DSGVO), Dokumentation des Vorfalls und Massnahmen zur Verhinderung kuenftiger Vorfaelle. Alle Szenarien, Notfallkontakte, Checklisten und Uebungen werden in der Datenbank gespeichert — kein Mock-Data mehr.',
legalBasis: 'Art. 33, 34 DSGVO (Meldung von Datenpannen)',
inputs: ['risks', 'controls'],
outputs: ['incidentResponsePlan'],
prerequisiteSteps: ['consent-management'],
dbTables: ['compliance_notfallplan_scenarios', 'compliance_notfallplan_contacts', 'compliance_notfallplan_checklists', 'compliance_notfallplan_exercises'],
dbMode: 'read/write',
ragCollections: [],
generates: ['Notfallplan (PDF)'],
isOptional: false,
url: '/sdk/notfallplan',
completion: 100,
},
{
id: 'incidents',
name: 'Incident Management',
nameShort: 'Incidents',
package: 'betrieb',
seq: 4500,
checkpointId: 'CP-INC',
checkpointType: 'REQUIRED',
checkpointReviewer: 'NONE',
description: 'Verwaltung und Dokumentation von Datenschutz-Vorfaellen und Sicherheitsereignissen.',
descriptionLong: 'Das Incident Management System ermoeglicht die strukturierte Erfassung, Bewertung und Bearbeitung von Datenschutzvorfaellen. Jeder Vorfall wird klassifiziert (Schweregrad, betroffene Daten, Anzahl Betroffener), der Notfallplan wird aktiviert und alle Massnahmen werden protokolliert. Das System berechnet automatisch, ob eine Meldepflicht an die Aufsichtsbehoerde oder eine Benachrichtigung der Betroffenen erforderlich ist. Historische Vorfaelle werden im Incident Registry archiviert.',
legalBasis: 'Art. 33 DSGVO (Meldung an Aufsichtsbehoerde)',
inputs: ['incidentResponsePlan'],
outputs: ['incidentRegistry'],
prerequisiteSteps: ['notfallplan'],
dbTables: [],
dbMode: 'none',
ragCollections: [],
isOptional: false,
url: '/sdk/incidents',
completion: 100,
},
{
id: 'whistleblower',
name: 'Hinweisgebersystem',
nameShort: 'Whistleblower',
package: 'betrieb',
seq: 4600,
checkpointId: 'CP-WB',
checkpointType: 'REQUIRED',
checkpointReviewer: 'NONE',
description: 'Einrichtung eines anonymen Meldekanals nach HinSchG.',
descriptionLong: 'Das Hinweisgebersystem erfuellt die Anforderungen des Hinweisgeberschutzgesetzes (HinSchG). Es bietet Mitarbeitern und externen Personen einen sicheren, anonymen Kanal zur Meldung von Verstoessen gegen Compliance-Regeln, Datenschutzrecht oder andere Vorschriften. Das System schuetzt die Identitaet des Hinweisgebers, dokumentiert den Bearbeitungsprozess und stellt die Einhaltung der gesetzlichen Fristen (7 Tage Eingangsbestaetigung, 3 Monate Rueckmeldung) sicher.',
legalBasis: 'HinSchG (Hinweisgeberschutzgesetz)',
inputs: ['companyProfile'],
outputs: ['whistleblowerConfig'],
prerequisiteSteps: ['incidents'],
dbTables: [],
dbMode: 'none',
ragCollections: [],
isOptional: false,
url: '/sdk/whistleblower',
completion: 100,
},
{
id: 'academy',
name: 'Compliance Academy',
nameShort: 'Academy',
package: 'betrieb',
seq: 4700,
checkpointId: 'CP-ACAD',
checkpointType: 'REQUIRED',
checkpointReviewer: 'NONE',
description: 'Erstellung eines Schulungsplans fuer Mitarbeiter zu Datenschutz und Compliance.',
descriptionLong: 'Die Compliance Academy erstellt basierend auf dem Unternehmensprofil und den aktivierten Modulen einen massgeschneiderten Schulungsplan. Verschiedene Mitarbeitergruppen erhalten unterschiedliche Schulungsinhalte: Grundlagen-Datenschutz fuer alle, vertiefte DSGVO-Schulung fuer die IT, AI-Act-Schulung fuer KI-Entwickler, Fuehrungskraefte-Schulung fuer das Management. Der Plan definiert Schulungsintervalle, Pflicht- und Wahlmodule und Erfolgskontrolle.',
inputs: ['companyProfile', 'modules'],
outputs: ['trainingPlan'],
prerequisiteSteps: ['whistleblower'],
dbTables: [],
dbMode: 'none',
ragCollections: [],
isOptional: false,
url: '/sdk/academy',
},
{
id: 'training',
name: 'Training Engine',
nameShort: 'Training',
package: 'betrieb',
seq: 4800,
checkpointId: 'CP-TRAIN',
checkpointType: 'REQUIRED',
checkpointReviewer: 'NONE',
description: 'Durchfuehrung und Tracking von Compliance-Schulungen mit Quizzes und Zertifikaten — vollstaendig backend-persistent.',
descriptionLong: 'Die Training Engine setzt den Schulungsplan der Academy um. Sie bietet interaktive Schulungsmodule (DSGVO, AI Act, ISO 27001 etc.) mit Quizzes, automatisch generierten Inhalten und Zertifikaten. 28 vordefinierte Schulungsmodule sind hinterlegt. Jede abgeschlossene Schulung wird dokumentiert (Teilnehmer, Datum, Ergebnis, Quiz-Versuch) und dient als Evidence fuer Audits. Die Engine ueberwacht Faelligkeiten, sendet Erinnerungen bei ausstehenden Pflichtschulungen und generiert Compliance-Reports ueber den Schulungsstand aller Mitarbeiter. Backend: ai-compliance-sdk (Go, Port 8093) via /sdk/v1/training/*. Schulungsmatrix ordnet Rollen Pflichtmodulen zu.',
inputs: ['trainingPlan', 'modules'],
outputs: ['trainingContent'],
prerequisiteSteps: ['academy'],
dbTables: ['training_modules', 'training_assignments', 'training_quiz_questions', 'training_quiz_attempts', 'training_matrix_entries', 'training_audit_log'],
dbMode: 'read/write',
ragCollections: [],
isOptional: false,
url: '/sdk/training',
},
{
id: 'security-backlog',
name: 'Security Backlog',
nameShort: 'Sec-Backlog',
package: 'betrieb',
seq: 4900,
checkpointId: 'CP-SEC',
checkpointType: 'RECOMMENDED',
checkpointReviewer: 'NONE',
description: 'Verwaltung offener Sicherheits-Findings: Schwachstellen, Fehlkonfigurationen und Haertungsmassnahmen.',
descriptionLong: 'Der Security Backlog erfasst alle identifizierten IT-Sicherheitsprobleme: CVE-Schwachstellen, Fehlkonfigurationen, Compliance-Luecken und Haertungsmassnahmen. Jeder Befund wird nach Schweregrad (critical/high/medium/low) klassifiziert, CVSS-Scores und betroffene Assets werden dokumentiert.',
legalBasis: 'Art. 32 DSGVO (Sicherheit der Verarbeitung), BSIG / IT-SiG 2.0',
inputs: ['risks', 'controls'],
outputs: ['securityBacklog'],
prerequisiteSteps: ['training'],
dbTables: ['compliance_security_backlog'],
dbMode: 'read/write',
ragCollections: [],
isOptional: true,
url: '/sdk/security-backlog',
completion: 100,
},
{
id: 'quality',
name: 'KI-Qualitaetsmanagement',
nameShort: 'Quality',
package: 'betrieb',
seq: 5000,
checkpointId: 'CP-QUAL',
checkpointType: 'RECOMMENDED',
checkpointReviewer: 'NONE',
description: 'Kontinuierliches Monitoring von KI-Qualitaetsmetriken: Genauigkeit, Fairness, Erklaerbarkeit und Tests.',
descriptionLong: 'Das KI-Qualitaetsmanagement ueberwacht alle KI-Systeme auf Qualitaetsmetriken. Fuer jede Metrik wird ein Schwellenwert definiert; Ueberschreitungen loesen Warnungen aus. Qualitaetstests werden dokumentiert. Liefert Evidence fuer AI-Act High-Risk Anforderungen (Art. 9, Art. 15).',
legalBasis: 'Art. 9 AI Act (Risikomanagementsystem), Art. 15 AI Act (Genauigkeit)',
inputs: ['aiActClassification'],
outputs: ['qualityMetrics'],
prerequisiteSteps: ['security-backlog'],
dbTables: ['compliance_quality_metrics', 'compliance_quality_tests'],
dbMode: 'read/write',
ragCollections: [],
isOptional: true,
url: '/sdk/quality',
completion: 100,
},
{
id: 'isms',
name: 'ISMS (ISO 27001)',
nameShort: 'ISMS',
package: 'betrieb',
seq: 5100,
checkpointId: 'CP-ISMS',
checkpointType: 'RECOMMENDED',
checkpointReviewer: 'DSB',
description: 'Informationssicherheits-Managementsystem: Scope, Policies, SoA, Audits, CAPA, Management-Reviews und Readiness-Check.',
descriptionLong: 'ISO 27001 Zertifizierungsvorbereitung. Verwaltet den ISMS-Scope (Kap. 4.3), Kontextanalyse (4.1/4.2), Sicherheitspolicies (5.2), Security Objectives mit SMART-KPIs (6.2), Statement of Applicability fuer alle 93 Annex-A-Controls, interne Audits (9.2), Management-Reviews (9.3), Audit-Findings mit CAPA-Workflow und einen automatischen Readiness-Check der potenzielle Major/Minor-Findings vor der externen Zertifizierung identifiziert.',
legalBasis: 'ISO/IEC 27001:2022, Art. 32 DSGVO (Sicherheit der Verarbeitung)',
inputs: ['risks', 'controls', 'requirements'],
outputs: ['ismsReadiness'],
prerequisiteSteps: ['quality'],
dbTables: [
'compliance_isms_scope', 'compliance_isms_context', 'compliance_isms_policy',
'compliance_security_objectives', 'compliance_soa',
'compliance_audit_findings', 'compliance_corrective_actions',
'compliance_management_reviews', 'compliance_internal_audits',
'compliance_audit_trail', 'compliance_isms_readiness_checks',
],
dbMode: 'read/write',
ragCollections: [],
isOptional: true,
url: '/sdk/isms',
completion: 100,
},
]

View File

@@ -0,0 +1,260 @@
/**
* SDK Flow Steps — Paket 3: Dokumentation (seq 20002500)
* + Paket 4: Rechtliche Texte (seq 30003400)
*/
import type { SDKFlowStep } from './types'
export const STEPS_DOKUMENTATION: SDKFlowStep[] = [
{
id: 'obligations',
name: 'Pflichtenuebersicht',
nameShort: 'Pflichten',
package: 'dokumentation',
seq: 2000,
checkpointId: 'CP-OBL',
checkpointType: 'REQUIRED',
checkpointReviewer: 'NONE',
description: 'Zusammenfassung aller gesetzlichen Pflichten aus DSGVO, AI Act, NIS2.',
descriptionLong: 'Die Pflichtenuebersicht konsolidiert alle gesetzlichen Pflichten, die sich aus den Requirements, der AI-Act-Klassifizierung und den aktivierten Modulen ergeben. Wenn applicableRegulations aus dem Scope-Profiling vorliegen, werden diese direkt als Vorfilter verwendet. Fuer jede Pflicht wird angegeben: Welches Gesetz (DSGVO, AI Act, NIS2), welcher Artikel, welche Frist, wer verantwortlich ist und welche Massnahmen erforderlich sind. Die RAG-Collection bp_compliance_recht liefert aktuelle Pflichtentexte und Auslegungshinweise.',
legalBasis: 'Art. 5 Abs. 2 DSGVO, Art. 9 AI Act',
inputs: ['requirements', 'aiActClassification', 'modules', 'applicableRegulations'],
outputs: ['obligationsOverview'],
prerequisiteSteps: ['audit-report'],
dbTables: ['compliance_obligations'],
dbMode: 'read/write',
ragCollections: ['bp_compliance_recht'],
ragPurpose: 'NIS2, DSGVO, AI Act Pflichtentexte',
isOptional: false,
url: '/sdk/obligations',
},
{
id: 'dsfa',
name: 'DSFA',
nameShort: 'DSFA',
package: 'dokumentation',
seq: 2100,
checkpointId: 'CP-DSFA',
checkpointType: 'REQUIRED',
checkpointReviewer: 'DSB',
description: 'Datenschutz-Folgenabschaetzung fuer Hochrisiko-Verarbeitungen. Draft-Modus (v1 + v2) nutzt RAG fuer rechtliche Praezision.',
descriptionLong: 'Die Datenschutz-Folgenabschaetzung (DSFA) ist nach Art. 35 DSGVO fuer Verarbeitungen mit hohem Risiko vorgeschrieben. Sie bewertet systematisch die Notwendigkeit, Verhaeltnismaessigkeit und Risiken der Datenverarbeitung. Die DSFA enthaelt: Beschreibung der Verarbeitung, Bewertung der Notwendigkeit, Risikobewertung fuer die Betroffenen, geplante Abhilfemassnahmen. Der DSB muss die DSFA freigeben. Bei verbleibendem Hochrisiko muss die Aufsichtsbehoerde konsultiert werden. Sowohl der v1- als auch der v2-Draft-Modus werden mit rechtlichem Kontext aus dem RAG-Corpus (bp_dsfa_corpus) angereichert. Die shared queryRAG-Utility (rag-query.ts) wird von Chat- und Draft-Pipelines gemeinsam genutzt.',
legalBasis: 'Art. 35, 36 DSGVO (DSFA und vorherige Konsultation)',
inputs: ['risks', 'aiActClassification', 'modules'],
outputs: ['dsfa'],
prerequisiteSteps: ['obligations'],
dbTables: [],
dbMode: 'none',
ragCollections: ['bp_dsfa_corpus'],
ragPurpose: 'DSFA-Vorlagen, Bewertungskriterien und Art. 35 DSGVO Rechtstexte. v1-Pipeline haengt RAG-Kontext an System-Prompt an, v2-Pipeline injiziert ihn pro Block als RECHTSKONTEXT-Referenz.',
generates: ['DSFA-Report'],
isOptional: true,
url: '/sdk/dsfa',
},
{
id: 'tom',
name: 'TOMs',
nameShort: 'TOMs',
package: 'dokumentation',
seq: 2200,
checkpointId: 'CP-TOM',
checkpointType: 'REQUIRED',
checkpointReviewer: 'NONE',
description: 'Dokumentation aller Technisch-Organisatorischen Massnahmen nach Art. 32 DSGVO.',
descriptionLong: 'Die Technisch-Organisatorischen Massnahmen (TOMs) dokumentieren alle Sicherheitsmassnahmen, die zum Schutz personenbezogener Daten implementiert sind. TOMs umfassen: Zutrittskontrolle, Zugangskontrolle, Zugriffskontrolle, Weitergabekontrolle, Eingabekontrolle, Auftragskontrolle, Verfuegbarkeitskontrolle und Trennungsgebot. Jede Massnahme wird mit Implementierungsstatus, Verantwortlichem und Pruefintervall dokumentiert. Die bestehenden Controls werden als Basis verwendet.',
legalBasis: 'Art. 32 DSGVO (Sicherheit der Verarbeitung)',
inputs: ['dsfa', 'controls', 'risks'],
outputs: ['toms'],
prerequisiteSteps: ['obligations'],
dbTables: ['compliance_controls'],
dbMode: 'read',
ragCollections: ['bp_compliance_datenschutz'],
ragPurpose: 'TOM-Massnahmenkataloge',
isOptional: false,
url: '/sdk/tom',
},
{
id: 'loeschfristen',
name: 'Loeschfristen',
nameShort: 'Loeschfristen',
package: 'dokumentation',
seq: 2300,
checkpointId: 'CP-RET',
checkpointType: 'REQUIRED',
checkpointReviewer: 'NONE',
description: 'Festlegung von Aufbewahrungs- und Loeschfristen fuer alle Datenkategorien.',
descriptionLong: 'Fuer jede Datenkategorie werden gesetzliche Aufbewahrungsfristen und Loeschzeitpunkte definiert. Dabei werden gesetzliche Mindestaufbewahrungsfristen (z.B. 10 Jahre Steuerrecht, 6 Jahre Handelsrecht, 3 Jahre Verjaehrung) mit dem Grundsatz der Datenminimierung abgewogen. Das Loeschkonzept definiert: Welche Daten, wann geloescht, wie geloescht (Anonymisierung vs. physische Loeschung) und wer verantwortlich ist.',
legalBasis: 'Art. 5 Abs. 1e DSGVO (Speicherbegrenzung), Art. 17 DSGVO (Recht auf Loeschung)',
inputs: ['vvt', 'dataMapping'],
outputs: ['retentionPolicies'],
prerequisiteSteps: ['tom'],
dbTables: ['compliance_loeschfristen'],
dbMode: 'read/write',
ragCollections: ['bp_compliance_recht'],
ragPurpose: 'Aufbewahrungsfristen nach Gesetz',
isOptional: false,
url: '/sdk/loeschfristen',
},
{
id: 'vvt',
name: 'Verarbeitungsverzeichnis',
nameShort: 'VVT',
package: 'dokumentation',
seq: 2400,
checkpointId: 'CP-VVT',
checkpointType: 'REQUIRED',
checkpointReviewer: 'DSB',
description: 'Erstellung des Verzeichnisses aller Verarbeitungstaetigkeiten nach Art. 30 DSGVO — vollstaendig backend-persistent.',
descriptionLong: 'Das VVT (Verzeichnis von Verarbeitungstaetigkeiten) ist eine gesetzliche Pflichtdokumentation nach Art. 30 DSGVO. Fuer jede Verarbeitungstaetigkeit wird dokumentiert: Zweck, Rechtsgrundlage, Kategorien betroffener Personen, Datenkategorien, Empfaenger, Drittlandtransfers, Loeschfristen und TOMs. Jede Aktivitaet wird mit einem eindeutigen VVT-ID versehen und in der Datenbank gespeichert (compliance_vvt_activities). Organisationsweite Metadaten (DSB-Kontakt, Branche, Standorte) werden separat verwaltet (compliance_vvt_organization). Alle Aenderungen werden in einem Audit-Log protokolliert (compliance_vvt_audit_log). Das VVT wird via FastAPI-Backend (backend-compliance:8002) persistent gespeichert. Der DSB muss das VVT freigeben.',
legalBasis: 'Art. 30 DSGVO (Verzeichnis von Verarbeitungstaetigkeiten)',
inputs: ['modules', 'toms', 'dataMapping'],
outputs: ['vvt'],
prerequisiteSteps: ['loeschfristen'],
dbTables: ['compliance_vvt_organization', 'compliance_vvt_activities', 'compliance_vvt_audit_log'],
dbMode: 'read/write',
ragCollections: ['bp_compliance_gesetze'],
ragPurpose: 'Art. 30 DSGVO Vorlage',
isOptional: false,
url: '/sdk/vvt',
},
{
id: 'vendor-compliance',
name: 'Vendor Compliance',
nameShort: 'Vendor',
package: 'dokumentation',
seq: 2500,
checkpointId: 'CP-VEND',
checkpointType: 'REQUIRED',
checkpointReviewer: 'NONE',
description: 'Pruefung und Verwaltung aller Auftragsverarbeiter und Drittanbieter — Cross-Modul-Integration mit VVT, Obligations, TOM und Loeschfristen.',
descriptionLong: 'Vendor Compliance verwaltet alle externen Dienstleister, die im Auftrag personenbezogene Daten verarbeiten (Auftragsverarbeiter nach Art. 28 DSGVO). Fuer jeden Vendor wird geprueft: Gibt es einen AVV? Wo werden Daten gespeichert (EU/Drittland)? Welche TOMs hat der Vendor? Gibt es Subunternehmer? Cross-Modul-Integration: VVT-Processor-Tab liest Vendors mit role=PROCESSOR direkt aus der Vendor-API, Obligations und Loeschfristen verknuepfen Vendors ueber linked_vendor_ids (JSONB), TOM zeigt Vendor-Controls als Querverweis.',
legalBasis: 'Art. 28 DSGVO (Auftragsverarbeiter), Art. 44-49 (Drittlandtransfer)',
inputs: ['modules', 'vvt'],
outputs: ['vendorAssessments', 'vendorControlInstances'],
prerequisiteSteps: ['vvt'],
dbTables: ['vendor_vendors', 'vendor_contracts', 'vendor_findings', 'vendor_control_instances', 'compliance_templates'],
dbMode: 'read/write',
ragCollections: ['bp_compliance_recht'],
ragPurpose: 'AVV-Vorlagen und Pruefkataloge',
isOptional: false,
url: '/sdk/vendor-compliance',
completion: 100,
},
]
export const STEPS_RECHTLICHE_TEXTE: SDKFlowStep[] = [
{
id: 'einwilligungen',
name: 'Einwilligungen',
nameShort: 'Einwilligungen',
package: 'rechtliche-texte',
seq: 3000,
checkpointId: 'CP-CONS',
checkpointType: 'REQUIRED',
checkpointReviewer: 'NONE',
description: 'Definition aller Einwilligungserklaerungen — vollstaendig backend-persistent mit Nachweis-Tracking.',
descriptionLong: 'Basierend auf dem VVT und den aktivierten Modulen werden alle Verarbeitungen identifiziert, die eine Einwilligung erfordern (Art. 6 Abs. 1a DSGVO). Der Datenkatalog definiert einwilligungspflichtige Datenpunkte. Erteilte und widerrufene Einwilligungen werden mit vollstaendigem Audit-Trail gespeichert: Zeitpunkt, Version, IP-Adresse, User-Agent, Quelle. Widerruf setzt `revoked_at` ohne den urspruenglichen Eintrag zu loeschen (Nachweispflicht). Cookie-Banner-Konfiguration ist ebenfalls hier zentral verwaltet.',
legalBasis: 'Art. 6 Abs. 1a, Art. 7 DSGVO (Einwilligung)',
inputs: ['vvt', 'modules'],
outputs: ['consents'],
prerequisiteSteps: ['vvt'],
dbTables: ['compliance_einwilligungen_catalog', 'compliance_einwilligungen_company', 'compliance_einwilligungen_consents', 'compliance_einwilligungen_cookies'],
dbMode: 'read/write',
ragCollections: ['bp_compliance_datenschutz'],
ragPurpose: 'Einwilligungsvorlagen DSGVO',
isOptional: false,
url: '/sdk/einwilligungen',
completion: 100,
},
{
id: 'consent',
name: 'Rechtliche Vorlagen',
nameShort: 'Vorlagen',
package: 'rechtliche-texte',
seq: 3100,
checkpointId: 'CP-DOC',
checkpointType: 'REQUIRED',
checkpointReviewer: 'NONE',
description: 'Verwaltung von Datenschutzerklaerung, AGB und Nutzungsbedingungen — vollstaendig backend-persistent.',
descriptionLong: 'In diesem Schritt werden die zentralen rechtlichen Dokumente verwaltet: Datenschutzerklaerung (Art. 13/14 DSGVO), AGB, Cookie-Richtlinie, Impressum und AVV. Jedes Dokument wird in `compliance_legal_documents` gespeichert. Ueber den Vorschau-Button kann die aktuell veroffentlichte HTML-Version im Browser angezeigt werden. Per Bearbeiten-Button gelangt man direkt in den Document Workflow. Schnellaktionen navigieren zum Dokumentengenerator fuer KI-gestuetzte Template-Generierung.',
legalBasis: 'Art. 13, 14 DSGVO (Informationspflichten)',
inputs: ['companyProfile', 'vvt', 'consents'],
outputs: ['documents'],
prerequisiteSteps: ['einwilligungen'],
dbTables: ['compliance_legal_documents', 'compliance_legal_document_versions'],
dbMode: 'read/write',
ragCollections: ['bp_legal_templates'],
ragPurpose: 'AGB, DSE, Nutzungsbedingungen Templates',
generates: ['Datenschutzerklaerung', 'AGB', 'Nutzungsbedingungen'],
isOptional: false,
url: '/sdk/consent',
completion: 100,
},
{
id: 'cookie-banner',
name: 'Cookie Banner',
nameShort: 'Cookies',
package: 'rechtliche-texte',
seq: 3200,
checkpointId: 'CP-COOK',
checkpointType: 'REQUIRED',
checkpointReviewer: 'NONE',
description: 'Konfiguration eines rechtskonformen Cookie-Banners — Texte und Kategorien persistent in DB.',
descriptionLong: 'Der Cookie-Banner wird basierend auf den definierten Einwilligungen konfiguriert. Alle Einstellungen (Position, Stil, Farbe, Texte) und Kategorien werden in `compliance_einwilligungen_cookies` gespeichert. Banner-Texte (Ueberschrift, Beschreibung, Datenschutz-Link) sind Controlled Inputs und werden beim Speichern persistiert. Die Live-Vorschau aktualisiert sich in Echtzeit. Der Embed-Code wird beim Export aus der DB-Konfiguration generiert — kein In-Memory-Speicher, kein Datenverlust bei Neustart. Implementiert "Privacy by Default": nur notwendige Cookies sind vorausgewaehlt.',
legalBasis: 'Art. 5 Abs. 3 ePrivacy-RL, TTDSG § 25',
inputs: ['consents', 'companyProfile'],
outputs: ['cookieBanner'],
prerequisiteSteps: ['consent'],
dbTables: ['compliance_einwilligungen_cookies'],
dbMode: 'read/write',
ragCollections: ['bp_compliance_datenschutz'],
ragPurpose: 'Cookie-Consent Richtlinien',
isOptional: false,
url: '/sdk/cookie-banner',
completion: 100,
},
{
id: 'document-generator',
name: 'Dokumentengenerator',
nameShort: 'Generator',
package: 'rechtliche-texte',
seq: 3300,
checkpointId: 'CP-DOCGEN',
checkpointType: 'RECOMMENDED',
checkpointReviewer: 'NONE',
description: 'Generierung weiterer rechtlicher Dokumente (Impressum, AVV, Auftragsverarbeitung) mit PDF-Export.',
descriptionLong: 'Der Dokumentengenerator erstellt zusaetzliche rechtliche Dokumente, die ueber die Pflichtdokumente hinausgehen: Impressum (nach TMG/DDG), Auftragsverarbeitungsvertraege (AVV nach Art. 28 DSGVO), Vertraulichkeitsvereinbarungen, Betriebsvereinbarungen zum Datenschutz und Datenschutz-Folgenabschaetzungs-Berichte. Die Templates werden aus bp_legal_templates geladen und mit den unternehmensspezifischen Daten befuellt. PDF-Export ist direkt im Browser via window.print() moeglich. Steht der Template-Service (breakpilot-core) nicht bereit, erscheint ein Fallback-Banner mit Hinweis.',
legalBasis: 'Art. 28 DSGVO (Auftragsverarbeitung), DDG § 5 (Impressum)',
inputs: ['companyProfile', 'toms', 'vvt'],
outputs: ['generatedDocuments'],
prerequisiteSteps: ['cookie-banner'],
dbTables: [],
dbMode: 'none',
ragCollections: ['bp_legal_templates'],
ragPurpose: 'Dokumenten-Templates',
generates: ['Impressum', 'Auftragsverarbeitungsvertrag'],
isOptional: true,
url: '/sdk/document-generator',
completion: 100,
},
{
id: 'workflow',
name: 'Document Workflow',
nameShort: 'Workflow',
package: 'rechtliche-texte',
seq: 3400,
checkpointId: 'CP-WRKF',
checkpointType: 'REQUIRED',
checkpointReviewer: 'NONE',
description: 'Freigabe-Workflow fuer alle rechtlichen Dokumente — vollstaendig backend-persistent mit Versionierung.',
descriptionLong: 'Der Document Workflow steuert den Freigabeprozess fuer alle rechtlichen Dokumente. Split-View-Editor: linkes Panel zeigt die veroffentlichte Version, rechtes Panel den Entwurf. Status-Workflow: draft → review → approved → published (oder rejected). Alle Versionen werden in `compliance_legal_document_versions` gespeichert. Der Versions-Endpoint gibt ein direktes JSON-Array zurueck. DOCX-Import via multipart/form-data moeglich. Freigabe-Historie wird in `compliance_legal_document_approvals` protokolliert (Zeitstempel, Benutzer, Kommentar). Veroeffentlichte Versionen sind unveraenderlich — Aenderungen erzeugen stets eine neue Version.',
inputs: ['documents', 'generatedDocuments'],
outputs: ['approvedDocuments'],
prerequisiteSteps: ['cookie-banner'],
dbTables: ['compliance_legal_documents', 'compliance_legal_document_versions', 'compliance_legal_document_approvals'],
dbMode: 'read/write',
ragCollections: [],
isOptional: false,
url: '/sdk/workflow',
completion: 100,
},
]

View File

@@ -0,0 +1,147 @@
/**
* SDK Flow Steps — Paket 1: Vorbereitung (seq 100700)
*/
import type { SDKFlowStep } from './types'
export const STEPS_VORBEREITUNG: SDKFlowStep[] = [
{
id: 'company-profile',
name: 'Unternehmensprofil',
nameShort: 'Profil',
package: 'vorbereitung',
seq: 100,
checkpointId: 'CP-PROF',
checkpointType: 'REQUIRED',
checkpointReviewer: 'NONE',
description: 'Erfassung aller Stammdaten des Unternehmens als Grundlage fuer die Compliance-Analyse.',
descriptionLong: 'Hier werden alle relevanten Unternehmensdaten erfasst: Firmenname, Rechtsform, Branche, Mitarbeiterzahl, Standorte, Datenschutzbeauftragter und Verantwortlicher. Diese Daten bilden die Basis fuer alle nachfolgenden Compliance-Schritte, da sie bestimmen, welche Regulierungen anwendbar sind (z.B. DSGVO, NIS2, AI Act). Nach Abschluss zeigt eine Summary-Seite alle erfassten Daten auf einen Blick. Ohne ein vollstaendiges Unternehmensprofil koennen keine weiteren Schritte durchgefuehrt werden.',
inputs: [],
outputs: ['companyProfile', 'complianceScope'],
prerequisiteSteps: [],
dbTables: ['sdk_states', 'compliance_company_profiles', 'compliance_company_profile_audit'],
dbMode: 'read/write',
ragCollections: [],
isOptional: false,
url: '/sdk/company-profile',
},
{
id: 'compliance-scope',
name: 'Compliance Scope',
nameShort: 'Scope',
package: 'vorbereitung',
seq: 200,
checkpointId: 'CP-SCOPE',
checkpointType: 'REQUIRED',
checkpointReviewer: 'NONE',
description: 'Bestimmung der Compliance-Tiefe und des Umfangs basierend auf Unternehmensprofil.',
descriptionLong: 'Basierend auf dem Unternehmensprofil wird automatisch ermittelt, wie tiefgehend die Compliance-Analyse sein muss. Kleine Unternehmen mit wenig Datenverarbeitung erhalten eine "BASIS"-Tiefe, waehrend grosse Unternehmen mit sensiblen Daten oder KI-Systemen eine "ERWEITERT" oder "VOLLSTAENDIG"-Tiefe erhalten. Der Compliance-Scope bestimmt, welche Module aktiviert werden und wie detailliert die Dokumentation sein muss. Zusaetzlich werden anwendbare Regulierungen (DSGVO, AI Act, NIS2 etc.) und zustaendige Aufsichtsbehoerden automatisch abgeleitet.',
inputs: ['companyProfile'],
outputs: ['complianceDepthLevel', 'applicableRegulations', 'supervisoryAuthorities'],
prerequisiteSteps: ['company-profile'],
dbTables: ['sdk_states'],
dbMode: 'read/write',
ragCollections: [],
isOptional: false,
url: '/sdk/compliance-scope',
},
{
id: 'use-case-assessment',
name: 'Anwendungsfall-Erfassung',
nameShort: 'Anwendung',
package: 'vorbereitung',
seq: 300,
checkpointId: 'CP-UC',
checkpointType: 'REQUIRED',
checkpointReviewer: 'NONE',
description: 'Systematische Erfassung aller Datenverarbeitungs- und KI-Anwendungsfaelle ueber einen 8-Schritte-Wizard mit Kachel-Auswahl.',
descriptionLong: 'In einem 8-Schritte-Wizard werden alle Use Cases erfasst: (1) Grundlegendes — Titel, Beschreibung, KI-Kategorie (21 Kacheln), Branche wird automatisch aus dem Profil abgeleitet. (2) Datenkategorien — ~60 Kategorien in 10 Gruppen als Kacheln (inkl. Art. 9 hervorgehoben). (3) Verarbeitungszweck — 16 Zweck-Kacheln, Rechtsgrundlage wird vom SDK automatisch ermittelt. (4) Automatisierungsgrad — assistiv/teilautomatisiert/vollautomatisiert. (5) Hosting & Modell — Provider, Region, Modellnutzung (Inferenz/RAG/Fine-Tuning/Training). (6) Datentransfer — Transferziele und Schutzmechanismen. (7) Datenhaltung — Aufbewahrungsfristen. (8) Vertraege — vorhandene Compliance-Dokumente. Die RAG-Collection bp_compliance_ce wird verwendet, um relevante CE-Regulierungen automatisch den Use Cases zuzuordnen (UCCA).',
legalBasis: 'Art. 30 DSGVO (Verzeichnis von Verarbeitungstaetigkeiten)',
inputs: ['companyProfile'],
outputs: ['useCases'],
prerequisiteSteps: ['company-profile'],
dbTables: ['ucca_assessments', 'ucca_findings', 'ucca_controls'],
dbMode: 'read/write',
ragCollections: ['bp_compliance_ce'],
ragPurpose: 'CE-Regulierungen fuer Use-Case Matching',
isOptional: false,
url: '/sdk/use-cases',
},
{
id: 'import',
name: 'Dokument-Import',
nameShort: 'Import',
package: 'vorbereitung',
seq: 400,
description: 'Import bestehender Compliance-Dokumente (Datenschutzerklaerungen, TOMs, VVTs).',
descriptionLong: 'Optionaler Schritt zum Import bereits vorhandener Compliance-Dokumente. Der Document Crawler analysiert hochgeladene PDFs, Word-Dokumente oder bestehende Datenschutzerklaerungen und extrahiert automatisch relevante Informationen wie bestehende TOMs, Verarbeitungsverzeichnisse oder Risikoanalysen. Diese importierten Daten werden als Grundlage fuer die nachfolgenden Schritte verwendet, damit nicht alles von Null aufgebaut werden muss.',
inputs: ['useCases'],
outputs: ['importedDocuments'],
prerequisiteSteps: ['use-case-assessment'],
dbTables: ['compliance_imported_documents', 'compliance_gap_analyses'],
dbMode: 'read/write',
ragCollections: [],
isOptional: true,
url: '/sdk/import',
},
{
id: 'screening',
name: 'System Screening',
nameShort: 'Screening',
package: 'vorbereitung',
seq: 500,
checkpointId: 'CP-SCAN',
checkpointType: 'REQUIRED',
checkpointReviewer: 'NONE',
description: 'Technische Analyse der eingesetzten Software, Dienste und deren Abhaengigkeiten.',
descriptionLong: 'Das System Screening analysiert die technische Infrastruktur des Unternehmens. Es werden alle eingesetzten Software-Systeme, Cloud-Dienste, APIs und deren Abhaengigkeiten erfasst. Dabei wird auch eine SBOM (Software Bill of Materials) erstellt, die alle Drittanbieter-Komponenten und deren Lizenzen dokumentiert. Das Screening identifiziert potenzielle Compliance-Risiken wie Datentransfers in Drittlaender, unsichere Abhaengigkeiten oder fehlende Verschluesselung.',
inputs: ['useCases'],
outputs: ['screening', 'sbom'],
prerequisiteSteps: ['use-case-assessment'],
dbTables: ['compliance_screenings', 'compliance_security_issues'],
dbMode: 'read/write',
ragCollections: [],
isOptional: false,
url: '/sdk/screening',
},
{
id: 'modules',
name: 'Compliance Modules',
nameShort: 'Module',
package: 'vorbereitung',
seq: 600,
checkpointId: 'CP-MOD',
checkpointType: 'REQUIRED',
checkpointReviewer: 'NONE',
description: 'Aktivierung der relevanten Compliance-Module basierend auf Screening-Ergebnissen.',
descriptionLong: 'Basierend auf dem Unternehmensprofil und den Screening-Ergebnissen werden die relevanten Compliance-Module aktiviert. Module umfassen z.B. DSGVO-Grundschutz, AI Act, NIS2, ePrivacy, Whistleblower-Richtlinie usw. Die RAG-Collection bp_compliance_gesetze wird verwendet, um aktuelle Gesetzestexte den Modulen zuzuordnen. Nur aktivierte Module erzeugen in den nachfolgenden Schritten Anforderungen, Controls und Dokumentation.',
inputs: ['companyProfile', 'screening'],
outputs: ['modules'],
prerequisiteSteps: ['screening'],
dbTables: ['compliance_service_modules', 'sdk_states'],
dbMode: 'read/write',
ragCollections: ['bp_compliance_gesetze'],
ragPurpose: 'Regulierungen den Modulen zuordnen',
isOptional: false,
url: '/sdk/modules',
},
{
id: 'source-policy',
name: 'Source Policy',
nameShort: 'Quellen',
package: 'vorbereitung',
seq: 700,
checkpointId: 'CP-SPOL',
checkpointType: 'REQUIRED',
checkpointReviewer: 'NONE',
description: 'Festlegung der Rechtsquellen und Normen fuer die Compliance-Analyse.',
descriptionLong: 'Die Source Policy definiert, welche Rechtsquellen und Normen fuer die Compliance-Analyse herangezogen werden. Dies umfasst EU-Verordnungen (DSGVO, AI Act, NIS2), nationale Gesetze (BDSG, TTDSG), Branchenstandards (ISO 27001, BSI Grundschutz) und interne Richtlinien. Die Source Policy stellt sicher, dass alle nachfolgenden Schritte konsistent auf denselben Rechtsgrundlagen basieren.',
inputs: ['modules'],
outputs: ['sourcePolicy'],
prerequisiteSteps: ['modules'],
dbTables: ['compliance_allowed_sources', 'compliance_pii_rules', 'compliance_source_operations', 'compliance_source_policy_audit'],
dbMode: 'read/write',
ragCollections: [],
isOptional: false,
url: '/sdk/source-policy',
},
]

View File

@@ -0,0 +1,75 @@
/**
* SDK Flow — Shared Types and Package Metadata
*/
export interface SDKFlowStep {
id: string
name: string
nameShort: string
package: 'vorbereitung' | 'analyse' | 'dokumentation' | 'rechtliche-texte' | 'betrieb'
seq: number
checkpointId?: string
checkpointType?: 'REQUIRED' | 'RECOMMENDED'
checkpointReviewer?: 'NONE' | 'DSB' | 'LEGAL'
// Beschreibung
description: string
descriptionLong: string
legalBasis?: string
// Datenfluss
inputs: string[]
outputs: string[]
prerequisiteSteps: string[]
// Infrastruktur
dbTables: string[]
dbMode: 'read' | 'write' | 'read/write' | 'none'
ragCollections: string[]
ragPurpose?: string
// Generierung
generates?: string[]
isOptional?: boolean
url: string
/**
* Fertigstellungsgrad in Prozent (0100).
* Nur für Betrieb-Module gesetzt (außer academy/training).
* Berechnung: Frontend-Reifegrad + Backend-Persistenz + API-Abdeckung.
*/
completion?: number
}
export const FLOW_PACKAGES = {
vorbereitung: {
name: 'Vorbereitung',
nameShort: 'Vorb.',
icon: '🎯',
color: { bg: '#dbeafe', border: '#3b82f6', text: '#1e40af' },
},
analyse: {
name: 'Analyse',
nameShort: 'Analyse',
icon: '🔍',
color: { bg: '#fef3c7', border: '#f59e0b', text: '#92400e' },
},
dokumentation: {
name: 'Dokumentation',
nameShort: 'Doku',
icon: '📋',
color: { bg: '#ede9fe', border: '#7c3aed', text: '#5b21b6' },
},
'rechtliche-texte': {
name: 'Rechtliche Texte',
nameShort: 'Legal',
icon: '📝',
color: { bg: '#d1fae5', border: '#10b981', text: '#065f46' },
},
betrieb: {
name: 'Betrieb',
nameShort: 'Betrieb',
icon: '⚙️',
color: { bg: '#f1f5f9', border: '#64748b', text: '#334155' },
},
} as const

View File

@@ -1,734 +1,12 @@
/** /**
* SDK Catalog Manager - Central Registry * SDK Catalog Manager - Central Registry
* *
* Maps all SDK catalogs to a unified interface for browsing, searching, and CRUD. * Barrel re-export — split into domain modules under registry/.
* Do NOT import directly from registry/ sub-files in consumers;
* always import from this barrel to preserve the stable public path.
*/ */
import type { export * from './registry/registry-dsfa'
CatalogId, export * from './registry/registry-vendor'
CatalogMeta, export * from './registry/registry-reference'
CatalogModule, export * from './registry/registry-api'
CatalogEntry,
CatalogStats,
CatalogOverviewStats,
CustomCatalogEntry,
CustomCatalogs,
} from './types'
// =============================================================================
// CATALOG DATA IMPORTS
// =============================================================================
import { RISK_CATALOG } from '../dsfa/risk-catalog'
import { MITIGATION_LIBRARY } from '../dsfa/mitigation-library'
import { AI_RISK_CATALOG } from '../dsfa/ai-risk-catalog'
import { AI_MITIGATION_LIBRARY } from '../dsfa/ai-mitigation-library'
import { PROHIBITED_AI_PRACTICES } from '../dsfa/prohibited-ai-practices'
import { EU_BASE_FRAMEWORKS, NATIONAL_FRAMEWORKS } from '../dsfa/eu-legal-frameworks'
import { GDPR_ENFORCEMENT_CASES } from '../dsfa/gdpr-enforcement-cases'
import { WP248_CRITERIA, SDM_GOALS, DSFA_AUTHORITY_RESOURCES } from '../dsfa/types'
import { VVT_BASELINE_CATALOG } from '../vvt-baseline-catalog'
import { BASELINE_TEMPLATES } from '../loeschfristen-baseline-catalog'
import { VENDOR_TEMPLATES, COUNTRY_RISK_PROFILES } from '../vendor-compliance/catalog/vendor-templates'
import { LEGAL_BASIS_INFO, STANDARD_RETENTION_PERIODS } from '../vendor-compliance/catalog/legal-basis'
// =============================================================================
// HELPER: Resolve localized text fields
// =============================================================================
function resolveField(value: unknown): string {
if (value === null || value === undefined) return ''
if (typeof value === 'string') return value
if (typeof value === 'number') return String(value)
if (typeof value === 'object' && 'de' in (value as Record<string, unknown>)) {
return String((value as Record<string, string>).de || '')
}
return String(value)
}
// =============================================================================
// SDM_GOALS as entries array (it's a Record, not an array)
// =============================================================================
const SDM_GOALS_ENTRIES = Object.entries(SDM_GOALS).map(([key, val]) => ({
id: key,
name: val.name,
description: val.description,
article: val.article,
}))
// =============================================================================
// CATALOG REGISTRY
// =============================================================================
export const CATALOG_REGISTRY: Record<CatalogId, CatalogMeta> = {
'dsfa-risks': {
id: 'dsfa-risks',
name: 'DSFA Risikokatalog',
description: 'Standardrisiken fuer Datenschutz-Folgenabschaetzungen',
module: 'dsfa',
icon: 'ShieldAlert',
systemCount: RISK_CATALOG.length,
allowCustom: true,
idField: 'id',
nameField: 'title',
descriptionField: 'description',
categoryField: 'category',
fields: [
{ key: 'id', label: 'Risiko-ID', type: 'text', required: true, placeholder: 'R-XXX-01' },
{ key: 'title', label: 'Titel', type: 'text', required: true },
{ key: 'description', label: 'Beschreibung', type: 'textarea', required: true },
{ key: 'category', label: 'Kategorie', type: 'select', required: true, options: [
{ value: 'confidentiality', label: 'Vertraulichkeit' },
{ value: 'integrity', label: 'Integritaet' },
{ value: 'availability', label: 'Verfuegbarkeit' },
{ value: 'rights_freedoms', label: 'Rechte & Freiheiten' },
]},
{ key: 'typicalLikelihood', label: 'Typische Eintrittswahrscheinlichkeit', type: 'select', required: false, options: [
{ value: 'low', label: 'Niedrig' },
{ value: 'medium', label: 'Mittel' },
{ value: 'high', label: 'Hoch' },
]},
{ key: 'typicalImpact', label: 'Typische Auswirkung', type: 'select', required: false, options: [
{ value: 'low', label: 'Niedrig' },
{ value: 'medium', label: 'Mittel' },
{ value: 'high', label: 'Hoch' },
]},
],
searchableFields: ['id', 'title', 'description', 'category'],
},
'dsfa-mitigations': {
id: 'dsfa-mitigations',
name: 'DSFA Massnahmenbibliothek',
description: 'Technische und organisatorische Massnahmen fuer DSFAs',
module: 'dsfa',
icon: 'Shield',
systemCount: MITIGATION_LIBRARY.length,
allowCustom: true,
idField: 'id',
nameField: 'title',
descriptionField: 'description',
categoryField: 'type',
fields: [
{ key: 'id', label: 'Massnahmen-ID', type: 'text', required: true, placeholder: 'M-XXX-01' },
{ key: 'title', label: 'Titel', type: 'text', required: true },
{ key: 'description', label: 'Beschreibung', type: 'textarea', required: true },
{ key: 'type', label: 'Typ', type: 'select', required: true, options: [
{ value: 'technical', label: 'Technisch' },
{ value: 'organizational', label: 'Organisatorisch' },
{ value: 'legal', label: 'Rechtlich' },
]},
{ key: 'effectiveness', label: 'Wirksamkeit', type: 'select', required: false, options: [
{ value: 'low', label: 'Niedrig' },
{ value: 'medium', label: 'Mittel' },
{ value: 'high', label: 'Hoch' },
]},
{ key: 'legalBasis', label: 'Rechtsgrundlage', type: 'text', required: false },
],
searchableFields: ['id', 'title', 'description', 'type', 'legalBasis'],
},
'ai-risks': {
id: 'ai-risks',
name: 'KI-Risikokatalog',
description: 'Spezifische Risiken fuer KI-Systeme',
module: 'ai_act',
icon: 'Bot',
systemCount: AI_RISK_CATALOG.length,
allowCustom: true,
idField: 'id',
nameField: 'title',
descriptionField: 'description',
categoryField: 'category',
fields: [
{ key: 'id', label: 'Risiko-ID', type: 'text', required: true, placeholder: 'R-AI-XXX-01' },
{ key: 'title', label: 'Titel', type: 'text', required: true },
{ key: 'description', label: 'Beschreibung', type: 'textarea', required: true },
{ key: 'category', label: 'Kategorie', type: 'select', required: true, options: [
{ value: 'confidentiality', label: 'Vertraulichkeit' },
{ value: 'integrity', label: 'Integritaet' },
{ value: 'availability', label: 'Verfuegbarkeit' },
{ value: 'rights_freedoms', label: 'Rechte & Freiheiten' },
]},
{ key: 'typicalLikelihood', label: 'Eintrittswahrscheinlichkeit', type: 'select', required: false, options: [
{ value: 'low', label: 'Niedrig' },
{ value: 'medium', label: 'Mittel' },
{ value: 'high', label: 'Hoch' },
]},
{ key: 'typicalImpact', label: 'Auswirkung', type: 'select', required: false, options: [
{ value: 'low', label: 'Niedrig' },
{ value: 'medium', label: 'Mittel' },
{ value: 'high', label: 'Hoch' },
]},
],
searchableFields: ['id', 'title', 'description', 'category'],
},
'ai-mitigations': {
id: 'ai-mitigations',
name: 'KI-Massnahmenbibliothek',
description: 'Massnahmen fuer KI-spezifische Risiken',
module: 'ai_act',
icon: 'ShieldCheck',
systemCount: AI_MITIGATION_LIBRARY.length,
allowCustom: true,
idField: 'id',
nameField: 'title',
descriptionField: 'description',
categoryField: 'type',
fields: [
{ key: 'id', label: 'Massnahmen-ID', type: 'text', required: true },
{ key: 'title', label: 'Titel', type: 'text', required: true },
{ key: 'description', label: 'Beschreibung', type: 'textarea', required: true },
{ key: 'type', label: 'Typ', type: 'select', required: true, options: [
{ value: 'technical', label: 'Technisch' },
{ value: 'organizational', label: 'Organisatorisch' },
{ value: 'legal', label: 'Rechtlich' },
]},
{ key: 'effectiveness', label: 'Wirksamkeit', type: 'select', required: false, options: [
{ value: 'low', label: 'Niedrig' },
{ value: 'medium', label: 'Mittel' },
{ value: 'high', label: 'Hoch' },
]},
],
searchableFields: ['id', 'title', 'description', 'type'],
},
'prohibited-ai-practices': {
id: 'prohibited-ai-practices',
name: 'Verbotene KI-Praktiken',
description: 'Absolut und bedingt verbotene KI-Anwendungen nach AI Act',
module: 'ai_act',
icon: 'Ban',
systemCount: PROHIBITED_AI_PRACTICES.length,
allowCustom: false,
idField: 'id',
nameField: 'title',
descriptionField: 'description',
categoryField: 'severity',
fields: [
{ key: 'id', label: 'ID', type: 'text', required: true },
{ key: 'title', label: 'Titel', type: 'text', required: true },
{ key: 'description', label: 'Beschreibung', type: 'textarea', required: true },
{ key: 'severity', label: 'Schwere', type: 'select', required: true, options: [
{ value: 'absolute', label: 'Absolutes Verbot' },
{ value: 'conditional', label: 'Bedingtes Verbot' },
]},
{ key: 'legalBasis', label: 'Rechtsgrundlage', type: 'text', required: false },
],
searchableFields: ['id', 'title', 'description', 'severity', 'legalBasis'],
},
'vvt-templates': {
id: 'vvt-templates',
name: 'VVT Baseline-Vorlagen',
description: 'Vorlagen fuer Verarbeitungstaetigkeiten',
module: 'vvt',
icon: 'FileText',
systemCount: VVT_BASELINE_CATALOG.length,
allowCustom: true,
idField: 'templateId',
nameField: 'name',
descriptionField: 'description',
categoryField: 'businessFunction',
fields: [
{ key: 'templateId', label: 'Vorlagen-ID', type: 'text', required: true },
{ key: 'name', label: 'Name', type: 'text', required: true },
{ key: 'description', label: 'Beschreibung', type: 'textarea', required: true },
{ key: 'businessFunction', label: 'Geschaeftsbereich', type: 'select', required: true, options: [
{ value: 'hr', label: 'Personal' },
{ value: 'finance', label: 'Finanzen' },
{ value: 'sales', label: 'Vertrieb' },
{ value: 'marketing', label: 'Marketing' },
{ value: 'support', label: 'Support' },
{ value: 'it', label: 'IT' },
{ value: 'other', label: 'Sonstige' },
]},
{ key: 'protectionLevel', label: 'Schutzniveau', type: 'select', required: false, options: [
{ value: 'LOW', label: 'Niedrig' },
{ value: 'MEDIUM', label: 'Mittel' },
{ value: 'HIGH', label: 'Hoch' },
]},
],
searchableFields: ['templateId', 'name', 'description', 'businessFunction'],
},
'loeschfristen-templates': {
id: 'loeschfristen-templates',
name: 'Loeschfristen-Vorlagen',
description: 'Baseline-Vorlagen fuer Aufbewahrungsfristen',
module: 'vvt',
icon: 'Clock',
systemCount: BASELINE_TEMPLATES.length,
allowCustom: true,
idField: 'templateId',
nameField: 'dataObjectName',
descriptionField: 'description',
categoryField: 'retentionDriver',
fields: [
{ key: 'templateId', label: 'Vorlagen-ID', type: 'text', required: true },
{ key: 'dataObjectName', label: 'Datenobjekt', type: 'text', required: true },
{ key: 'description', label: 'Beschreibung', type: 'textarea', required: true },
{ key: 'retentionDuration', label: 'Aufbewahrungsdauer', type: 'number', required: true, min: 0 },
{ key: 'retentionUnit', label: 'Einheit', type: 'select', required: true, options: [
{ value: 'days', label: 'Tage' },
{ value: 'months', label: 'Monate' },
{ value: 'years', label: 'Jahre' },
]},
{ key: 'deletionMethod', label: 'Loeschmethode', type: 'text', required: false },
{ key: 'responsibleRole', label: 'Verantwortlich', type: 'text', required: false },
],
searchableFields: ['templateId', 'dataObjectName', 'description', 'retentionDriver'],
},
'vendor-templates': {
id: 'vendor-templates',
name: 'AV-Vorlagen',
description: 'Vorlagen fuer Auftragsverarbeitungsvertraege',
module: 'vendor',
icon: 'Building2',
systemCount: VENDOR_TEMPLATES.length,
allowCustom: true,
idField: 'id',
nameField: 'name',
descriptionField: 'description',
categoryField: 'serviceCategory',
fields: [
{ key: 'id', label: 'ID', type: 'text', required: true },
{ key: 'name', label: 'Name', type: 'text', required: true },
{ key: 'description', label: 'Beschreibung', type: 'textarea', required: true },
{ key: 'serviceCategory', label: 'Dienstleistungskategorie', type: 'select', required: true, options: [
{ value: 'HOSTING', label: 'Hosting' },
{ value: 'CLOUD_INFRASTRUCTURE', label: 'Cloud-Infrastruktur' },
{ value: 'ANALYTICS', label: 'Analyse' },
{ value: 'CRM', label: 'CRM' },
{ value: 'ERP', label: 'ERP' },
{ value: 'HR_SOFTWARE', label: 'HR-Software' },
{ value: 'PAYMENT', label: 'Zahlungsdienstleister' },
{ value: 'EMAIL', label: 'E-Mail' },
{ value: 'MARKETING', label: 'Marketing' },
{ value: 'SUPPORT', label: 'Support' },
{ value: 'SECURITY', label: 'Sicherheit' },
{ value: 'COMMUNICATION', label: 'Kommunikation' },
{ value: 'STORAGE', label: 'Speicher' },
{ value: 'BACKUP', label: 'Backup' },
{ value: 'CDN', label: 'CDN' },
{ value: 'ACCOUNTING', label: 'Buchhaltung' },
{ value: 'CONSULTING', label: 'Beratung' },
{ value: 'OTHER', label: 'Sonstige' },
]},
{ key: 'suggestedRole', label: 'Vorgeschlagene Rolle', type: 'select', required: false, options: [
{ value: 'PROCESSOR', label: 'Auftragsverarbeiter' },
{ value: 'JOINT_CONTROLLER', label: 'Gemeinsam Verantwortlicher' },
{ value: 'CONTROLLER', label: 'Eigenstaendiger Verantwortlicher' },
{ value: 'SUB_PROCESSOR', label: 'Unterauftragnehmer' },
{ value: 'THIRD_PARTY', label: 'Dritter' },
]},
{ key: 'suggestedDataAccess', label: 'Datenzugriff', type: 'select', required: false, options: [
{ value: 'NONE', label: 'Kein Zugriff' },
{ value: 'POTENTIAL', label: 'Potenzieller Zugriff' },
{ value: 'ADMINISTRATIVE', label: 'Administrativer Zugriff' },
{ value: 'CONTENT', label: 'Inhaltlicher Zugriff' },
]},
{ key: 'suggestedTransferMechanisms', label: 'Transfer-Mechanismen', type: 'multiselect', required: false, options: [
{ value: 'ADEQUACY_DECISION', label: 'Angemessenheitsbeschluss' },
{ value: 'SCC_CONTROLLER', label: 'SCC Controller-to-Controller' },
{ value: 'SCC_PROCESSOR', label: 'SCC Controller-to-Processor' },
{ value: 'BCR', label: 'Binding Corporate Rules' },
{ value: 'DEROGATION_CONSENT', label: 'Einwilligung' },
{ value: 'DEROGATION_CONTRACT', label: 'Vertragserfuellung' },
{ value: 'CERTIFICATION', label: 'Zertifizierung' },
{ value: 'CODE_OF_CONDUCT', label: 'Verhaltensregeln' },
]},
{ key: 'suggestedContractTypes', label: 'Vertragstypen', type: 'multiselect', required: false, options: [
{ value: 'AVV', label: 'AVV (Auftragsverarbeitung)' },
{ value: 'MSA', label: 'MSA (Master Service)' },
{ value: 'SLA', label: 'SLA (Service Level)' },
{ value: 'SCC', label: 'SCC (Standardvertragsklauseln)' },
{ value: 'NDA', label: 'NDA (Geheimhaltung)' },
{ value: 'TOM_ANNEX', label: 'TOM-Anlage' },
{ value: 'CERTIFICATION', label: 'Zertifikat' },
{ value: 'SUB_PROCESSOR_LIST', label: 'Unterauftragnehmer-Liste' },
]},
{ key: 'typicalDataCategories', label: 'Typische Datenkategorien', type: 'multiselect', required: false, options: [
{ value: 'NAME', label: 'Name' },
{ value: 'CONTACT', label: 'Kontaktdaten' },
{ value: 'ADDRESS', label: 'Adressdaten' },
{ value: 'DOB', label: 'Geburtsdatum' },
{ value: 'BANK_ACCOUNT', label: 'Bankverbindung' },
{ value: 'PAYMENT_DATA', label: 'Zahlungsdaten' },
{ value: 'EMPLOYMENT_DATA', label: 'Beschaeftigungsdaten' },
{ value: 'SALARY_DATA', label: 'Gehaltsdaten' },
{ value: 'HEALTH_DATA', label: 'Gesundheitsdaten' },
{ value: 'IP_ADDRESS', label: 'IP-Adresse' },
{ value: 'USAGE_DATA', label: 'Nutzungsdaten' },
{ value: 'LOCATION_DATA', label: 'Standortdaten' },
{ value: 'COMMUNICATION_DATA', label: 'Kommunikationsdaten' },
]},
{ key: 'typicalCertifications', label: 'Typische Zertifizierungen', type: 'tags', required: false, placeholder: 'z.B. ISO 27001, SOC 2, C5' },
{ key: 'commonProviders', label: 'Typische Anbieter', type: 'tags', required: false, placeholder: 'z.B. AWS, Azure, GCP' },
],
searchableFields: ['id', 'name', 'description', 'serviceCategory', 'suggestedRole', 'commonProviders'],
},
'country-risk-profiles': {
id: 'country-risk-profiles',
name: 'Laenderrisikoprofile',
description: 'Datenschutz-Risikobewertung nach Laendern',
module: 'vendor',
icon: 'Globe',
systemCount: COUNTRY_RISK_PROFILES.length,
allowCustom: false,
idField: 'code',
nameField: 'name',
categoryField: 'riskLevel',
fields: [
{ key: 'code', label: 'Laendercode', type: 'text', required: true },
{ key: 'name', label: 'Land', type: 'text', required: true },
{ key: 'riskLevel', label: 'Risikostufe', type: 'select', required: true, options: [
{ value: 'LOW', label: 'Niedrig' },
{ value: 'MEDIUM', label: 'Mittel' },
{ value: 'HIGH', label: 'Hoch' },
{ value: 'VERY_HIGH', label: 'Sehr hoch' },
]},
{ key: 'isEU', label: 'EU-Mitglied', type: 'boolean', required: false },
{ key: 'isEEA', label: 'EWR-Mitglied', type: 'boolean', required: false },
{ key: 'hasAdequacyDecision', label: 'Angemessenheitsbeschluss', type: 'boolean', required: false },
],
searchableFields: ['code', 'name', 'riskLevel'],
},
'legal-bases': {
id: 'legal-bases',
name: 'Rechtsgrundlagen',
description: 'DSGVO Art. 6 und Art. 9 Rechtsgrundlagen',
module: 'reference',
icon: 'Scale',
systemCount: LEGAL_BASIS_INFO.length,
allowCustom: false,
idField: 'type',
nameField: 'name',
descriptionField: 'description',
categoryField: 'article',
fields: [
{ key: 'type', label: 'Typ', type: 'text', required: true },
{ key: 'article', label: 'Artikel', type: 'text', required: true },
{ key: 'name', label: 'Name', type: 'text', required: true },
{ key: 'description', label: 'Beschreibung', type: 'textarea', required: true },
{ key: 'isSpecialCategory', label: 'Besondere Kategorie (Art. 9)', type: 'boolean', required: false },
],
searchableFields: ['type', 'article', 'name', 'description'],
},
'retention-periods': {
id: 'retention-periods',
name: 'Aufbewahrungsfristen',
description: 'Gesetzliche Standard-Aufbewahrungsfristen',
module: 'reference',
icon: 'Timer',
systemCount: STANDARD_RETENTION_PERIODS.length,
allowCustom: false,
idField: 'id',
nameField: 'name',
descriptionField: 'description',
fields: [
{ key: 'id', label: 'ID', type: 'text', required: true },
{ key: 'name', label: 'Name', type: 'text', required: true },
{ key: 'legalBasis', label: 'Rechtsgrundlage', type: 'text', required: true },
{ key: 'description', label: 'Beschreibung', type: 'textarea', required: true },
],
searchableFields: ['id', 'name', 'legalBasis', 'description'],
},
'eu-legal-frameworks': {
id: 'eu-legal-frameworks',
name: 'EU-Rechtsrahmen',
description: 'EU-weite Datenschutzgesetze und -verordnungen',
module: 'reference',
icon: 'Landmark',
systemCount: EU_BASE_FRAMEWORKS.length,
allowCustom: false,
idField: 'id',
nameField: 'name',
descriptionField: 'description',
categoryField: 'type',
fields: [
{ key: 'id', label: 'ID', type: 'text', required: true },
{ key: 'name', label: 'Name', type: 'text', required: true },
{ key: 'fullName', label: 'Vollstaendiger Name', type: 'text', required: true },
{ key: 'type', label: 'Typ', type: 'text', required: true },
{ key: 'description', label: 'Beschreibung', type: 'textarea', required: true },
],
searchableFields: ['id', 'name', 'fullName', 'description', 'type'],
},
'national-legal-frameworks': {
id: 'national-legal-frameworks',
name: 'Nationale Rechtsrahmen',
description: 'Nationale Datenschutzgesetze der EU/EWR-Staaten',
module: 'reference',
icon: 'Flag',
systemCount: NATIONAL_FRAMEWORKS.length,
allowCustom: false,
idField: 'id',
nameField: 'name',
descriptionField: 'description',
categoryField: 'countryCode',
fields: [
{ key: 'id', label: 'ID', type: 'text', required: true },
{ key: 'name', label: 'Name', type: 'text', required: true },
{ key: 'countryCode', label: 'Land', type: 'text', required: true },
{ key: 'type', label: 'Typ', type: 'text', required: true },
{ key: 'description', label: 'Beschreibung', type: 'textarea', required: true },
],
searchableFields: ['id', 'name', 'countryCode', 'description', 'type'],
},
'gdpr-enforcement-cases': {
id: 'gdpr-enforcement-cases',
name: 'DSGVO-Bussgeldentscheidungen',
description: 'Relevante Bussgeldentscheidungen als Referenz',
module: 'reference',
icon: 'Gavel',
systemCount: GDPR_ENFORCEMENT_CASES.length,
allowCustom: false,
idField: 'id',
nameField: 'company',
descriptionField: 'description',
categoryField: 'country',
fields: [
{ key: 'id', label: 'ID', type: 'text', required: true },
{ key: 'company', label: 'Unternehmen', type: 'text', required: true },
{ key: 'country', label: 'Land', type: 'text', required: true },
{ key: 'year', label: 'Jahr', type: 'number', required: true },
{ key: 'fineOriginal', label: 'Bussgeld (EUR)', type: 'number', required: true },
{ key: 'description', label: 'Beschreibung', type: 'textarea', required: true },
],
searchableFields: ['id', 'company', 'country', 'description'],
},
'wp248-criteria': {
id: 'wp248-criteria',
name: 'WP248 Kriterien',
description: 'Kriterien zur DSFA-Pflichtpruefung nach WP248',
module: 'dsfa',
icon: 'ClipboardCheck',
systemCount: WP248_CRITERIA.length,
allowCustom: false,
idField: 'code',
nameField: 'title',
descriptionField: 'description',
fields: [
{ key: 'code', label: 'Code', type: 'text', required: true },
{ key: 'title', label: 'Titel', type: 'text', required: true },
{ key: 'description', label: 'Beschreibung', type: 'textarea', required: true },
{ key: 'gdprRef', label: 'DSGVO-Referenz', type: 'text', required: false },
],
searchableFields: ['code', 'title', 'description', 'gdprRef'],
},
'sdm-goals': {
id: 'sdm-goals',
name: 'SDM Gewaehrleistungsziele',
description: 'Standard-Datenschutzmodell Gewaehrleistungsziele',
module: 'dsfa',
icon: 'Target',
systemCount: SDM_GOALS_ENTRIES.length,
allowCustom: false,
idField: 'id',
nameField: 'name',
descriptionField: 'description',
fields: [
{ key: 'id', label: 'ID', type: 'text', required: true },
{ key: 'name', label: 'Name', type: 'text', required: true },
{ key: 'description', label: 'Beschreibung', type: 'textarea', required: true },
{ key: 'article', label: 'DSGVO-Artikel', type: 'text', required: false },
],
searchableFields: ['id', 'name', 'description', 'article'],
},
'dsfa-authority-resources': {
id: 'dsfa-authority-resources',
name: 'Aufsichtsbehoerden-Ressourcen',
description: 'DSFA-Ressourcen der deutschen Aufsichtsbehoerden',
module: 'dsfa',
icon: 'Building',
systemCount: DSFA_AUTHORITY_RESOURCES.length,
allowCustom: false,
idField: 'id',
nameField: 'shortName',
descriptionField: 'name',
categoryField: 'state',
fields: [
{ key: 'id', label: 'ID', type: 'text', required: true },
{ key: 'shortName', label: 'Kurzname', type: 'text', required: true },
{ key: 'name', label: 'Voller Name', type: 'text', required: true },
{ key: 'state', label: 'Bundesland', type: 'text', required: true },
],
searchableFields: ['id', 'shortName', 'name', 'state'],
},
}
// =============================================================================
// SYSTEM ENTRIES MAP
// =============================================================================
const SYSTEM_ENTRIES_MAP: Record<CatalogId, Record<string, unknown>[]> = {
'dsfa-risks': RISK_CATALOG as unknown as Record<string, unknown>[],
'dsfa-mitigations': MITIGATION_LIBRARY as unknown as Record<string, unknown>[],
'ai-risks': AI_RISK_CATALOG as unknown as Record<string, unknown>[],
'ai-mitigations': AI_MITIGATION_LIBRARY as unknown as Record<string, unknown>[],
'prohibited-ai-practices': PROHIBITED_AI_PRACTICES as unknown as Record<string, unknown>[],
'vvt-templates': VVT_BASELINE_CATALOG as unknown as Record<string, unknown>[],
'loeschfristen-templates': BASELINE_TEMPLATES as unknown as Record<string, unknown>[],
'vendor-templates': VENDOR_TEMPLATES as unknown as Record<string, unknown>[],
'country-risk-profiles': COUNTRY_RISK_PROFILES as unknown as Record<string, unknown>[],
'legal-bases': LEGAL_BASIS_INFO as unknown as Record<string, unknown>[],
'retention-periods': STANDARD_RETENTION_PERIODS as unknown as Record<string, unknown>[],
'eu-legal-frameworks': EU_BASE_FRAMEWORKS as unknown as Record<string, unknown>[],
'national-legal-frameworks': NATIONAL_FRAMEWORKS as unknown as Record<string, unknown>[],
'gdpr-enforcement-cases': GDPR_ENFORCEMENT_CASES as unknown as Record<string, unknown>[],
'wp248-criteria': WP248_CRITERIA as unknown as Record<string, unknown>[],
'sdm-goals': SDM_GOALS_ENTRIES as unknown as Record<string, unknown>[],
'dsfa-authority-resources': DSFA_AUTHORITY_RESOURCES as unknown as Record<string, unknown>[],
}
// =============================================================================
// ENTRY CONVERTERS
// =============================================================================
function systemEntryToCatalogEntry(
catalogId: CatalogId,
data: Record<string, unknown>,
): CatalogEntry {
const meta = CATALOG_REGISTRY[catalogId]
const idValue = resolveField(data[meta.idField])
const nameValue = resolveField(data[meta.nameField])
const descValue = meta.descriptionField ? resolveField(data[meta.descriptionField]) : undefined
const catValue = meta.categoryField ? resolveField(data[meta.categoryField]) : undefined
return {
id: idValue || crypto.randomUUID(),
catalogId,
source: 'system',
data,
displayName: nameValue || idValue || '(Unbenannt)',
displayDescription: descValue,
category: catValue,
}
}
function customEntryToCatalogEntry(
catalogId: CatalogId,
entry: CustomCatalogEntry,
): CatalogEntry {
const meta = CATALOG_REGISTRY[catalogId]
const nameValue = resolveField(entry.data[meta.nameField])
const descValue = meta.descriptionField ? resolveField(entry.data[meta.descriptionField]) : undefined
const catValue = meta.categoryField ? resolveField(entry.data[meta.categoryField]) : undefined
return {
id: entry.id,
catalogId,
source: 'custom',
data: entry.data,
displayName: nameValue || '(Unbenannt)',
displayDescription: descValue,
category: catValue,
}
}
// =============================================================================
// PUBLIC API
// =============================================================================
export function getSystemEntries(catalogId: CatalogId): CatalogEntry[] {
const raw = SYSTEM_ENTRIES_MAP[catalogId] || []
return raw.map(data => systemEntryToCatalogEntry(catalogId, data))
}
export function getAllEntries(
catalogId: CatalogId,
customEntries: CustomCatalogEntry[] = [],
): CatalogEntry[] {
const system = getSystemEntries(catalogId)
const custom = customEntries.map(e => customEntryToCatalogEntry(catalogId, e))
return [...system, ...custom]
}
export function getCatalogsByModule(module: CatalogModule): CatalogMeta[] {
return Object.values(CATALOG_REGISTRY).filter(c => c.module === module)
}
export function getCatalogStats(
catalogId: CatalogId,
customEntries: CustomCatalogEntry[] = [],
): CatalogStats {
const meta = CATALOG_REGISTRY[catalogId]
return {
catalogId,
systemCount: meta.systemCount,
customCount: customEntries.length,
totalCount: meta.systemCount + customEntries.length,
}
}
export function getOverviewStats(customCatalogs: CustomCatalogs): CatalogOverviewStats {
const modules: CatalogModule[] = ['dsfa', 'vvt', 'vendor', 'ai_act', 'reference']
const byModule = {} as Record<CatalogModule, { catalogs: number; entries: number }>
let totalSystemEntries = 0
let totalCustomEntries = 0
for (const mod of modules) {
const cats = getCatalogsByModule(mod)
let entries = 0
for (const cat of cats) {
const customCount = customCatalogs[cat.id]?.length ?? 0
entries += cat.systemCount + customCount
totalSystemEntries += cat.systemCount
totalCustomEntries += customCount
}
byModule[mod] = { catalogs: cats.length, entries }
}
return {
totalCatalogs: Object.keys(CATALOG_REGISTRY).length,
totalSystemEntries,
totalCustomEntries,
totalEntries: totalSystemEntries + totalCustomEntries,
byModule,
}
}
export function searchCatalog(
catalogId: CatalogId,
query: string,
customEntries: CustomCatalogEntry[] = [],
): CatalogEntry[] {
const allEntries = getAllEntries(catalogId, customEntries)
const meta = CATALOG_REGISTRY[catalogId]
const q = query.toLowerCase().trim()
if (!q) return allEntries
return allEntries
.map(entry => {
let score = 0
for (const field of meta.searchableFields) {
const value = resolveField(entry.data[field]).toLowerCase()
if (value.includes(q)) {
score += value.startsWith(q) ? 10 : 5
}
}
// Also search display name
if (entry.displayName.toLowerCase().includes(q)) {
score += 15
}
return { entry, score }
})
.filter(r => r.score > 0)
.sort((a, b) => b.score - a.score)
.map(r => r.entry)
}

View File

@@ -0,0 +1,190 @@
/**
* Catalog Registry — Public API, Entry Converters & Registry Assembly
*/
import type {
CatalogId,
CatalogMeta,
CatalogModule,
CatalogEntry,
CatalogStats,
CatalogOverviewStats,
CustomCatalogEntry,
CustomCatalogs,
} from '../types'
import { DSFA_AI_CATALOG_META, DSFA_AI_SYSTEM_ENTRIES } from './registry-dsfa'
import { VENDOR_VVT_CATALOG_META, VENDOR_VVT_SYSTEM_ENTRIES } from './registry-vendor'
import { REFERENCE_CATALOG_META, REFERENCE_SYSTEM_ENTRIES } from './registry-reference'
// =============================================================================
// CATALOG REGISTRY (assembled from sub-registries)
// =============================================================================
export const CATALOG_REGISTRY: Record<CatalogId, CatalogMeta> = {
...DSFA_AI_CATALOG_META,
...VENDOR_VVT_CATALOG_META,
...REFERENCE_CATALOG_META,
} as Record<CatalogId, CatalogMeta>
// =============================================================================
// SYSTEM ENTRIES MAP (assembled from sub-registries)
// =============================================================================
const SYSTEM_ENTRIES_MAP: Record<CatalogId, Record<string, unknown>[]> = {
...DSFA_AI_SYSTEM_ENTRIES,
...VENDOR_VVT_SYSTEM_ENTRIES,
...REFERENCE_SYSTEM_ENTRIES,
} as Record<CatalogId, Record<string, unknown>[]>
// =============================================================================
// HELPER: Resolve localized text fields
// =============================================================================
function resolveField(value: unknown): string {
if (value === null || value === undefined) return ''
if (typeof value === 'string') return value
if (typeof value === 'number') return String(value)
if (typeof value === 'object' && 'de' in (value as Record<string, unknown>)) {
return String((value as Record<string, string>).de || '')
}
return String(value)
}
// =============================================================================
// ENTRY CONVERTERS
// =============================================================================
function systemEntryToCatalogEntry(
catalogId: CatalogId,
data: Record<string, unknown>,
): CatalogEntry {
const meta = CATALOG_REGISTRY[catalogId]
const idValue = resolveField(data[meta.idField])
const nameValue = resolveField(data[meta.nameField])
const descValue = meta.descriptionField ? resolveField(data[meta.descriptionField]) : undefined
const catValue = meta.categoryField ? resolveField(data[meta.categoryField]) : undefined
return {
id: idValue || crypto.randomUUID(),
catalogId,
source: 'system',
data,
displayName: nameValue || idValue || '(Unbenannt)',
displayDescription: descValue,
category: catValue,
}
}
function customEntryToCatalogEntry(
catalogId: CatalogId,
entry: CustomCatalogEntry,
): CatalogEntry {
const meta = CATALOG_REGISTRY[catalogId]
const nameValue = resolveField(entry.data[meta.nameField])
const descValue = meta.descriptionField ? resolveField(entry.data[meta.descriptionField]) : undefined
const catValue = meta.categoryField ? resolveField(entry.data[meta.categoryField]) : undefined
return {
id: entry.id,
catalogId,
source: 'custom',
data: entry.data,
displayName: nameValue || '(Unbenannt)',
displayDescription: descValue,
category: catValue,
}
}
// =============================================================================
// PUBLIC API
// =============================================================================
export function getSystemEntries(catalogId: CatalogId): CatalogEntry[] {
const raw = SYSTEM_ENTRIES_MAP[catalogId] || []
return raw.map(data => systemEntryToCatalogEntry(catalogId, data))
}
export function getAllEntries(
catalogId: CatalogId,
customEntries: CustomCatalogEntry[] = [],
): CatalogEntry[] {
const system = getSystemEntries(catalogId)
const custom = customEntries.map(e => customEntryToCatalogEntry(catalogId, e))
return [...system, ...custom]
}
export function getCatalogsByModule(module: CatalogModule): CatalogMeta[] {
return Object.values(CATALOG_REGISTRY).filter(c => c.module === module)
}
export function getCatalogStats(
catalogId: CatalogId,
customEntries: CustomCatalogEntry[] = [],
): CatalogStats {
const meta = CATALOG_REGISTRY[catalogId]
return {
catalogId,
systemCount: meta.systemCount,
customCount: customEntries.length,
totalCount: meta.systemCount + customEntries.length,
}
}
export function getOverviewStats(customCatalogs: CustomCatalogs): CatalogOverviewStats {
const modules: CatalogModule[] = ['dsfa', 'vvt', 'vendor', 'ai_act', 'reference']
const byModule = {} as Record<CatalogModule, { catalogs: number; entries: number }>
let totalSystemEntries = 0
let totalCustomEntries = 0
for (const mod of modules) {
const cats = getCatalogsByModule(mod)
let entries = 0
for (const cat of cats) {
const customCount = customCatalogs[cat.id]?.length ?? 0
entries += cat.systemCount + customCount
totalSystemEntries += cat.systemCount
totalCustomEntries += customCount
}
byModule[mod] = { catalogs: cats.length, entries }
}
return {
totalCatalogs: Object.keys(CATALOG_REGISTRY).length,
totalSystemEntries,
totalCustomEntries,
totalEntries: totalSystemEntries + totalCustomEntries,
byModule,
}
}
export function searchCatalog(
catalogId: CatalogId,
query: string,
customEntries: CustomCatalogEntry[] = [],
): CatalogEntry[] {
const allEntries = getAllEntries(catalogId, customEntries)
const meta = CATALOG_REGISTRY[catalogId]
const q = query.toLowerCase().trim()
if (!q) return allEntries
return allEntries
.map(entry => {
let score = 0
for (const field of meta.searchableFields) {
const value = resolveField(entry.data[field]).toLowerCase()
if (value.includes(q)) {
score += value.startsWith(q) ? 10 : 5
}
}
// Also search display name
if (entry.displayName.toLowerCase().includes(q)) {
score += 15
}
return { entry, score }
})
.filter(r => r.score > 0)
.sort((a, b) => b.score - a.score)
.map(r => r.entry)
}

View File

@@ -0,0 +1,250 @@
/**
* Catalog Registry — DSFA & AI Act Catalogs
*/
import type { CatalogId, CatalogMeta } from '../types'
import { RISK_CATALOG } from '../../dsfa/risk-catalog'
import { MITIGATION_LIBRARY } from '../../dsfa/mitigation-library'
import { AI_RISK_CATALOG } from '../../dsfa/ai-risk-catalog'
import { AI_MITIGATION_LIBRARY } from '../../dsfa/ai-mitigation-library'
import { PROHIBITED_AI_PRACTICES } from '../../dsfa/prohibited-ai-practices'
import { WP248_CRITERIA, SDM_GOALS, DSFA_AUTHORITY_RESOURCES } from '../../dsfa/types'
export const SDM_GOALS_ENTRIES = Object.entries(SDM_GOALS).map(([key, val]) => ({
id: key,
name: val.name,
description: val.description,
article: val.article,
}))
export const DSFA_AI_CATALOG_META: Partial<Record<CatalogId, CatalogMeta>> = {
'dsfa-risks': {
id: 'dsfa-risks',
name: 'DSFA Risikokatalog',
description: 'Standardrisiken fuer Datenschutz-Folgenabschaetzungen',
module: 'dsfa',
icon: 'ShieldAlert',
systemCount: RISK_CATALOG.length,
allowCustom: true,
idField: 'id',
nameField: 'title',
descriptionField: 'description',
categoryField: 'category',
fields: [
{ key: 'id', label: 'Risiko-ID', type: 'text', required: true, placeholder: 'R-XXX-01' },
{ key: 'title', label: 'Titel', type: 'text', required: true },
{ key: 'description', label: 'Beschreibung', type: 'textarea', required: true },
{ key: 'category', label: 'Kategorie', type: 'select', required: true, options: [
{ value: 'confidentiality', label: 'Vertraulichkeit' },
{ value: 'integrity', label: 'Integritaet' },
{ value: 'availability', label: 'Verfuegbarkeit' },
{ value: 'rights_freedoms', label: 'Rechte & Freiheiten' },
]},
{ key: 'typicalLikelihood', label: 'Typische Eintrittswahrscheinlichkeit', type: 'select', required: false, options: [
{ value: 'low', label: 'Niedrig' },
{ value: 'medium', label: 'Mittel' },
{ value: 'high', label: 'Hoch' },
]},
{ key: 'typicalImpact', label: 'Typische Auswirkung', type: 'select', required: false, options: [
{ value: 'low', label: 'Niedrig' },
{ value: 'medium', label: 'Mittel' },
{ value: 'high', label: 'Hoch' },
]},
],
searchableFields: ['id', 'title', 'description', 'category'],
},
'dsfa-mitigations': {
id: 'dsfa-mitigations',
name: 'DSFA Massnahmenbibliothek',
description: 'Technische und organisatorische Massnahmen fuer DSFAs',
module: 'dsfa',
icon: 'Shield',
systemCount: MITIGATION_LIBRARY.length,
allowCustom: true,
idField: 'id',
nameField: 'title',
descriptionField: 'description',
categoryField: 'type',
fields: [
{ key: 'id', label: 'Massnahmen-ID', type: 'text', required: true, placeholder: 'M-XXX-01' },
{ key: 'title', label: 'Titel', type: 'text', required: true },
{ key: 'description', label: 'Beschreibung', type: 'textarea', required: true },
{ key: 'type', label: 'Typ', type: 'select', required: true, options: [
{ value: 'technical', label: 'Technisch' },
{ value: 'organizational', label: 'Organisatorisch' },
{ value: 'legal', label: 'Rechtlich' },
]},
{ key: 'effectiveness', label: 'Wirksamkeit', type: 'select', required: false, options: [
{ value: 'low', label: 'Niedrig' },
{ value: 'medium', label: 'Mittel' },
{ value: 'high', label: 'Hoch' },
]},
{ key: 'legalBasis', label: 'Rechtsgrundlage', type: 'text', required: false },
],
searchableFields: ['id', 'title', 'description', 'type', 'legalBasis'],
},
'ai-risks': {
id: 'ai-risks',
name: 'KI-Risikokatalog',
description: 'Spezifische Risiken fuer KI-Systeme',
module: 'ai_act',
icon: 'Bot',
systemCount: AI_RISK_CATALOG.length,
allowCustom: true,
idField: 'id',
nameField: 'title',
descriptionField: 'description',
categoryField: 'category',
fields: [
{ key: 'id', label: 'Risiko-ID', type: 'text', required: true, placeholder: 'R-AI-XXX-01' },
{ key: 'title', label: 'Titel', type: 'text', required: true },
{ key: 'description', label: 'Beschreibung', type: 'textarea', required: true },
{ key: 'category', label: 'Kategorie', type: 'select', required: true, options: [
{ value: 'confidentiality', label: 'Vertraulichkeit' },
{ value: 'integrity', label: 'Integritaet' },
{ value: 'availability', label: 'Verfuegbarkeit' },
{ value: 'rights_freedoms', label: 'Rechte & Freiheiten' },
]},
{ key: 'typicalLikelihood', label: 'Eintrittswahrscheinlichkeit', type: 'select', required: false, options: [
{ value: 'low', label: 'Niedrig' },
{ value: 'medium', label: 'Mittel' },
{ value: 'high', label: 'Hoch' },
]},
{ key: 'typicalImpact', label: 'Auswirkung', type: 'select', required: false, options: [
{ value: 'low', label: 'Niedrig' },
{ value: 'medium', label: 'Mittel' },
{ value: 'high', label: 'Hoch' },
]},
],
searchableFields: ['id', 'title', 'description', 'category'],
},
'ai-mitigations': {
id: 'ai-mitigations',
name: 'KI-Massnahmenbibliothek',
description: 'Massnahmen fuer KI-spezifische Risiken',
module: 'ai_act',
icon: 'ShieldCheck',
systemCount: AI_MITIGATION_LIBRARY.length,
allowCustom: true,
idField: 'id',
nameField: 'title',
descriptionField: 'description',
categoryField: 'type',
fields: [
{ key: 'id', label: 'Massnahmen-ID', type: 'text', required: true },
{ key: 'title', label: 'Titel', type: 'text', required: true },
{ key: 'description', label: 'Beschreibung', type: 'textarea', required: true },
{ key: 'type', label: 'Typ', type: 'select', required: true, options: [
{ value: 'technical', label: 'Technisch' },
{ value: 'organizational', label: 'Organisatorisch' },
{ value: 'legal', label: 'Rechtlich' },
]},
{ key: 'effectiveness', label: 'Wirksamkeit', type: 'select', required: false, options: [
{ value: 'low', label: 'Niedrig' },
{ value: 'medium', label: 'Mittel' },
{ value: 'high', label: 'Hoch' },
]},
],
searchableFields: ['id', 'title', 'description', 'type'],
},
'prohibited-ai-practices': {
id: 'prohibited-ai-practices',
name: 'Verbotene KI-Praktiken',
description: 'Absolut und bedingt verbotene KI-Anwendungen nach AI Act',
module: 'ai_act',
icon: 'Ban',
systemCount: PROHIBITED_AI_PRACTICES.length,
allowCustom: false,
idField: 'id',
nameField: 'title',
descriptionField: 'description',
categoryField: 'severity',
fields: [
{ key: 'id', label: 'ID', type: 'text', required: true },
{ key: 'title', label: 'Titel', type: 'text', required: true },
{ key: 'description', label: 'Beschreibung', type: 'textarea', required: true },
{ key: 'severity', label: 'Schwere', type: 'select', required: true, options: [
{ value: 'absolute', label: 'Absolutes Verbot' },
{ value: 'conditional', label: 'Bedingtes Verbot' },
]},
{ key: 'legalBasis', label: 'Rechtsgrundlage', type: 'text', required: false },
],
searchableFields: ['id', 'title', 'description', 'severity', 'legalBasis'],
},
'wp248-criteria': {
id: 'wp248-criteria',
name: 'WP248 Kriterien',
description: 'Kriterien zur DSFA-Pflichtpruefung nach WP248',
module: 'dsfa',
icon: 'ClipboardCheck',
systemCount: WP248_CRITERIA.length,
allowCustom: false,
idField: 'code',
nameField: 'title',
descriptionField: 'description',
fields: [
{ key: 'code', label: 'Code', type: 'text', required: true },
{ key: 'title', label: 'Titel', type: 'text', required: true },
{ key: 'description', label: 'Beschreibung', type: 'textarea', required: true },
{ key: 'gdprRef', label: 'DSGVO-Referenz', type: 'text', required: false },
],
searchableFields: ['code', 'title', 'description', 'gdprRef'],
},
'sdm-goals': {
id: 'sdm-goals',
name: 'SDM Gewaehrleistungsziele',
description: 'Standard-Datenschutzmodell Gewaehrleistungsziele',
module: 'dsfa',
icon: 'Target',
systemCount: SDM_GOALS_ENTRIES.length,
allowCustom: false,
idField: 'id',
nameField: 'name',
descriptionField: 'description',
fields: [
{ key: 'id', label: 'ID', type: 'text', required: true },
{ key: 'name', label: 'Name', type: 'text', required: true },
{ key: 'description', label: 'Beschreibung', type: 'textarea', required: true },
{ key: 'article', label: 'DSGVO-Artikel', type: 'text', required: false },
],
searchableFields: ['id', 'name', 'description', 'article'],
},
'dsfa-authority-resources': {
id: 'dsfa-authority-resources',
name: 'Aufsichtsbehoerden-Ressourcen',
description: 'DSFA-Ressourcen der deutschen Aufsichtsbehoerden',
module: 'dsfa',
icon: 'Building',
systemCount: DSFA_AUTHORITY_RESOURCES.length,
allowCustom: false,
idField: 'id',
nameField: 'shortName',
descriptionField: 'name',
categoryField: 'state',
fields: [
{ key: 'id', label: 'ID', type: 'text', required: true },
{ key: 'shortName', label: 'Kurzname', type: 'text', required: true },
{ key: 'name', label: 'Voller Name', type: 'text', required: true },
{ key: 'state', label: 'Bundesland', type: 'text', required: true },
],
searchableFields: ['id', 'shortName', 'name', 'state'],
},
}
export const DSFA_AI_SYSTEM_ENTRIES: Partial<Record<CatalogId, Record<string, unknown>[]>> = {
'dsfa-risks': RISK_CATALOG as unknown as Record<string, unknown>[],
'dsfa-mitigations': MITIGATION_LIBRARY as unknown as Record<string, unknown>[],
'ai-risks': AI_RISK_CATALOG as unknown as Record<string, unknown>[],
'ai-mitigations': AI_MITIGATION_LIBRARY as unknown as Record<string, unknown>[],
'prohibited-ai-practices': PROHIBITED_AI_PRACTICES as unknown as Record<string, unknown>[],
'wp248-criteria': WP248_CRITERIA as unknown as Record<string, unknown>[],
'sdm-goals': SDM_GOALS_ENTRIES as unknown as Record<string, unknown>[],
'dsfa-authority-resources': DSFA_AUTHORITY_RESOURCES as unknown as Record<string, unknown>[],
}

View File

@@ -0,0 +1,127 @@
/**
* Catalog Registry — Reference Catalogs (Legal Bases, Frameworks, Enforcement)
*/
import type { CatalogId, CatalogMeta } from '../types'
import { EU_BASE_FRAMEWORKS, NATIONAL_FRAMEWORKS } from '../../dsfa/eu-legal-frameworks'
import { GDPR_ENFORCEMENT_CASES } from '../../dsfa/gdpr-enforcement-cases'
import { LEGAL_BASIS_INFO, STANDARD_RETENTION_PERIODS } from '../../vendor-compliance/catalog/legal-basis'
export const REFERENCE_CATALOG_META: Partial<Record<CatalogId, CatalogMeta>> = {
'legal-bases': {
id: 'legal-bases',
name: 'Rechtsgrundlagen',
description: 'DSGVO Art. 6 und Art. 9 Rechtsgrundlagen',
module: 'reference',
icon: 'Scale',
systemCount: LEGAL_BASIS_INFO.length,
allowCustom: false,
idField: 'type',
nameField: 'name',
descriptionField: 'description',
categoryField: 'article',
fields: [
{ key: 'type', label: 'Typ', type: 'text', required: true },
{ key: 'article', label: 'Artikel', type: 'text', required: true },
{ key: 'name', label: 'Name', type: 'text', required: true },
{ key: 'description', label: 'Beschreibung', type: 'textarea', required: true },
{ key: 'isSpecialCategory', label: 'Besondere Kategorie (Art. 9)', type: 'boolean', required: false },
],
searchableFields: ['type', 'article', 'name', 'description'],
},
'retention-periods': {
id: 'retention-periods',
name: 'Aufbewahrungsfristen',
description: 'Gesetzliche Standard-Aufbewahrungsfristen',
module: 'reference',
icon: 'Timer',
systemCount: STANDARD_RETENTION_PERIODS.length,
allowCustom: false,
idField: 'id',
nameField: 'name',
descriptionField: 'description',
fields: [
{ key: 'id', label: 'ID', type: 'text', required: true },
{ key: 'name', label: 'Name', type: 'text', required: true },
{ key: 'legalBasis', label: 'Rechtsgrundlage', type: 'text', required: true },
{ key: 'description', label: 'Beschreibung', type: 'textarea', required: true },
],
searchableFields: ['id', 'name', 'legalBasis', 'description'],
},
'eu-legal-frameworks': {
id: 'eu-legal-frameworks',
name: 'EU-Rechtsrahmen',
description: 'EU-weite Datenschutzgesetze und -verordnungen',
module: 'reference',
icon: 'Landmark',
systemCount: EU_BASE_FRAMEWORKS.length,
allowCustom: false,
idField: 'id',
nameField: 'name',
descriptionField: 'description',
categoryField: 'type',
fields: [
{ key: 'id', label: 'ID', type: 'text', required: true },
{ key: 'name', label: 'Name', type: 'text', required: true },
{ key: 'fullName', label: 'Vollstaendiger Name', type: 'text', required: true },
{ key: 'type', label: 'Typ', type: 'text', required: true },
{ key: 'description', label: 'Beschreibung', type: 'textarea', required: true },
],
searchableFields: ['id', 'name', 'fullName', 'description', 'type'],
},
'national-legal-frameworks': {
id: 'national-legal-frameworks',
name: 'Nationale Rechtsrahmen',
description: 'Nationale Datenschutzgesetze der EU/EWR-Staaten',
module: 'reference',
icon: 'Flag',
systemCount: NATIONAL_FRAMEWORKS.length,
allowCustom: false,
idField: 'id',
nameField: 'name',
descriptionField: 'description',
categoryField: 'countryCode',
fields: [
{ key: 'id', label: 'ID', type: 'text', required: true },
{ key: 'name', label: 'Name', type: 'text', required: true },
{ key: 'countryCode', label: 'Land', type: 'text', required: true },
{ key: 'type', label: 'Typ', type: 'text', required: true },
{ key: 'description', label: 'Beschreibung', type: 'textarea', required: true },
],
searchableFields: ['id', 'name', 'countryCode', 'description', 'type'],
},
'gdpr-enforcement-cases': {
id: 'gdpr-enforcement-cases',
name: 'DSGVO-Bussgeldentscheidungen',
description: 'Relevante Bussgeldentscheidungen als Referenz',
module: 'reference',
icon: 'Gavel',
systemCount: GDPR_ENFORCEMENT_CASES.length,
allowCustom: false,
idField: 'id',
nameField: 'company',
descriptionField: 'description',
categoryField: 'country',
fields: [
{ key: 'id', label: 'ID', type: 'text', required: true },
{ key: 'company', label: 'Unternehmen', type: 'text', required: true },
{ key: 'country', label: 'Land', type: 'text', required: true },
{ key: 'year', label: 'Jahr', type: 'number', required: true },
{ key: 'fineOriginal', label: 'Bussgeld (EUR)', type: 'number', required: true },
{ key: 'description', label: 'Beschreibung', type: 'textarea', required: true },
],
searchableFields: ['id', 'company', 'country', 'description'],
},
}
export const REFERENCE_SYSTEM_ENTRIES: Partial<Record<CatalogId, Record<string, unknown>[]>> = {
'legal-bases': LEGAL_BASIS_INFO as unknown as Record<string, unknown>[],
'retention-periods': STANDARD_RETENTION_PERIODS as unknown as Record<string, unknown>[],
'eu-legal-frameworks': EU_BASE_FRAMEWORKS as unknown as Record<string, unknown>[],
'national-legal-frameworks': NATIONAL_FRAMEWORKS as unknown as Record<string, unknown>[],
'gdpr-enforcement-cases': GDPR_ENFORCEMENT_CASES as unknown as Record<string, unknown>[],
}

View File

@@ -0,0 +1,159 @@
/**
* Catalog Registry — Vendor, VVT & Loeschfristen Catalogs
*/
import type { CatalogId, CatalogMeta } from '../types'
import { VVT_BASELINE_CATALOG } from '../../vvt-baseline-catalog'
import { BASELINE_TEMPLATES } from '../../loeschfristen-baseline-catalog'
import { VENDOR_TEMPLATES, COUNTRY_RISK_PROFILES } from '../../vendor-compliance/catalog/vendor-templates'
export const VENDOR_VVT_CATALOG_META: Partial<Record<CatalogId, CatalogMeta>> = {
'vvt-templates': {
id: 'vvt-templates',
name: 'VVT Baseline-Vorlagen',
description: 'Vorlagen fuer Verarbeitungstaetigkeiten',
module: 'vvt',
icon: 'FileText',
systemCount: VVT_BASELINE_CATALOG.length,
allowCustom: true,
idField: 'templateId',
nameField: 'name',
descriptionField: 'description',
categoryField: 'businessFunction',
fields: [
{ key: 'templateId', label: 'Vorlagen-ID', type: 'text', required: true },
{ key: 'name', label: 'Name', type: 'text', required: true },
{ key: 'description', label: 'Beschreibung', type: 'textarea', required: true },
{ key: 'businessFunction', label: 'Geschaeftsbereich', type: 'select', required: true, options: [
{ value: 'hr', label: 'Personal' },
{ value: 'finance', label: 'Finanzen' },
{ value: 'sales', label: 'Vertrieb' },
{ value: 'marketing', label: 'Marketing' },
{ value: 'support', label: 'Support' },
{ value: 'it', label: 'IT' },
{ value: 'other', label: 'Sonstige' },
]},
{ key: 'protectionLevel', label: 'Schutzniveau', type: 'select', required: false, options: [
{ value: 'LOW', label: 'Niedrig' },
{ value: 'MEDIUM', label: 'Mittel' },
{ value: 'HIGH', label: 'Hoch' },
]},
],
searchableFields: ['templateId', 'name', 'description', 'businessFunction'],
},
'loeschfristen-templates': {
id: 'loeschfristen-templates',
name: 'Loeschfristen-Vorlagen',
description: 'Baseline-Vorlagen fuer Aufbewahrungsfristen',
module: 'vvt',
icon: 'Clock',
systemCount: BASELINE_TEMPLATES.length,
allowCustom: true,
idField: 'templateId',
nameField: 'dataObjectName',
descriptionField: 'description',
categoryField: 'retentionDriver',
fields: [
{ key: 'templateId', label: 'Vorlagen-ID', type: 'text', required: true },
{ key: 'dataObjectName', label: 'Datenobjekt', type: 'text', required: true },
{ key: 'description', label: 'Beschreibung', type: 'textarea', required: true },
{ key: 'retentionDuration', label: 'Aufbewahrungsdauer', type: 'number', required: true, min: 0 },
{ key: 'retentionUnit', label: 'Einheit', type: 'select', required: true, options: [
{ value: 'days', label: 'Tage' },
{ value: 'months', label: 'Monate' },
{ value: 'years', label: 'Jahre' },
]},
{ key: 'deletionMethod', label: 'Loeschmethode', type: 'text', required: false },
{ key: 'responsibleRole', label: 'Verantwortlich', type: 'text', required: false },
],
searchableFields: ['templateId', 'dataObjectName', 'description', 'retentionDriver'],
},
'vendor-templates': {
id: 'vendor-templates',
name: 'AV-Vorlagen',
description: 'Vorlagen fuer Auftragsverarbeitungsvertraege',
module: 'vendor',
icon: 'Building2',
systemCount: VENDOR_TEMPLATES.length,
allowCustom: true,
idField: 'id',
nameField: 'name',
descriptionField: 'description',
categoryField: 'serviceCategory',
fields: [
{ key: 'id', label: 'ID', type: 'text', required: true },
{ key: 'name', label: 'Name', type: 'text', required: true },
{ key: 'description', label: 'Beschreibung', type: 'textarea', required: true },
{ key: 'serviceCategory', label: 'Dienstleistungskategorie', type: 'select', required: true, options: [
{ value: 'HOSTING', label: 'Hosting' },
{ value: 'CLOUD_INFRASTRUCTURE', label: 'Cloud-Infrastruktur' },
{ value: 'ANALYTICS', label: 'Analyse' },
{ value: 'CRM', label: 'CRM' },
{ value: 'ERP', label: 'ERP' },
{ value: 'HR_SOFTWARE', label: 'HR-Software' },
{ value: 'PAYMENT', label: 'Zahlungsdienstleister' },
{ value: 'EMAIL', label: 'E-Mail' },
{ value: 'MARKETING', label: 'Marketing' },
{ value: 'SUPPORT', label: 'Support' },
{ value: 'SECURITY', label: 'Sicherheit' },
{ value: 'COMMUNICATION', label: 'Kommunikation' },
{ value: 'STORAGE', label: 'Speicher' },
{ value: 'BACKUP', label: 'Backup' },
{ value: 'CDN', label: 'CDN' },
{ value: 'ACCOUNTING', label: 'Buchhaltung' },
{ value: 'CONSULTING', label: 'Beratung' },
{ value: 'OTHER', label: 'Sonstige' },
]},
{ key: 'suggestedRole', label: 'Vorgeschlagene Rolle', type: 'select', required: false, options: [
{ value: 'PROCESSOR', label: 'Auftragsverarbeiter' },
{ value: 'JOINT_CONTROLLER', label: 'Gemeinsam Verantwortlicher' },
{ value: 'CONTROLLER', label: 'Eigenstaendiger Verantwortlicher' },
{ value: 'SUB_PROCESSOR', label: 'Unterauftragnehmer' },
{ value: 'THIRD_PARTY', label: 'Dritter' },
]},
{ key: 'suggestedDataAccess', label: 'Datenzugriff', type: 'select', required: false, options: [
{ value: 'NONE', label: 'Kein Zugriff' },
{ value: 'POTENTIAL', label: 'Potenzieller Zugriff' },
{ value: 'ADMINISTRATIVE', label: 'Administrativer Zugriff' },
{ value: 'CONTENT', label: 'Inhaltlicher Zugriff' },
]},
],
searchableFields: ['id', 'name', 'description', 'serviceCategory', 'suggestedRole', 'commonProviders'],
},
'country-risk-profiles': {
id: 'country-risk-profiles',
name: 'Laenderrisikoprofile',
description: 'Datenschutz-Risikobewertung nach Laendern',
module: 'vendor',
icon: 'Globe',
systemCount: COUNTRY_RISK_PROFILES.length,
allowCustom: false,
idField: 'code',
nameField: 'name',
categoryField: 'riskLevel',
fields: [
{ key: 'code', label: 'Laendercode', type: 'text', required: true },
{ key: 'name', label: 'Land', type: 'text', required: true },
{ key: 'riskLevel', label: 'Risikostufe', type: 'select', required: true, options: [
{ value: 'LOW', label: 'Niedrig' },
{ value: 'MEDIUM', label: 'Mittel' },
{ value: 'HIGH', label: 'Hoch' },
{ value: 'VERY_HIGH', label: 'Sehr hoch' },
]},
{ key: 'isEU', label: 'EU-Mitglied', type: 'boolean', required: false },
{ key: 'isEEA', label: 'EWR-Mitglied', type: 'boolean', required: false },
{ key: 'hasAdequacyDecision', label: 'Angemessenheitsbeschluss', type: 'boolean', required: false },
],
searchableFields: ['code', 'name', 'riskLevel'],
},
}
export const VENDOR_VVT_SYSTEM_ENTRIES: Partial<Record<CatalogId, Record<string, unknown>[]>> = {
'vvt-templates': VVT_BASELINE_CATALOG as unknown as Record<string, unknown>[],
'loeschfristen-templates': BASELINE_TEMPLATES as unknown as Record<string, unknown>[],
'vendor-templates': VENDOR_TEMPLATES as unknown as Record<string, unknown>[],
'country-risk-profiles': COUNTRY_RISK_PROFILES as unknown as Record<string, unknown>[],
}

View File

@@ -1,823 +1,15 @@
/** /**
* 50 Hard Trigger Rules — data table. * 50 Hard Trigger Rules — barrel re-export.
* * Implementation split into compliance-scope-triggers/
* This file legitimately exceeds 500 LOC because it is a pure data
* definition with no logic. Splitting it further would hurt readability.
*/ */
import type { HardTriggerRule } from './compliance-scope-types' import type { HardTriggerRule } from './compliance-scope-types'
import { HARD_TRIGGER_RULES_A_E } from './compliance-scope-triggers/triggers-a-e'
import { HARD_TRIGGER_RULES_F_M } from './compliance-scope-triggers/triggers-f-m'
// ============================================================================ export { HARD_TRIGGER_RULES_A_E } from './compliance-scope-triggers/triggers-a-e'
// 50 HARD TRIGGER RULES export { HARD_TRIGGER_RULES_F_M } from './compliance-scope-triggers/triggers-f-m'
// ============================================================================
export const HARD_TRIGGER_RULES: HardTriggerRule[] = [ export const HARD_TRIGGER_RULES: HardTriggerRule[] = [
// ========== A: Art. 9 Besondere Kategorien (9 rules) ========== ...HARD_TRIGGER_RULES_A_E,
{ ...HARD_TRIGGER_RULES_F_M,
id: 'HT-A01',
category: 'art9',
questionId: 'data_art9',
condition: 'CONTAINS',
conditionValue: 'gesundheit',
minimumLevel: 'L3',
requiresDSFA: true,
mandatoryDocuments: ['VVT', 'TOM', 'DSFA'],
legalReference: 'Art. 9 Abs. 1 DSGVO',
description: 'Verarbeitung von Gesundheitsdaten',
},
{
id: 'HT-A02',
category: 'art9',
questionId: 'data_art9',
condition: 'CONTAINS',
conditionValue: 'biometrie',
minimumLevel: 'L3',
requiresDSFA: true,
mandatoryDocuments: ['VVT', 'TOM', 'DSFA'],
legalReference: 'Art. 9 Abs. 1 DSGVO',
description: 'Verarbeitung biometrischer Daten zur eindeutigen Identifizierung',
},
{
id: 'HT-A03',
category: 'art9',
questionId: 'data_art9',
condition: 'CONTAINS',
conditionValue: 'genetik',
minimumLevel: 'L3',
requiresDSFA: true,
mandatoryDocuments: ['VVT', 'TOM', 'DSFA'],
legalReference: 'Art. 9 Abs. 1 DSGVO',
description: 'Verarbeitung genetischer Daten',
},
{
id: 'HT-A04',
category: 'art9',
questionId: 'data_art9',
condition: 'CONTAINS',
conditionValue: 'politisch',
minimumLevel: 'L3',
requiresDSFA: true,
mandatoryDocuments: ['VVT', 'TOM', 'DSFA'],
legalReference: 'Art. 9 Abs. 1 DSGVO',
description: 'Verarbeitung politischer Meinungen',
},
{
id: 'HT-A05',
category: 'art9',
questionId: 'data_art9',
condition: 'CONTAINS',
conditionValue: 'religion',
minimumLevel: 'L3',
requiresDSFA: true,
mandatoryDocuments: ['VVT', 'TOM', 'DSFA'],
legalReference: 'Art. 9 Abs. 1 DSGVO',
description: 'Verarbeitung religiöser oder weltanschaulicher Überzeugungen',
},
{
id: 'HT-A06',
category: 'art9',
questionId: 'data_art9',
condition: 'CONTAINS',
conditionValue: 'gewerkschaft',
minimumLevel: 'L3',
requiresDSFA: true,
mandatoryDocuments: ['VVT', 'TOM', 'DSFA'],
legalReference: 'Art. 9 Abs. 1 DSGVO',
description: 'Verarbeitung von Gewerkschaftszugehörigkeit',
},
{
id: 'HT-A07',
category: 'art9',
questionId: 'data_art9',
condition: 'CONTAINS',
conditionValue: 'sexualleben',
minimumLevel: 'L3',
requiresDSFA: true,
mandatoryDocuments: ['VVT', 'TOM', 'DSFA'],
legalReference: 'Art. 9 Abs. 1 DSGVO',
description: 'Verarbeitung von Daten zum Sexualleben oder zur sexuellen Orientierung',
},
{
id: 'HT-A08',
category: 'art9',
questionId: 'data_art9',
condition: 'CONTAINS',
conditionValue: 'strafrechtlich',
minimumLevel: 'L3',
requiresDSFA: true,
mandatoryDocuments: ['VVT', 'TOM', 'DSFA'],
legalReference: 'Art. 10 DSGVO',
description: 'Verarbeitung strafrechtlicher Verurteilungen',
},
{
id: 'HT-A09',
category: 'art9',
questionId: 'data_art9',
condition: 'CONTAINS',
conditionValue: 'ethnisch',
minimumLevel: 'L3',
requiresDSFA: true,
mandatoryDocuments: ['VVT', 'TOM', 'DSFA'],
legalReference: 'Art. 9 Abs. 1 DSGVO',
description: 'Verarbeitung der rassischen oder ethnischen Herkunft',
},
// ========== B: Vulnerable Gruppen (3 rules) ==========
{
id: 'HT-B01',
category: 'vulnerable',
questionId: 'data_minors',
condition: 'EQUALS',
conditionValue: true,
minimumLevel: 'L3',
requiresDSFA: true,
mandatoryDocuments: ['VVT', 'TOM', 'DSFA', 'DSE'],
legalReference: 'Art. 8 DSGVO',
description: 'Verarbeitung von Daten Minderjähriger',
},
{
id: 'HT-B02',
category: 'vulnerable',
questionId: 'data_minors',
condition: 'EQUALS',
conditionValue: true,
minimumLevel: 'L4',
requiresDSFA: true,
mandatoryDocuments: ['VVT', 'TOM', 'DSFA', 'DSE'],
legalReference: 'Art. 8 + Art. 9 DSGVO',
description: 'Verarbeitung besonderer Kategorien von Daten Minderjähriger',
combineWithArt9: true,
},
{
id: 'HT-B03',
category: 'vulnerable',
questionId: 'data_minors',
condition: 'EQUALS',
conditionValue: true,
minimumLevel: 'L4',
requiresDSFA: true,
mandatoryDocuments: ['VVT', 'TOM', 'DSFA', 'AI_ACT_DOKU'],
legalReference: 'Art. 8 DSGVO + AI Act',
description: 'KI-gestützte Verarbeitung von Daten Minderjähriger',
combineWithAI: true,
},
// ========== C: ADM/KI (6 rules) ==========
{
id: 'HT-C01',
category: 'adm',
questionId: 'proc_adm_scoring',
condition: 'EQUALS',
conditionValue: true,
minimumLevel: 'L3',
requiresDSFA: true,
mandatoryDocuments: ['VVT', 'TOM', 'DSFA'],
legalReference: 'Art. 22 DSGVO',
description: 'Automatisierte Einzelentscheidung mit Rechtswirkung oder erheblicher Beeinträchtigung',
},
{
id: 'HT-C02',
category: 'adm',
questionId: 'proc_ai_usage',
condition: 'CONTAINS',
conditionValue: 'autonom',
minimumLevel: 'L3',
requiresDSFA: true,
mandatoryDocuments: ['VVT', 'TOM', 'DSFA', 'AI_ACT_DOKU'],
legalReference: 'Art. 22 DSGVO + AI Act',
description: 'Autonome KI-Systeme mit Entscheidungsbefugnis',
},
{
id: 'HT-C03',
category: 'adm',
questionId: 'proc_ai_usage',
condition: 'CONTAINS',
conditionValue: 'scoring',
minimumLevel: 'L2',
requiresDSFA: false,
mandatoryDocuments: ['VVT', 'TOM'],
legalReference: 'Art. 22 DSGVO',
description: 'KI-gestütztes Scoring',
},
{
id: 'HT-C04',
category: 'adm',
questionId: 'proc_ai_usage',
condition: 'CONTAINS',
conditionValue: 'profiling',
minimumLevel: 'L3',
requiresDSFA: true,
mandatoryDocuments: ['VVT', 'TOM', 'DSFA'],
legalReference: 'Art. 22 DSGVO',
description: 'KI-gestütztes Profiling mit erheblicher Wirkung',
},
{
id: 'HT-C05',
category: 'adm',
questionId: 'proc_ai_usage',
condition: 'CONTAINS',
conditionValue: 'generativ',
minimumLevel: 'L2',
requiresDSFA: false,
mandatoryDocuments: ['VVT', 'TOM', 'AI_ACT_DOKU'],
legalReference: 'AI Act',
description: 'Generative KI-Systeme',
},
{
id: 'HT-C06',
category: 'adm',
questionId: 'proc_ai_usage',
condition: 'CONTAINS',
conditionValue: 'chatbot',
minimumLevel: 'L2',
requiresDSFA: false,
mandatoryDocuments: ['VVT', 'AI_ACT_DOKU'],
legalReference: 'AI Act',
description: 'Chatbots mit Personendatenverarbeitung',
},
// ========== D: Überwachung (5 rules) ==========
{
id: 'HT-D01',
category: 'surveillance',
questionId: 'proc_video_surveillance',
condition: 'EQUALS',
conditionValue: true,
minimumLevel: 'L2',
requiresDSFA: false,
mandatoryDocuments: ['VVT', 'TOM', 'DSE'],
legalReference: 'Art. 6 DSGVO',
description: 'Videoüberwachung',
},
{
id: 'HT-D02',
category: 'surveillance',
questionId: 'proc_employee_monitoring',
condition: 'EQUALS',
conditionValue: true,
minimumLevel: 'L2',
requiresDSFA: false,
mandatoryDocuments: ['VVT', 'TOM', 'DSFA'],
legalReference: 'Art. 88 DSGVO + BetrVG',
description: 'Mitarbeiterüberwachung',
},
{
id: 'HT-D03',
category: 'surveillance',
questionId: 'proc_tracking',
condition: 'EQUALS',
conditionValue: true,
minimumLevel: 'L2',
requiresDSFA: false,
mandatoryDocuments: ['VVT', 'TOM', 'COOKIE_BANNER', 'EINWILLIGUNGEN'],
legalReference: 'Art. 6 DSGVO + ePrivacy',
description: 'Online-Tracking',
},
{
id: 'HT-D04',
category: 'surveillance',
questionId: 'proc_video_surveillance',
condition: 'EQUALS',
conditionValue: true,
minimumLevel: 'L3',
requiresDSFA: true,
mandatoryDocuments: ['VVT', 'TOM', 'DSFA'],
legalReference: 'Art. 35 Abs. 3 DSGVO',
description: 'Videoüberwachung kombiniert mit Mitarbeitermonitoring',
combineWithEmployeeMonitoring: true,
},
{
id: 'HT-D05',
category: 'surveillance',
questionId: 'proc_video_surveillance',
condition: 'EQUALS',
conditionValue: true,
minimumLevel: 'L3',
requiresDSFA: true,
mandatoryDocuments: ['VVT', 'TOM', 'DSFA'],
legalReference: 'Art. 35 Abs. 3 DSGVO',
description: 'Videoüberwachung kombiniert mit automatisierter Bewertung',
combineWithADM: true,
},
// ========== E: Drittland (5 rules) ==========
{
id: 'HT-E01',
category: 'third_country',
questionId: 'tech_third_country',
condition: 'EQUALS',
conditionValue: true,
minimumLevel: 'L2',
requiresDSFA: false,
mandatoryDocuments: ['VVT', 'TRANSFER_DOKU'],
legalReference: 'Art. 44 ff. DSGVO',
description: 'Datenübermittlung in Drittland',
},
{
id: 'HT-E02',
category: 'third_country',
questionId: 'tech_hosting_location',
condition: 'EQUALS',
conditionValue: 'drittland',
minimumLevel: 'L2',
requiresDSFA: false,
mandatoryDocuments: ['VVT', 'TOM', 'TRANSFER_DOKU'],
legalReference: 'Art. 44 ff. DSGVO',
description: 'Hosting in Drittland',
},
{
id: 'HT-E03',
category: 'third_country',
questionId: 'tech_hosting_location',
condition: 'EQUALS',
conditionValue: 'us_adequacy',
minimumLevel: 'L2',
requiresDSFA: false,
mandatoryDocuments: ['TRANSFER_DOKU'],
legalReference: 'Art. 45 DSGVO',
description: 'Hosting in USA mit Angemessenheitsbeschluss',
},
{
id: 'HT-E04',
category: 'third_country',
questionId: 'tech_third_country',
condition: 'EQUALS',
conditionValue: true,
minimumLevel: 'L3',
requiresDSFA: false,
mandatoryDocuments: ['VVT', 'TOM', 'TRANSFER_DOKU', 'DSFA'],
legalReference: 'Art. 44 ff. + Art. 9 DSGVO',
description: 'Drittlandtransfer besonderer Kategorien',
combineWithArt9: true,
},
{
id: 'HT-E05',
category: 'third_country',
questionId: 'tech_third_country',
condition: 'EQUALS',
conditionValue: true,
minimumLevel: 'L3',
requiresDSFA: false,
mandatoryDocuments: ['VVT', 'TOM', 'TRANSFER_DOKU', 'DSFA'],
legalReference: 'Art. 44 ff. + Art. 8 DSGVO',
description: 'Drittlandtransfer von Daten Minderjähriger',
combineWithMinors: true,
},
// ========== F: Zertifizierung (5 rules) ==========
{
id: 'HT-F01',
category: 'certification',
questionId: 'org_cert_target',
condition: 'CONTAINS',
conditionValue: 'ISO27001',
minimumLevel: 'L4',
requiresDSFA: false,
mandatoryDocuments: ['TOM', 'AUDIT_CHECKLIST'],
legalReference: 'ISO/IEC 27001',
description: 'Angestrebte ISO 27001 Zertifizierung',
},
{
id: 'HT-F02',
category: 'certification',
questionId: 'org_cert_target',
condition: 'CONTAINS',
conditionValue: 'ISO27701',
minimumLevel: 'L4',
requiresDSFA: false,
mandatoryDocuments: ['TOM', 'VVT', 'AUDIT_CHECKLIST'],
legalReference: 'ISO/IEC 27701',
description: 'Angestrebte ISO 27701 Zertifizierung',
},
{
id: 'HT-F03',
category: 'certification',
questionId: 'org_cert_target',
condition: 'CONTAINS',
conditionValue: 'SOC2',
minimumLevel: 'L4',
requiresDSFA: false,
mandatoryDocuments: ['TOM', 'AUDIT_CHECKLIST'],
legalReference: 'SOC 2 Type II',
description: 'Angestrebte SOC 2 Zertifizierung',
},
{
id: 'HT-F04',
category: 'certification',
questionId: 'org_cert_target',
condition: 'CONTAINS',
conditionValue: 'TISAX',
minimumLevel: 'L4',
requiresDSFA: false,
mandatoryDocuments: ['TOM', 'AUDIT_CHECKLIST', 'VENDOR_MANAGEMENT'],
legalReference: 'TISAX',
description: 'Angestrebte TISAX Zertifizierung',
},
{
id: 'HT-F05',
category: 'certification',
questionId: 'org_cert_target',
condition: 'CONTAINS',
conditionValue: 'BSI-Grundschutz',
minimumLevel: 'L4',
requiresDSFA: false,
mandatoryDocuments: ['TOM', 'AUDIT_CHECKLIST'],
legalReference: 'BSI IT-Grundschutz',
description: 'Angestrebte BSI-Grundschutz Zertifizierung',
},
// ========== G: Volumen/Skala (5 rules) ==========
{
id: 'HT-G01',
category: 'scale',
questionId: 'data_volume',
condition: 'EQUALS',
conditionValue: '>1000000',
minimumLevel: 'L3',
requiresDSFA: false,
mandatoryDocuments: ['VVT', 'TOM', 'LOESCHKONZEPT'],
legalReference: 'Art. 35 Abs. 3 lit. b DSGVO',
description: 'Umfangreiche Verarbeitung personenbezogener Daten (>1 Mio. Datensätze)',
},
{
id: 'HT-G02',
category: 'scale',
questionId: 'data_volume',
condition: 'EQUALS',
conditionValue: '100000-1000000',
minimumLevel: 'L2',
requiresDSFA: false,
mandatoryDocuments: ['VVT', 'TOM'],
legalReference: 'Art. 35 Abs. 3 lit. b DSGVO',
description: 'Großvolumige Datenverarbeitung (100k-1M Datensätze)',
},
{
id: 'HT-G03',
category: 'scale',
questionId: 'org_customer_count',
condition: 'EQUALS',
conditionValue: '100000+',
minimumLevel: 'L3',
requiresDSFA: false,
mandatoryDocuments: ['VVT', 'TOM', 'DSR_PROZESS'],
legalReference: 'Art. 15-22 DSGVO',
description: 'Großer Kundenstamm (>100k) mit hoher Betroffenenanzahl',
},
{
id: 'HT-G04',
category: 'scale',
questionId: 'org_employee_count',
condition: 'GREATER_THAN',
conditionValue: 249,
minimumLevel: 'L3',
requiresDSFA: false,
mandatoryDocuments: ['VVT', 'TOM', 'LOESCHKONZEPT', 'NOTFALLPLAN'],
legalReference: 'Art. 37 DSGVO',
description: 'Große Organisation (>250 Mitarbeiter) mit erhöhten Compliance-Anforderungen',
},
{
id: 'HT-G05',
category: 'scale',
questionId: 'org_employee_count',
condition: 'GREATER_THAN',
conditionValue: 999,
minimumLevel: 'L4',
requiresDSFA: false,
mandatoryDocuments: ['VVT', 'TOM', 'DSFA', 'LOESCHKONZEPT'],
legalReference: 'Art. 35 + Art. 37 DSGVO',
description: 'Sehr große Organisation (>1000 Mitarbeiter) mit Art. 9 Daten',
combineWithArt9: true,
},
// ========== H: Produkt/Business (7 rules) ==========
{
id: 'HT-H01a',
category: 'product',
questionId: 'prod_webshop',
condition: 'EQUALS',
conditionValue: true,
excludeWhen: { questionId: 'org_business_model', value: 'B2B' },
minimumLevel: 'L2',
requiresDSFA: false,
mandatoryDocuments: ['DSE', 'AGB', 'COOKIE_BANNER', 'EINWILLIGUNGEN',
'WIDERRUFSBELEHRUNG', 'PREISANGABEN', 'FERNABSATZ_INFO', 'STREITBEILEGUNG'],
legalReference: 'Art. 6 DSGVO + Fernabsatzrecht + PAngV + VSBG',
description: 'E-Commerce / Webshop (B2C) — Verbraucherschutzpflichten',
},
{
id: 'HT-H01b',
category: 'product',
questionId: 'prod_webshop',
condition: 'EQUALS',
conditionValue: true,
requireWhen: { questionId: 'org_business_model', value: 'B2B' },
minimumLevel: 'L2',
requiresDSFA: false,
mandatoryDocuments: ['DSE', 'AGB', 'COOKIE_BANNER'],
legalReference: 'Art. 6 DSGVO + eCommerce',
description: 'E-Commerce / Webshop (B2B) — Basis-Pflichten',
},
{
id: 'HT-H02',
category: 'product',
questionId: 'prod_data_broker',
condition: 'EQUALS',
conditionValue: true,
minimumLevel: 'L3',
requiresDSFA: true,
mandatoryDocuments: ['VVT', 'TOM', 'DSFA', 'EINWILLIGUNGEN'],
legalReference: 'Art. 35 Abs. 3 DSGVO',
description: 'Datenhandel oder Datenmakler-Tätigkeit',
},
{
id: 'HT-H03',
category: 'product',
questionId: 'prod_api_external',
condition: 'EQUALS',
conditionValue: true,
minimumLevel: 'L2',
requiresDSFA: false,
mandatoryDocuments: ['TOM', 'AVV'],
legalReference: 'Art. 28 DSGVO',
description: 'Externe API mit Datenweitergabe',
},
{
id: 'HT-H04',
category: 'product',
questionId: 'org_business_model',
condition: 'EQUALS',
conditionValue: 'b2c',
minimumLevel: 'L2',
requiresDSFA: false,
mandatoryDocuments: ['DSE', 'COOKIE_BANNER', 'EINWILLIGUNGEN'],
legalReference: 'Art. 6 DSGVO',
description: 'B2C-Geschäftsmodell mit Endkundenkontakt',
},
{
id: 'HT-H05',
category: 'product',
questionId: 'org_industry',
condition: 'EQUALS',
conditionValue: 'finance',
minimumLevel: 'L2',
requiresDSFA: false,
mandatoryDocuments: ['VVT', 'TOM'],
legalReference: 'Art. 6 DSGVO + Finanzaufsicht',
description: 'Finanzbranche mit erhöhten regulatorischen Anforderungen',
},
{
id: 'HT-H06',
category: 'product',
questionId: 'org_industry',
condition: 'EQUALS',
conditionValue: 'healthcare',
minimumLevel: 'L3',
requiresDSFA: true,
mandatoryDocuments: ['VVT', 'TOM', 'DSFA'],
legalReference: 'Art. 9 DSGVO + Gesundheitsrecht',
description: 'Gesundheitsbranche mit sensiblen Daten',
},
{
id: 'HT-H07',
category: 'product',
questionId: 'org_industry',
condition: 'EQUALS',
conditionValue: 'public',
minimumLevel: 'L2',
requiresDSFA: false,
mandatoryDocuments: ['VVT', 'TOM', 'DSR_PROZESS'],
legalReference: 'Art. 6 Abs. 1 lit. e DSGVO',
description: 'Öffentlicher Sektor',
},
// ========== I: Prozessreife - Gap Flags (5 rules) ==========
{
id: 'HT-I01',
category: 'process_maturity',
questionId: 'proc_dsar_process',
condition: 'EQUALS',
conditionValue: false,
minimumLevel: 'L1',
requiresDSFA: false,
mandatoryDocuments: [],
legalReference: 'Art. 15-22 DSGVO',
description: 'Fehlender Prozess für Betroffenenrechte',
},
{
id: 'HT-I02',
category: 'process_maturity',
questionId: 'proc_deletion_concept',
condition: 'EQUALS',
conditionValue: false,
minimumLevel: 'L1',
requiresDSFA: false,
mandatoryDocuments: [],
legalReference: 'Art. 17 DSGVO',
description: 'Fehlendes Löschkonzept',
},
{
id: 'HT-I03',
category: 'process_maturity',
questionId: 'proc_incident_response',
condition: 'EQUALS',
conditionValue: false,
minimumLevel: 'L1',
requiresDSFA: false,
mandatoryDocuments: [],
legalReference: 'Art. 33 DSGVO',
description: 'Fehlender Incident-Response-Prozess',
},
{
id: 'HT-I04',
category: 'process_maturity',
questionId: 'proc_regular_audits',
condition: 'EQUALS',
conditionValue: false,
minimumLevel: 'L1',
requiresDSFA: false,
mandatoryDocuments: [],
legalReference: 'Art. 24 DSGVO',
description: 'Fehlende regelmäßige Audits',
},
{
id: 'HT-I05',
category: 'process_maturity',
questionId: 'comp_training',
condition: 'EQUALS',
conditionValue: false,
minimumLevel: 'L1',
requiresDSFA: false,
mandatoryDocuments: [],
legalReference: 'Art. 39 Abs. 1 lit. b DSGVO',
description: 'Fehlende Schulungen zum Datenschutz',
},
// ========== J: IACE — AI Act Produkt-Triggers (3 rules) ==========
{
id: 'HT-J01',
category: 'iace_ai_act_product',
questionId: 'machineBuilder.containsAI',
condition: 'EQUALS',
conditionValue: true,
minimumLevel: 'L3',
requiresDSFA: false,
mandatoryDocuments: ['VVT', 'TOM'],
legalReference: 'EU AI Act Annex I + EU Maschinenverordnung 2023/1230',
description: 'KI mit Sicherheitsfunktion in Maschine → AI Act High-Risk',
combineWithMachineBuilder: { field: 'hasSafetyFunction', value: true },
riskWeight: 9,
},
{
id: 'HT-J02',
category: 'iace_ai_act_product',
questionId: 'machineBuilder.containsAI',
condition: 'EQUALS',
conditionValue: true,
minimumLevel: 'L3',
requiresDSFA: false,
mandatoryDocuments: ['VVT', 'TOM'],
legalReference: 'EU AI Act + EU Maschinenverordnung 2023/1230',
description: 'Autonome KI in Maschine → AI Act + Maschinenverordnung',
combineWithMachineBuilder: { field: 'autonomousBehavior', value: true },
riskWeight: 8,
},
{
id: 'HT-J03',
category: 'iace_ai_act_product',
questionId: 'machineBuilder.hasSafetyFunction',
condition: 'EQUALS',
conditionValue: true,
minimumLevel: 'L3',
requiresDSFA: false,
mandatoryDocuments: ['VVT', 'TOM'],
legalReference: 'EU AI Act Annex III',
description: 'KI-Bildverarbeitung mit Sicherheitsbezug',
combineWithMachineBuilder: { field: 'aiIntegrationType', includes: 'vision' },
riskWeight: 8,
},
// ========== K: IACE — CRA Triggers (3 rules) ==========
{
id: 'HT-K01',
category: 'iace_cra',
questionId: 'machineBuilder.isNetworked',
condition: 'EQUALS',
conditionValue: true,
minimumLevel: 'L2',
requiresDSFA: false,
mandatoryDocuments: ['TOM'],
legalReference: 'EU Cyber Resilience Act (CRA)',
description: 'Vernetztes Produkt → Cyber Resilience Act',
riskWeight: 6,
},
{
id: 'HT-K02',
category: 'iace_cra',
questionId: 'machineBuilder.hasRemoteAccess',
condition: 'EQUALS',
conditionValue: true,
minimumLevel: 'L2',
requiresDSFA: false,
mandatoryDocuments: ['TOM'],
legalReference: 'CRA + NIS2 Art. 21',
description: 'Remote-Zugriff → CRA + NIS2 Supply Chain',
riskWeight: 7,
},
{
id: 'HT-K03',
category: 'iace_cra',
questionId: 'machineBuilder.hasOTAUpdates',
condition: 'EQUALS',
conditionValue: true,
minimumLevel: 'L2',
requiresDSFA: false,
mandatoryDocuments: ['TOM'],
legalReference: 'CRA Art. 10 - Patch Management',
description: 'OTA-Updates → CRA Patch Management Pflicht',
riskWeight: 7,
},
// ========== L: IACE — NIS2 indirekt (2 rules) ==========
{
id: 'HT-L01',
category: 'iace_nis2_indirect',
questionId: 'machineBuilder.criticalSectorClients',
condition: 'EQUALS',
conditionValue: true,
minimumLevel: 'L2',
requiresDSFA: false,
mandatoryDocuments: ['TOM'],
legalReference: 'NIS2 Art. 21 - Supply Chain',
description: 'Lieferant an KRITIS → NIS2 Supply Chain Anforderungen',
riskWeight: 7,
},
{
id: 'HT-L02',
category: 'iace_nis2_indirect',
questionId: 'machineBuilder.oemClients',
condition: 'EQUALS',
conditionValue: true,
minimumLevel: 'L2',
requiresDSFA: false,
mandatoryDocuments: [],
legalReference: 'NIS2 + EU Maschinenverordnung',
description: 'OEM-Zulieferer → Compliance-Nachweispflicht',
riskWeight: 5,
},
// ========== M: IACE — Maschinenverordnung Triggers (4 rules) ==========
{
id: 'HT-M01',
category: 'iace_machinery_regulation',
questionId: 'machineBuilder.containsSoftware',
condition: 'EQUALS',
conditionValue: true,
minimumLevel: 'L3',
requiresDSFA: false,
mandatoryDocuments: ['TOM'],
legalReference: 'EU Maschinenverordnung 2023/1230 Anhang III',
description: 'Software als Sicherheitskomponente → Maschinenverordnung',
combineWithMachineBuilder: { field: 'hasSafetyFunction', value: true },
riskWeight: 9,
},
{
id: 'HT-M02',
category: 'iace_machinery_regulation',
questionId: 'machineBuilder.ceMarkingRequired',
condition: 'EQUALS',
conditionValue: true,
minimumLevel: 'L2',
requiresDSFA: false,
mandatoryDocuments: [],
legalReference: 'EU Maschinenverordnung 2023/1230',
description: 'CE-Kennzeichnung erforderlich',
riskWeight: 6,
},
{
id: 'HT-M03',
category: 'iace_machinery_regulation',
questionId: 'machineBuilder.ceMarkingRequired',
condition: 'EQUALS',
conditionValue: true,
minimumLevel: 'L3',
requiresDSFA: false,
mandatoryDocuments: [],
legalReference: 'EU Maschinenverordnung 2023/1230 Art. 10',
description: 'CE ohne bestehende Risikobeurteilung → Dringend!',
combineWithMachineBuilder: { field: 'hasRiskAssessment', value: false },
riskWeight: 9,
},
{
id: 'HT-M04',
category: 'iace_machinery_regulation',
questionId: 'machineBuilder.containsFirmware',
condition: 'EQUALS',
conditionValue: true,
minimumLevel: 'L2',
requiresDSFA: false,
mandatoryDocuments: ['TOM'],
legalReference: 'EU Maschinenverordnung + CRA',
description: 'Firmware mit Remote-Update → Change Management Pflicht',
combineWithMachineBuilder: { field: 'hasOTAUpdates', value: true },
riskWeight: 7,
},
] ]

View File

@@ -0,0 +1,359 @@
/**
* Hard Trigger Rules AE
* Groups: Art.9 (A), Vulnerable (B), ADM/KI (C), Ueberwachung (D), Drittland (E)
*/
import type { HardTriggerRule } from '../compliance-scope-types'
export const HARD_TRIGGER_RULES_A_E: HardTriggerRule[] = [
// ========== A: Art. 9 Besondere Kategorien (9 rules) ==========
{
id: 'HT-A01',
category: 'art9',
questionId: 'data_art9',
condition: 'CONTAINS',
conditionValue: 'gesundheit',
minimumLevel: 'L3',
requiresDSFA: true,
mandatoryDocuments: ['VVT', 'TOM', 'DSFA'],
legalReference: 'Art. 9 Abs. 1 DSGVO',
description: 'Verarbeitung von Gesundheitsdaten',
},
{
id: 'HT-A02',
category: 'art9',
questionId: 'data_art9',
condition: 'CONTAINS',
conditionValue: 'biometrie',
minimumLevel: 'L3',
requiresDSFA: true,
mandatoryDocuments: ['VVT', 'TOM', 'DSFA'],
legalReference: 'Art. 9 Abs. 1 DSGVO',
description: 'Verarbeitung biometrischer Daten zur eindeutigen Identifizierung',
},
{
id: 'HT-A03',
category: 'art9',
questionId: 'data_art9',
condition: 'CONTAINS',
conditionValue: 'genetik',
minimumLevel: 'L3',
requiresDSFA: true,
mandatoryDocuments: ['VVT', 'TOM', 'DSFA'],
legalReference: 'Art. 9 Abs. 1 DSGVO',
description: 'Verarbeitung genetischer Daten',
},
{
id: 'HT-A04',
category: 'art9',
questionId: 'data_art9',
condition: 'CONTAINS',
conditionValue: 'politisch',
minimumLevel: 'L3',
requiresDSFA: true,
mandatoryDocuments: ['VVT', 'TOM', 'DSFA'],
legalReference: 'Art. 9 Abs. 1 DSGVO',
description: 'Verarbeitung politischer Meinungen',
},
{
id: 'HT-A05',
category: 'art9',
questionId: 'data_art9',
condition: 'CONTAINS',
conditionValue: 'religion',
minimumLevel: 'L3',
requiresDSFA: true,
mandatoryDocuments: ['VVT', 'TOM', 'DSFA'],
legalReference: 'Art. 9 Abs. 1 DSGVO',
description: 'Verarbeitung religiöser oder weltanschaulicher Überzeugungen',
},
{
id: 'HT-A06',
category: 'art9',
questionId: 'data_art9',
condition: 'CONTAINS',
conditionValue: 'gewerkschaft',
minimumLevel: 'L3',
requiresDSFA: true,
mandatoryDocuments: ['VVT', 'TOM', 'DSFA'],
legalReference: 'Art. 9 Abs. 1 DSGVO',
description: 'Verarbeitung von Gewerkschaftszugehörigkeit',
},
{
id: 'HT-A07',
category: 'art9',
questionId: 'data_art9',
condition: 'CONTAINS',
conditionValue: 'sexualleben',
minimumLevel: 'L3',
requiresDSFA: true,
mandatoryDocuments: ['VVT', 'TOM', 'DSFA'],
legalReference: 'Art. 9 Abs. 1 DSGVO',
description: 'Verarbeitung von Daten zum Sexualleben oder zur sexuellen Orientierung',
},
{
id: 'HT-A08',
category: 'art9',
questionId: 'data_art9',
condition: 'CONTAINS',
conditionValue: 'strafrechtlich',
minimumLevel: 'L3',
requiresDSFA: true,
mandatoryDocuments: ['VVT', 'TOM', 'DSFA'],
legalReference: 'Art. 10 DSGVO',
description: 'Verarbeitung strafrechtlicher Verurteilungen',
},
{
id: 'HT-A09',
category: 'art9',
questionId: 'data_art9',
condition: 'CONTAINS',
conditionValue: 'ethnisch',
minimumLevel: 'L3',
requiresDSFA: true,
mandatoryDocuments: ['VVT', 'TOM', 'DSFA'],
legalReference: 'Art. 9 Abs. 1 DSGVO',
description: 'Verarbeitung der rassischen oder ethnischen Herkunft',
},
// ========== B: Vulnerable Gruppen (3 rules) ==========
{
id: 'HT-B01',
category: 'vulnerable',
questionId: 'data_minors',
condition: 'EQUALS',
conditionValue: true,
minimumLevel: 'L3',
requiresDSFA: true,
mandatoryDocuments: ['VVT', 'TOM', 'DSFA', 'DSE'],
legalReference: 'Art. 8 DSGVO',
description: 'Verarbeitung von Daten Minderjähriger',
},
{
id: 'HT-B02',
category: 'vulnerable',
questionId: 'data_minors',
condition: 'EQUALS',
conditionValue: true,
minimumLevel: 'L4',
requiresDSFA: true,
mandatoryDocuments: ['VVT', 'TOM', 'DSFA', 'DSE'],
legalReference: 'Art. 8 + Art. 9 DSGVO',
description: 'Verarbeitung besonderer Kategorien von Daten Minderjähriger',
combineWithArt9: true,
},
{
id: 'HT-B03',
category: 'vulnerable',
questionId: 'data_minors',
condition: 'EQUALS',
conditionValue: true,
minimumLevel: 'L4',
requiresDSFA: true,
mandatoryDocuments: ['VVT', 'TOM', 'DSFA', 'AI_ACT_DOKU'],
legalReference: 'Art. 8 DSGVO + AI Act',
description: 'KI-gestützte Verarbeitung von Daten Minderjähriger',
combineWithAI: true,
},
// ========== C: ADM/KI (6 rules) ==========
{
id: 'HT-C01',
category: 'adm',
questionId: 'proc_adm_scoring',
condition: 'EQUALS',
conditionValue: true,
minimumLevel: 'L3',
requiresDSFA: true,
mandatoryDocuments: ['VVT', 'TOM', 'DSFA'],
legalReference: 'Art. 22 DSGVO',
description: 'Automatisierte Einzelentscheidung mit Rechtswirkung oder erheblicher Beeinträchtigung',
},
{
id: 'HT-C02',
category: 'adm',
questionId: 'proc_ai_usage',
condition: 'CONTAINS',
conditionValue: 'autonom',
minimumLevel: 'L3',
requiresDSFA: true,
mandatoryDocuments: ['VVT', 'TOM', 'DSFA', 'AI_ACT_DOKU'],
legalReference: 'Art. 22 DSGVO + AI Act',
description: 'Autonome KI-Systeme mit Entscheidungsbefugnis',
},
{
id: 'HT-C03',
category: 'adm',
questionId: 'proc_ai_usage',
condition: 'CONTAINS',
conditionValue: 'scoring',
minimumLevel: 'L2',
requiresDSFA: false,
mandatoryDocuments: ['VVT', 'TOM'],
legalReference: 'Art. 22 DSGVO',
description: 'KI-gestütztes Scoring',
},
{
id: 'HT-C04',
category: 'adm',
questionId: 'proc_ai_usage',
condition: 'CONTAINS',
conditionValue: 'profiling',
minimumLevel: 'L3',
requiresDSFA: true,
mandatoryDocuments: ['VVT', 'TOM', 'DSFA'],
legalReference: 'Art. 22 DSGVO',
description: 'KI-gestütztes Profiling mit erheblicher Wirkung',
},
{
id: 'HT-C05',
category: 'adm',
questionId: 'proc_ai_usage',
condition: 'CONTAINS',
conditionValue: 'generativ',
minimumLevel: 'L2',
requiresDSFA: false,
mandatoryDocuments: ['VVT', 'TOM', 'AI_ACT_DOKU'],
legalReference: 'AI Act',
description: 'Generative KI-Systeme',
},
{
id: 'HT-C06',
category: 'adm',
questionId: 'proc_ai_usage',
condition: 'CONTAINS',
conditionValue: 'chatbot',
minimumLevel: 'L2',
requiresDSFA: false,
mandatoryDocuments: ['VVT', 'AI_ACT_DOKU'],
legalReference: 'AI Act',
description: 'Chatbots mit Personendatenverarbeitung',
},
// ========== D: Überwachung (5 rules) ==========
{
id: 'HT-D01',
category: 'surveillance',
questionId: 'proc_video_surveillance',
condition: 'EQUALS',
conditionValue: true,
minimumLevel: 'L2',
requiresDSFA: false,
mandatoryDocuments: ['VVT', 'TOM', 'DSE'],
legalReference: 'Art. 6 DSGVO',
description: 'Videoüberwachung',
},
{
id: 'HT-D02',
category: 'surveillance',
questionId: 'proc_employee_monitoring',
condition: 'EQUALS',
conditionValue: true,
minimumLevel: 'L2',
requiresDSFA: false,
mandatoryDocuments: ['VVT', 'TOM', 'DSFA'],
legalReference: 'Art. 88 DSGVO + BetrVG',
description: 'Mitarbeiterüberwachung',
},
{
id: 'HT-D03',
category: 'surveillance',
questionId: 'proc_tracking',
condition: 'EQUALS',
conditionValue: true,
minimumLevel: 'L2',
requiresDSFA: false,
mandatoryDocuments: ['VVT', 'TOM', 'COOKIE_BANNER', 'EINWILLIGUNGEN'],
legalReference: 'Art. 6 DSGVO + ePrivacy',
description: 'Online-Tracking',
},
{
id: 'HT-D04',
category: 'surveillance',
questionId: 'proc_video_surveillance',
condition: 'EQUALS',
conditionValue: true,
minimumLevel: 'L3',
requiresDSFA: true,
mandatoryDocuments: ['VVT', 'TOM', 'DSFA'],
legalReference: 'Art. 35 Abs. 3 DSGVO',
description: 'Videoüberwachung kombiniert mit Mitarbeitermonitoring',
combineWithEmployeeMonitoring: true,
},
{
id: 'HT-D05',
category: 'surveillance',
questionId: 'proc_video_surveillance',
condition: 'EQUALS',
conditionValue: true,
minimumLevel: 'L3',
requiresDSFA: true,
mandatoryDocuments: ['VVT', 'TOM', 'DSFA'],
legalReference: 'Art. 35 Abs. 3 DSGVO',
description: 'Videoüberwachung kombiniert mit automatisierter Bewertung',
combineWithADM: true,
},
// ========== E: Drittland (5 rules) ==========
{
id: 'HT-E01',
category: 'third_country',
questionId: 'tech_third_country',
condition: 'EQUALS',
conditionValue: true,
minimumLevel: 'L2',
requiresDSFA: false,
mandatoryDocuments: ['VVT', 'TRANSFER_DOKU'],
legalReference: 'Art. 44 ff. DSGVO',
description: 'Datenübermittlung in Drittland',
},
{
id: 'HT-E02',
category: 'third_country',
questionId: 'tech_hosting_location',
condition: 'EQUALS',
conditionValue: 'drittland',
minimumLevel: 'L2',
requiresDSFA: false,
mandatoryDocuments: ['VVT', 'TOM', 'TRANSFER_DOKU'],
legalReference: 'Art. 44 ff. DSGVO',
description: 'Hosting in Drittland',
},
{
id: 'HT-E03',
category: 'third_country',
questionId: 'tech_hosting_location',
condition: 'EQUALS',
conditionValue: 'us_adequacy',
minimumLevel: 'L2',
requiresDSFA: false,
mandatoryDocuments: ['TRANSFER_DOKU'],
legalReference: 'Art. 45 DSGVO',
description: 'Hosting in USA mit Angemessenheitsbeschluss',
},
{
id: 'HT-E04',
category: 'third_country',
questionId: 'tech_third_country',
condition: 'EQUALS',
conditionValue: true,
minimumLevel: 'L3',
requiresDSFA: false,
mandatoryDocuments: ['VVT', 'TOM', 'TRANSFER_DOKU', 'DSFA'],
legalReference: 'Art. 44 ff. + Art. 9 DSGVO',
description: 'Drittlandtransfer besonderer Kategorien',
combineWithArt9: true,
},
{
id: 'HT-E05',
category: 'third_country',
questionId: 'tech_third_country',
condition: 'EQUALS',
conditionValue: true,
minimumLevel: 'L3',
requiresDSFA: false,
mandatoryDocuments: ['VVT', 'TOM', 'TRANSFER_DOKU', 'DSFA'],
legalReference: 'Art. 44 ff. + Art. 8 DSGVO',
description: 'Drittlandtransfer von Daten Minderjähriger',
combineWithMinors: true,
},
]

View File

@@ -0,0 +1,467 @@
/**
* Hard Trigger Rules FM
* Groups: Zertifizierung (F), Volumen/Skala (G), Produkt/Business (H),
* Prozessreife (I), IACE AI Act Produkt (J), IACE CRA (K),
* IACE NIS2 indirekt (L), IACE Maschinenverordnung (M)
*/
import type { HardTriggerRule } from '../compliance-scope-types'
export const HARD_TRIGGER_RULES_F_M: HardTriggerRule[] = [
// ========== F: Zertifizierung (5 rules) ==========
{
id: 'HT-F01',
category: 'certification',
questionId: 'org_cert_target',
condition: 'CONTAINS',
conditionValue: 'ISO27001',
minimumLevel: 'L4',
requiresDSFA: false,
mandatoryDocuments: ['TOM', 'AUDIT_CHECKLIST'],
legalReference: 'ISO/IEC 27001',
description: 'Angestrebte ISO 27001 Zertifizierung',
},
{
id: 'HT-F02',
category: 'certification',
questionId: 'org_cert_target',
condition: 'CONTAINS',
conditionValue: 'ISO27701',
minimumLevel: 'L4',
requiresDSFA: false,
mandatoryDocuments: ['TOM', 'VVT', 'AUDIT_CHECKLIST'],
legalReference: 'ISO/IEC 27701',
description: 'Angestrebte ISO 27701 Zertifizierung',
},
{
id: 'HT-F03',
category: 'certification',
questionId: 'org_cert_target',
condition: 'CONTAINS',
conditionValue: 'SOC2',
minimumLevel: 'L4',
requiresDSFA: false,
mandatoryDocuments: ['TOM', 'AUDIT_CHECKLIST'],
legalReference: 'SOC 2 Type II',
description: 'Angestrebte SOC 2 Zertifizierung',
},
{
id: 'HT-F04',
category: 'certification',
questionId: 'org_cert_target',
condition: 'CONTAINS',
conditionValue: 'TISAX',
minimumLevel: 'L4',
requiresDSFA: false,
mandatoryDocuments: ['TOM', 'AUDIT_CHECKLIST', 'VENDOR_MANAGEMENT'],
legalReference: 'TISAX',
description: 'Angestrebte TISAX Zertifizierung',
},
{
id: 'HT-F05',
category: 'certification',
questionId: 'org_cert_target',
condition: 'CONTAINS',
conditionValue: 'BSI-Grundschutz',
minimumLevel: 'L4',
requiresDSFA: false,
mandatoryDocuments: ['TOM', 'AUDIT_CHECKLIST'],
legalReference: 'BSI IT-Grundschutz',
description: 'Angestrebte BSI-Grundschutz Zertifizierung',
},
// ========== G: Volumen/Skala (5 rules) ==========
{
id: 'HT-G01',
category: 'scale',
questionId: 'data_volume',
condition: 'EQUALS',
conditionValue: '>1000000',
minimumLevel: 'L3',
requiresDSFA: false,
mandatoryDocuments: ['VVT', 'TOM', 'LOESCHKONZEPT'],
legalReference: 'Art. 35 Abs. 3 lit. b DSGVO',
description: 'Umfangreiche Verarbeitung personenbezogener Daten (>1 Mio. Datensätze)',
},
{
id: 'HT-G02',
category: 'scale',
questionId: 'data_volume',
condition: 'EQUALS',
conditionValue: '100000-1000000',
minimumLevel: 'L2',
requiresDSFA: false,
mandatoryDocuments: ['VVT', 'TOM'],
legalReference: 'Art. 35 Abs. 3 lit. b DSGVO',
description: 'Großvolumige Datenverarbeitung (100k-1M Datensätze)',
},
{
id: 'HT-G03',
category: 'scale',
questionId: 'org_customer_count',
condition: 'EQUALS',
conditionValue: '100000+',
minimumLevel: 'L3',
requiresDSFA: false,
mandatoryDocuments: ['VVT', 'TOM', 'DSR_PROZESS'],
legalReference: 'Art. 15-22 DSGVO',
description: 'Großer Kundenstamm (>100k) mit hoher Betroffenenanzahl',
},
{
id: 'HT-G04',
category: 'scale',
questionId: 'org_employee_count',
condition: 'GREATER_THAN',
conditionValue: 249,
minimumLevel: 'L3',
requiresDSFA: false,
mandatoryDocuments: ['VVT', 'TOM', 'LOESCHKONZEPT', 'NOTFALLPLAN'],
legalReference: 'Art. 37 DSGVO',
description: 'Große Organisation (>250 Mitarbeiter) mit erhöhten Compliance-Anforderungen',
},
{
id: 'HT-G05',
category: 'scale',
questionId: 'org_employee_count',
condition: 'GREATER_THAN',
conditionValue: 999,
minimumLevel: 'L4',
requiresDSFA: false,
mandatoryDocuments: ['VVT', 'TOM', 'DSFA', 'LOESCHKONZEPT'],
legalReference: 'Art. 35 + Art. 37 DSGVO',
description: 'Sehr große Organisation (>1000 Mitarbeiter) mit Art. 9 Daten',
combineWithArt9: true,
},
// ========== H: Produkt/Business (7 rules) ==========
{
id: 'HT-H01a',
category: 'product',
questionId: 'prod_webshop',
condition: 'EQUALS',
conditionValue: true,
excludeWhen: { questionId: 'org_business_model', value: 'B2B' },
minimumLevel: 'L2',
requiresDSFA: false,
mandatoryDocuments: ['DSE', 'AGB', 'COOKIE_BANNER', 'EINWILLIGUNGEN',
'WIDERRUFSBELEHRUNG', 'PREISANGABEN', 'FERNABSATZ_INFO', 'STREITBEILEGUNG'],
legalReference: 'Art. 6 DSGVO + Fernabsatzrecht + PAngV + VSBG',
description: 'E-Commerce / Webshop (B2C) — Verbraucherschutzpflichten',
},
{
id: 'HT-H01b',
category: 'product',
questionId: 'prod_webshop',
condition: 'EQUALS',
conditionValue: true,
requireWhen: { questionId: 'org_business_model', value: 'B2B' },
minimumLevel: 'L2',
requiresDSFA: false,
mandatoryDocuments: ['DSE', 'AGB', 'COOKIE_BANNER'],
legalReference: 'Art. 6 DSGVO + eCommerce',
description: 'E-Commerce / Webshop (B2B) — Basis-Pflichten',
},
{
id: 'HT-H02',
category: 'product',
questionId: 'prod_data_broker',
condition: 'EQUALS',
conditionValue: true,
minimumLevel: 'L3',
requiresDSFA: true,
mandatoryDocuments: ['VVT', 'TOM', 'DSFA', 'EINWILLIGUNGEN'],
legalReference: 'Art. 35 Abs. 3 DSGVO',
description: 'Datenhandel oder Datenmakler-Tätigkeit',
},
{
id: 'HT-H03',
category: 'product',
questionId: 'prod_api_external',
condition: 'EQUALS',
conditionValue: true,
minimumLevel: 'L2',
requiresDSFA: false,
mandatoryDocuments: ['TOM', 'AVV'],
legalReference: 'Art. 28 DSGVO',
description: 'Externe API mit Datenweitergabe',
},
{
id: 'HT-H04',
category: 'product',
questionId: 'org_business_model',
condition: 'EQUALS',
conditionValue: 'b2c',
minimumLevel: 'L2',
requiresDSFA: false,
mandatoryDocuments: ['DSE', 'COOKIE_BANNER', 'EINWILLIGUNGEN'],
legalReference: 'Art. 6 DSGVO',
description: 'B2C-Geschäftsmodell mit Endkundenkontakt',
},
{
id: 'HT-H05',
category: 'product',
questionId: 'org_industry',
condition: 'EQUALS',
conditionValue: 'finance',
minimumLevel: 'L2',
requiresDSFA: false,
mandatoryDocuments: ['VVT', 'TOM'],
legalReference: 'Art. 6 DSGVO + Finanzaufsicht',
description: 'Finanzbranche mit erhöhten regulatorischen Anforderungen',
},
{
id: 'HT-H06',
category: 'product',
questionId: 'org_industry',
condition: 'EQUALS',
conditionValue: 'healthcare',
minimumLevel: 'L3',
requiresDSFA: true,
mandatoryDocuments: ['VVT', 'TOM', 'DSFA'],
legalReference: 'Art. 9 DSGVO + Gesundheitsrecht',
description: 'Gesundheitsbranche mit sensiblen Daten',
},
{
id: 'HT-H07',
category: 'product',
questionId: 'org_industry',
condition: 'EQUALS',
conditionValue: 'public',
minimumLevel: 'L2',
requiresDSFA: false,
mandatoryDocuments: ['VVT', 'TOM', 'DSR_PROZESS'],
legalReference: 'Art. 6 Abs. 1 lit. e DSGVO',
description: 'Öffentlicher Sektor',
},
// ========== I: Prozessreife - Gap Flags (5 rules) ==========
{
id: 'HT-I01',
category: 'process_maturity',
questionId: 'proc_dsar_process',
condition: 'EQUALS',
conditionValue: false,
minimumLevel: 'L1',
requiresDSFA: false,
mandatoryDocuments: [],
legalReference: 'Art. 15-22 DSGVO',
description: 'Fehlender Prozess für Betroffenenrechte',
},
{
id: 'HT-I02',
category: 'process_maturity',
questionId: 'proc_deletion_concept',
condition: 'EQUALS',
conditionValue: false,
minimumLevel: 'L1',
requiresDSFA: false,
mandatoryDocuments: [],
legalReference: 'Art. 17 DSGVO',
description: 'Fehlendes Löschkonzept',
},
{
id: 'HT-I03',
category: 'process_maturity',
questionId: 'proc_incident_response',
condition: 'EQUALS',
conditionValue: false,
minimumLevel: 'L1',
requiresDSFA: false,
mandatoryDocuments: [],
legalReference: 'Art. 33 DSGVO',
description: 'Fehlender Incident-Response-Prozess',
},
{
id: 'HT-I04',
category: 'process_maturity',
questionId: 'proc_regular_audits',
condition: 'EQUALS',
conditionValue: false,
minimumLevel: 'L1',
requiresDSFA: false,
mandatoryDocuments: [],
legalReference: 'Art. 24 DSGVO',
description: 'Fehlende regelmäßige Audits',
},
{
id: 'HT-I05',
category: 'process_maturity',
questionId: 'comp_training',
condition: 'EQUALS',
conditionValue: false,
minimumLevel: 'L1',
requiresDSFA: false,
mandatoryDocuments: [],
legalReference: 'Art. 39 Abs. 1 lit. b DSGVO',
description: 'Fehlende Schulungen zum Datenschutz',
},
// ========== J: IACE — AI Act Produkt-Triggers (3 rules) ==========
{
id: 'HT-J01',
category: 'iace_ai_act_product',
questionId: 'machineBuilder.containsAI',
condition: 'EQUALS',
conditionValue: true,
minimumLevel: 'L3',
requiresDSFA: false,
mandatoryDocuments: ['VVT', 'TOM'],
legalReference: 'EU AI Act Annex I + EU Maschinenverordnung 2023/1230',
description: 'KI mit Sicherheitsfunktion in Maschine → AI Act High-Risk',
combineWithMachineBuilder: { field: 'hasSafetyFunction', value: true },
riskWeight: 9,
},
{
id: 'HT-J02',
category: 'iace_ai_act_product',
questionId: 'machineBuilder.containsAI',
condition: 'EQUALS',
conditionValue: true,
minimumLevel: 'L3',
requiresDSFA: false,
mandatoryDocuments: ['VVT', 'TOM'],
legalReference: 'EU AI Act + EU Maschinenverordnung 2023/1230',
description: 'Autonome KI in Maschine → AI Act + Maschinenverordnung',
combineWithMachineBuilder: { field: 'autonomousBehavior', value: true },
riskWeight: 8,
},
{
id: 'HT-J03',
category: 'iace_ai_act_product',
questionId: 'machineBuilder.hasSafetyFunction',
condition: 'EQUALS',
conditionValue: true,
minimumLevel: 'L3',
requiresDSFA: false,
mandatoryDocuments: ['VVT', 'TOM'],
legalReference: 'EU AI Act Annex III',
description: 'KI-Bildverarbeitung mit Sicherheitsbezug',
combineWithMachineBuilder: { field: 'aiIntegrationType', includes: 'vision' },
riskWeight: 8,
},
// ========== K: IACE — CRA Triggers (3 rules) ==========
{
id: 'HT-K01',
category: 'iace_cra',
questionId: 'machineBuilder.isNetworked',
condition: 'EQUALS',
conditionValue: true,
minimumLevel: 'L2',
requiresDSFA: false,
mandatoryDocuments: ['TOM'],
legalReference: 'EU Cyber Resilience Act (CRA)',
description: 'Vernetztes Produkt → Cyber Resilience Act',
riskWeight: 6,
},
{
id: 'HT-K02',
category: 'iace_cra',
questionId: 'machineBuilder.hasRemoteAccess',
condition: 'EQUALS',
conditionValue: true,
minimumLevel: 'L2',
requiresDSFA: false,
mandatoryDocuments: ['TOM'],
legalReference: 'CRA + NIS2 Art. 21',
description: 'Remote-Zugriff → CRA + NIS2 Supply Chain',
riskWeight: 7,
},
{
id: 'HT-K03',
category: 'iace_cra',
questionId: 'machineBuilder.hasOTAUpdates',
condition: 'EQUALS',
conditionValue: true,
minimumLevel: 'L2',
requiresDSFA: false,
mandatoryDocuments: ['TOM'],
legalReference: 'CRA Art. 10 - Patch Management',
description: 'OTA-Updates → CRA Patch Management Pflicht',
riskWeight: 7,
},
// ========== L: IACE — NIS2 indirekt (2 rules) ==========
{
id: 'HT-L01',
category: 'iace_nis2_indirect',
questionId: 'machineBuilder.criticalSectorClients',
condition: 'EQUALS',
conditionValue: true,
minimumLevel: 'L2',
requiresDSFA: false,
mandatoryDocuments: ['TOM'],
legalReference: 'NIS2 Art. 21 - Supply Chain',
description: 'Lieferant an KRITIS → NIS2 Supply Chain Anforderungen',
riskWeight: 7,
},
{
id: 'HT-L02',
category: 'iace_nis2_indirect',
questionId: 'machineBuilder.oemClients',
condition: 'EQUALS',
conditionValue: true,
minimumLevel: 'L2',
requiresDSFA: false,
mandatoryDocuments: [],
legalReference: 'NIS2 + EU Maschinenverordnung',
description: 'OEM-Zulieferer → Compliance-Nachweispflicht',
riskWeight: 5,
},
// ========== M: IACE — Maschinenverordnung Triggers (4 rules) ==========
{
id: 'HT-M01',
category: 'iace_machinery_regulation',
questionId: 'machineBuilder.containsSoftware',
condition: 'EQUALS',
conditionValue: true,
minimumLevel: 'L3',
requiresDSFA: false,
mandatoryDocuments: ['TOM'],
legalReference: 'EU Maschinenverordnung 2023/1230 Anhang III',
description: 'Software als Sicherheitskomponente → Maschinenverordnung',
combineWithMachineBuilder: { field: 'hasSafetyFunction', value: true },
riskWeight: 9,
},
{
id: 'HT-M02',
category: 'iace_machinery_regulation',
questionId: 'machineBuilder.ceMarkingRequired',
condition: 'EQUALS',
conditionValue: true,
minimumLevel: 'L2',
requiresDSFA: false,
mandatoryDocuments: [],
legalReference: 'EU Maschinenverordnung 2023/1230',
description: 'CE-Kennzeichnung erforderlich',
riskWeight: 6,
},
{
id: 'HT-M03',
category: 'iace_machinery_regulation',
questionId: 'machineBuilder.ceMarkingRequired',
condition: 'EQUALS',
conditionValue: true,
minimumLevel: 'L3',
requiresDSFA: false,
mandatoryDocuments: [],
legalReference: 'EU Maschinenverordnung 2023/1230 Art. 10',
description: 'CE ohne bestehende Risikobeurteilung → Dringend!',
combineWithMachineBuilder: { field: 'hasRiskAssessment', value: false },
riskWeight: 9,
},
{
id: 'HT-M04',
category: 'iace_machinery_regulation',
questionId: 'machineBuilder.containsFirmware',
condition: 'EQUALS',
conditionValue: true,
minimumLevel: 'L2',
requiresDSFA: false,
mandatoryDocuments: ['TOM'],
legalReference: 'EU Maschinenverordnung + CRA',
description: 'Firmware mit Remote-Update → Change Management Pflicht',
combineWithMachineBuilder: { field: 'hasOTAUpdates', value: true },
riskWeight: 7,
},
]

View File

@@ -0,0 +1,217 @@
/**
* Demo State Generator
*
* Generates a complete demo SDKState object for seeding.
* Barrel-split from index.ts. Do NOT import directly; use index.ts.
*/
import { SDKState } from '../types'
import { getDemoUseCases } from './use-cases'
import { getDemoRisks } from './risks'
import { getDemoControls } from './controls'
import { getDemoDSFA } from './dsfa'
import { getDemoTOMs } from './toms'
import { getDemoProcessingActivities, getDemoRetentionPolicies } from './vvt'
/**
* Generate a complete demo state object
* This is used as seed data for the API, not as runtime data
*/
export function generateDemoState(tenantId: string, userId: string): Partial<SDKState> {
const now = new Date()
return {
// Metadata
version: '1.0.0',
projectVersion: 1,
lastModified: now,
// Tenant & User
tenantId,
userId,
subscription: 'PROFESSIONAL',
// Customer Type
customerType: 'new',
// Company Profile (Demo: TechStart GmbH - SaaS-Startup aus Berlin)
companyProfile: {
companyName: 'TechStart GmbH',
legalForm: 'gmbh',
industry: ['Technologie / IT'],
industryOther: '',
foundedYear: 2022,
businessModel: 'B2B_B2C',
offerings: ['app_web', 'software_saas', 'services_consulting'],
companySize: 'small',
employeeCount: '10-49',
annualRevenue: '2-10 Mio',
headquartersCountry: 'DE',
headquartersCity: 'Berlin',
hasInternationalLocations: false,
internationalCountries: [],
targetMarkets: ['germany_only', 'dach'],
primaryJurisdiction: 'DE',
isDataController: true,
isDataProcessor: true,
dpoName: 'Max Mustermann',
dpoEmail: 'dsb@techstart.de',
legalContactName: null,
legalContactEmail: null,
isComplete: true,
completedAt: new Date('2026-01-14'),
},
// Progress - showing a realistic partially completed workflow
currentPhase: 2,
currentStep: 'tom',
completedSteps: [
'company-profile',
'use-case-assessment',
'screening',
'modules',
'requirements',
'controls',
'evidence',
'audit-checklist',
'risks',
'ai-act',
'obligations',
'dsfa',
],
checkpoints: {
'CP-PROF': { checkpointId: 'CP-PROF', passed: true, validatedAt: new Date('2026-01-14'), validatedBy: 'demo-user', errors: [], warnings: [] },
'CP-UC': { checkpointId: 'CP-UC', passed: true, validatedAt: new Date('2026-01-15'), validatedBy: 'demo-user', errors: [], warnings: [] },
'CP-SCAN': { checkpointId: 'CP-SCAN', passed: true, validatedAt: new Date('2026-01-16'), validatedBy: 'demo-user', errors: [], warnings: [] },
'CP-MOD': { checkpointId: 'CP-MOD', passed: true, validatedAt: new Date('2026-01-17'), validatedBy: 'demo-user', errors: [], warnings: [] },
'CP-REQ': { checkpointId: 'CP-REQ', passed: true, validatedAt: new Date('2026-01-18'), validatedBy: 'demo-user', errors: [], warnings: [] },
'CP-CTRL': { checkpointId: 'CP-CTRL', passed: true, validatedAt: new Date('2026-01-19'), validatedBy: 'demo-user', errors: [], warnings: [] },
'CP-EVI': { checkpointId: 'CP-EVI', passed: true, validatedAt: new Date('2026-01-20'), validatedBy: 'demo-user', errors: [], warnings: [] },
'CP-CHK': { checkpointId: 'CP-CHK', passed: true, validatedAt: new Date('2026-01-21'), validatedBy: 'demo-user', errors: [], warnings: [] },
'CP-RISK': { checkpointId: 'CP-RISK', passed: true, validatedAt: new Date('2026-01-22'), validatedBy: 'demo-user', errors: [], warnings: [] },
'CP-AI': { checkpointId: 'CP-AI', passed: true, validatedAt: new Date('2026-01-25'), validatedBy: 'demo-user', errors: [], warnings: [] },
'CP-OBL': { checkpointId: 'CP-OBL', passed: true, validatedAt: new Date('2026-01-27'), validatedBy: 'demo-user', errors: [], warnings: [] },
'CP-DSFA': { checkpointId: 'CP-DSFA', passed: true, validatedAt: new Date('2026-01-30'), validatedBy: 'DSB', errors: [], warnings: [] },
},
// Phase 1 Data
useCases: getDemoUseCases(),
activeUseCase: 'demo-uc-1',
screening: {
id: 'demo-scan-1',
status: 'COMPLETED',
startedAt: new Date('2026-01-16T09:00:00'),
completedAt: new Date('2026-01-16T09:15:00'),
sbom: {
format: 'CycloneDX',
version: '1.4',
components: [
{ name: 'tensorflow', version: '2.15.0', type: 'library', purl: 'pkg:pypi/tensorflow@2.15.0', licenses: ['Apache-2.0'], vulnerabilities: [] },
{ name: 'scikit-learn', version: '1.4.0', type: 'library', purl: 'pkg:pypi/scikit-learn@1.4.0', licenses: ['BSD-3-Clause'], vulnerabilities: [] },
{ name: 'pandas', version: '2.2.0', type: 'library', purl: 'pkg:pypi/pandas@2.2.0', licenses: ['BSD-3-Clause'], vulnerabilities: [] },
],
dependencies: [],
generatedAt: new Date('2026-01-16T09:10:00'),
},
securityScan: {
totalIssues: 3,
critical: 0,
high: 1,
medium: 1,
low: 1,
issues: [
{
id: 'sec-issue-1', severity: 'HIGH', title: 'Outdated cryptography library',
description: 'The cryptography library version 41.0.0 has known vulnerabilities',
cve: 'CVE-2024-1234', cvss: 7.5, affectedComponent: 'cryptography',
remediation: 'Upgrade to cryptography >= 42.0.0', status: 'RESOLVED',
},
{
id: 'sec-issue-2', severity: 'MEDIUM', title: 'Insecure default configuration',
description: 'Debug mode enabled in production configuration',
cve: null, cvss: 5.3, affectedComponent: 'app-config',
remediation: 'Set DEBUG=false in production', status: 'RESOLVED',
},
{
id: 'sec-issue-3', severity: 'LOW', title: 'Missing security headers',
description: 'X-Content-Type-Options header not set',
cve: null, cvss: 3.1, affectedComponent: 'web-server',
remediation: 'Add security headers middleware', status: 'RESOLVED',
},
],
},
error: null,
},
modules: [
{ id: 'demo-mod-1', name: 'Kundendaten-Modul', description: 'Verarbeitung von Kundendaten für Marketing und Analyse', regulations: ['DSGVO', 'TTDSG'], criticality: 'HIGH', processesPersonalData: true, hasAIComponents: true },
{ id: 'demo-mod-2', name: 'HR-Modul', description: 'Bewerbermanagement und Personalverwaltung', regulations: ['DSGVO', 'AGG', 'AI Act'], criticality: 'HIGH', processesPersonalData: true, hasAIComponents: true },
{ id: 'demo-mod-3', name: 'Support-Modul', description: 'Kundenservice und Chatbot-System', regulations: ['DSGVO', 'AI Act'], criticality: 'MEDIUM', processesPersonalData: true, hasAIComponents: true },
],
requirements: [
{ id: 'demo-req-1', regulation: 'DSGVO', article: 'Art. 5', title: 'Grundsätze der Verarbeitung', description: 'Einhaltung der Grundsätze für die Verarbeitung personenbezogener Daten', criticality: 'CRITICAL', applicableModules: ['demo-mod-1', 'demo-mod-2', 'demo-mod-3'], status: 'IMPLEMENTED', controls: ['demo-ctrl-1', 'demo-ctrl-2', 'demo-ctrl-9'] },
{ id: 'demo-req-2', regulation: 'DSGVO', article: 'Art. 32', title: 'Sicherheit der Verarbeitung', description: 'Geeignete technische und organisatorische Maßnahmen', criticality: 'CRITICAL', applicableModules: ['demo-mod-1', 'demo-mod-2', 'demo-mod-3'], status: 'IMPLEMENTED', controls: ['demo-ctrl-1', 'demo-ctrl-3', 'demo-ctrl-4'] },
{ id: 'demo-req-3', regulation: 'DSGVO', article: 'Art. 25', title: 'Datenschutz durch Technikgestaltung', description: 'Privacy by Design und Privacy by Default', criticality: 'HIGH', applicableModules: ['demo-mod-1', 'demo-mod-2'], status: 'IMPLEMENTED', controls: ['demo-ctrl-9', 'demo-ctrl-10'] },
{ id: 'demo-req-4', regulation: 'AI Act', article: 'Art. 13', title: 'Transparenz', description: 'Transparenzanforderungen für KI-Systeme', criticality: 'HIGH', applicableModules: ['demo-mod-1', 'demo-mod-2', 'demo-mod-3'], status: 'IMPLEMENTED', controls: ['demo-ctrl-7', 'demo-ctrl-8'] },
{ id: 'demo-req-5', regulation: 'AI Act', article: 'Art. 9', title: 'Risikomanagement', description: 'Risikomanagementsystem für Hochrisiko-KI', criticality: 'HIGH', applicableModules: ['demo-mod-2'], status: 'IMPLEMENTED', controls: ['demo-ctrl-5', 'demo-ctrl-6', 'demo-ctrl-11', 'demo-ctrl-12'] },
],
controls: getDemoControls(),
evidence: [
{ id: 'demo-evi-1', controlId: 'demo-ctrl-1', type: 'SCREENSHOT', name: 'MFA-Konfiguration Azure AD', description: 'Screenshot der MFA-Einstellungen im Azure AD Admin Portal', fileUrl: null, validFrom: new Date('2026-01-01'), validUntil: new Date('2027-01-01'), uploadedBy: 'IT-Security', uploadedAt: new Date('2026-01-10') },
{ id: 'demo-evi-2', controlId: 'demo-ctrl-2', type: 'DOCUMENT', name: 'Berechtigungskonzept v2.1', description: 'Dokumentiertes Berechtigungskonzept mit Rollenmatrix', fileUrl: null, validFrom: new Date('2026-01-01'), validUntil: null, uploadedBy: 'IT-Security', uploadedAt: new Date('2026-01-05') },
{ id: 'demo-evi-5', controlId: 'demo-ctrl-5', type: 'AUDIT_REPORT', name: 'Bias-Audit Q1/2026', description: 'Externer Audit-Bericht zur Fairness des KI-Modells', fileUrl: null, validFrom: new Date('2026-01-15'), validUntil: new Date('2026-04-15'), uploadedBy: 'Data Science Lead', uploadedAt: new Date('2026-01-20') },
],
checklist: [
{ id: 'demo-chk-1', requirementId: 'demo-req-1', title: 'Rechtmäßigkeit der Verarbeitung geprüft', description: 'Dokumentierte Prüfung der Rechtsgrundlagen', status: 'PASSED', notes: 'Geprüft durch DSB', verifiedBy: 'DSB', verifiedAt: new Date('2026-01-20') },
{ id: 'demo-chk-2', requirementId: 'demo-req-2', title: 'TOMs dokumentiert und umgesetzt', description: 'Technische und organisatorische Maßnahmen', status: 'PASSED', notes: 'Alle TOMs implementiert', verifiedBy: 'CISO', verifiedAt: new Date('2026-01-21') },
],
risks: getDemoRisks(),
// Phase 2 Data
aiActClassification: {
riskCategory: 'HIGH',
systemType: 'Beschäftigungsbezogenes KI-System (Art. 6 Abs. 2 AI Act)',
obligations: [
{ id: 'demo-ai-obl-1', article: 'Art. 9', title: 'Risikomanagementsystem', description: 'Einrichtung eines KI-Risikomanagementsystems', deadline: new Date('2026-08-01'), status: 'IN_PROGRESS' },
{ id: 'demo-ai-obl-2', article: 'Art. 10', title: 'Daten-Governance', description: 'Anforderungen an Trainingsdaten', deadline: new Date('2026-08-01'), status: 'COMPLETED' },
{ id: 'demo-ai-obl-3', article: 'Art. 13', title: 'Transparenz', description: 'Dokumentation für Nutzer', deadline: new Date('2026-08-01'), status: 'COMPLETED' },
],
assessmentDate: new Date('2026-01-25'),
assessedBy: 'Compliance Team',
justification: 'Das System fällt unter Art. 6 Abs. 2 lit. a AI Act (Einstellung und Auswahl von Personen).',
},
obligations: [
{ id: 'demo-obl-1', regulation: 'DSGVO', article: 'Art. 30', title: 'Verarbeitungsverzeichnis', description: 'Führung eines Verzeichnisses der Verarbeitungstätigkeiten', deadline: null, penalty: 'Bis zu 10 Mio. EUR oder 2% des Jahresumsatzes', status: 'COMPLETED', responsible: 'DSB' },
{ id: 'demo-obl-2', regulation: 'DSGVO', article: 'Art. 35', title: 'Datenschutz-Folgenabschätzung', description: 'Durchführung einer DSFA für Hochrisiko-Verarbeitungen', deadline: null, penalty: 'Bis zu 10 Mio. EUR oder 2% des Jahresumsatzes', status: 'COMPLETED', responsible: 'DSB' },
{ id: 'demo-obl-3', regulation: 'AI Act', article: 'Art. 49', title: 'CE-Kennzeichnung', description: 'CE-Kennzeichnung für Hochrisiko-KI-Systeme', deadline: new Date('2026-08-01'), penalty: 'Bis zu 35 Mio. EUR oder 7% des Jahresumsatzes', status: 'PENDING', responsible: 'Compliance' },
],
dsfa: getDemoDSFA(),
toms: getDemoTOMs(),
retentionPolicies: getDemoRetentionPolicies(),
vvt: getDemoProcessingActivities(),
// Documents, Cookie Banner, etc. - partially filled
documents: [],
cookieBanner: null,
consents: [],
dsrConfig: null,
escalationWorkflows: [],
// Security
sbom: null,
securityIssues: [],
securityBacklog: [],
// UI State
commandBarHistory: [],
recentSearches: ['DSGVO Art. 5', 'Bias-Monitoring', 'TOM Verschlüsselung'],
preferences: {
language: 'de',
theme: 'light',
compactMode: false,
showHints: true,
autoSave: true,
autoValidate: true,
allowParallelWork: true,
},
}
}

View File

@@ -7,6 +7,8 @@
* *
* The seedDemoData() function writes data through the API, * The seedDemoData() function writes data through the API,
* and the data is then loaded from the database like any other data. * and the data is then loaded from the database like any other data.
*
* generateDemoState lives in ./demo-state.ts (barrel split).
*/ */
import { SDKState } from '../types' import { SDKState } from '../types'
@@ -39,420 +41,9 @@ export {
DEMO_RETENTION_POLICIES, DEMO_RETENTION_POLICIES,
} }
/** // Re-export generateDemoState from its own module
* Generate a complete demo state object export { generateDemoState } from './demo-state'
* This is used as seed data for the API, not as runtime data import { generateDemoState } from './demo-state'
*/
export function generateDemoState(tenantId: string, userId: string): Partial<SDKState> {
const now = new Date()
return {
// Metadata
version: '1.0.0',
projectVersion: 1,
lastModified: now,
// Tenant & User
tenantId,
userId,
subscription: 'PROFESSIONAL',
// Customer Type
customerType: 'new',
// Company Profile (Demo: TechStart GmbH - SaaS-Startup aus Berlin)
companyProfile: {
companyName: 'TechStart GmbH',
legalForm: 'gmbh',
industry: ['Technologie / IT'],
industryOther: '',
foundedYear: 2022,
businessModel: 'B2B_B2C',
offerings: ['app_web', 'software_saas', 'services_consulting'],
companySize: 'small',
employeeCount: '10-49',
annualRevenue: '2-10 Mio',
headquartersCountry: 'DE',
headquartersCity: 'Berlin',
hasInternationalLocations: false,
internationalCountries: [],
targetMarkets: ['germany_only', 'dach'],
primaryJurisdiction: 'DE',
isDataController: true,
isDataProcessor: true,
dpoName: 'Max Mustermann',
dpoEmail: 'dsb@techstart.de',
legalContactName: null,
legalContactEmail: null,
isComplete: true,
completedAt: new Date('2026-01-14'),
},
// Progress - showing a realistic partially completed workflow
currentPhase: 2,
currentStep: 'tom',
completedSteps: [
'company-profile',
'use-case-assessment',
'screening',
'modules',
'requirements',
'controls',
'evidence',
'audit-checklist',
'risks',
'ai-act',
'obligations',
'dsfa',
],
checkpoints: {
'CP-PROF': { checkpointId: 'CP-PROF', passed: true, validatedAt: new Date('2026-01-14'), validatedBy: 'demo-user', errors: [], warnings: [] },
'CP-UC': { checkpointId: 'CP-UC', passed: true, validatedAt: new Date('2026-01-15'), validatedBy: 'demo-user', errors: [], warnings: [] },
'CP-SCAN': { checkpointId: 'CP-SCAN', passed: true, validatedAt: new Date('2026-01-16'), validatedBy: 'demo-user', errors: [], warnings: [] },
'CP-MOD': { checkpointId: 'CP-MOD', passed: true, validatedAt: new Date('2026-01-17'), validatedBy: 'demo-user', errors: [], warnings: [] },
'CP-REQ': { checkpointId: 'CP-REQ', passed: true, validatedAt: new Date('2026-01-18'), validatedBy: 'demo-user', errors: [], warnings: [] },
'CP-CTRL': { checkpointId: 'CP-CTRL', passed: true, validatedAt: new Date('2026-01-19'), validatedBy: 'demo-user', errors: [], warnings: [] },
'CP-EVI': { checkpointId: 'CP-EVI', passed: true, validatedAt: new Date('2026-01-20'), validatedBy: 'demo-user', errors: [], warnings: [] },
'CP-CHK': { checkpointId: 'CP-CHK', passed: true, validatedAt: new Date('2026-01-21'), validatedBy: 'demo-user', errors: [], warnings: [] },
'CP-RISK': { checkpointId: 'CP-RISK', passed: true, validatedAt: new Date('2026-01-22'), validatedBy: 'demo-user', errors: [], warnings: [] },
'CP-AI': { checkpointId: 'CP-AI', passed: true, validatedAt: new Date('2026-01-25'), validatedBy: 'demo-user', errors: [], warnings: [] },
'CP-OBL': { checkpointId: 'CP-OBL', passed: true, validatedAt: new Date('2026-01-27'), validatedBy: 'demo-user', errors: [], warnings: [] },
'CP-DSFA': { checkpointId: 'CP-DSFA', passed: true, validatedAt: new Date('2026-01-30'), validatedBy: 'DSB', errors: [], warnings: [] },
},
// Phase 1 Data
useCases: getDemoUseCases(),
activeUseCase: 'demo-uc-1',
screening: {
id: 'demo-scan-1',
status: 'COMPLETED',
startedAt: new Date('2026-01-16T09:00:00'),
completedAt: new Date('2026-01-16T09:15:00'),
sbom: {
format: 'CycloneDX',
version: '1.4',
components: [
{
name: 'tensorflow',
version: '2.15.0',
type: 'library',
purl: 'pkg:pypi/tensorflow@2.15.0',
licenses: ['Apache-2.0'],
vulnerabilities: [],
},
{
name: 'scikit-learn',
version: '1.4.0',
type: 'library',
purl: 'pkg:pypi/scikit-learn@1.4.0',
licenses: ['BSD-3-Clause'],
vulnerabilities: [],
},
{
name: 'pandas',
version: '2.2.0',
type: 'library',
purl: 'pkg:pypi/pandas@2.2.0',
licenses: ['BSD-3-Clause'],
vulnerabilities: [],
},
],
dependencies: [],
generatedAt: new Date('2026-01-16T09:10:00'),
},
securityScan: {
totalIssues: 3,
critical: 0,
high: 1,
medium: 1,
low: 1,
issues: [
{
id: 'sec-issue-1',
severity: 'HIGH',
title: 'Outdated cryptography library',
description: 'The cryptography library version 41.0.0 has known vulnerabilities',
cve: 'CVE-2024-1234',
cvss: 7.5,
affectedComponent: 'cryptography',
remediation: 'Upgrade to cryptography >= 42.0.0',
status: 'RESOLVED',
},
{
id: 'sec-issue-2',
severity: 'MEDIUM',
title: 'Insecure default configuration',
description: 'Debug mode enabled in production configuration',
cve: null,
cvss: 5.3,
affectedComponent: 'app-config',
remediation: 'Set DEBUG=false in production',
status: 'RESOLVED',
},
{
id: 'sec-issue-3',
severity: 'LOW',
title: 'Missing security headers',
description: 'X-Content-Type-Options header not set',
cve: null,
cvss: 3.1,
affectedComponent: 'web-server',
remediation: 'Add security headers middleware',
status: 'RESOLVED',
},
],
},
error: null,
},
modules: [
{
id: 'demo-mod-1',
name: 'Kundendaten-Modul',
description: 'Verarbeitung von Kundendaten für Marketing und Analyse',
regulations: ['DSGVO', 'TTDSG'],
criticality: 'HIGH',
processesPersonalData: true,
hasAIComponents: true,
},
{
id: 'demo-mod-2',
name: 'HR-Modul',
description: 'Bewerbermanagement und Personalverwaltung',
regulations: ['DSGVO', 'AGG', 'AI Act'],
criticality: 'HIGH',
processesPersonalData: true,
hasAIComponents: true,
},
{
id: 'demo-mod-3',
name: 'Support-Modul',
description: 'Kundenservice und Chatbot-System',
regulations: ['DSGVO', 'AI Act'],
criticality: 'MEDIUM',
processesPersonalData: true,
hasAIComponents: true,
},
],
requirements: [
{
id: 'demo-req-1',
regulation: 'DSGVO',
article: 'Art. 5',
title: 'Grundsätze der Verarbeitung',
description: 'Einhaltung der Grundsätze für die Verarbeitung personenbezogener Daten',
criticality: 'CRITICAL',
applicableModules: ['demo-mod-1', 'demo-mod-2', 'demo-mod-3'],
status: 'IMPLEMENTED',
controls: ['demo-ctrl-1', 'demo-ctrl-2', 'demo-ctrl-9'],
},
{
id: 'demo-req-2',
regulation: 'DSGVO',
article: 'Art. 32',
title: 'Sicherheit der Verarbeitung',
description: 'Geeignete technische und organisatorische Maßnahmen',
criticality: 'CRITICAL',
applicableModules: ['demo-mod-1', 'demo-mod-2', 'demo-mod-3'],
status: 'IMPLEMENTED',
controls: ['demo-ctrl-1', 'demo-ctrl-3', 'demo-ctrl-4'],
},
{
id: 'demo-req-3',
regulation: 'DSGVO',
article: 'Art. 25',
title: 'Datenschutz durch Technikgestaltung',
description: 'Privacy by Design und Privacy by Default',
criticality: 'HIGH',
applicableModules: ['demo-mod-1', 'demo-mod-2'],
status: 'IMPLEMENTED',
controls: ['demo-ctrl-9', 'demo-ctrl-10'],
},
{
id: 'demo-req-4',
regulation: 'AI Act',
article: 'Art. 13',
title: 'Transparenz',
description: 'Transparenzanforderungen für KI-Systeme',
criticality: 'HIGH',
applicableModules: ['demo-mod-1', 'demo-mod-2', 'demo-mod-3'],
status: 'IMPLEMENTED',
controls: ['demo-ctrl-7', 'demo-ctrl-8'],
},
{
id: 'demo-req-5',
regulation: 'AI Act',
article: 'Art. 9',
title: 'Risikomanagement',
description: 'Risikomanagementsystem für Hochrisiko-KI',
criticality: 'HIGH',
applicableModules: ['demo-mod-2'],
status: 'IMPLEMENTED',
controls: ['demo-ctrl-5', 'demo-ctrl-6', 'demo-ctrl-11', 'demo-ctrl-12'],
},
],
controls: getDemoControls(),
evidence: [
{
id: 'demo-evi-1',
controlId: 'demo-ctrl-1',
type: 'SCREENSHOT',
name: 'MFA-Konfiguration Azure AD',
description: 'Screenshot der MFA-Einstellungen im Azure AD Admin Portal',
fileUrl: null,
validFrom: new Date('2026-01-01'),
validUntil: new Date('2027-01-01'),
uploadedBy: 'IT-Security',
uploadedAt: new Date('2026-01-10'),
},
{
id: 'demo-evi-2',
controlId: 'demo-ctrl-2',
type: 'DOCUMENT',
name: 'Berechtigungskonzept v2.1',
description: 'Dokumentiertes Berechtigungskonzept mit Rollenmatrix',
fileUrl: null,
validFrom: new Date('2026-01-01'),
validUntil: null,
uploadedBy: 'IT-Security',
uploadedAt: new Date('2026-01-05'),
},
{
id: 'demo-evi-5',
controlId: 'demo-ctrl-5',
type: 'AUDIT_REPORT',
name: 'Bias-Audit Q1/2026',
description: 'Externer Audit-Bericht zur Fairness des KI-Modells',
fileUrl: null,
validFrom: new Date('2026-01-15'),
validUntil: new Date('2026-04-15'),
uploadedBy: 'Data Science Lead',
uploadedAt: new Date('2026-01-20'),
},
],
checklist: [
{
id: 'demo-chk-1',
requirementId: 'demo-req-1',
title: 'Rechtmäßigkeit der Verarbeitung geprüft',
description: 'Dokumentierte Prüfung der Rechtsgrundlagen',
status: 'PASSED',
notes: 'Geprüft durch DSB',
verifiedBy: 'DSB',
verifiedAt: new Date('2026-01-20'),
},
{
id: 'demo-chk-2',
requirementId: 'demo-req-2',
title: 'TOMs dokumentiert und umgesetzt',
description: 'Technische und organisatorische Maßnahmen',
status: 'PASSED',
notes: 'Alle TOMs implementiert',
verifiedBy: 'CISO',
verifiedAt: new Date('2026-01-21'),
},
],
risks: getDemoRisks(),
// Phase 2 Data
aiActClassification: {
riskCategory: 'HIGH',
systemType: 'Beschäftigungsbezogenes KI-System (Art. 6 Abs. 2 AI Act)',
obligations: [
{
id: 'demo-ai-obl-1',
article: 'Art. 9',
title: 'Risikomanagementsystem',
description: 'Einrichtung eines KI-Risikomanagementsystems',
deadline: new Date('2026-08-01'),
status: 'IN_PROGRESS',
},
{
id: 'demo-ai-obl-2',
article: 'Art. 10',
title: 'Daten-Governance',
description: 'Anforderungen an Trainingsdaten',
deadline: new Date('2026-08-01'),
status: 'COMPLETED',
},
{
id: 'demo-ai-obl-3',
article: 'Art. 13',
title: 'Transparenz',
description: 'Dokumentation für Nutzer',
deadline: new Date('2026-08-01'),
status: 'COMPLETED',
},
],
assessmentDate: new Date('2026-01-25'),
assessedBy: 'Compliance Team',
justification: 'Das System fällt unter Art. 6 Abs. 2 lit. a AI Act (Einstellung und Auswahl von Personen).',
},
obligations: [
{
id: 'demo-obl-1',
regulation: 'DSGVO',
article: 'Art. 30',
title: 'Verarbeitungsverzeichnis',
description: 'Führung eines Verzeichnisses der Verarbeitungstätigkeiten',
deadline: null,
penalty: 'Bis zu 10 Mio. EUR oder 2% des Jahresumsatzes',
status: 'COMPLETED',
responsible: 'DSB',
},
{
id: 'demo-obl-2',
regulation: 'DSGVO',
article: 'Art. 35',
title: 'Datenschutz-Folgenabschätzung',
description: 'Durchführung einer DSFA für Hochrisiko-Verarbeitungen',
deadline: null,
penalty: 'Bis zu 10 Mio. EUR oder 2% des Jahresumsatzes',
status: 'COMPLETED',
responsible: 'DSB',
},
{
id: 'demo-obl-3',
regulation: 'AI Act',
article: 'Art. 49',
title: 'CE-Kennzeichnung',
description: 'CE-Kennzeichnung für Hochrisiko-KI-Systeme',
deadline: new Date('2026-08-01'),
penalty: 'Bis zu 35 Mio. EUR oder 7% des Jahresumsatzes',
status: 'PENDING',
responsible: 'Compliance',
},
],
dsfa: getDemoDSFA(),
toms: getDemoTOMs(),
retentionPolicies: getDemoRetentionPolicies(),
vvt: getDemoProcessingActivities(),
// Documents, Cookie Banner, etc. - partially filled
documents: [],
cookieBanner: null,
consents: [],
dsrConfig: null,
escalationWorkflows: [],
// Security
sbom: null,
securityIssues: [],
securityBacklog: [],
// UI State
commandBarHistory: [],
recentSearches: ['DSGVO Art. 5', 'Bias-Monitoring', 'TOM Verschlüsselung'],
preferences: {
language: 'de',
theme: 'light',
compactMode: false,
showHints: true,
autoSave: true,
autoValidate: true,
allowParallelWork: true,
},
}
}
/** /**
* Seed demo data into the database via API * Seed demo data into the database via API

View File

@@ -1,694 +1,12 @@
/** /**
* DSFA Massnahmenbibliothek - Vordefinierte Massnahmen * DSFA Massnahmenbibliothek — Barrel
* *
* ~50 Massnahmen gegliedert nach SDM-Gewaehrleistungszielen * Split into domain modules under mitigations/.
* (Vertraulichkeit, Integritaet, Verfuegbarkeit, Datenminimierung, * Import from this file to preserve the stable public path.
* Transparenz, Nichtverkettung, Intervenierbarkeit) sowie
* Automatisierung/KI, Rechtlich/Organisatorisch.
*
* Quellen: Art. 25/32 DSGVO, SDM V2.0, BSI Grundschutz,
* Baseline-DSFA Katalog
*/ */
import type { DSFAMitigationType } from './types' export type { CatalogMitigation } from './mitigations/types'
import type { SDMGoal } from './types' export * from './mitigations/access-integrity'
export * from './mitigations/availability-minimization'
// ============================================================================= export * from './mitigations/transparency-intervention-org'
// TYPES export * from './mitigations/helpers'
// =============================================================================
export interface CatalogMitigation {
id: string
type: DSFAMitigationType
sdmGoals: SDMGoal[]
title: string
description: string
legalBasis: string
evidenceTypes: string[]
addressesRiskIds: string[]
effectiveness: 'low' | 'medium' | 'high'
}
// =============================================================================
// MASSNAHMENBIBLIOTHEK
// =============================================================================
export const MITIGATION_LIBRARY: CatalogMitigation[] = [
// =========================================================================
// VERTRAULICHKEIT (Access Control & Encryption)
// =========================================================================
{
id: 'M-ACC-01',
type: 'technical',
sdmGoals: ['vertraulichkeit'],
title: 'Multi-Faktor-Authentifizierung (MFA) & Conditional Access',
description: 'Einfuehrung von MFA fuer alle Benutzerkonten mit Zugriff auf personenbezogene Daten. Conditional Access Policies beschraenken den Zugriff basierend auf Standort, Geraet und Risikobewertung.',
legalBasis: 'Art. 32 Abs. 1 lit. b DSGVO',
evidenceTypes: ['MFA-Policy-Screenshot', 'Conditional-Access-Regeln', 'Login-Statistiken'],
addressesRiskIds: ['R-CONF-02', 'R-CONF-06'],
effectiveness: 'high',
},
{
id: 'M-ACC-02',
type: 'technical',
sdmGoals: ['vertraulichkeit'],
title: 'Passwort-Policy & Credential-Schutz',
description: 'Durchsetzung starker Passwort-Richtlinien, Credential-Rotation, Einsatz eines Passwort-Managers und Monitoring auf kompromittierte Zugangsdaten (Breach Detection).',
legalBasis: 'Art. 32 Abs. 1 lit. b DSGVO',
evidenceTypes: ['Passwort-Policy-Dokument', 'Breach-Detection-Report'],
addressesRiskIds: ['R-CONF-02'],
effectiveness: 'medium',
},
{
id: 'M-CONF-01',
type: 'technical',
sdmGoals: ['vertraulichkeit'],
title: 'Rollenbasierte Zugriffskontrolle (RBAC) & Least Privilege',
description: 'Implementierung eines RBAC-Systems mit dem Prinzip der minimalen Berechtigung. Jeder Benutzer erhaelt nur die Rechte, die fuer seine Aufgabe erforderlich sind.',
legalBasis: 'Art. 32 Abs. 1 lit. b DSGVO, Art. 25 Abs. 2 DSGVO',
evidenceTypes: ['Rollen-Matrix', 'Berechtigungs-Audit-Report', 'Access-Review-Protokoll'],
addressesRiskIds: ['R-CONF-01', 'R-CONF-03', 'R-INT-04'],
effectiveness: 'high',
},
{
id: 'M-CONF-02',
type: 'technical',
sdmGoals: ['vertraulichkeit'],
title: 'Security Configuration Management',
description: 'Regelmaessige Ueberpruefung und Haertung der Systemkonfiguration. Automatisierte Konfigurationschecks (CIS Benchmarks) und Monitoring auf Konfigurationsaenderungen.',
legalBasis: 'Art. 32 Abs. 1 lit. d DSGVO',
evidenceTypes: ['CIS-Benchmark-Report', 'Konfigurationsaenderungs-Log'],
addressesRiskIds: ['R-CONF-01'],
effectiveness: 'high',
},
{
id: 'M-CONF-03',
type: 'organizational',
sdmGoals: ['vertraulichkeit'],
title: 'Regelmaessige Zugriffsrechte-Ueberpruefung (Access Review)',
description: 'Quartalsweiser Review aller Zugriffsberechtigungen durch Vorgesetzte. Entzug nicht mehr benoetigter Rechte, Offboarding-Prozess bei Mitarbeiteraustritt.',
legalBasis: 'Art. 32 Abs. 1 lit. d DSGVO',
evidenceTypes: ['Access-Review-Protokoll', 'Offboarding-Checkliste'],
addressesRiskIds: ['R-CONF-01', 'R-CONF-03'],
effectiveness: 'medium',
},
{
id: 'M-CONF-04',
type: 'technical',
sdmGoals: ['vertraulichkeit', 'integritaet'],
title: 'Privileged Access Management (PAM)',
description: 'Absicherung administrativer Zugriffe durch Just-in-Time-Elevation, Session-Recording und Break-Glass-Prozeduren fuer Notfallzugriffe.',
legalBasis: 'Art. 32 Abs. 1 lit. b DSGVO',
evidenceTypes: ['PAM-Policy', 'Session-Recording-Logs', 'Break-Glass-Protokolle'],
addressesRiskIds: ['R-CONF-03', 'R-INT-04'],
effectiveness: 'high',
},
{
id: 'M-CONF-05',
type: 'organizational',
sdmGoals: ['vertraulichkeit'],
title: 'Vier-Augen-Prinzip fuer sensible Operationen',
description: 'Fuer den Zugriff auf besonders schutzwuerdige Daten oder kritische Systemoperationen ist die Genehmigung durch eine zweite Person erforderlich.',
legalBasis: 'Art. 32 Abs. 1 lit. b DSGVO',
evidenceTypes: ['Prozessbeschreibung', 'Genehmigungsprotokoll'],
addressesRiskIds: ['R-CONF-03'],
effectiveness: 'medium',
},
{
id: 'M-CONF-06',
type: 'technical',
sdmGoals: ['vertraulichkeit'],
title: 'Verschluesselung at-rest und in-transit',
description: 'Vollstaendige Verschluesselung personenbezogener Daten bei Speicherung (AES-256) und Uebertragung (TLS 1.3). Verwaltung der Schluessel ueber ein zentrales Key-Management-System.',
legalBasis: 'Art. 32 Abs. 1 lit. a DSGVO',
evidenceTypes: ['Verschluesselungs-Policy', 'TLS-Konfigurationsreport', 'KMS-Audit'],
addressesRiskIds: ['R-CONF-04', 'R-TRANS-01', 'R-AUTO-05'],
effectiveness: 'high',
},
{
id: 'M-CONF-07',
type: 'technical',
sdmGoals: ['vertraulichkeit'],
title: 'End-to-End-Verschluesselung fuer Kommunikation',
description: 'Einsatz von End-to-End-Verschluesselung fuer sensible Kommunikation (E-Mail, Messaging), sodass auch der Betreiber keinen Zugriff auf die Inhalte hat.',
legalBasis: 'Art. 32 Abs. 1 lit. a DSGVO',
evidenceTypes: ['E2E-Konfiguration', 'Testbericht'],
addressesRiskIds: ['R-CONF-04'],
effectiveness: 'high',
},
{
id: 'M-CONF-08',
type: 'technical',
sdmGoals: ['vertraulichkeit', 'datenminimierung'],
title: 'Log-Sanitization & PII-Filtering',
description: 'Automatische Filterung personenbezogener Daten aus Logs, Fehlermeldungen und Debug-Ausgaben. Einsatz von Tokenisierung oder Maskierung.',
legalBasis: 'Art. 25 Abs. 1 DSGVO, Art. 32 Abs. 1 lit. a DSGVO',
evidenceTypes: ['Log-Policy', 'PII-Filter-Konfiguration', 'Stichproben-Audit'],
addressesRiskIds: ['R-CONF-07'],
effectiveness: 'medium',
},
// =========================================================================
// INTEGRITAET (Audit, Monitoring, Integrity Checks)
// =========================================================================
{
id: 'M-INT-01',
type: 'technical',
sdmGoals: ['integritaet'],
title: 'Input-Validierung & Injection-Schutz',
description: 'Konsequente Validierung aller Eingaben, Prepared Statements fuer Datenbankzugriffe, Content Security Policy und Output-Encoding zum Schutz vor Injection-Angriffen.',
legalBasis: 'Art. 32 Abs. 1 lit. b DSGVO',
evidenceTypes: ['SAST-Report', 'Penetrationstest-Bericht', 'WAF-Regeln'],
addressesRiskIds: ['R-INT-01'],
effectiveness: 'high',
},
{
id: 'M-INT-02',
type: 'technical',
sdmGoals: ['integritaet', 'transparenz'],
title: 'Audit-Logging & SIEM-Integration',
description: 'Lueckenlose Protokollierung aller sicherheitsrelevanten Ereignisse mit Weiterleitung an ein SIEM-System. Manipulation-sichere Logs mit Integritaetspruefung.',
legalBasis: 'Art. 32 Abs. 1 lit. d DSGVO',
evidenceTypes: ['SIEM-Dashboard-Screenshot', 'Audit-Log-Beispiel', 'Alert-Regeln'],
addressesRiskIds: ['R-INT-01', 'R-INT-04', 'R-INT-05', 'R-CONF-03', 'R-ORG-04'],
effectiveness: 'high',
},
{
id: 'M-INT-03',
type: 'technical',
sdmGoals: ['integritaet'],
title: 'Web Application Firewall (WAF) & API-Gateway',
description: 'Einsatz einer WAF zum Schutz vor OWASP Top 10 Angriffen und eines API-Gateways fuer Rate-Limiting, Schema-Validierung und Anomalie-Erkennung.',
legalBasis: 'Art. 32 Abs. 1 lit. b DSGVO',
evidenceTypes: ['WAF-Regelset', 'API-Gateway-Konfiguration', 'Blockierungs-Statistiken'],
addressesRiskIds: ['R-INT-01'],
effectiveness: 'medium',
},
{
id: 'M-INT-04',
type: 'technical',
sdmGoals: ['integritaet'],
title: 'Daten-Synchronisations-Monitoring & Integritaetspruefung',
description: 'Automatische Ueberwachung von Synchronisationsprozessen mit Checksummen-Vergleich, Konflikterkennung und Alerting bei Inkonsistenzen.',
legalBasis: 'Art. 32 Abs. 1 lit. b DSGVO',
evidenceTypes: ['Sync-Monitoring-Dashboard', 'Checksummen-Report', 'Incident-Log'],
addressesRiskIds: ['R-INT-02'],
effectiveness: 'medium',
},
{
id: 'M-INT-05',
type: 'technical',
sdmGoals: ['integritaet'],
title: 'Versionierung & Change-Tracking fuer personenbezogene Daten',
description: 'Alle Aenderungen an personenbezogenen Daten werden versioniert gespeichert (Audit-Trail). Wer hat wann was geaendert ist jederzeit nachvollziehbar.',
legalBasis: 'Art. 5 Abs. 1 lit. f DSGVO',
evidenceTypes: ['Versionierungs-Schema', 'Change-Log-Beispiel'],
addressesRiskIds: ['R-INT-02', 'R-INT-05'],
effectiveness: 'medium',
},
// =========================================================================
// VERFUEGBARKEIT (Backup, Recovery, Redundancy)
// =========================================================================
{
id: 'M-AVAIL-01',
type: 'technical',
sdmGoals: ['verfuegbarkeit'],
title: 'Backup-Strategie mit 3-2-1-Regel',
description: 'Implementierung einer Backup-Strategie nach der 3-2-1-Regel: 3 Kopien, 2 verschiedene Medien, 1 Offsite. Verschluesselte Backups mit regelmaessiger Integritaetspruefung.',
legalBasis: 'Art. 32 Abs. 1 lit. c DSGVO',
evidenceTypes: ['Backup-Policy', 'Backup-Monitoring-Report', 'Offsite-Nachweis'],
addressesRiskIds: ['R-AVAIL-01', 'R-AVAIL-03', 'R-INT-03'],
effectiveness: 'high',
},
{
id: 'M-AVAIL-02',
type: 'organizational',
sdmGoals: ['verfuegbarkeit'],
title: 'Regelmaessige Restore-Tests & Disaster Recovery Uebungen',
description: 'Mindestens quartalsweise Durchfuehrung von Restore-Tests und jaehrliche Disaster-Recovery-Uebungen. Dokumentation der Ergebnisse und Lessons Learned.',
legalBasis: 'Art. 32 Abs. 1 lit. d DSGVO',
evidenceTypes: ['Restore-Test-Protokoll', 'DR-Uebungs-Dokumentation', 'RTO/RPO-Nachweis'],
addressesRiskIds: ['R-AVAIL-01', 'R-AVAIL-03', 'R-INT-03'],
effectiveness: 'high',
},
{
id: 'M-AVAIL-03',
type: 'technical',
sdmGoals: ['verfuegbarkeit'],
title: 'Endpoint Protection & Anti-Ransomware',
description: 'Einsatz von Endpoint-Detection-and-Response (EDR) Loesungen mit spezifischem Ransomware-Schutz, Verhaltensanalyse und automatischer Isolation kompromittierter Systeme.',
legalBasis: 'Art. 32 Abs. 1 lit. b DSGVO',
evidenceTypes: ['EDR-Dashboard', 'Threat-Detection-Statistiken', 'Incident-Response-Plan'],
addressesRiskIds: ['R-AVAIL-01'],
effectiveness: 'high',
},
{
id: 'M-AVAIL-04',
type: 'technical',
sdmGoals: ['verfuegbarkeit'],
title: 'Redundanz & High-Availability-Architektur',
description: 'Redundante Systemauslegung mit automatischem Failover, Load-Balancing und geo-redundanter Datenhaltung zur Sicherstellung der Verfuegbarkeit.',
legalBasis: 'Art. 32 Abs. 1 lit. b DSGVO',
evidenceTypes: ['HA-Architekturdiagramm', 'Failover-Testprotokoll', 'SLA-Dokumentation'],
addressesRiskIds: ['R-AVAIL-02', 'R-AVAIL-04'],
effectiveness: 'high',
},
{
id: 'M-AVAIL-05',
type: 'organizational',
sdmGoals: ['verfuegbarkeit', 'intervenierbarkeit'],
title: 'Exit-Strategie & Datenportabilitaetsplan',
description: 'Dokumentierte Exit-Strategie fuer jeden kritischen Anbieter mit Datenexport-Verfahren, Migrationsplan und Uebergangsfristen. Regelmaessiger Export-Test.',
legalBasis: 'Art. 28 Abs. 3 lit. g DSGVO, Art. 20 DSGVO',
evidenceTypes: ['Exit-Plan-Dokument', 'Export-Test-Protokoll', 'Vertragliche-Regelung'],
addressesRiskIds: ['R-AVAIL-02', 'R-AVAIL-05'],
effectiveness: 'medium',
},
{
id: 'M-AVAIL-06',
type: 'technical',
sdmGoals: ['verfuegbarkeit'],
title: 'DDoS-Schutz & Rate-Limiting',
description: 'Einsatz von DDoS-Mitigation-Services, CDN-basiertem Schutz und anwendungsspezifischem Rate-Limiting zur Abwehr von Verfuegbarkeitsangriffen.',
legalBasis: 'Art. 32 Abs. 1 lit. b DSGVO',
evidenceTypes: ['DDoS-Schutz-Konfiguration', 'Rate-Limit-Regeln', 'Traffic-Analyse'],
addressesRiskIds: ['R-AVAIL-04'],
effectiveness: 'high',
},
// =========================================================================
// DATENMINIMIERUNG (Retention, Anonymization, Purpose Limitation)
// =========================================================================
{
id: 'M-DMIN-01',
type: 'technical',
sdmGoals: ['datenminimierung'],
title: 'Privacy by Design: Datenerhebung auf das Minimum beschraenken',
description: 'Technische Massnahmen zur Beschraenkung der Datenerhebung: Pflichtfelder minimieren, optionale Felder deutlich kennzeichnen, Default-Einstellungen datenschutzfreundlich.',
legalBasis: 'Art. 25 Abs. 1 DSGVO',
evidenceTypes: ['Formular-Review', 'Default-Settings-Dokumentation'],
addressesRiskIds: ['R-RIGHTS-07', 'R-CONF-07'],
effectiveness: 'medium',
},
{
id: 'M-DMIN-02',
type: 'technical',
sdmGoals: ['datenminimierung', 'nichtverkettung'],
title: 'Pseudonymisierung & Anonymisierung',
description: 'Einsatz von Pseudonymisierungsverfahren (Token-basiert, Hash-basiert) und k-Anonymity/Differential Privacy bei der Weitergabe oder Analyse von Daten.',
legalBasis: 'Art. 25 Abs. 1 DSGVO, Art. 32 Abs. 1 lit. a DSGVO',
evidenceTypes: ['Pseudonymisierungs-Konzept', 'Re-Identifizierungs-Risiko-Analyse'],
addressesRiskIds: ['R-RIGHTS-04', 'R-RIGHTS-07'],
effectiveness: 'high',
},
{
id: 'M-DMIN-03',
type: 'technical',
sdmGoals: ['datenminimierung'],
title: 'Automatisiertes Loeschkonzept mit Aufbewahrungsfristen',
description: 'Implementierung automatischer Loeschroutinen basierend auf definierten Aufbewahrungsfristen. Monitoring der Loeschvorgaenge und Nachweis der Loeschung.',
legalBasis: 'Art. 5 Abs. 1 lit. e DSGVO, Art. 17 DSGVO',
evidenceTypes: ['Loeschkonzept-Dokument', 'Loeschfrist-Uebersicht', 'Loeschprotokoll'],
addressesRiskIds: ['R-RIGHTS-07', 'R-ORG-02'],
effectiveness: 'high',
},
{
id: 'M-DMIN-04',
type: 'organizational',
sdmGoals: ['datenminimierung'],
title: 'Regelmaessige Ueberpruefung der Datenbestaende',
description: 'Jaehrlicher Review aller gespeicherten personenbezogenen Daten auf Erforderlichkeit. Identifikation und Bereinigung von Altbestaenden, verwaisten Datensaetzen und redundanten Kopien.',
legalBasis: 'Art. 5 Abs. 1 lit. e DSGVO',
evidenceTypes: ['Datenbestand-Review-Bericht', 'Bereinigungs-Protokoll'],
addressesRiskIds: ['R-ORG-02'],
effectiveness: 'medium',
},
// =========================================================================
// TRANSPARENZ (Information, Documentation, Auditability)
// =========================================================================
{
id: 'M-TRANS-01',
type: 'organizational',
sdmGoals: ['transparenz'],
title: 'Datenschutzhinweise & Privacy Notices',
description: 'Umfassende, verstaendliche Datenschutzhinweise gemaess Art. 13/14 DSGVO an allen Erhebungsstellen. Layered-Approach fuer unterschiedliche Detailstufen.',
legalBasis: 'Art. 13, Art. 14 DSGVO',
evidenceTypes: ['Privacy-Notice-Review', 'Zustellungs-Nachweis', 'Usability-Test'],
addressesRiskIds: ['R-CONF-05', 'R-RIGHTS-02', 'R-RIGHTS-03', 'R-RIGHTS-06', 'R-TRANS-03', 'R-SPEC-02'],
effectiveness: 'medium',
},
{
id: 'M-TRANS-02',
type: 'technical',
sdmGoals: ['transparenz'],
title: 'Vollstaendiger Audit-Trail fuer personenbezogene Daten',
description: 'Lueckenloser, manipulationssicherer Audit-Trail fuer alle Verarbeitungsvorgaenge personenbezogener Daten. Wer hat wann auf welche Daten zugegriffen oder sie veraendert.',
legalBasis: 'Art. 5 Abs. 2 DSGVO (Rechenschaftspflicht)',
evidenceTypes: ['Audit-Trail-Architektur', 'Log-Integritaets-Nachweis', 'Beispiel-Audit-Export'],
addressesRiskIds: ['R-INT-05'],
effectiveness: 'high',
},
{
id: 'M-TRANS-03',
type: 'technical',
sdmGoals: ['transparenz'],
title: 'Erklaerbarkeit von KI-Entscheidungen (Explainability)',
description: 'Implementierung von Erklaerungsverfahren (SHAP, LIME, Feature-Importance) fuer automatisierte Entscheidungen. Bereitstellung verstaendlicher Begruendungen fuer Betroffene.',
legalBasis: 'Art. 22 Abs. 3 DSGVO, Art. 13 Abs. 2 lit. f DSGVO',
evidenceTypes: ['XAI-Konzept', 'Erklaerbarkeits-Beispiel', 'Betroffenen-Information'],
addressesRiskIds: ['R-AUTO-01', 'R-AUTO-03', 'R-RIGHTS-01'],
effectiveness: 'medium',
},
{
id: 'M-TRANS-04',
type: 'organizational',
sdmGoals: ['transparenz'],
title: 'Ueberwachungs-Folgenabschaetzung & Informationspflicht',
description: 'Bei systematischer Ueberwachung: Gesonderte Folgenabschaetzung, klare Beschilderung/Information, Verhaeltnismaessigkeitspruefung und zeitliche Begrenzung.',
legalBasis: 'Art. 35 Abs. 3 lit. c DSGVO, Art. 13 DSGVO',
evidenceTypes: ['Ueberwachungs-DSFA', 'Beschilderungs-Nachweis', 'Verhaeltnismaessigkeits-Bewertung'],
addressesRiskIds: ['R-RIGHTS-03'],
effectiveness: 'medium',
},
{
id: 'M-TRANS-05',
type: 'organizational',
sdmGoals: ['transparenz'],
title: 'Verzeichnis von Verarbeitungstaetigkeiten (VVT) pflegen',
description: 'Vollstaendiges und aktuelles VVT gemaess Art. 30 DSGVO fuer alle Verarbeitungstaetigkeiten. Regelmaessige Aktualisierung bei Aenderungen.',
legalBasis: 'Art. 30 DSGVO',
evidenceTypes: ['VVT-Export', 'Aktualisierungs-Log'],
addressesRiskIds: ['R-RIGHTS-06'],
effectiveness: 'medium',
},
{
id: 'M-TRANS-06',
type: 'legal',
sdmGoals: ['transparenz', 'vertraulichkeit'],
title: 'Transfer Impact Assessment (TIA) fuer Drittlandtransfer',
description: 'Durchfuehrung eines Transfer Impact Assessments vor jedem Drittlandtransfer. Bewertung des Schutzniveaus im Empfaengerland und Festlegung zusaetzlicher Garantien.',
legalBasis: 'Art. 46 DSGVO, Schrems-II-Urteil',
evidenceTypes: ['TIA-Dokument', 'Schutzniveau-Analyse', 'Zusaetzliche-Garantien-Vereinbarung'],
addressesRiskIds: ['R-TRANS-01', 'R-TRANS-02'],
effectiveness: 'high',
},
{
id: 'M-TRANS-07',
type: 'legal',
sdmGoals: ['vertraulichkeit'],
title: 'Standardvertragsklauseln (SCC) & Supplementary Measures',
description: 'Abschluss aktueller EU-Standardvertragsklauseln (2021/914) mit Auftragsverarbeitern im Drittland. Ergaenzende technische und organisatorische Massnahmen (Verschluesselung, Pseudonymisierung).',
legalBasis: 'Art. 46 Abs. 2 lit. c DSGVO',
evidenceTypes: ['Unterzeichnete SCC', 'Supplementary-Measures-Dokumentation'],
addressesRiskIds: ['R-TRANS-01', 'R-TRANS-02'],
effectiveness: 'medium',
},
// =========================================================================
// NICHTVERKETTUNG (Purpose Limitation, Data Separation, DLP)
// =========================================================================
{
id: 'M-NONL-01',
type: 'technical',
sdmGoals: ['nichtverkettung'],
title: 'Zweckbindung & Consent-Management',
description: 'Technische Durchsetzung der Zweckbindung: Daten werden nur fuer den erhobenen Zweck verwendet. Consent-Management-System protokolliert und erzwingt Einwilligungen.',
legalBasis: 'Art. 5 Abs. 1 lit. b DSGVO, Art. 6 Abs. 1 lit. a DSGVO',
evidenceTypes: ['Consent-Management-System', 'Zweckbindungs-Matrix', 'Consent-Protokolle'],
addressesRiskIds: ['R-CONF-05', 'R-RIGHTS-02', 'R-RIGHTS-03'],
effectiveness: 'high',
},
{
id: 'M-NONL-02',
type: 'technical',
sdmGoals: ['nichtverkettung'],
title: 'Data Loss Prevention (DLP) & Datenklassifikation',
description: 'Implementierung von DLP-Regeln zur Verhinderung unkontrollierter Datenweitergabe. Datenklassifikation (oeffentlich, intern, vertraulich, streng vertraulich) als Grundlage.',
legalBasis: 'Art. 32 Abs. 1 lit. b DSGVO',
evidenceTypes: ['DLP-Policy', 'Datenklassifikations-Schema', 'DLP-Incident-Report'],
addressesRiskIds: ['R-RIGHTS-02'],
effectiveness: 'medium',
},
{
id: 'M-NONL-03',
type: 'technical',
sdmGoals: ['nichtverkettung', 'datenminimierung'],
title: 'Differential Privacy & k-Anonymity bei Datenanalysen',
description: 'Einsatz von Differential Privacy oder k-Anonymity-Verfahren bei der Analyse personenbezogener Daten, um Re-Identifizierung zu verhindern.',
legalBasis: 'Art. 25 Abs. 1 DSGVO',
evidenceTypes: ['Anonymisierungs-Konzept', 'Privacy-Budget-Berechnung', 'k-Anonymity-Nachweis'],
addressesRiskIds: ['R-RIGHTS-04', 'R-AUTO-05'],
effectiveness: 'high',
},
{
id: 'M-NONL-04',
type: 'technical',
sdmGoals: ['nichtverkettung'],
title: 'Mandantentrennung & Datenisolierung',
description: 'Strikte logische oder physische Trennung personenbezogener Daten verschiedener Mandanten/Zwecke. Verhinderung unbeabsichtigter Zusammenfuehrung.',
legalBasis: 'Art. 5 Abs. 1 lit. b DSGVO',
evidenceTypes: ['Mandantentrennungs-Konzept', 'Isolierungs-Test-Bericht'],
addressesRiskIds: ['R-RIGHTS-04'],
effectiveness: 'high',
},
// =========================================================================
// INTERVENIERBARKEIT (Data Subject Rights, Correction, Deletion)
// =========================================================================
{
id: 'M-INTERV-01',
type: 'technical',
sdmGoals: ['intervenierbarkeit'],
title: 'DSAR-Workflow (Data Subject Access Request)',
description: 'Automatisierter Workflow fuer Betroffenenanfragen (Auskunft, Loeschung, Berichtigung, Export). Fristenmanagement (1 Monat), Identitaetspruefung und Dokumentation.',
legalBasis: 'Art. 15-22 DSGVO, Art. 12 Abs. 3 DSGVO',
evidenceTypes: ['DSAR-Workflow-Dokumentation', 'Bearbeitungszeiten-Statistik', 'Audit-Trail'],
addressesRiskIds: ['R-RIGHTS-05', 'R-AVAIL-05'],
effectiveness: 'high',
},
{
id: 'M-INTERV-02',
type: 'technical',
sdmGoals: ['intervenierbarkeit'],
title: 'Self-Service Datenverwaltung fuer Betroffene',
description: 'Bereitstellung eines Self-Service-Portals, ueber das Betroffene ihre Daten einsehen, korrigieren, exportieren und die Loeschung beantragen koennen.',
legalBasis: 'Art. 15-20 DSGVO',
evidenceTypes: ['Portal-Screenshot', 'Funktions-Testprotokoll', 'Nutzungs-Statistik'],
addressesRiskIds: ['R-RIGHTS-05'],
effectiveness: 'high',
},
{
id: 'M-INTERV-03',
type: 'organizational',
sdmGoals: ['intervenierbarkeit'],
title: 'Widerspruchs- und Einschraenkungsprozess',
description: 'Definierter Prozess fuer die Bearbeitung von Widerspruechen (Art. 21) und Einschraenkungsersuchen (Art. 18). Technische Moeglichkeit zur Sperrung einzelner Datensaetze.',
legalBasis: 'Art. 18, Art. 21 DSGVO',
evidenceTypes: ['Prozessbeschreibung', 'Sperr-Funktionalitaets-Nachweis'],
addressesRiskIds: ['R-RIGHTS-05'],
effectiveness: 'medium',
},
{
id: 'M-INTERV-04',
type: 'organizational',
sdmGoals: ['intervenierbarkeit'],
title: 'Human-in-the-Loop bei automatisierten Entscheidungen',
description: 'Sicherstellung menschlicher Ueberpruefung bei automatisierten Entscheidungen mit erheblicher Auswirkung. Eskalationsprozess und Einspruchsmoeglichkeit fuer Betroffene.',
legalBasis: 'Art. 22 Abs. 3 DSGVO',
evidenceTypes: ['HITL-Prozessbeschreibung', 'Eskalations-Statistik', 'Einspruchs-Protokoll'],
addressesRiskIds: ['R-AUTO-04'],
effectiveness: 'high',
},
// =========================================================================
// AUTOMATISIERUNG / KI
// =========================================================================
{
id: 'M-AUTO-01',
type: 'technical',
sdmGoals: ['nichtverkettung', 'transparenz'],
title: 'Bias-Monitoring & Fairness-Tests',
description: 'Regelmaessige Ueberpruefung von KI-Modellen auf Bias und Diskriminierung. Fairness-Metriken (Demographic Parity, Equal Opportunity) und Korrekturmassnahmen bei Abweichungen.',
legalBasis: 'Art. 22 Abs. 3 DSGVO, AI Act Art. 10',
evidenceTypes: ['Bias-Audit-Report', 'Fairness-Metriken-Dashboard', 'Korrektur-Dokumentation'],
addressesRiskIds: ['R-RIGHTS-01', 'R-AUTO-01', 'R-AUTO-02'],
effectiveness: 'high',
},
{
id: 'M-AUTO-02',
type: 'technical',
sdmGoals: ['transparenz'],
title: 'KI-Modell-Dokumentation & Model Cards',
description: 'Ausfuehrliche Dokumentation aller KI-Modelle: Trainingsdaten, Architektur, Performance-Metriken, bekannte Einschraenkungen, Einsatzzweck (Model Cards).',
legalBasis: 'Art. 13 Abs. 2 lit. f DSGVO, AI Act Art. 11',
evidenceTypes: ['Model-Card', 'Performance-Report', 'Einsatzbereich-Dokumentation'],
addressesRiskIds: ['R-AUTO-01', 'R-AUTO-03'],
effectiveness: 'medium',
},
{
id: 'M-AUTO-03',
type: 'organizational',
sdmGoals: ['intervenierbarkeit', 'transparenz'],
title: 'KI-Governance-Framework & Human Oversight Board',
description: 'Etablierung eines KI-Governance-Frameworks mit einem Human Oversight Board, das alle KI-Systeme mit hohem Risiko ueberwacht und Interventionsmoeglichkeiten hat.',
legalBasis: 'Art. 22 DSGVO, AI Act Art. 14',
evidenceTypes: ['Governance-Policy', 'Oversight-Board-Protokolle', 'Interventions-Log'],
addressesRiskIds: ['R-AUTO-01', 'R-AUTO-04'],
effectiveness: 'high',
},
{
id: 'M-AUTO-04',
type: 'technical',
sdmGoals: ['nichtverkettung', 'datenminimierung'],
title: 'Datenschutzkonformes KI-Training (Privacy-Preserving ML)',
description: 'Einsatz von Federated Learning, Differential Privacy beim Training oder synthetischen Trainingsdaten, um personenbezogene Daten im Modell zu schuetzen.',
legalBasis: 'Art. 25 Abs. 1 DSGVO',
evidenceTypes: ['Privacy-Preserving-ML-Konzept', 'Training-Daten-Analyse', 'Modell-Invertierbarkeiots-Test'],
addressesRiskIds: ['R-AUTO-02', 'R-AUTO-05'],
effectiveness: 'high',
},
// =========================================================================
// ORGANISATORISCHE MASSNAHMEN
// =========================================================================
{
id: 'M-ORG-01',
type: 'organizational',
sdmGoals: ['vertraulichkeit', 'integritaet'],
title: 'Datenschutz-Schulungen & Awareness-Programm',
description: 'Regelmaessige verpflichtende Datenschutz-Schulungen fuer alle Mitarbeiter. Awareness-Kampagnen zu Phishing, Social Engineering und sicherem Datenumgang.',
legalBasis: 'Art. 32 Abs. 1 lit. b DSGVO, Art. 39 Abs. 1 lit. a DSGVO',
evidenceTypes: ['Schulungsplan', 'Teilnahmequoten', 'Phishing-Simulations-Ergebnis'],
addressesRiskIds: ['R-CONF-06', 'R-ORG-03'],
effectiveness: 'medium',
},
{
id: 'M-ORG-02',
type: 'organizational',
sdmGoals: ['integritaet'],
title: 'Verpflichtung auf Vertraulichkeit & Datenschutz-Policy',
description: 'Schriftliche Verpflichtung aller Mitarbeiter und externen Dienstleister auf Vertraulichkeit und Einhaltung der Datenschutz-Policies.',
legalBasis: 'Art. 28 Abs. 3 lit. b DSGVO, Art. 29 DSGVO',
evidenceTypes: ['Unterzeichnete-Verpflichtungserklaerung', 'Datenschutz-Policy'],
addressesRiskIds: ['R-ORG-03'],
effectiveness: 'medium',
},
{
id: 'M-ORG-03',
type: 'organizational',
sdmGoals: ['transparenz'],
title: 'Datenpannen-Erkennungs- und Meldeprozess (Incident Response)',
description: 'Definierter Incident-Response-Prozess mit klaren Eskalationswegen, 72h-Meldepflicht-Tracking, Klassifizierungsschema und Kommunikationsplan.',
legalBasis: 'Art. 33, Art. 34 DSGVO',
evidenceTypes: ['Incident-Response-Plan', 'Melde-Template', 'Uebungs-Protokoll'],
addressesRiskIds: ['R-ORG-04'],
effectiveness: 'high',
},
{
id: 'M-ORG-04',
type: 'technical',
sdmGoals: ['transparenz', 'verfuegbarkeit'],
title: 'Automatisiertes Breach-Detection & Alerting',
description: 'Automatische Erkennung von Datenpannen durch Anomalie-Detection, ungewoehnliche Zugriffsmuster und Datenexfiltrations-Erkennung mit sofortigem Alert an den Incident-Response-Team.',
legalBasis: 'Art. 33 Abs. 1 DSGVO',
evidenceTypes: ['Alert-Regeln', 'Detection-Dashboard', 'Reaktionszeiten-Statistik'],
addressesRiskIds: ['R-ORG-04'],
effectiveness: 'high',
},
// =========================================================================
// RECHTLICHE MASSNAHMEN
// =========================================================================
{
id: 'M-LEGAL-01',
type: 'legal',
sdmGoals: ['transparenz'],
title: 'Angemessenheitsbeschluss oder Binding Corporate Rules (BCR)',
description: 'Sicherstellung, dass Drittlandtransfers auf einem Angemessenheitsbeschluss oder genehmigten BCRs basieren. Laufende Ueberwachung des Schutzniveaus.',
legalBasis: 'Art. 45, Art. 47 DSGVO',
evidenceTypes: ['Angemessenheitsbeschluss-Referenz', 'BCR-Genehmigung'],
addressesRiskIds: ['R-TRANS-02'],
effectiveness: 'high',
},
{
id: 'M-LEGAL-02',
type: 'legal',
sdmGoals: ['transparenz'],
title: 'Auftragsverarbeitungsvertrag (AVV) nach Art. 28 DSGVO',
description: 'Abschluss vollstaendiger AVVs mit allen Auftragsverarbeitern. Regelung von Zweck, Dauer, Datenkategorien, Weisungsbindung, Sub-Auftragsverarbeiter und Audit-Rechten.',
legalBasis: 'Art. 28 Abs. 3 DSGVO',
evidenceTypes: ['Unterzeichneter-AVV', 'Sub-Auftragsverarbeiter-Liste', 'Audit-Bericht'],
addressesRiskIds: ['R-ORG-01', 'R-TRANS-03'],
effectiveness: 'high',
},
{
id: 'M-LEGAL-03',
type: 'legal',
sdmGoals: ['transparenz'],
title: 'Regelmaessige Auftragsverarbeiter-Audits',
description: 'Jaehrliche Ueberpruefung der Auftragsverarbeiter auf Einhaltung der AVV-Vorgaben. Dokumentierte Audits vor Ort oder anhand von Zertifizierungen (SOC 2, ISO 27001).',
legalBasis: 'Art. 28 Abs. 3 lit. h DSGVO',
evidenceTypes: ['Audit-Bericht', 'Zertifizierungs-Nachweis', 'Massnahmenplan'],
addressesRiskIds: ['R-ORG-01'],
effectiveness: 'medium',
},
{
id: 'M-LEGAL-04',
type: 'legal',
sdmGoals: ['intervenierbarkeit', 'transparenz'],
title: 'Altersverifikation & Eltern-Einwilligung (Art. 8)',
description: 'Implementierung einer altersgerechten Verifikation und Einholung der Eltern-Einwilligung bei Minderjaehrigen unter 16 Jahren. Kindgerechte Datenschutzinformationen.',
legalBasis: 'Art. 8 DSGVO, EG 38 DSGVO',
evidenceTypes: ['Altersverifikations-Konzept', 'Eltern-Einwilligungs-Formular', 'Kindgerechte-Privacy-Notice'],
addressesRiskIds: ['R-SPEC-02'],
effectiveness: 'medium',
},
]
// =============================================================================
// HELPER FUNCTIONS
// =============================================================================
export function getMitigationsBySDMGoal(goal: SDMGoal): CatalogMitigation[] {
return MITIGATION_LIBRARY.filter(m => m.sdmGoals.includes(goal))
}
export function getMitigationsByType(type: DSFAMitigationType): CatalogMitigation[] {
return MITIGATION_LIBRARY.filter(m => m.type === type)
}
export function getMitigationsForRisk(riskId: string): CatalogMitigation[] {
return MITIGATION_LIBRARY.filter(m => m.addressesRiskIds.includes(riskId))
}
export function getCatalogMitigationById(id: string): CatalogMitigation | undefined {
return MITIGATION_LIBRARY.find(m => m.id === id)
}
export function getMitigationsByEffectiveness(effectiveness: 'low' | 'medium' | 'high'): CatalogMitigation[] {
return MITIGATION_LIBRARY.filter(m => m.effectiveness === effectiveness)
}
export const MITIGATION_TYPE_LABELS: Record<DSFAMitigationType, string> = {
technical: 'Technisch',
organizational: 'Organisatorisch',
legal: 'Rechtlich',
}
export const SDM_GOAL_LABELS: Record<SDMGoal, string> = {
datenminimierung: 'Datenminimierung',
verfuegbarkeit: 'Verfuegbarkeit',
integritaet: 'Integritaet',
vertraulichkeit: 'Vertraulichkeit',
nichtverkettung: 'Nichtverkettung',
transparenz: 'Transparenz',
intervenierbarkeit: 'Intervenierbarkeit',
}
export const EFFECTIVENESS_LABELS: Record<string, string> = {
low: 'Gering',
medium: 'Mittel',
high: 'Hoch',
}

View File

@@ -0,0 +1,176 @@
/**
* DSFA Massnahmenbibliothek — Vertraulichkeit / Zugriff & Integritaet
*/
import type { CatalogMitigation } from './types'
export const ACCESS_CONTROL_MITIGATIONS: CatalogMitigation[] = [
{
id: 'M-ACC-01',
type: 'technical',
sdmGoals: ['vertraulichkeit'],
title: 'Multi-Faktor-Authentifizierung (MFA) & Conditional Access',
description: 'Einfuehrung von MFA fuer alle Benutzerkonten mit Zugriff auf personenbezogene Daten. Conditional Access Policies beschraenken den Zugriff basierend auf Standort, Geraet und Risikobewertung.',
legalBasis: 'Art. 32 Abs. 1 lit. b DSGVO',
evidenceTypes: ['MFA-Policy-Screenshot', 'Conditional-Access-Regeln', 'Login-Statistiken'],
addressesRiskIds: ['R-CONF-02', 'R-CONF-06'],
effectiveness: 'high',
},
{
id: 'M-ACC-02',
type: 'technical',
sdmGoals: ['vertraulichkeit'],
title: 'Passwort-Policy & Credential-Schutz',
description: 'Durchsetzung starker Passwort-Richtlinien, Credential-Rotation, Einsatz eines Passwort-Managers und Monitoring auf kompromittierte Zugangsdaten (Breach Detection).',
legalBasis: 'Art. 32 Abs. 1 lit. b DSGVO',
evidenceTypes: ['Passwort-Policy-Dokument', 'Breach-Detection-Report'],
addressesRiskIds: ['R-CONF-02'],
effectiveness: 'medium',
},
{
id: 'M-CONF-01',
type: 'technical',
sdmGoals: ['vertraulichkeit'],
title: 'Rollenbasierte Zugriffskontrolle (RBAC) & Least Privilege',
description: 'Implementierung eines RBAC-Systems mit dem Prinzip der minimalen Berechtigung. Jeder Benutzer erhaelt nur die Rechte, die fuer seine Aufgabe erforderlich sind.',
legalBasis: 'Art. 32 Abs. 1 lit. b DSGVO, Art. 25 Abs. 2 DSGVO',
evidenceTypes: ['Rollen-Matrix', 'Berechtigungs-Audit-Report', 'Access-Review-Protokoll'],
addressesRiskIds: ['R-CONF-01', 'R-CONF-03', 'R-INT-04'],
effectiveness: 'high',
},
{
id: 'M-CONF-02',
type: 'technical',
sdmGoals: ['vertraulichkeit'],
title: 'Security Configuration Management',
description: 'Regelmaessige Ueberpruefung und Haertung der Systemkonfiguration. Automatisierte Konfigurationschecks (CIS Benchmarks) und Monitoring auf Konfigurationsaenderungen.',
legalBasis: 'Art. 32 Abs. 1 lit. d DSGVO',
evidenceTypes: ['CIS-Benchmark-Report', 'Konfigurationsaenderungs-Log'],
addressesRiskIds: ['R-CONF-01'],
effectiveness: 'high',
},
{
id: 'M-CONF-03',
type: 'organizational',
sdmGoals: ['vertraulichkeit'],
title: 'Regelmaessige Zugriffsrechte-Ueberpruefung (Access Review)',
description: 'Quartalsweiser Review aller Zugriffsberechtigungen durch Vorgesetzte. Entzug nicht mehr benoetigter Rechte, Offboarding-Prozess bei Mitarbeiteraustritt.',
legalBasis: 'Art. 32 Abs. 1 lit. d DSGVO',
evidenceTypes: ['Access-Review-Protokoll', 'Offboarding-Checkliste'],
addressesRiskIds: ['R-CONF-01', 'R-CONF-03'],
effectiveness: 'medium',
},
{
id: 'M-CONF-04',
type: 'technical',
sdmGoals: ['vertraulichkeit', 'integritaet'],
title: 'Privileged Access Management (PAM)',
description: 'Absicherung administrativer Zugriffe durch Just-in-Time-Elevation, Session-Recording und Break-Glass-Prozeduren fuer Notfallzugriffe.',
legalBasis: 'Art. 32 Abs. 1 lit. b DSGVO',
evidenceTypes: ['PAM-Policy', 'Session-Recording-Logs', 'Break-Glass-Protokolle'],
addressesRiskIds: ['R-CONF-03', 'R-INT-04'],
effectiveness: 'high',
},
{
id: 'M-CONF-05',
type: 'organizational',
sdmGoals: ['vertraulichkeit'],
title: 'Vier-Augen-Prinzip fuer sensible Operationen',
description: 'Fuer den Zugriff auf besonders schutzwuerdige Daten oder kritische Systemoperationen ist die Genehmigung durch eine zweite Person erforderlich.',
legalBasis: 'Art. 32 Abs. 1 lit. b DSGVO',
evidenceTypes: ['Prozessbeschreibung', 'Genehmigungsprotokoll'],
addressesRiskIds: ['R-CONF-03'],
effectiveness: 'medium',
},
{
id: 'M-CONF-06',
type: 'technical',
sdmGoals: ['vertraulichkeit'],
title: 'Verschluesselung at-rest und in-transit',
description: 'Vollstaendige Verschluesselung personenbezogener Daten bei Speicherung (AES-256) und Uebertragung (TLS 1.3). Verwaltung der Schluessel ueber ein zentrales Key-Management-System.',
legalBasis: 'Art. 32 Abs. 1 lit. a DSGVO',
evidenceTypes: ['Verschluesselungs-Policy', 'TLS-Konfigurationsreport', 'KMS-Audit'],
addressesRiskIds: ['R-CONF-04', 'R-TRANS-01', 'R-AUTO-05'],
effectiveness: 'high',
},
{
id: 'M-CONF-07',
type: 'technical',
sdmGoals: ['vertraulichkeit'],
title: 'End-to-End-Verschluesselung fuer Kommunikation',
description: 'Einsatz von End-to-End-Verschluesselung fuer sensible Kommunikation (E-Mail, Messaging), sodass auch der Betreiber keinen Zugriff auf die Inhalte hat.',
legalBasis: 'Art. 32 Abs. 1 lit. a DSGVO',
evidenceTypes: ['E2E-Konfiguration', 'Testbericht'],
addressesRiskIds: ['R-CONF-04'],
effectiveness: 'high',
},
{
id: 'M-CONF-08',
type: 'technical',
sdmGoals: ['vertraulichkeit', 'datenminimierung'],
title: 'Log-Sanitization & PII-Filtering',
description: 'Automatische Filterung personenbezogener Daten aus Logs, Fehlermeldungen und Debug-Ausgaben. Einsatz von Tokenisierung oder Maskierung.',
legalBasis: 'Art. 25 Abs. 1 DSGVO, Art. 32 Abs. 1 lit. a DSGVO',
evidenceTypes: ['Log-Policy', 'PII-Filter-Konfiguration', 'Stichproben-Audit'],
addressesRiskIds: ['R-CONF-07'],
effectiveness: 'medium',
},
]
export const INTEGRITY_MITIGATIONS: CatalogMitigation[] = [
{
id: 'M-INT-01',
type: 'technical',
sdmGoals: ['integritaet'],
title: 'Input-Validierung & Injection-Schutz',
description: 'Konsequente Validierung aller Eingaben, Prepared Statements fuer Datenbankzugriffe, Content Security Policy und Output-Encoding zum Schutz vor Injection-Angriffen.',
legalBasis: 'Art. 32 Abs. 1 lit. b DSGVO',
evidenceTypes: ['SAST-Report', 'Penetrationstest-Bericht', 'WAF-Regeln'],
addressesRiskIds: ['R-INT-01'],
effectiveness: 'high',
},
{
id: 'M-INT-02',
type: 'technical',
sdmGoals: ['integritaet', 'transparenz'],
title: 'Audit-Logging & SIEM-Integration',
description: 'Lueckenlose Protokollierung aller sicherheitsrelevanten Ereignisse mit Weiterleitung an ein SIEM-System. Manipulation-sichere Logs mit Integritaetspruefung.',
legalBasis: 'Art. 32 Abs. 1 lit. d DSGVO',
evidenceTypes: ['SIEM-Dashboard-Screenshot', 'Audit-Log-Beispiel', 'Alert-Regeln'],
addressesRiskIds: ['R-INT-01', 'R-INT-04', 'R-INT-05', 'R-CONF-03', 'R-ORG-04'],
effectiveness: 'high',
},
{
id: 'M-INT-03',
type: 'technical',
sdmGoals: ['integritaet'],
title: 'Web Application Firewall (WAF) & API-Gateway',
description: 'Einsatz einer WAF zum Schutz vor OWASP Top 10 Angriffen und eines API-Gateways fuer Rate-Limiting, Schema-Validierung und Anomalie-Erkennung.',
legalBasis: 'Art. 32 Abs. 1 lit. b DSGVO',
evidenceTypes: ['WAF-Regelset', 'API-Gateway-Konfiguration', 'Blockierungs-Statistiken'],
addressesRiskIds: ['R-INT-01'],
effectiveness: 'medium',
},
{
id: 'M-INT-04',
type: 'technical',
sdmGoals: ['integritaet'],
title: 'Daten-Synchronisations-Monitoring & Integritaetspruefung',
description: 'Automatische Ueberwachung von Synchronisationsprozessen mit Checksummen-Vergleich, Konflikterkennung und Alerting bei Inkonsistenzen.',
legalBasis: 'Art. 32 Abs. 1 lit. b DSGVO',
evidenceTypes: ['Sync-Monitoring-Dashboard', 'Checksummen-Report', 'Incident-Log'],
addressesRiskIds: ['R-INT-02'],
effectiveness: 'medium',
},
{
id: 'M-INT-05',
type: 'technical',
sdmGoals: ['integritaet'],
title: 'Versionierung & Change-Tracking fuer personenbezogene Daten',
description: 'Alle Aenderungen an personenbezogenen Daten werden versioniert gespeichert (Audit-Trail). Wer hat wann was geaendert ist jederzeit nachvollziehbar.',
legalBasis: 'Art. 5 Abs. 1 lit. f DSGVO',
evidenceTypes: ['Versionierungs-Schema', 'Change-Log-Beispiel'],
addressesRiskIds: ['R-INT-02', 'R-INT-05'],
effectiveness: 'medium',
},
]

View File

@@ -0,0 +1,165 @@
/**
* DSFA Massnahmenbibliothek — Verfuegbarkeit, Datenminimierung & Nichtverkettung
*/
import type { CatalogMitigation } from './types'
export const AVAILABILITY_MITIGATIONS: CatalogMitigation[] = [
{
id: 'M-AVAIL-01',
type: 'technical',
sdmGoals: ['verfuegbarkeit'],
title: 'Backup-Strategie mit 3-2-1-Regel',
description: 'Implementierung einer Backup-Strategie nach der 3-2-1-Regel: 3 Kopien, 2 verschiedene Medien, 1 Offsite. Verschluesselte Backups mit regelmaessiger Integritaetspruefung.',
legalBasis: 'Art. 32 Abs. 1 lit. c DSGVO',
evidenceTypes: ['Backup-Policy', 'Backup-Monitoring-Report', 'Offsite-Nachweis'],
addressesRiskIds: ['R-AVAIL-01', 'R-AVAIL-03', 'R-INT-03'],
effectiveness: 'high',
},
{
id: 'M-AVAIL-02',
type: 'organizational',
sdmGoals: ['verfuegbarkeit'],
title: 'Regelmaessige Restore-Tests & Disaster Recovery Uebungen',
description: 'Mindestens quartalsweise Durchfuehrung von Restore-Tests und jaehrliche Disaster-Recovery-Uebungen. Dokumentation der Ergebnisse und Lessons Learned.',
legalBasis: 'Art. 32 Abs. 1 lit. d DSGVO',
evidenceTypes: ['Restore-Test-Protokoll', 'DR-Uebungs-Dokumentation', 'RTO/RPO-Nachweis'],
addressesRiskIds: ['R-AVAIL-01', 'R-AVAIL-03', 'R-INT-03'],
effectiveness: 'high',
},
{
id: 'M-AVAIL-03',
type: 'technical',
sdmGoals: ['verfuegbarkeit'],
title: 'Endpoint Protection & Anti-Ransomware',
description: 'Einsatz von Endpoint-Detection-and-Response (EDR) Loesungen mit spezifischem Ransomware-Schutz, Verhaltensanalyse und automatischer Isolation kompromittierter Systeme.',
legalBasis: 'Art. 32 Abs. 1 lit. b DSGVO',
evidenceTypes: ['EDR-Dashboard', 'Threat-Detection-Statistiken', 'Incident-Response-Plan'],
addressesRiskIds: ['R-AVAIL-01'],
effectiveness: 'high',
},
{
id: 'M-AVAIL-04',
type: 'technical',
sdmGoals: ['verfuegbarkeit'],
title: 'Redundanz & High-Availability-Architektur',
description: 'Redundante Systemauslegung mit automatischem Failover, Load-Balancing und geo-redundanter Datenhaltung zur Sicherstellung der Verfuegbarkeit.',
legalBasis: 'Art. 32 Abs. 1 lit. b DSGVO',
evidenceTypes: ['HA-Architekturdiagramm', 'Failover-Testprotokoll', 'SLA-Dokumentation'],
addressesRiskIds: ['R-AVAIL-02', 'R-AVAIL-04'],
effectiveness: 'high',
},
{
id: 'M-AVAIL-05',
type: 'organizational',
sdmGoals: ['verfuegbarkeit', 'intervenierbarkeit'],
title: 'Exit-Strategie & Datenportabilitaetsplan',
description: 'Dokumentierte Exit-Strategie fuer jeden kritischen Anbieter mit Datenexport-Verfahren, Migrationsplan und Uebergangsfristen. Regelmaessiger Export-Test.',
legalBasis: 'Art. 28 Abs. 3 lit. g DSGVO, Art. 20 DSGVO',
evidenceTypes: ['Exit-Plan-Dokument', 'Export-Test-Protokoll', 'Vertragliche-Regelung'],
addressesRiskIds: ['R-AVAIL-02', 'R-AVAIL-05'],
effectiveness: 'medium',
},
{
id: 'M-AVAIL-06',
type: 'technical',
sdmGoals: ['verfuegbarkeit'],
title: 'DDoS-Schutz & Rate-Limiting',
description: 'Einsatz von DDoS-Mitigation-Services, CDN-basiertem Schutz und anwendungsspezifischem Rate-Limiting zur Abwehr von Verfuegbarkeitsangriffen.',
legalBasis: 'Art. 32 Abs. 1 lit. b DSGVO',
evidenceTypes: ['DDoS-Schutz-Konfiguration', 'Rate-Limit-Regeln', 'Traffic-Analyse'],
addressesRiskIds: ['R-AVAIL-04'],
effectiveness: 'high',
},
]
export const MINIMIZATION_NONLINKAGE_MITIGATIONS: CatalogMitigation[] = [
{
id: 'M-DMIN-01',
type: 'technical',
sdmGoals: ['datenminimierung'],
title: 'Privacy by Design: Datenerhebung auf das Minimum beschraenken',
description: 'Technische Massnahmen zur Beschraenkung der Datenerhebung: Pflichtfelder minimieren, optionale Felder deutlich kennzeichnen, Default-Einstellungen datenschutzfreundlich.',
legalBasis: 'Art. 25 Abs. 1 DSGVO',
evidenceTypes: ['Formular-Review', 'Default-Settings-Dokumentation'],
addressesRiskIds: ['R-RIGHTS-07', 'R-CONF-07'],
effectiveness: 'medium',
},
{
id: 'M-DMIN-02',
type: 'technical',
sdmGoals: ['datenminimierung', 'nichtverkettung'],
title: 'Pseudonymisierung & Anonymisierung',
description: 'Einsatz von Pseudonymisierungsverfahren (Token-basiert, Hash-basiert) und k-Anonymity/Differential Privacy bei der Weitergabe oder Analyse von Daten.',
legalBasis: 'Art. 25 Abs. 1 DSGVO, Art. 32 Abs. 1 lit. a DSGVO',
evidenceTypes: ['Pseudonymisierungs-Konzept', 'Re-Identifizierungs-Risiko-Analyse'],
addressesRiskIds: ['R-RIGHTS-04', 'R-RIGHTS-07'],
effectiveness: 'high',
},
{
id: 'M-DMIN-03',
type: 'technical',
sdmGoals: ['datenminimierung'],
title: 'Automatisiertes Loeschkonzept mit Aufbewahrungsfristen',
description: 'Implementierung automatischer Loeschroutinen basierend auf definierten Aufbewahrungsfristen. Monitoring der Loeschvorgaenge und Nachweis der Loeschung.',
legalBasis: 'Art. 5 Abs. 1 lit. e DSGVO, Art. 17 DSGVO',
evidenceTypes: ['Loeschkonzept-Dokument', 'Loeschfrist-Uebersicht', 'Loeschprotokoll'],
addressesRiskIds: ['R-RIGHTS-07', 'R-ORG-02'],
effectiveness: 'high',
},
{
id: 'M-DMIN-04',
type: 'organizational',
sdmGoals: ['datenminimierung'],
title: 'Regelmaessige Ueberpruefung der Datenbestaende',
description: 'Jaehrlicher Review aller gespeicherten personenbezogenen Daten auf Erforderlichkeit. Identifikation und Bereinigung von Altbestaenden, verwaisten Datensaetzen und redundanten Kopien.',
legalBasis: 'Art. 5 Abs. 1 lit. e DSGVO',
evidenceTypes: ['Datenbestand-Review-Bericht', 'Bereinigungs-Protokoll'],
addressesRiskIds: ['R-ORG-02'],
effectiveness: 'medium',
},
{
id: 'M-NONL-01',
type: 'technical',
sdmGoals: ['nichtverkettung'],
title: 'Zweckbindung & Consent-Management',
description: 'Technische Durchsetzung der Zweckbindung: Daten werden nur fuer den erhobenen Zweck verwendet. Consent-Management-System protokolliert und erzwingt Einwilligungen.',
legalBasis: 'Art. 5 Abs. 1 lit. b DSGVO, Art. 6 Abs. 1 lit. a DSGVO',
evidenceTypes: ['Consent-Management-System', 'Zweckbindungs-Matrix', 'Consent-Protokolle'],
addressesRiskIds: ['R-CONF-05', 'R-RIGHTS-02', 'R-RIGHTS-03'],
effectiveness: 'high',
},
{
id: 'M-NONL-02',
type: 'technical',
sdmGoals: ['nichtverkettung'],
title: 'Data Loss Prevention (DLP) & Datenklassifikation',
description: 'Implementierung von DLP-Regeln zur Verhinderung unkontrollierter Datenweitergabe. Datenklassifikation (oeffentlich, intern, vertraulich, streng vertraulich) als Grundlage.',
legalBasis: 'Art. 32 Abs. 1 lit. b DSGVO',
evidenceTypes: ['DLP-Policy', 'Datenklassifikations-Schema', 'DLP-Incident-Report'],
addressesRiskIds: ['R-RIGHTS-02'],
effectiveness: 'medium',
},
{
id: 'M-NONL-03',
type: 'technical',
sdmGoals: ['nichtverkettung', 'datenminimierung'],
title: 'Differential Privacy & k-Anonymity bei Datenanalysen',
description: 'Einsatz von Differential Privacy oder k-Anonymity-Verfahren bei der Analyse personenbezogener Daten, um Re-Identifizierung zu verhindern.',
legalBasis: 'Art. 25 Abs. 1 DSGVO',
evidenceTypes: ['Anonymisierungs-Konzept', 'Privacy-Budget-Berechnung', 'k-Anonymity-Nachweis'],
addressesRiskIds: ['R-RIGHTS-04', 'R-AUTO-05'],
effectiveness: 'high',
},
{
id: 'M-NONL-04',
type: 'technical',
sdmGoals: ['nichtverkettung'],
title: 'Mandantentrennung & Datenisolierung',
description: 'Strikte logische oder physische Trennung personenbezogener Daten verschiedener Mandanten/Zwecke. Verhinderung unbeabsichtigter Zusammenfuehrung.',
legalBasis: 'Art. 5 Abs. 1 lit. b DSGVO',
evidenceTypes: ['Mandantentrennungs-Konzept', 'Isolierungs-Test-Bericht'],
addressesRiskIds: ['R-RIGHTS-04'],
effectiveness: 'high',
},
]

View File

@@ -0,0 +1,61 @@
/**
* DSFA Massnahmenbibliothek — Helpers & Assembled Library
*/
import type { DSFAMitigationType, SDMGoal } from '../types'
import type { CatalogMitigation } from './types'
import { ACCESS_CONTROL_MITIGATIONS, INTEGRITY_MITIGATIONS } from './access-integrity'
import { AVAILABILITY_MITIGATIONS, MINIMIZATION_NONLINKAGE_MITIGATIONS } from './availability-minimization'
import { TRANSPARENCY_MITIGATIONS, INTERVENTION_MITIGATIONS, AUTOMATION_ORG_LEGAL_MITIGATIONS } from './transparency-intervention-org'
export const MITIGATION_LIBRARY: CatalogMitigation[] = [
...ACCESS_CONTROL_MITIGATIONS,
...INTEGRITY_MITIGATIONS,
...AVAILABILITY_MITIGATIONS,
...MINIMIZATION_NONLINKAGE_MITIGATIONS,
...TRANSPARENCY_MITIGATIONS,
...INTERVENTION_MITIGATIONS,
...AUTOMATION_ORG_LEGAL_MITIGATIONS,
]
export function getMitigationsBySDMGoal(goal: SDMGoal): CatalogMitigation[] {
return MITIGATION_LIBRARY.filter(m => m.sdmGoals.includes(goal))
}
export function getMitigationsByType(type: DSFAMitigationType): CatalogMitigation[] {
return MITIGATION_LIBRARY.filter(m => m.type === type)
}
export function getMitigationsForRisk(riskId: string): CatalogMitigation[] {
return MITIGATION_LIBRARY.filter(m => m.addressesRiskIds.includes(riskId))
}
export function getCatalogMitigationById(id: string): CatalogMitigation | undefined {
return MITIGATION_LIBRARY.find(m => m.id === id)
}
export function getMitigationsByEffectiveness(effectiveness: 'low' | 'medium' | 'high'): CatalogMitigation[] {
return MITIGATION_LIBRARY.filter(m => m.effectiveness === effectiveness)
}
export const MITIGATION_TYPE_LABELS: Record<DSFAMitigationType, string> = {
technical: 'Technisch',
organizational: 'Organisatorisch',
legal: 'Rechtlich',
}
export const SDM_GOAL_LABELS: Record<SDMGoal, string> = {
datenminimierung: 'Datenminimierung',
verfuegbarkeit: 'Verfuegbarkeit',
integritaet: 'Integritaet',
vertraulichkeit: 'Vertraulichkeit',
nichtverkettung: 'Nichtverkettung',
transparenz: 'Transparenz',
intervenierbarkeit: 'Intervenierbarkeit',
}
export const EFFECTIVENESS_LABELS: Record<string, string> = {
low: 'Gering',
medium: 'Mittel',
high: 'Hoch',
}

View File

@@ -0,0 +1,267 @@
/**
* DSFA Massnahmenbibliothek — Transparenz, Intervenierbarkeit, Automatisierung, Org & Legal
*/
import type { CatalogMitigation } from './types'
export const TRANSPARENCY_MITIGATIONS: CatalogMitigation[] = [
{
id: 'M-TRANS-01',
type: 'organizational',
sdmGoals: ['transparenz'],
title: 'Datenschutzhinweise & Privacy Notices',
description: 'Umfassende, verstaendliche Datenschutzhinweise gemaess Art. 13/14 DSGVO an allen Erhebungsstellen. Layered-Approach fuer unterschiedliche Detailstufen.',
legalBasis: 'Art. 13, Art. 14 DSGVO',
evidenceTypes: ['Privacy-Notice-Review', 'Zustellungs-Nachweis', 'Usability-Test'],
addressesRiskIds: ['R-CONF-05', 'R-RIGHTS-02', 'R-RIGHTS-03', 'R-RIGHTS-06', 'R-TRANS-03', 'R-SPEC-02'],
effectiveness: 'medium',
},
{
id: 'M-TRANS-02',
type: 'technical',
sdmGoals: ['transparenz'],
title: 'Vollstaendiger Audit-Trail fuer personenbezogene Daten',
description: 'Lueckenloser, manipulationssicherer Audit-Trail fuer alle Verarbeitungsvorgaenge personenbezogener Daten. Wer hat wann auf welche Daten zugegriffen oder sie veraendert.',
legalBasis: 'Art. 5 Abs. 2 DSGVO (Rechenschaftspflicht)',
evidenceTypes: ['Audit-Trail-Architektur', 'Log-Integritaets-Nachweis', 'Beispiel-Audit-Export'],
addressesRiskIds: ['R-INT-05'],
effectiveness: 'high',
},
{
id: 'M-TRANS-03',
type: 'technical',
sdmGoals: ['transparenz'],
title: 'Erklaerbarkeit von KI-Entscheidungen (Explainability)',
description: 'Implementierung von Erklaerungsverfahren (SHAP, LIME, Feature-Importance) fuer automatisierte Entscheidungen. Bereitstellung verstaendlicher Begruendungen fuer Betroffene.',
legalBasis: 'Art. 22 Abs. 3 DSGVO, Art. 13 Abs. 2 lit. f DSGVO',
evidenceTypes: ['XAI-Konzept', 'Erklaerbarkeits-Beispiel', 'Betroffenen-Information'],
addressesRiskIds: ['R-AUTO-01', 'R-AUTO-03', 'R-RIGHTS-01'],
effectiveness: 'medium',
},
{
id: 'M-TRANS-04',
type: 'organizational',
sdmGoals: ['transparenz'],
title: 'Ueberwachungs-Folgenabschaetzung & Informationspflicht',
description: 'Bei systematischer Ueberwachung: Gesonderte Folgenabschaetzung, klare Beschilderung/Information, Verhaeltnismaessigkeitspruefung und zeitliche Begrenzung.',
legalBasis: 'Art. 35 Abs. 3 lit. c DSGVO, Art. 13 DSGVO',
evidenceTypes: ['Ueberwachungs-DSFA', 'Beschilderungs-Nachweis', 'Verhaeltnismaessigkeits-Bewertung'],
addressesRiskIds: ['R-RIGHTS-03'],
effectiveness: 'medium',
},
{
id: 'M-TRANS-05',
type: 'organizational',
sdmGoals: ['transparenz'],
title: 'Verzeichnis von Verarbeitungstaetigkeiten (VVT) pflegen',
description: 'Vollstaendiges und aktuelles VVT gemaess Art. 30 DSGVO fuer alle Verarbeitungstaetigkeiten. Regelmaessige Aktualisierung bei Aenderungen.',
legalBasis: 'Art. 30 DSGVO',
evidenceTypes: ['VVT-Export', 'Aktualisierungs-Log'],
addressesRiskIds: ['R-RIGHTS-06'],
effectiveness: 'medium',
},
{
id: 'M-TRANS-06',
type: 'legal',
sdmGoals: ['transparenz', 'vertraulichkeit'],
title: 'Transfer Impact Assessment (TIA) fuer Drittlandtransfer',
description: 'Durchfuehrung eines Transfer Impact Assessments vor jedem Drittlandtransfer. Bewertung des Schutzniveaus im Empfaengerland und Festlegung zusaetzlicher Garantien.',
legalBasis: 'Art. 46 DSGVO, Schrems-II-Urteil',
evidenceTypes: ['TIA-Dokument', 'Schutzniveau-Analyse', 'Zusaetzliche-Garantien-Vereinbarung'],
addressesRiskIds: ['R-TRANS-01', 'R-TRANS-02'],
effectiveness: 'high',
},
{
id: 'M-TRANS-07',
type: 'legal',
sdmGoals: ['vertraulichkeit'],
title: 'Standardvertragsklauseln (SCC) & Supplementary Measures',
description: 'Abschluss aktueller EU-Standardvertragsklauseln (2021/914) mit Auftragsverarbeitern im Drittland. Ergaenzende technische und organisatorische Massnahmen (Verschluesselung, Pseudonymisierung).',
legalBasis: 'Art. 46 Abs. 2 lit. c DSGVO',
evidenceTypes: ['Unterzeichnete SCC', 'Supplementary-Measures-Dokumentation'],
addressesRiskIds: ['R-TRANS-01', 'R-TRANS-02'],
effectiveness: 'medium',
},
]
export const INTERVENTION_MITIGATIONS: CatalogMitigation[] = [
{
id: 'M-INTERV-01',
type: 'technical',
sdmGoals: ['intervenierbarkeit'],
title: 'DSAR-Workflow (Data Subject Access Request)',
description: 'Automatisierter Workflow fuer Betroffenenanfragen (Auskunft, Loeschung, Berichtigung, Export). Fristenmanagement (1 Monat), Identitaetspruefung und Dokumentation.',
legalBasis: 'Art. 15-22 DSGVO, Art. 12 Abs. 3 DSGVO',
evidenceTypes: ['DSAR-Workflow-Dokumentation', 'Bearbeitungszeiten-Statistik', 'Audit-Trail'],
addressesRiskIds: ['R-RIGHTS-05', 'R-AVAIL-05'],
effectiveness: 'high',
},
{
id: 'M-INTERV-02',
type: 'technical',
sdmGoals: ['intervenierbarkeit'],
title: 'Self-Service Datenverwaltung fuer Betroffene',
description: 'Bereitstellung eines Self-Service-Portals, ueber das Betroffene ihre Daten einsehen, korrigieren, exportieren und die Loeschung beantragen koennen.',
legalBasis: 'Art. 15-20 DSGVO',
evidenceTypes: ['Portal-Screenshot', 'Funktions-Testprotokoll', 'Nutzungs-Statistik'],
addressesRiskIds: ['R-RIGHTS-05'],
effectiveness: 'high',
},
{
id: 'M-INTERV-03',
type: 'organizational',
sdmGoals: ['intervenierbarkeit'],
title: 'Widerspruchs- und Einschraenkungsprozess',
description: 'Definierter Prozess fuer die Bearbeitung von Widerspruechen (Art. 21) und Einschraenkungsersuchen (Art. 18). Technische Moeglichkeit zur Sperrung einzelner Datensaetze.',
legalBasis: 'Art. 18, Art. 21 DSGVO',
evidenceTypes: ['Prozessbeschreibung', 'Sperr-Funktionalitaets-Nachweis'],
addressesRiskIds: ['R-RIGHTS-05'],
effectiveness: 'medium',
},
{
id: 'M-INTERV-04',
type: 'organizational',
sdmGoals: ['intervenierbarkeit'],
title: 'Human-in-the-Loop bei automatisierten Entscheidungen',
description: 'Sicherstellung menschlicher Ueberpruefung bei automatisierten Entscheidungen mit erheblicher Auswirkung. Eskalationsprozess und Einspruchsmoeglichkeit fuer Betroffene.',
legalBasis: 'Art. 22 Abs. 3 DSGVO',
evidenceTypes: ['HITL-Prozessbeschreibung', 'Eskalations-Statistik', 'Einspruchs-Protokoll'],
addressesRiskIds: ['R-AUTO-04'],
effectiveness: 'high',
},
]
export const AUTOMATION_ORG_LEGAL_MITIGATIONS: CatalogMitigation[] = [
{
id: 'M-AUTO-01',
type: 'technical',
sdmGoals: ['nichtverkettung', 'transparenz'],
title: 'Bias-Monitoring & Fairness-Tests',
description: 'Regelmaessige Ueberpruefung von KI-Modellen auf Bias und Diskriminierung. Fairness-Metriken (Demographic Parity, Equal Opportunity) und Korrekturmassnahmen bei Abweichungen.',
legalBasis: 'Art. 22 Abs. 3 DSGVO, AI Act Art. 10',
evidenceTypes: ['Bias-Audit-Report', 'Fairness-Metriken-Dashboard', 'Korrektur-Dokumentation'],
addressesRiskIds: ['R-RIGHTS-01', 'R-AUTO-01', 'R-AUTO-02'],
effectiveness: 'high',
},
{
id: 'M-AUTO-02',
type: 'technical',
sdmGoals: ['transparenz'],
title: 'KI-Modell-Dokumentation & Model Cards',
description: 'Ausfuehrliche Dokumentation aller KI-Modelle: Trainingsdaten, Architektur, Performance-Metriken, bekannte Einschraenkungen, Einsatzzweck (Model Cards).',
legalBasis: 'Art. 13 Abs. 2 lit. f DSGVO, AI Act Art. 11',
evidenceTypes: ['Model-Card', 'Performance-Report', 'Einsatzbereich-Dokumentation'],
addressesRiskIds: ['R-AUTO-01', 'R-AUTO-03'],
effectiveness: 'medium',
},
{
id: 'M-AUTO-03',
type: 'organizational',
sdmGoals: ['intervenierbarkeit', 'transparenz'],
title: 'KI-Governance-Framework & Human Oversight Board',
description: 'Etablierung eines KI-Governance-Frameworks mit einem Human Oversight Board, das alle KI-Systeme mit hohem Risiko ueberwacht und Interventionsmoeglichkeiten hat.',
legalBasis: 'Art. 22 DSGVO, AI Act Art. 14',
evidenceTypes: ['Governance-Policy', 'Oversight-Board-Protokolle', 'Interventions-Log'],
addressesRiskIds: ['R-AUTO-01', 'R-AUTO-04'],
effectiveness: 'high',
},
{
id: 'M-AUTO-04',
type: 'technical',
sdmGoals: ['nichtverkettung', 'datenminimierung'],
title: 'Datenschutzkonformes KI-Training (Privacy-Preserving ML)',
description: 'Einsatz von Federated Learning, Differential Privacy beim Training oder synthetischen Trainingsdaten, um personenbezogene Daten im Modell zu schuetzen.',
legalBasis: 'Art. 25 Abs. 1 DSGVO',
evidenceTypes: ['Privacy-Preserving-ML-Konzept', 'Training-Daten-Analyse', 'Modell-Invertierbarkeiots-Test'],
addressesRiskIds: ['R-AUTO-02', 'R-AUTO-05'],
effectiveness: 'high',
},
{
id: 'M-ORG-01',
type: 'organizational',
sdmGoals: ['vertraulichkeit', 'integritaet'],
title: 'Datenschutz-Schulungen & Awareness-Programm',
description: 'Regelmaessige verpflichtende Datenschutz-Schulungen fuer alle Mitarbeiter. Awareness-Kampagnen zu Phishing, Social Engineering und sicherem Datenumgang.',
legalBasis: 'Art. 32 Abs. 1 lit. b DSGVO, Art. 39 Abs. 1 lit. a DSGVO',
evidenceTypes: ['Schulungsplan', 'Teilnahmequoten', 'Phishing-Simulations-Ergebnis'],
addressesRiskIds: ['R-CONF-06', 'R-ORG-03'],
effectiveness: 'medium',
},
{
id: 'M-ORG-02',
type: 'organizational',
sdmGoals: ['integritaet'],
title: 'Verpflichtung auf Vertraulichkeit & Datenschutz-Policy',
description: 'Schriftliche Verpflichtung aller Mitarbeiter und externen Dienstleister auf Vertraulichkeit und Einhaltung der Datenschutz-Policies.',
legalBasis: 'Art. 28 Abs. 3 lit. b DSGVO, Art. 29 DSGVO',
evidenceTypes: ['Unterzeichnete-Verpflichtungserklaerung', 'Datenschutz-Policy'],
addressesRiskIds: ['R-ORG-03'],
effectiveness: 'medium',
},
{
id: 'M-ORG-03',
type: 'organizational',
sdmGoals: ['transparenz'],
title: 'Datenpannen-Erkennungs- und Meldeprozess (Incident Response)',
description: 'Definierter Incident-Response-Prozess mit klaren Eskalationswegen, 72h-Meldepflicht-Tracking, Klassifizierungsschema und Kommunikationsplan.',
legalBasis: 'Art. 33, Art. 34 DSGVO',
evidenceTypes: ['Incident-Response-Plan', 'Melde-Template', 'Uebungs-Protokoll'],
addressesRiskIds: ['R-ORG-04'],
effectiveness: 'high',
},
{
id: 'M-ORG-04',
type: 'technical',
sdmGoals: ['transparenz', 'verfuegbarkeit'],
title: 'Automatisiertes Breach-Detection & Alerting',
description: 'Automatische Erkennung von Datenpannen durch Anomalie-Detection, ungewoehnliche Zugriffsmuster und Datenexfiltrations-Erkennung mit sofortigem Alert an den Incident-Response-Team.',
legalBasis: 'Art. 33 Abs. 1 DSGVO',
evidenceTypes: ['Alert-Regeln', 'Detection-Dashboard', 'Reaktionszeiten-Statistik'],
addressesRiskIds: ['R-ORG-04'],
effectiveness: 'high',
},
{
id: 'M-LEGAL-01',
type: 'legal',
sdmGoals: ['transparenz'],
title: 'Angemessenheitsbeschluss oder Binding Corporate Rules (BCR)',
description: 'Sicherstellung, dass Drittlandtransfers auf einem Angemessenheitsbeschluss oder genehmigten BCRs basieren. Laufende Ueberwachung des Schutzniveaus.',
legalBasis: 'Art. 45, Art. 47 DSGVO',
evidenceTypes: ['Angemessenheitsbeschluss-Referenz', 'BCR-Genehmigung'],
addressesRiskIds: ['R-TRANS-02'],
effectiveness: 'high',
},
{
id: 'M-LEGAL-02',
type: 'legal',
sdmGoals: ['transparenz'],
title: 'Auftragsverarbeitungsvertrag (AVV) nach Art. 28 DSGVO',
description: 'Abschluss vollstaendiger AVVs mit allen Auftragsverarbeitern. Regelung von Zweck, Dauer, Datenkategorien, Weisungsbindung, Sub-Auftragsverarbeiter und Audit-Rechten.',
legalBasis: 'Art. 28 Abs. 3 DSGVO',
evidenceTypes: ['Unterzeichneter-AVV', 'Sub-Auftragsverarbeiter-Liste', 'Audit-Bericht'],
addressesRiskIds: ['R-ORG-01', 'R-TRANS-03'],
effectiveness: 'high',
},
{
id: 'M-LEGAL-03',
type: 'legal',
sdmGoals: ['transparenz'],
title: 'Regelmaessige Auftragsverarbeiter-Audits',
description: 'Jaehrliche Ueberpruefung der Auftragsverarbeiter auf Einhaltung der AVV-Vorgaben. Dokumentierte Audits vor Ort oder anhand von Zertifizierungen (SOC 2, ISO 27001).',
legalBasis: 'Art. 28 Abs. 3 lit. h DSGVO',
evidenceTypes: ['Audit-Bericht', 'Zertifizierungs-Nachweis', 'Massnahmenplan'],
addressesRiskIds: ['R-ORG-01'],
effectiveness: 'medium',
},
{
id: 'M-LEGAL-04',
type: 'legal',
sdmGoals: ['intervenierbarkeit', 'transparenz'],
title: 'Altersverifikation & Eltern-Einwilligung (Art. 8)',
description: 'Implementierung einer altersgerechten Verifikation und Einholung der Eltern-Einwilligung bei Minderjaehrigen unter 16 Jahren. Kindgerechte Datenschutzinformationen.',
legalBasis: 'Art. 8 DSGVO, EG 38 DSGVO',
evidenceTypes: ['Altersverifikations-Konzept', 'Eltern-Einwilligungs-Formular', 'Kindgerechte-Privacy-Notice'],
addressesRiskIds: ['R-SPEC-02'],
effectiveness: 'medium',
},
]

View File

@@ -0,0 +1,17 @@
/**
* DSFA Massnahmenbibliothek — Types
*/
import type { DSFAMitigationType, SDMGoal } from '../types'
export interface CatalogMitigation {
id: string
type: DSFAMitigationType
sdmGoals: SDMGoal[]
title: string
description: string
legalBasis: string
evidenceTypes: string[]
addressesRiskIds: string[]
effectiveness: 'low' | 'medium' | 'high'
}

View File

@@ -1,615 +1,11 @@
/** /**
* DSFA Risikokatalog - Vordefinierte Risikoszenarien * DSFA Risikokatalog — Barrel
* *
* ~40 Risiken gegliedert nach Vertraulichkeit, Integritaet, Verfuegbarkeit, * Split into domain modules under risks/.
* Rechte & Freiheiten, Drittlandtransfer und Automatisierung. * Import from this file to preserve the stable public path.
*
* Quellen: EG 75 DSGVO, Art. 32 DSGVO, Art. 28/46 DSGVO, Art. 22 DSGVO,
* Baseline-DSFA Katalog, SDM V2.0
*/ */
import type { DSFARiskCategory } from './types' export type { CatalogRisk } from './risks/types'
import type { SDMGoal } from './types' export * from './risks/confidentiality-integrity'
export * from './risks/availability-rights-auto-org'
// ============================================================================= export * from './risks/helpers'
// TYPES
// =============================================================================
export interface CatalogRisk {
id: string
category: DSFARiskCategory
sdmGoal: SDMGoal
title: string
description: string
impactExamples: string[]
typicalLikelihood: 'low' | 'medium' | 'high'
typicalImpact: 'low' | 'medium' | 'high'
wp248Criteria: string[]
applicableTo: string[]
mitigationIds: string[]
}
// =============================================================================
// RISIKOKATALOG
// =============================================================================
export const RISK_CATALOG: CatalogRisk[] = [
// =========================================================================
// VERTRAULICHKEIT (Confidentiality)
// =========================================================================
{
id: 'R-CONF-01',
category: 'confidentiality',
sdmGoal: 'vertraulichkeit',
title: 'Unbefugte Offenlegung durch Fehlkonfiguration',
description: 'Personenbezogene Daten werden durch fehlerhafte Systemkonfiguration (z.B. offene APIs, fehlerhafte Zugriffsrechte, oeffentliche Cloud-Speicher) unbefugt zugaenglich.',
impactExamples: ['Identitaetsdiebstahl', 'Reputationsschaden', 'Diskriminierung'],
typicalLikelihood: 'medium',
typicalImpact: 'high',
wp248Criteria: ['K4', 'K5'],
applicableTo: ['cloud_storage', 'web_application', 'api_service'],
mitigationIds: ['M-CONF-01', 'M-CONF-02', 'M-CONF-03'],
},
{
id: 'R-CONF-02',
category: 'confidentiality',
sdmGoal: 'vertraulichkeit',
title: 'Account Takeover / Credential Stuffing',
description: 'Angreifer uebernehmen Benutzerkonten durch gestohlene Zugangsdaten, Brute-Force-Angriffe oder Phishing und erlangen Zugriff auf personenbezogene Daten.',
impactExamples: ['Kontrollverlust ueber eigene Daten', 'Finanzieller Schaden', 'Missbrauch der Identitaet'],
typicalLikelihood: 'high',
typicalImpact: 'high',
wp248Criteria: ['K4', 'K7'],
applicableTo: ['identity', 'web_application', 'email_service'],
mitigationIds: ['M-ACC-01', 'M-ACC-02'],
},
{
id: 'R-CONF-03',
category: 'confidentiality',
sdmGoal: 'vertraulichkeit',
title: 'Unbefugter Zugriff durch Support-/Administrationspersonal',
description: 'Administratoren oder Support-Mitarbeiter greifen ohne dienstliche Notwendigkeit auf personenbezogene Daten zu (Insider-Bedrohung).',
impactExamples: ['Verletzung der Privatsphaere', 'Datenmissbrauch', 'Vertrauensverlust'],
typicalLikelihood: 'medium',
typicalImpact: 'medium',
wp248Criteria: ['K4'],
applicableTo: ['identity', 'crm', 'cloud_storage', 'support_system'],
mitigationIds: ['M-CONF-04', 'M-CONF-05', 'M-INT-02'],
},
{
id: 'R-CONF-04',
category: 'confidentiality',
sdmGoal: 'vertraulichkeit',
title: 'Datenleck durch unzureichende Verschluesselung',
description: 'Personenbezogene Daten werden bei Uebertragung oder Speicherung nicht oder unzureichend verschluesselt und koennen abgefangen werden.',
impactExamples: ['Man-in-the-Middle-Angriff', 'Datendiebstahl bei Speichermedien-Verlust'],
typicalLikelihood: 'medium',
typicalImpact: 'high',
wp248Criteria: ['K4', 'K8'],
applicableTo: ['cloud_storage', 'email_service', 'mobile_app', 'api_service'],
mitigationIds: ['M-CONF-06', 'M-CONF-07'],
},
{
id: 'R-CONF-05',
category: 'confidentiality',
sdmGoal: 'vertraulichkeit',
title: 'Unkontrollierte Datenweitergabe an Dritte',
description: 'Personenbezogene Daten werden ohne Rechtsgrundlage oder ueber das vereinbarte Mass hinaus an Dritte weitergegeben (z.B. durch Tracking, Analyse-Tools, Sub-Auftragsverarbeiter).',
impactExamples: ['Unerwuenschte Werbung', 'Profiling ohne Wissen', 'Kontrollverlust'],
typicalLikelihood: 'medium',
typicalImpact: 'medium',
wp248Criteria: ['K1', 'K6'],
applicableTo: ['web_application', 'analytics', 'marketing', 'crm'],
mitigationIds: ['M-NONL-01', 'M-TRANS-01'],
},
{
id: 'R-CONF-06',
category: 'confidentiality',
sdmGoal: 'vertraulichkeit',
title: 'Social Engineering / Phishing gegen Betroffene',
description: 'Betroffene werden durch manipulative Kommunikation dazu verleitet, personenbezogene Daten preiszugeben oder Zugriff zu gewaehren.',
impactExamples: ['Identitaetsdiebstahl', 'Finanzieller Schaden', 'Uebernahme von Konten'],
typicalLikelihood: 'high',
typicalImpact: 'medium',
wp248Criteria: ['K7'],
applicableTo: ['email_service', 'web_application', 'identity'],
mitigationIds: ['M-ACC-01', 'M-ORG-01'],
},
{
id: 'R-CONF-07',
category: 'confidentiality',
sdmGoal: 'vertraulichkeit',
title: 'Unbeabsichtigte Offenlegung in Logs/Debugging',
description: 'Personenbezogene Daten gelangen in Protokolldateien, Fehlermeldungen oder Debug-Ausgaben und werden dort nicht geschuetzt.',
impactExamples: ['Zugriff durch Unbefugte auf Logdaten', 'Langzeitspeicherung ohne Rechtsgrundlage'],
typicalLikelihood: 'medium',
typicalImpact: 'medium',
wp248Criteria: ['K4'],
applicableTo: ['api_service', 'web_application', 'cloud_storage'],
mitigationIds: ['M-CONF-08', 'M-DMIN-01'],
},
// =========================================================================
// INTEGRITAET (Integrity)
// =========================================================================
{
id: 'R-INT-01',
category: 'integrity',
sdmGoal: 'integritaet',
title: 'Datenmanipulation durch externen Angriff',
description: 'Personenbezogene Daten werden durch einen Cyberangriff (SQL-Injection, API-Manipulation) veraendert, ohne dass dies erkannt wird.',
impactExamples: ['Falsche Entscheidungen auf Basis manipulierter Daten', 'Rufschaedigung'],
typicalLikelihood: 'medium',
typicalImpact: 'high',
wp248Criteria: ['K4', 'K8'],
applicableTo: ['api_service', 'web_application', 'database'],
mitigationIds: ['M-INT-01', 'M-INT-02', 'M-INT-03'],
},
{
id: 'R-INT-02',
category: 'integrity',
sdmGoal: 'integritaet',
title: 'Fehlerhafte Synchronisation zwischen Systemen',
description: 'Bei der Synchronisation personenbezogener Daten zwischen verschiedenen Systemen kommt es zu Inkonsistenzen, Duplikaten oder Datenverlust.',
impactExamples: ['Falsche Kontaktdaten', 'Doppelte Verarbeitung', 'Falsche Auskuenfte'],
typicalLikelihood: 'medium',
typicalImpact: 'medium',
wp248Criteria: ['K6'],
applicableTo: ['crm', 'cloud_storage', 'erp', 'identity'],
mitigationIds: ['M-INT-04', 'M-INT-05'],
},
{
id: 'R-INT-03',
category: 'integrity',
sdmGoal: 'integritaet',
title: 'Backup-Korruption oder fehlerhafte Wiederherstellung',
description: 'Backups personenbezogener Daten sind beschaedigt, unvollstaendig oder veraltet, sodass eine zuverlaessige Wiederherstellung nicht moeglich ist.',
impactExamples: ['Datenverlust bei Wiederherstellung', 'Veraltete Datenbasis', 'Compliance-Verstoss'],
typicalLikelihood: 'low',
typicalImpact: 'high',
wp248Criteria: ['K5'],
applicableTo: ['database', 'cloud_storage', 'erp'],
mitigationIds: ['M-AVAIL-01', 'M-AVAIL-02'],
},
{
id: 'R-INT-04',
category: 'integrity',
sdmGoal: 'integritaet',
title: 'Unbemerkte Aenderung von Zugriffsrechten',
description: 'Zugriffsberechtigungen werden unbefugt oder fehlerhaft geaendert, wodurch unberechtigte Personen Zugang zu personenbezogenen Daten erhalten.',
impactExamples: ['Privilege Escalation', 'Unbefugter Datenzugriff'],
typicalLikelihood: 'medium',
typicalImpact: 'high',
wp248Criteria: ['K4'],
applicableTo: ['identity', 'cloud_storage', 'api_service'],
mitigationIds: ['M-INT-02', 'M-CONF-04'],
},
{
id: 'R-INT-05',
category: 'integrity',
sdmGoal: 'integritaet',
title: 'Fehlende Nachvollziehbarkeit von Datenveraenderungen',
description: 'Aenderungen an personenbezogenen Daten werden nicht protokolliert, sodass Manipulationen oder Fehler nicht erkannt oder nachvollzogen werden koennen.',
impactExamples: ['Unmoeglich festzustellen wer/wann Daten geaendert hat', 'Audit-Versagen'],
typicalLikelihood: 'medium',
typicalImpact: 'medium',
wp248Criteria: ['K3'],
applicableTo: ['database', 'crm', 'erp', 'web_application'],
mitigationIds: ['M-INT-02', 'M-TRANS-02'],
},
// =========================================================================
// VERFUEGBARKEIT (Availability)
// =========================================================================
{
id: 'R-AVAIL-01',
category: 'availability',
sdmGoal: 'verfuegbarkeit',
title: 'Ransomware-Angriff mit Datenverschluesselung',
description: 'Schadsoftware verschluesselt personenbezogene Daten und macht sie unzugaenglich. Die Wiederherstellung erfordert entweder Loesegeldzahlung oder Backup-Restore.',
impactExamples: ['Verlust des Zugangs zu eigenen Daten', 'Betriebsunterbrechung', 'Loesegeld-Erpressung'],
typicalLikelihood: 'medium',
typicalImpact: 'high',
wp248Criteria: ['K5', 'K8'],
applicableTo: ['cloud_storage', 'database', 'erp', 'web_application'],
mitigationIds: ['M-AVAIL-01', 'M-AVAIL-02', 'M-AVAIL-03'],
},
{
id: 'R-AVAIL-02',
category: 'availability',
sdmGoal: 'verfuegbarkeit',
title: 'Provider-Ausfall / Cloud-Service Nichtverfuegbarkeit',
description: 'Der Cloud-/Hosting-Provider faellt aus, was den Zugang zu personenbezogenen Daten verhindert. Betroffene koennen ihre Rechte nicht ausueben.',
impactExamples: ['Keine Auskunft moeglich', 'Vertragsverletzung', 'Geschaeftsunterbrechung'],
typicalLikelihood: 'low',
typicalImpact: 'high',
wp248Criteria: ['K5', 'K9'],
applicableTo: ['cloud_storage', 'web_application', 'api_service'],
mitigationIds: ['M-AVAIL-04', 'M-AVAIL-05'],
},
{
id: 'R-AVAIL-03',
category: 'availability',
sdmGoal: 'verfuegbarkeit',
title: 'Datenverlust durch fehlende oder ungetestete Backups',
description: 'Personenbezogene Daten gehen unwiederbringlich verloren, weil keine ausreichenden Backups existieren oder Restore-Prozesse nicht getestet werden.',
impactExamples: ['Unwiderruflicher Datenverlust', 'Verlust von Beweismitteln', 'Compliance-Verstoss'],
typicalLikelihood: 'low',
typicalImpact: 'high',
wp248Criteria: ['K5'],
applicableTo: ['database', 'cloud_storage', 'erp'],
mitigationIds: ['M-AVAIL-01', 'M-AVAIL-02'],
},
{
id: 'R-AVAIL-04',
category: 'availability',
sdmGoal: 'verfuegbarkeit',
title: 'DDoS-Angriff auf oeffentliche Dienste',
description: 'Ein Distributed-Denial-of-Service-Angriff verhindert den Zugang zu Systemen, die personenbezogene Daten verarbeiten.',
impactExamples: ['Betroffene koennen Rechte nicht ausueben', 'Geschaeftsausfall'],
typicalLikelihood: 'medium',
typicalImpact: 'medium',
wp248Criteria: ['K5', 'K9'],
applicableTo: ['web_application', 'api_service'],
mitigationIds: ['M-AVAIL-06', 'M-AVAIL-04'],
},
{
id: 'R-AVAIL-05',
category: 'availability',
sdmGoal: 'verfuegbarkeit',
title: 'Vendor Lock-in mit Kontrollverlust',
description: 'Abhaengigkeit von einem einzelnen Anbieter erschwert oder verhindert den Zugang zu personenbezogenen Daten bei Vertragsbeendigung oder Anbieterwechsel.',
impactExamples: ['Datenexport nicht moeglich', 'Erzwungene Weiternutzung', 'Datenverlust bei Kuendigung'],
typicalLikelihood: 'medium',
typicalImpact: 'medium',
wp248Criteria: ['K9'],
applicableTo: ['cloud_storage', 'erp', 'crm'],
mitigationIds: ['M-AVAIL-05', 'M-INTERV-01'],
},
// =========================================================================
// RECHTE & FREIHEITEN (Rights & Freedoms)
// =========================================================================
{
id: 'R-RIGHTS-01',
category: 'rights_freedoms',
sdmGoal: 'nichtverkettung',
title: 'Diskriminierung durch automatisierte Verarbeitung',
description: 'Automatisierte Entscheidungssysteme fuehren zu einer diskriminierenden Behandlung bestimmter Personengruppen aufgrund von Merkmalen wie Alter, Geschlecht, Herkunft oder Gesundheitszustand.',
impactExamples: ['Benachteiligung bei Kreditvergabe', 'Ausschluss von Dienstleistungen', 'Ungleichbehandlung'],
typicalLikelihood: 'medium',
typicalImpact: 'high',
wp248Criteria: ['K1', 'K2', 'K7'],
applicableTo: ['ai_ml', 'scoring', 'identity'],
mitigationIds: ['M-AUTO-01', 'M-AUTO-02', 'M-TRANS-03'],
},
{
id: 'R-RIGHTS-02',
category: 'rights_freedoms',
sdmGoal: 'nichtverkettung',
title: 'Unzulaessiges Profiling ohne Einwilligung',
description: 'Nutzerverhalten wird systematisch analysiert und zu Profilen zusammengefuehrt, ohne dass eine Rechtsgrundlage oder Einwilligung vorliegt.',
impactExamples: ['Persoenlichkeitsprofile ohne Wissen', 'Gezielte Manipulation', 'Filterblase'],
typicalLikelihood: 'medium',
typicalImpact: 'high',
wp248Criteria: ['K1', 'K3', 'K6'],
applicableTo: ['analytics', 'marketing', 'web_application', 'ai_ml'],
mitigationIds: ['M-NONL-01', 'M-NONL-02', 'M-TRANS-01'],
},
{
id: 'R-RIGHTS-03',
category: 'rights_freedoms',
sdmGoal: 'transparenz',
title: 'Systematische Ueberwachung von Betroffenen',
description: 'Betroffene werden systematisch ueberwacht (z.B. durch Standorttracking, E-Mail-Monitoring, Videoueberwachung), ohne angemessene Transparenz oder Rechtsgrundlage.',
impactExamples: ['Einschuechterungseffekt (Chilling Effect)', 'Verletzung der Privatsphaere', 'Vertrauensverlust'],
typicalLikelihood: 'medium',
typicalImpact: 'high',
wp248Criteria: ['K3', 'K4', 'K7'],
applicableTo: ['monitoring', 'hr_system', 'mobile_app'],
mitigationIds: ['M-TRANS-01', 'M-TRANS-04', 'M-NONL-01'],
},
{
id: 'R-RIGHTS-04',
category: 'rights_freedoms',
sdmGoal: 'nichtverkettung',
title: 'Re-Identifizierung pseudonymisierter Daten',
description: 'Pseudonymisierte oder anonymisierte Daten werden durch Zusammenfuehrung mit anderen Datenquellen re-identifiziert, wodurch der Schutz der Betroffenen aufgehoben wird.',
impactExamples: ['Verlust der Anonymitaet', 'Unerwuenschte Identifizierung', 'Zweckentfremdung'],
typicalLikelihood: 'low',
typicalImpact: 'high',
wp248Criteria: ['K1', 'K6', 'K8'],
applicableTo: ['analytics', 'ai_ml', 'research'],
mitigationIds: ['M-NONL-03', 'M-NONL-04', 'M-DMIN-02'],
},
{
id: 'R-RIGHTS-05',
category: 'rights_freedoms',
sdmGoal: 'intervenierbarkeit',
title: 'Hinderung bei Ausuebung von Betroffenenrechten',
description: 'Betroffene werden an der Ausuebung ihrer Rechte (Auskunft, Loeschung, Berichtigung, Widerspruch) gehindert — z.B. durch fehlende Prozesse, technische Huerden oder Verzoegerungen.',
impactExamples: ['Keine Loeschung moeglich', 'Verzoegerte Auskunft', 'Bussgeld gem. Art. 83'],
typicalLikelihood: 'medium',
typicalImpact: 'high',
wp248Criteria: ['K9'],
applicableTo: ['web_application', 'crm', 'identity', 'cloud_storage'],
mitigationIds: ['M-INTERV-01', 'M-INTERV-02', 'M-INTERV-03'],
},
{
id: 'R-RIGHTS-06',
category: 'rights_freedoms',
sdmGoal: 'transparenz',
title: 'Fehlende oder unzureichende Informationspflichten',
description: 'Betroffene werden nicht oder unzureichend ueber die Verarbeitung ihrer Daten informiert (Verstoss gegen Art. 13/14 DSGVO).',
impactExamples: ['Keine informierte Einwilligung moeglich', 'Vertrauensverlust', 'Bussgeld'],
typicalLikelihood: 'medium',
typicalImpact: 'medium',
wp248Criteria: ['K9'],
applicableTo: ['web_application', 'mobile_app', 'marketing'],
mitigationIds: ['M-TRANS-01', 'M-TRANS-05'],
},
{
id: 'R-RIGHTS-07',
category: 'rights_freedoms',
sdmGoal: 'datenminimierung',
title: 'Uebermassige Datenerhebung (Verstoss Datenminimierung)',
description: 'Es werden mehr personenbezogene Daten erhoben als fuer den Verarbeitungszweck notwendig (Verstoss gegen Art. 5 Abs. 1 lit. c DSGVO).',
impactExamples: ['Unnoetige Risikoexposition', 'Hoeherer Schaden bei Datenpanne'],
typicalLikelihood: 'medium',
typicalImpact: 'medium',
wp248Criteria: ['K5'],
applicableTo: ['web_application', 'mobile_app', 'crm', 'hr_system'],
mitigationIds: ['M-DMIN-01', 'M-DMIN-02', 'M-DMIN-03'],
},
// =========================================================================
// DRITTLANDTRANSFER
// =========================================================================
{
id: 'R-TRANS-01',
category: 'rights_freedoms',
sdmGoal: 'vertraulichkeit',
title: 'Zugriff durch Drittland-Behoerden (FISA/CLOUD Act)',
description: 'Behoerden eines Drittlandes (z.B. USA) greifen auf personenbezogene Daten zu, die bei einem Cloud-Provider in der EU oder im Drittland gespeichert sind.',
impactExamples: ['Ueberwachung ohne Wissen', 'Kein Rechtsschutz', 'Schrems-II-Risiko'],
typicalLikelihood: 'medium',
typicalImpact: 'high',
wp248Criteria: ['K4', 'K5', 'K7'],
applicableTo: ['cloud_storage', 'email_service', 'crm', 'analytics'],
mitigationIds: ['M-TRANS-06', 'M-TRANS-07', 'M-CONF-06'],
},
{
id: 'R-TRANS-02',
category: 'rights_freedoms',
sdmGoal: 'vertraulichkeit',
title: 'Unzureichende Schutzgarantien bei Drittlandtransfer',
description: 'Personenbezogene Daten werden in Drittlaender uebermittelt, ohne dass angemessene Garantien (SCC, BCR, Angemessenheitsbeschluss) vorhanden sind.',
impactExamples: ['Rechtswidriger Transfer', 'Bussgeld', 'Untersagung der Verarbeitung'],
typicalLikelihood: 'medium',
typicalImpact: 'high',
wp248Criteria: ['K5', 'K7'],
applicableTo: ['cloud_storage', 'email_service', 'crm', 'analytics'],
mitigationIds: ['M-TRANS-06', 'M-TRANS-07', 'M-LEGAL-01'],
},
{
id: 'R-TRANS-03',
category: 'rights_freedoms',
sdmGoal: 'transparenz',
title: 'Intransparente Sub-Auftragsverarbeiter-Kette',
description: 'Die Kette der Sub-Auftragsverarbeiter ist nicht transparent. Betroffene und Verantwortliche wissen nicht, wo ihre Daten tatsaechlich verarbeitet werden.',
impactExamples: ['Unkontrollierte Datenweitergabe', 'Unbekannter Verarbeitungsort'],
typicalLikelihood: 'medium',
typicalImpact: 'medium',
wp248Criteria: ['K5'],
applicableTo: ['cloud_storage', 'crm', 'analytics'],
mitigationIds: ['M-TRANS-01', 'M-LEGAL-02'],
},
// =========================================================================
// AUTOMATISIERUNG / KI
// =========================================================================
{
id: 'R-AUTO-01',
category: 'rights_freedoms',
sdmGoal: 'transparenz',
title: 'KI-Fehlentscheidung mit erheblicher Auswirkung',
description: 'Ein KI-System trifft eine fehlerhafte automatisierte Entscheidung (z.B. Ablehnung, Sperrung, Bewertung), die erhebliche Auswirkungen auf eine betroffene Person hat.',
impactExamples: ['Unrechtmaessige Ablehnung', 'Falsche Risikoeinstufung', 'Benachteiligung'],
typicalLikelihood: 'medium',
typicalImpact: 'high',
wp248Criteria: ['K1', 'K2', 'K8'],
applicableTo: ['ai_ml', 'scoring', 'hr_system'],
mitigationIds: ['M-AUTO-01', 'M-AUTO-02', 'M-AUTO-03'],
},
{
id: 'R-AUTO-02',
category: 'rights_freedoms',
sdmGoal: 'nichtverkettung',
title: 'Algorithmischer Bias in Trainingsdaten',
description: 'KI-Modelle spiegeln Vorurteile in den Trainingsdaten wider und treffen diskriminierende Entscheidungen bezueglich geschuetzter Merkmale.',
impactExamples: ['Diskriminierung nach Geschlecht/Herkunft', 'Systematische Benachteiligung'],
typicalLikelihood: 'medium',
typicalImpact: 'high',
wp248Criteria: ['K1', 'K2', 'K7', 'K8'],
applicableTo: ['ai_ml', 'scoring'],
mitigationIds: ['M-AUTO-01', 'M-AUTO-04'],
},
{
id: 'R-AUTO-03',
category: 'rights_freedoms',
sdmGoal: 'transparenz',
title: 'Fehlende Erklaerbarkeit automatisierter Entscheidungen',
description: 'Automatisierte Entscheidungen koennen den Betroffenen nicht erklaert werden ("Black Box"), sodass der Anspruch auf aussagekraeftige Informationen (Art. 22 Abs. 3) nicht erfuellt wird.',
impactExamples: ['Keine Anfechtbarkeit', 'Vertrauensverlust', 'Verstoss gegen Art. 22'],
typicalLikelihood: 'high',
typicalImpact: 'medium',
wp248Criteria: ['K2', 'K8'],
applicableTo: ['ai_ml', 'scoring'],
mitigationIds: ['M-AUTO-02', 'M-TRANS-03'],
},
{
id: 'R-AUTO-04',
category: 'rights_freedoms',
sdmGoal: 'intervenierbarkeit',
title: 'Fehlende menschliche Aufsicht bei KI-Entscheidungen',
description: 'Automatisierte Entscheidungen werden ohne menschliche Ueberpruefung oder Interventionsmoeglichkeit getroffen, obwohl dies erforderlich waere.',
impactExamples: ['Keine Korrekturmoeglichkeit', 'Eskalation von Fehlern'],
typicalLikelihood: 'medium',
typicalImpact: 'high',
wp248Criteria: ['K2', 'K8'],
applicableTo: ['ai_ml', 'scoring', 'hr_system'],
mitigationIds: ['M-AUTO-03', 'M-INTERV-04'],
},
{
id: 'R-AUTO-05',
category: 'confidentiality',
sdmGoal: 'vertraulichkeit',
title: 'Datenleck durch KI-Training mit personenbezogenen Daten',
description: 'Personenbezogene Daten, die fuer das Training von KI-Modellen verwendet werden, koennen durch das Modell reproduziert oder extrahiert werden (Model Inversion, Membership Inference).',
impactExamples: ['Offenlegung von Trainingsdaten', 'Re-Identifizierung'],
typicalLikelihood: 'low',
typicalImpact: 'high',
wp248Criteria: ['K4', 'K8'],
applicableTo: ['ai_ml'],
mitigationIds: ['M-CONF-06', 'M-NONL-03', 'M-AUTO-04'],
},
// =========================================================================
// ORGANISATORISCHE RISIKEN
// =========================================================================
{
id: 'R-ORG-01',
category: 'rights_freedoms',
sdmGoal: 'transparenz',
title: 'Fehlende oder fehlerhafte Auftragsverarbeitungsvertraege',
description: 'Mit Auftragsverarbeitern existieren keine oder unzureichende Vertraege gemaess Art. 28 DSGVO, sodass Pflichten und Rechte nicht geregelt sind.',
impactExamples: ['Keine Kontrolle ueber Verarbeiter', 'Bussgeld', 'Datenmissbrauch durch Verarbeiter'],
typicalLikelihood: 'medium',
typicalImpact: 'medium',
wp248Criteria: ['K5'],
applicableTo: ['cloud_storage', 'crm', 'analytics', 'email_service'],
mitigationIds: ['M-LEGAL-02', 'M-LEGAL-03'],
},
{
id: 'R-ORG-02',
category: 'rights_freedoms',
sdmGoal: 'datenminimierung',
title: 'Fehlende Loeschprozesse / Ueberschreitung von Aufbewahrungsfristen',
description: 'Personenbezogene Daten werden laenger als notwendig gespeichert, weil keine automatischen Loeschprozesse oder Aufbewahrungsfristen definiert sind.',
impactExamples: ['Unnoetige Risikoexposition', 'Verstoss gegen Speicherbegrenzung', 'Bussgeld'],
typicalLikelihood: 'high',
typicalImpact: 'medium',
wp248Criteria: ['K5'],
applicableTo: ['database', 'cloud_storage', 'crm', 'erp', 'email_service'],
mitigationIds: ['M-DMIN-03', 'M-DMIN-04'],
},
{
id: 'R-ORG-03',
category: 'integrity',
sdmGoal: 'integritaet',
title: 'Unzureichende Schulung/Sensibilisierung der Mitarbeiter',
description: 'Mitarbeiter sind nicht ausreichend im Umgang mit personenbezogenen Daten geschult und verursachen durch Unkenntnis Datenpannen oder Verarbeitungsfehler.',
impactExamples: ['Versehentliche Datenweitergabe', 'Phishing-Erfolg', 'Fehlerhafte Verarbeitung'],
typicalLikelihood: 'high',
typicalImpact: 'medium',
wp248Criteria: ['K5', 'K7'],
applicableTo: ['hr_system', 'email_service', 'crm', 'web_application'],
mitigationIds: ['M-ORG-01', 'M-ORG-02'],
},
{
id: 'R-ORG-04',
category: 'rights_freedoms',
sdmGoal: 'transparenz',
title: 'Fehlende Datenpannen-Erkennung und -Meldung',
description: 'Datenpannen werden nicht rechtzeitig erkannt oder nicht innerhalb der 72-Stunden-Frist (Art. 33 DSGVO) an die Aufsichtsbehoerde gemeldet.',
impactExamples: ['Verspaetete Meldung', 'Bussgeld', 'Verzoegerte Benachrichtigung Betroffener'],
typicalLikelihood: 'medium',
typicalImpact: 'high',
wp248Criteria: ['K5'],
applicableTo: ['web_application', 'cloud_storage', 'database', 'api_service'],
mitigationIds: ['M-ORG-03', 'M-ORG-04', 'M-INT-02'],
},
// =========================================================================
// BESONDERE DATENKATEGORIEN
// =========================================================================
{
id: 'R-SPEC-01',
category: 'confidentiality',
sdmGoal: 'vertraulichkeit',
title: 'Kompromittierung besonderer Datenkategorien (Art. 9)',
description: 'Besonders schutzwuerdige Daten (Gesundheit, Religion, Biometrie, Gewerkschaftszugehoerigkeit) werden offengelegt oder missbraucht.',
impactExamples: ['Schwerwiegende Diskriminierung', 'Existenzielle Bedrohung', 'Soziale Ausgrenzung'],
typicalLikelihood: 'low',
typicalImpact: 'high',
wp248Criteria: ['K4', 'K7'],
applicableTo: ['hr_system', 'health_system', 'identity'],
mitigationIds: ['M-CONF-06', 'M-CONF-01', 'M-CONF-04'],
},
{
id: 'R-SPEC-02',
category: 'rights_freedoms',
sdmGoal: 'intervenierbarkeit',
title: 'Verarbeitung von Kinderdaten ohne angemessenen Schutz',
description: 'Daten von Minderjaehrigen werden verarbeitet, ohne die besonderen Schutzmassnahmen fuer Kinder (Art. 8, EG 38 DSGVO) zu beachten.',
impactExamples: ['Langzeitfolgen fuer Minderjaehrige', 'Einschraenkung der Entwicklung', 'Manipulation'],
typicalLikelihood: 'low',
typicalImpact: 'high',
wp248Criteria: ['K4', 'K7'],
applicableTo: ['web_application', 'mobile_app', 'education'],
mitigationIds: ['M-LEGAL-04', 'M-DMIN-01', 'M-TRANS-01'],
},
]
// =============================================================================
// HELPER FUNCTIONS
// =============================================================================
export function getRisksByCategory(category: DSFARiskCategory): CatalogRisk[] {
return RISK_CATALOG.filter(r => r.category === category)
}
export function getRisksBySDMGoal(goal: SDMGoal): CatalogRisk[] {
return RISK_CATALOG.filter(r => r.sdmGoal === goal)
}
export function getRisksByWP248Criterion(criterionCode: string): CatalogRisk[] {
return RISK_CATALOG.filter(r => r.wp248Criteria.includes(criterionCode))
}
export function getRisksByComponent(component: string): CatalogRisk[] {
return RISK_CATALOG.filter(r => r.applicableTo.includes(component))
}
export function getCatalogRiskById(id: string): CatalogRisk | undefined {
return RISK_CATALOG.find(r => r.id === id)
}
export const RISK_CATEGORY_LABELS: Record<DSFARiskCategory, string> = {
confidentiality: 'Vertraulichkeit',
integrity: 'Integritaet',
availability: 'Verfuegbarkeit',
rights_freedoms: 'Rechte & Freiheiten',
}
export const COMPONENT_FAMILY_LABELS: Record<string, string> = {
identity: 'Identitaet & Zugang',
cloud_storage: 'Cloud-Speicher',
web_application: 'Web-Anwendung',
api_service: 'API-Service',
email_service: 'E-Mail-Dienst',
mobile_app: 'Mobile App',
database: 'Datenbank',
crm: 'CRM-System',
erp: 'ERP-System',
analytics: 'Analyse/Tracking',
marketing: 'Marketing',
ai_ml: 'KI / Machine Learning',
scoring: 'Scoring / Bewertung',
hr_system: 'HR-System',
health_system: 'Gesundheitssystem',
monitoring: 'Ueberwachungssystem',
support_system: 'Support-System',
education: 'Bildungsplattform',
research: 'Forschung',
}

View File

@@ -0,0 +1,310 @@
/**
* DSFA Risikokatalog — Verfuegbarkeit, Rechte & Freiheiten, Drittlandtransfer, Auto/KI, Org
*/
import type { CatalogRisk } from './types'
export const AVAILABILITY_RISKS: CatalogRisk[] = [
{
id: 'R-AVAIL-01',
category: 'availability',
sdmGoal: 'verfuegbarkeit',
title: 'Ransomware-Angriff mit Datenverschluesselung',
description: 'Schadsoftware verschluesselt personenbezogene Daten und macht sie unzugaenglich. Die Wiederherstellung erfordert entweder Loesegeldzahlung oder Backup-Restore.',
impactExamples: ['Verlust des Zugangs zu eigenen Daten', 'Betriebsunterbrechung', 'Loesegeld-Erpressung'],
typicalLikelihood: 'medium',
typicalImpact: 'high',
wp248Criteria: ['K5', 'K8'],
applicableTo: ['cloud_storage', 'database', 'erp', 'web_application'],
mitigationIds: ['M-AVAIL-01', 'M-AVAIL-02', 'M-AVAIL-03'],
},
{
id: 'R-AVAIL-02',
category: 'availability',
sdmGoal: 'verfuegbarkeit',
title: 'Provider-Ausfall / Cloud-Service Nichtverfuegbarkeit',
description: 'Der Cloud-/Hosting-Provider faellt aus, was den Zugang zu personenbezogenen Daten verhindert. Betroffene koennen ihre Rechte nicht ausueben.',
impactExamples: ['Keine Auskunft moeglich', 'Vertragsverletzung', 'Geschaeftsunterbrechung'],
typicalLikelihood: 'low',
typicalImpact: 'high',
wp248Criteria: ['K5', 'K9'],
applicableTo: ['cloud_storage', 'web_application', 'api_service'],
mitigationIds: ['M-AVAIL-04', 'M-AVAIL-05'],
},
{
id: 'R-AVAIL-03',
category: 'availability',
sdmGoal: 'verfuegbarkeit',
title: 'Datenverlust durch fehlende oder ungetestete Backups',
description: 'Personenbezogene Daten gehen unwiederbringlich verloren, weil keine ausreichenden Backups existieren oder Restore-Prozesse nicht getestet werden.',
impactExamples: ['Unwiderruflicher Datenverlust', 'Verlust von Beweismitteln', 'Compliance-Verstoss'],
typicalLikelihood: 'low',
typicalImpact: 'high',
wp248Criteria: ['K5'],
applicableTo: ['database', 'cloud_storage', 'erp'],
mitigationIds: ['M-AVAIL-01', 'M-AVAIL-02'],
},
{
id: 'R-AVAIL-04',
category: 'availability',
sdmGoal: 'verfuegbarkeit',
title: 'DDoS-Angriff auf oeffentliche Dienste',
description: 'Ein Distributed-Denial-of-Service-Angriff verhindert den Zugang zu Systemen, die personenbezogene Daten verarbeiten.',
impactExamples: ['Betroffene koennen Rechte nicht ausueben', 'Geschaeftsausfall'],
typicalLikelihood: 'medium',
typicalImpact: 'medium',
wp248Criteria: ['K5', 'K9'],
applicableTo: ['web_application', 'api_service'],
mitigationIds: ['M-AVAIL-06', 'M-AVAIL-04'],
},
{
id: 'R-AVAIL-05',
category: 'availability',
sdmGoal: 'verfuegbarkeit',
title: 'Vendor Lock-in mit Kontrollverlust',
description: 'Abhaengigkeit von einem einzelnen Anbieter erschwert oder verhindert den Zugang zu personenbezogenen Daten bei Vertragsbeendigung oder Anbieterwechsel.',
impactExamples: ['Datenexport nicht moeglich', 'Erzwungene Weiternutzung', 'Datenverlust bei Kuendigung'],
typicalLikelihood: 'medium',
typicalImpact: 'medium',
wp248Criteria: ['K9'],
applicableTo: ['cloud_storage', 'erp', 'crm'],
mitigationIds: ['M-AVAIL-05', 'M-INTERV-01'],
},
]
export const RIGHTS_FREEDOMS_RISKS: CatalogRisk[] = [
{
id: 'R-RIGHTS-01',
category: 'rights_freedoms',
sdmGoal: 'nichtverkettung',
title: 'Diskriminierung durch automatisierte Verarbeitung',
description: 'Automatisierte Entscheidungssysteme fuehren zu einer diskriminierenden Behandlung bestimmter Personengruppen aufgrund von Merkmalen wie Alter, Geschlecht, Herkunft oder Gesundheitszustand.',
impactExamples: ['Benachteiligung bei Kreditvergabe', 'Ausschluss von Dienstleistungen', 'Ungleichbehandlung'],
typicalLikelihood: 'medium',
typicalImpact: 'high',
wp248Criteria: ['K1', 'K2', 'K7'],
applicableTo: ['ai_ml', 'scoring', 'identity'],
mitigationIds: ['M-AUTO-01', 'M-AUTO-02', 'M-TRANS-03'],
},
{
id: 'R-RIGHTS-02',
category: 'rights_freedoms',
sdmGoal: 'nichtverkettung',
title: 'Unzulaessiges Profiling ohne Einwilligung',
description: 'Nutzerverhalten wird systematisch analysiert und zu Profilen zusammengefuehrt, ohne dass eine Rechtsgrundlage oder Einwilligung vorliegt.',
impactExamples: ['Persoenlichkeitsprofile ohne Wissen', 'Gezielte Manipulation', 'Filterblase'],
typicalLikelihood: 'medium',
typicalImpact: 'high',
wp248Criteria: ['K1', 'K3', 'K6'],
applicableTo: ['analytics', 'marketing', 'web_application', 'ai_ml'],
mitigationIds: ['M-NONL-01', 'M-NONL-02', 'M-TRANS-01'],
},
{
id: 'R-RIGHTS-03',
category: 'rights_freedoms',
sdmGoal: 'transparenz',
title: 'Systematische Ueberwachung von Betroffenen',
description: 'Betroffene werden systematisch ueberwacht (z.B. durch Standorttracking, E-Mail-Monitoring, Videoueberwachung), ohne angemessene Transparenz oder Rechtsgrundlage.',
impactExamples: ['Einschuechterungseffekt (Chilling Effect)', 'Verletzung der Privatsphaere', 'Vertrauensverlust'],
typicalLikelihood: 'medium',
typicalImpact: 'high',
wp248Criteria: ['K3', 'K4', 'K7'],
applicableTo: ['monitoring', 'hr_system', 'mobile_app'],
mitigationIds: ['M-TRANS-01', 'M-TRANS-04', 'M-NONL-01'],
},
{
id: 'R-RIGHTS-04',
category: 'rights_freedoms',
sdmGoal: 'nichtverkettung',
title: 'Re-Identifizierung pseudonymisierter Daten',
description: 'Pseudonymisierte oder anonymisierte Daten werden durch Zusammenfuehrung mit anderen Datenquellen re-identifiziert, wodurch der Schutz der Betroffenen aufgehoben wird.',
impactExamples: ['Verlust der Anonymitaet', 'Unerwuenschte Identifizierung', 'Zweckentfremdung'],
typicalLikelihood: 'low',
typicalImpact: 'high',
wp248Criteria: ['K1', 'K6', 'K8'],
applicableTo: ['analytics', 'ai_ml', 'research'],
mitigationIds: ['M-NONL-03', 'M-NONL-04', 'M-DMIN-02'],
},
{
id: 'R-RIGHTS-05',
category: 'rights_freedoms',
sdmGoal: 'intervenierbarkeit',
title: 'Hinderung bei Ausuebung von Betroffenenrechten',
description: 'Betroffene werden an der Ausuebung ihrer Rechte (Auskunft, Loeschung, Berichtigung, Widerspruch) gehindert — z.B. durch fehlende Prozesse, technische Huerden oder Verzoegerungen.',
impactExamples: ['Keine Loeschung moeglich', 'Verzoegerte Auskunft', 'Bussgeld gem. Art. 83'],
typicalLikelihood: 'medium',
typicalImpact: 'high',
wp248Criteria: ['K9'],
applicableTo: ['web_application', 'crm', 'identity', 'cloud_storage'],
mitigationIds: ['M-INTERV-01', 'M-INTERV-02', 'M-INTERV-03'],
},
{
id: 'R-RIGHTS-06',
category: 'rights_freedoms',
sdmGoal: 'transparenz',
title: 'Fehlende oder unzureichende Informationspflichten',
description: 'Betroffene werden nicht oder unzureichend ueber die Verarbeitung ihrer Daten informiert (Verstoss gegen Art. 13/14 DSGVO).',
impactExamples: ['Keine informierte Einwilligung moeglich', 'Vertrauensverlust', 'Bussgeld'],
typicalLikelihood: 'medium',
typicalImpact: 'medium',
wp248Criteria: ['K9'],
applicableTo: ['web_application', 'mobile_app', 'marketing'],
mitigationIds: ['M-TRANS-01', 'M-TRANS-05'],
},
{
id: 'R-RIGHTS-07',
category: 'rights_freedoms',
sdmGoal: 'datenminimierung',
title: 'Uebermassige Datenerhebung (Verstoss Datenminimierung)',
description: 'Es werden mehr personenbezogene Daten erhoben als fuer den Verarbeitungszweck notwendig (Verstoss gegen Art. 5 Abs. 1 lit. c DSGVO).',
impactExamples: ['Unnoetige Risikoexposition', 'Hoeherer Schaden bei Datenpanne'],
typicalLikelihood: 'medium',
typicalImpact: 'medium',
wp248Criteria: ['K5'],
applicableTo: ['web_application', 'mobile_app', 'crm', 'hr_system'],
mitigationIds: ['M-DMIN-01', 'M-DMIN-02', 'M-DMIN-03'],
},
{
id: 'R-TRANS-01',
category: 'rights_freedoms',
sdmGoal: 'vertraulichkeit',
title: 'Zugriff durch Drittland-Behoerden (FISA/CLOUD Act)',
description: 'Behoerden eines Drittlandes (z.B. USA) greifen auf personenbezogene Daten zu, die bei einem Cloud-Provider in der EU oder im Drittland gespeichert sind.',
impactExamples: ['Ueberwachung ohne Wissen', 'Kein Rechtsschutz', 'Schrems-II-Risiko'],
typicalLikelihood: 'medium',
typicalImpact: 'high',
wp248Criteria: ['K4', 'K5', 'K7'],
applicableTo: ['cloud_storage', 'email_service', 'crm', 'analytics'],
mitigationIds: ['M-TRANS-06', 'M-TRANS-07', 'M-CONF-06'],
},
{
id: 'R-TRANS-02',
category: 'rights_freedoms',
sdmGoal: 'vertraulichkeit',
title: 'Unzureichende Schutzgarantien bei Drittlandtransfer',
description: 'Personenbezogene Daten werden in Drittlaender uebermittelt, ohne dass angemessene Garantien (SCC, BCR, Angemessenheitsbeschluss) vorhanden sind.',
impactExamples: ['Rechtswidriger Transfer', 'Bussgeld', 'Untersagung der Verarbeitung'],
typicalLikelihood: 'medium',
typicalImpact: 'high',
wp248Criteria: ['K5', 'K7'],
applicableTo: ['cloud_storage', 'email_service', 'crm', 'analytics'],
mitigationIds: ['M-TRANS-06', 'M-TRANS-07', 'M-LEGAL-01'],
},
{
id: 'R-TRANS-03',
category: 'rights_freedoms',
sdmGoal: 'transparenz',
title: 'Intransparente Sub-Auftragsverarbeiter-Kette',
description: 'Die Kette der Sub-Auftragsverarbeiter ist nicht transparent. Betroffene und Verantwortliche wissen nicht, wo ihre Daten tatsaechlich verarbeitet werden.',
impactExamples: ['Unkontrollierte Datenweitergabe', 'Unbekannter Verarbeitungsort'],
typicalLikelihood: 'medium',
typicalImpact: 'medium',
wp248Criteria: ['K5'],
applicableTo: ['cloud_storage', 'crm', 'analytics'],
mitigationIds: ['M-TRANS-01', 'M-LEGAL-02'],
},
{
id: 'R-AUTO-01',
category: 'rights_freedoms',
sdmGoal: 'transparenz',
title: 'KI-Fehlentscheidung mit erheblicher Auswirkung',
description: 'Ein KI-System trifft eine fehlerhafte automatisierte Entscheidung (z.B. Ablehnung, Sperrung, Bewertung), die erhebliche Auswirkungen auf eine betroffene Person hat.',
impactExamples: ['Unrechtmaessige Ablehnung', 'Falsche Risikoeinstufung', 'Benachteiligung'],
typicalLikelihood: 'medium',
typicalImpact: 'high',
wp248Criteria: ['K1', 'K2', 'K8'],
applicableTo: ['ai_ml', 'scoring', 'hr_system'],
mitigationIds: ['M-AUTO-01', 'M-AUTO-02', 'M-AUTO-03'],
},
{
id: 'R-AUTO-02',
category: 'rights_freedoms',
sdmGoal: 'nichtverkettung',
title: 'Algorithmischer Bias in Trainingsdaten',
description: 'KI-Modelle spiegeln Vorurteile in den Trainingsdaten wider und treffen diskriminierende Entscheidungen bezueglich geschuetzter Merkmale.',
impactExamples: ['Diskriminierung nach Geschlecht/Herkunft', 'Systematische Benachteiligung'],
typicalLikelihood: 'medium',
typicalImpact: 'high',
wp248Criteria: ['K1', 'K2', 'K7', 'K8'],
applicableTo: ['ai_ml', 'scoring'],
mitigationIds: ['M-AUTO-01', 'M-AUTO-04'],
},
{
id: 'R-AUTO-03',
category: 'rights_freedoms',
sdmGoal: 'transparenz',
title: 'Fehlende Erklaerbarkeit automatisierter Entscheidungen',
description: 'Automatisierte Entscheidungen koennen den Betroffenen nicht erklaert werden ("Black Box"), sodass der Anspruch auf aussagekraeftige Informationen (Art. 22 Abs. 3) nicht erfuellt wird.',
impactExamples: ['Keine Anfechtbarkeit', 'Vertrauensverlust', 'Verstoss gegen Art. 22'],
typicalLikelihood: 'high',
typicalImpact: 'medium',
wp248Criteria: ['K2', 'K8'],
applicableTo: ['ai_ml', 'scoring'],
mitigationIds: ['M-AUTO-02', 'M-TRANS-03'],
},
{
id: 'R-AUTO-04',
category: 'rights_freedoms',
sdmGoal: 'intervenierbarkeit',
title: 'Fehlende menschliche Aufsicht bei KI-Entscheidungen',
description: 'Automatisierte Entscheidungen werden ohne menschliche Ueberpruefung oder Interventionsmoeglichkeit getroffen, obwohl dies erforderlich waere.',
impactExamples: ['Keine Korrekturmoeglichkeit', 'Eskalation von Fehlern'],
typicalLikelihood: 'medium',
typicalImpact: 'high',
wp248Criteria: ['K2', 'K8'],
applicableTo: ['ai_ml', 'scoring', 'hr_system'],
mitigationIds: ['M-AUTO-03', 'M-INTERV-04'],
},
{
id: 'R-ORG-01',
category: 'rights_freedoms',
sdmGoal: 'transparenz',
title: 'Fehlende oder fehlerhafte Auftragsverarbeitungsvertraege',
description: 'Mit Auftragsverarbeitern existieren keine oder unzureichende Vertraege gemaess Art. 28 DSGVO, sodass Pflichten und Rechte nicht geregelt sind.',
impactExamples: ['Keine Kontrolle ueber Verarbeiter', 'Bussgeld', 'Datenmissbrauch durch Verarbeiter'],
typicalLikelihood: 'medium',
typicalImpact: 'medium',
wp248Criteria: ['K5'],
applicableTo: ['cloud_storage', 'crm', 'analytics', 'email_service'],
mitigationIds: ['M-LEGAL-02', 'M-LEGAL-03'],
},
{
id: 'R-ORG-02',
category: 'rights_freedoms',
sdmGoal: 'datenminimierung',
title: 'Fehlende Loeschprozesse / Ueberschreitung von Aufbewahrungsfristen',
description: 'Personenbezogene Daten werden laenger als notwendig gespeichert, weil keine automatischen Loeschprozesse oder Aufbewahrungsfristen definiert sind.',
impactExamples: ['Unnoetige Risikoexposition', 'Verstoss gegen Speicherbegrenzung', 'Bussgeld'],
typicalLikelihood: 'high',
typicalImpact: 'medium',
wp248Criteria: ['K5'],
applicableTo: ['database', 'cloud_storage', 'crm', 'erp', 'email_service'],
mitigationIds: ['M-DMIN-03', 'M-DMIN-04'],
},
{
id: 'R-ORG-04',
category: 'rights_freedoms',
sdmGoal: 'transparenz',
title: 'Fehlende Datenpannen-Erkennung und -Meldung',
description: 'Datenpannen werden nicht rechtzeitig erkannt oder nicht innerhalb der 72-Stunden-Frist (Art. 33 DSGVO) an die Aufsichtsbehoerde gemeldet.',
impactExamples: ['Verspaetete Meldung', 'Bussgeld', 'Verzoegerte Benachrichtigung Betroffener'],
typicalLikelihood: 'medium',
typicalImpact: 'high',
wp248Criteria: ['K5'],
applicableTo: ['web_application', 'cloud_storage', 'database', 'api_service'],
mitigationIds: ['M-ORG-03', 'M-ORG-04', 'M-INT-02'],
},
{
id: 'R-SPEC-02',
category: 'rights_freedoms',
sdmGoal: 'intervenierbarkeit',
title: 'Verarbeitung von Kinderdaten ohne angemessenen Schutz',
description: 'Daten von Minderjaehrigen werden verarbeitet, ohne die besonderen Schutzmassnahmen fuer Kinder (Art. 8, EG 38 DSGVO) zu beachten.',
impactExamples: ['Langzeitfolgen fuer Minderjaehrige', 'Einschraenkung der Entwicklung', 'Manipulation'],
typicalLikelihood: 'low',
typicalImpact: 'high',
wp248Criteria: ['K4', 'K7'],
applicableTo: ['web_application', 'mobile_app', 'education'],
mitigationIds: ['M-LEGAL-04', 'M-DMIN-01', 'M-TRANS-01'],
},
]

View File

@@ -0,0 +1,206 @@
/**
* DSFA Risikokatalog — Vertraulichkeit & Integritaet
*/
import type { CatalogRisk } from './types'
export const CONFIDENTIALITY_RISKS: CatalogRisk[] = [
{
id: 'R-CONF-01',
category: 'confidentiality',
sdmGoal: 'vertraulichkeit',
title: 'Unbefugte Offenlegung durch Fehlkonfiguration',
description: 'Personenbezogene Daten werden durch fehlerhafte Systemkonfiguration (z.B. offene APIs, fehlerhafte Zugriffsrechte, oeffentliche Cloud-Speicher) unbefugt zugaenglich.',
impactExamples: ['Identitaetsdiebstahl', 'Reputationsschaden', 'Diskriminierung'],
typicalLikelihood: 'medium',
typicalImpact: 'high',
wp248Criteria: ['K4', 'K5'],
applicableTo: ['cloud_storage', 'web_application', 'api_service'],
mitigationIds: ['M-CONF-01', 'M-CONF-02', 'M-CONF-03'],
},
{
id: 'R-CONF-02',
category: 'confidentiality',
sdmGoal: 'vertraulichkeit',
title: 'Account Takeover / Credential Stuffing',
description: 'Angreifer uebernehmen Benutzerkonten durch gestohlene Zugangsdaten, Brute-Force-Angriffe oder Phishing und erlangen Zugriff auf personenbezogene Daten.',
impactExamples: ['Kontrollverlust ueber eigene Daten', 'Finanzieller Schaden', 'Missbrauch der Identitaet'],
typicalLikelihood: 'high',
typicalImpact: 'high',
wp248Criteria: ['K4', 'K7'],
applicableTo: ['identity', 'web_application', 'email_service'],
mitigationIds: ['M-ACC-01', 'M-ACC-02'],
},
{
id: 'R-CONF-03',
category: 'confidentiality',
sdmGoal: 'vertraulichkeit',
title: 'Unbefugter Zugriff durch Support-/Administrationspersonal',
description: 'Administratoren oder Support-Mitarbeiter greifen ohne dienstliche Notwendigkeit auf personenbezogene Daten zu (Insider-Bedrohung).',
impactExamples: ['Verletzung der Privatsphaere', 'Datenmissbrauch', 'Vertrauensverlust'],
typicalLikelihood: 'medium',
typicalImpact: 'medium',
wp248Criteria: ['K4'],
applicableTo: ['identity', 'crm', 'cloud_storage', 'support_system'],
mitigationIds: ['M-CONF-04', 'M-CONF-05', 'M-INT-02'],
},
{
id: 'R-CONF-04',
category: 'confidentiality',
sdmGoal: 'vertraulichkeit',
title: 'Datenleck durch unzureichende Verschluesselung',
description: 'Personenbezogene Daten werden bei Uebertragung oder Speicherung nicht oder unzureichend verschluesselt und koennen abgefangen werden.',
impactExamples: ['Man-in-the-Middle-Angriff', 'Datendiebstahl bei Speichermedien-Verlust'],
typicalLikelihood: 'medium',
typicalImpact: 'high',
wp248Criteria: ['K4', 'K8'],
applicableTo: ['cloud_storage', 'email_service', 'mobile_app', 'api_service'],
mitigationIds: ['M-CONF-06', 'M-CONF-07'],
},
{
id: 'R-CONF-05',
category: 'confidentiality',
sdmGoal: 'vertraulichkeit',
title: 'Unkontrollierte Datenweitergabe an Dritte',
description: 'Personenbezogene Daten werden ohne Rechtsgrundlage oder ueber das vereinbarte Mass hinaus an Dritte weitergegeben (z.B. durch Tracking, Analyse-Tools, Sub-Auftragsverarbeiter).',
impactExamples: ['Unerwuenschte Werbung', 'Profiling ohne Wissen', 'Kontrollverlust'],
typicalLikelihood: 'medium',
typicalImpact: 'medium',
wp248Criteria: ['K1', 'K6'],
applicableTo: ['web_application', 'analytics', 'marketing', 'crm'],
mitigationIds: ['M-NONL-01', 'M-TRANS-01'],
},
{
id: 'R-CONF-06',
category: 'confidentiality',
sdmGoal: 'vertraulichkeit',
title: 'Social Engineering / Phishing gegen Betroffene',
description: 'Betroffene werden durch manipulative Kommunikation dazu verleitet, personenbezogene Daten preiszugeben oder Zugriff zu gewaehren.',
impactExamples: ['Identitaetsdiebstahl', 'Finanzieller Schaden', 'Uebernahme von Konten'],
typicalLikelihood: 'high',
typicalImpact: 'medium',
wp248Criteria: ['K7'],
applicableTo: ['email_service', 'web_application', 'identity'],
mitigationIds: ['M-ACC-01', 'M-ORG-01'],
},
{
id: 'R-CONF-07',
category: 'confidentiality',
sdmGoal: 'vertraulichkeit',
title: 'Unbeabsichtigte Offenlegung in Logs/Debugging',
description: 'Personenbezogene Daten gelangen in Protokolldateien, Fehlermeldungen oder Debug-Ausgaben und werden dort nicht geschuetzt.',
impactExamples: ['Zugriff durch Unbefugte auf Logdaten', 'Langzeitspeicherung ohne Rechtsgrundlage'],
typicalLikelihood: 'medium',
typicalImpact: 'medium',
wp248Criteria: ['K4'],
applicableTo: ['api_service', 'web_application', 'cloud_storage'],
mitigationIds: ['M-CONF-08', 'M-DMIN-01'],
},
{
id: 'R-SPEC-01',
category: 'confidentiality',
sdmGoal: 'vertraulichkeit',
title: 'Kompromittierung besonderer Datenkategorien (Art. 9)',
description: 'Besonders schutzwuerdige Daten (Gesundheit, Religion, Biometrie, Gewerkschaftszugehoerigkeit) werden offengelegt oder missbraucht.',
impactExamples: ['Schwerwiegende Diskriminierung', 'Existenzielle Bedrohung', 'Soziale Ausgrenzung'],
typicalLikelihood: 'low',
typicalImpact: 'high',
wp248Criteria: ['K4', 'K7'],
applicableTo: ['hr_system', 'health_system', 'identity'],
mitigationIds: ['M-CONF-06', 'M-CONF-01', 'M-CONF-04'],
},
{
id: 'R-AUTO-05',
category: 'confidentiality',
sdmGoal: 'vertraulichkeit',
title: 'Datenleck durch KI-Training mit personenbezogenen Daten',
description: 'Personenbezogene Daten, die fuer das Training von KI-Modellen verwendet werden, koennen durch das Modell reproduziert oder extrahiert werden (Model Inversion, Membership Inference).',
impactExamples: ['Offenlegung von Trainingsdaten', 'Re-Identifizierung'],
typicalLikelihood: 'low',
typicalImpact: 'high',
wp248Criteria: ['K4', 'K8'],
applicableTo: ['ai_ml'],
mitigationIds: ['M-CONF-06', 'M-NONL-03', 'M-AUTO-04'],
},
]
export const INTEGRITY_RISKS: CatalogRisk[] = [
{
id: 'R-INT-01',
category: 'integrity',
sdmGoal: 'integritaet',
title: 'Datenmanipulation durch externen Angriff',
description: 'Personenbezogene Daten werden durch einen Cyberangriff (SQL-Injection, API-Manipulation) veraendert, ohne dass dies erkannt wird.',
impactExamples: ['Falsche Entscheidungen auf Basis manipulierter Daten', 'Rufschaedigung'],
typicalLikelihood: 'medium',
typicalImpact: 'high',
wp248Criteria: ['K4', 'K8'],
applicableTo: ['api_service', 'web_application', 'database'],
mitigationIds: ['M-INT-01', 'M-INT-02', 'M-INT-03'],
},
{
id: 'R-INT-02',
category: 'integrity',
sdmGoal: 'integritaet',
title: 'Fehlerhafte Synchronisation zwischen Systemen',
description: 'Bei der Synchronisation personenbezogener Daten zwischen verschiedenen Systemen kommt es zu Inkonsistenzen, Duplikaten oder Datenverlust.',
impactExamples: ['Falsche Kontaktdaten', 'Doppelte Verarbeitung', 'Falsche Auskuenfte'],
typicalLikelihood: 'medium',
typicalImpact: 'medium',
wp248Criteria: ['K6'],
applicableTo: ['crm', 'cloud_storage', 'erp', 'identity'],
mitigationIds: ['M-INT-04', 'M-INT-05'],
},
{
id: 'R-INT-03',
category: 'integrity',
sdmGoal: 'integritaet',
title: 'Backup-Korruption oder fehlerhafte Wiederherstellung',
description: 'Backups personenbezogener Daten sind beschaedigt, unvollstaendig oder veraltet, sodass eine zuverlaessige Wiederherstellung nicht moeglich ist.',
impactExamples: ['Datenverlust bei Wiederherstellung', 'Veraltete Datenbasis', 'Compliance-Verstoss'],
typicalLikelihood: 'low',
typicalImpact: 'high',
wp248Criteria: ['K5'],
applicableTo: ['database', 'cloud_storage', 'erp'],
mitigationIds: ['M-AVAIL-01', 'M-AVAIL-02'],
},
{
id: 'R-INT-04',
category: 'integrity',
sdmGoal: 'integritaet',
title: 'Unbemerkte Aenderung von Zugriffsrechten',
description: 'Zugriffsberechtigungen werden unbefugt oder fehlerhaft geaendert, wodurch unberechtigte Personen Zugang zu personenbezogenen Daten erhalten.',
impactExamples: ['Privilege Escalation', 'Unbefugter Datenzugriff'],
typicalLikelihood: 'medium',
typicalImpact: 'high',
wp248Criteria: ['K4'],
applicableTo: ['identity', 'cloud_storage', 'api_service'],
mitigationIds: ['M-INT-02', 'M-CONF-04'],
},
{
id: 'R-INT-05',
category: 'integrity',
sdmGoal: 'integritaet',
title: 'Fehlende Nachvollziehbarkeit von Datenveraenderungen',
description: 'Aenderungen an personenbezogenen Daten werden nicht protokolliert, sodass Manipulationen oder Fehler nicht erkannt oder nachvollzogen werden koennen.',
impactExamples: ['Unmoeglich festzustellen wer/wann Daten geaendert hat', 'Audit-Versagen'],
typicalLikelihood: 'medium',
typicalImpact: 'medium',
wp248Criteria: ['K3'],
applicableTo: ['database', 'crm', 'erp', 'web_application'],
mitigationIds: ['M-INT-02', 'M-TRANS-02'],
},
{
id: 'R-ORG-03',
category: 'integrity',
sdmGoal: 'integritaet',
title: 'Unzureichende Schulung/Sensibilisierung der Mitarbeiter',
description: 'Mitarbeiter sind nicht ausreichend im Umgang mit personenbezogenen Daten geschult und verursachen durch Unkenntnis Datenpannen oder Verarbeitungsfehler.',
impactExamples: ['Versehentliche Datenweitergabe', 'Phishing-Erfolg', 'Fehlerhafte Verarbeitung'],
typicalLikelihood: 'high',
typicalImpact: 'medium',
wp248Criteria: ['K5', 'K7'],
applicableTo: ['hr_system', 'email_service', 'crm', 'web_application'],
mitigationIds: ['M-ORG-01', 'M-ORG-02'],
},
]

View File

@@ -0,0 +1,64 @@
/**
* DSFA Risikokatalog — Helpers & Assembled Catalog
*/
import type { DSFARiskCategory, SDMGoal } from '../types'
import type { CatalogRisk } from './types'
import { CONFIDENTIALITY_RISKS, INTEGRITY_RISKS } from './confidentiality-integrity'
import { AVAILABILITY_RISKS, RIGHTS_FREEDOMS_RISKS } from './availability-rights-auto-org'
export const RISK_CATALOG: CatalogRisk[] = [
...CONFIDENTIALITY_RISKS,
...INTEGRITY_RISKS,
...AVAILABILITY_RISKS,
...RIGHTS_FREEDOMS_RISKS,
]
export function getRisksByCategory(category: DSFARiskCategory): CatalogRisk[] {
return RISK_CATALOG.filter(r => r.category === category)
}
export function getRisksBySDMGoal(goal: SDMGoal): CatalogRisk[] {
return RISK_CATALOG.filter(r => r.sdmGoal === goal)
}
export function getRisksByWP248Criterion(criterionCode: string): CatalogRisk[] {
return RISK_CATALOG.filter(r => r.wp248Criteria.includes(criterionCode))
}
export function getRisksByComponent(component: string): CatalogRisk[] {
return RISK_CATALOG.filter(r => r.applicableTo.includes(component))
}
export function getCatalogRiskById(id: string): CatalogRisk | undefined {
return RISK_CATALOG.find(r => r.id === id)
}
export const RISK_CATEGORY_LABELS: Record<DSFARiskCategory, string> = {
confidentiality: 'Vertraulichkeit',
integrity: 'Integritaet',
availability: 'Verfuegbarkeit',
rights_freedoms: 'Rechte & Freiheiten',
}
export const COMPONENT_FAMILY_LABELS: Record<string, string> = {
identity: 'Identitaet & Zugang',
cloud_storage: 'Cloud-Speicher',
web_application: 'Web-Anwendung',
api_service: 'API-Service',
email_service: 'E-Mail-Dienst',
mobile_app: 'Mobile App',
database: 'Datenbank',
crm: 'CRM-System',
erp: 'ERP-System',
analytics: 'Analyse/Tracking',
marketing: 'Marketing',
ai_ml: 'KI / Machine Learning',
scoring: 'Scoring / Bewertung',
hr_system: 'HR-System',
health_system: 'Gesundheitssystem',
monitoring: 'Ueberwachungssystem',
support_system: 'Support-System',
education: 'Bildungsplattform',
research: 'Forschung',
}

View File

@@ -0,0 +1,19 @@
/**
* DSFA Risikokatalog — Types
*/
import type { DSFARiskCategory, SDMGoal } from '../types'
export interface CatalogRisk {
id: string
category: DSFARiskCategory
sdmGoal: SDMGoal
title: string
description: string
impactExamples: string[]
typicalLikelihood: 'low' | 'medium' | 'high'
typicalImpact: 'low' | 'medium' | 'high'
wp248Criteria: string[]
applicableTo: string[]
mitigationIds: string[]
}

View File

@@ -1,760 +1,13 @@
/** /**
* Loeschfristen Baseline-Katalog * Loeschfristen Baseline-Katalog — Barrel
* *
* 25 vordefinierte Aufbewahrungsfristen-Templates fuer gaengige * 25 vordefinierte Aufbewahrungsfristen-Templates fuer gaengige
* Datenobjekte in deutschen Unternehmen. Basierend auf AO, HGB, * Datenobjekte. Split into domain modules; re-exported here for backward compatibility.
* UStG, BGB, ArbZG, AGG, BDSG, BSIG und ArbMedVV.
*
* Werden genutzt, um neue Loeschfrist-Policies schnell aus
* bewaehrten Vorlagen zu erstellen.
*/ */
import type { export * from './loeschfristen-baseline-catalog/types'
LoeschfristPolicy, export * from './loeschfristen-baseline-catalog/finance-legal'
RetentionDriverType, export * from './loeschfristen-baseline-catalog/hr'
DeletionMethodType, export * from './loeschfristen-baseline-catalog/it-security'
StorageLocation, export * from './loeschfristen-baseline-catalog/marketing-crm'
PolicyStatus, export * from './loeschfristen-baseline-catalog/helpers'
ReviewInterval,
RetentionUnit,
DeletionTriggerLevel,
} from './loeschfristen-types'
import { createEmptyPolicy } from './loeschfristen-types'
// =============================================================================
// BASELINE TEMPLATE INTERFACE
// =============================================================================
export interface BaselineTemplate {
templateId: string
dataObjectName: string
description: string
affectedGroups: string[]
dataCategories: string[]
primaryPurpose: string
deletionTrigger: DeletionTriggerLevel
retentionDriver: RetentionDriverType | null
retentionDriverDetail: string
retentionDuration: number | null
retentionUnit: RetentionUnit | null
retentionDescription: string
startEvent: string
deletionMethod: DeletionMethodType
deletionMethodDetail: string
responsibleRole: string
reviewInterval: ReviewInterval
tags: string[]
}
// =============================================================================
// BASELINE TEMPLATES (25 Vorlagen)
// =============================================================================
export const BASELINE_TEMPLATES: BaselineTemplate[] = [
// ==================== 1. Personalakten ====================
{
templateId: 'personal-akten',
dataObjectName: 'Personalakten',
description:
'Vollstaendige Personalakten inkl. Arbeitsvertraege, Zeugnisse, Abmahnungen und sonstige beschaeftigungsrelevante Dokumente.',
affectedGroups: ['Mitarbeiter'],
dataCategories: ['Stammdaten', 'Vertragsdaten', 'Gehaltsdaten', 'Zeugnisse'],
primaryPurpose:
'Dokumentation und Nachweisfuehrung des Beschaeftigungsverhaeltnisses sowie Erfuellung steuerrechtlicher Aufbewahrungspflichten.',
deletionTrigger: 'RETENTION_DRIVER',
retentionDriver: 'AO_147',
retentionDriverDetail:
'Aufbewahrungspflicht gemaess 147 AO fuer steuerlich relevante Unterlagen der Personalakte.',
retentionDuration: 10,
retentionUnit: 'YEARS',
retentionDescription: '10 Jahre nach Ende des Beschaeftigungsverhaeltnisses',
startEvent: 'Ende des Beschaeftigungsverhaeltnisses',
deletionMethod: 'AUTO_DELETE',
deletionMethodDetail:
'Automatische Loeschung aller digitalen Personalakten-Dokumente nach Ablauf der Aufbewahrungsfrist. Papierakten werden datenschutzkonform vernichtet.',
responsibleRole: 'HR-Abteilung',
reviewInterval: 'ANNUAL',
tags: ['hr', 'steuer'],
},
// ==================== 2. Buchhaltungsbelege ====================
{
templateId: 'buchhaltungsbelege',
dataObjectName: 'Buchhaltungsbelege',
description:
'Buchungsbelege, Kontoauszuege, Kassenbuecher und sonstige Belege der laufenden Buchhaltung.',
affectedGroups: ['Kunden', 'Lieferanten'],
dataCategories: ['Finanzdaten', 'Transaktionsdaten', 'Kontodaten'],
primaryPurpose:
'Ordnungsgemaesse Buchfuehrung und Erfuellung handelsrechtlicher Aufbewahrungspflichten nach HGB.',
deletionTrigger: 'RETENTION_DRIVER',
retentionDriver: 'HGB_257',
retentionDriverDetail:
'Aufbewahrungspflicht gemaess 257 HGB fuer Handelsbuecher und Buchungsbelege.',
retentionDuration: 10,
retentionUnit: 'YEARS',
retentionDescription: '10 Jahre nach Ende des Geschaeftsjahres',
startEvent: 'Ende des Geschaeftsjahres',
deletionMethod: 'MANUAL_REVIEW_DELETE',
deletionMethodDetail:
'Manuelle Pruefung durch die Buchhaltung vor Loeschung, um sicherzustellen, dass keine laufenden Pruefungen oder Rechtsstreitigkeiten bestehen.',
responsibleRole: 'Buchhaltung',
reviewInterval: 'ANNUAL',
tags: ['finanzen', 'hgb'],
},
// ==================== 3. Rechnungen ====================
{
templateId: 'rechnungen',
dataObjectName: 'Rechnungen',
description:
'Eingangs- und Ausgangsrechnungen inkl. Rechnungsanhaenge und rechnungsbegruendende Unterlagen.',
affectedGroups: ['Kunden', 'Lieferanten'],
dataCategories: ['Rechnungsdaten', 'Umsatzsteuerdaten', 'Adressdaten'],
primaryPurpose:
'Dokumentation umsatzsteuerrelevanter Vorgaenge und Erfuellung der Aufbewahrungspflicht nach UStG.',
deletionTrigger: 'RETENTION_DRIVER',
retentionDriver: 'USTG_14B',
retentionDriverDetail:
'Aufbewahrungspflicht gemaess 14b UStG fuer Rechnungen und rechnungsbegruendende Unterlagen.',
retentionDuration: 10,
retentionUnit: 'YEARS',
retentionDescription: '10 Jahre ab Rechnungsdatum',
startEvent: 'Rechnungsdatum',
deletionMethod: 'AUTO_DELETE',
deletionMethodDetail:
'Automatische Loeschung nach Ablauf der 10-Jahres-Frist. Vor Loeschung wird geprueft, ob Rechnungen in laufenden Betriebspruefungen benoetigt werden.',
responsibleRole: 'Buchhaltung',
reviewInterval: 'ANNUAL',
tags: ['finanzen', 'ustg'],
},
// ==================== 4. Geschaeftsbriefe ====================
{
templateId: 'geschaeftsbriefe',
dataObjectName: 'Geschaeftsbriefe',
description:
'Empfangene und versandte Handelsbriefe, Geschaeftskorrespondenz und geschaeftsrelevante E-Mails.',
affectedGroups: ['Kunden', 'Lieferanten'],
dataCategories: ['Korrespondenz', 'Vertragskommunikation', 'Angebote'],
primaryPurpose:
'Nachweisfuehrung geschaeftlicher Kommunikation und Erfuellung der handelsrechtlichen Aufbewahrungspflicht fuer Handelsbriefe.',
deletionTrigger: 'RETENTION_DRIVER',
retentionDriver: 'HGB_257',
retentionDriverDetail:
'Aufbewahrungspflicht gemaess 257 HGB fuer empfangene und versandte Handelsbriefe (6 Jahre).',
retentionDuration: 6,
retentionUnit: 'YEARS',
retentionDescription: '6 Jahre ab Eingang oder Versand des Geschaeftsbriefes',
startEvent: 'Eingang bzw. Versand des Geschaeftsbriefes',
deletionMethod: 'MANUAL_REVIEW_DELETE',
deletionMethodDetail:
'Manuelle Pruefung durch die Geschaeftsleitung, da Geschaeftsbriefe ggf. als Beweismittel in Rechtsstreitigkeiten dienen koennen.',
responsibleRole: 'Geschaeftsleitung',
reviewInterval: 'ANNUAL',
tags: ['kommunikation', 'hgb'],
},
// ==================== 5. Bewerbungsunterlagen ====================
{
templateId: 'bewerbungsunterlagen',
dataObjectName: 'Bewerbungsunterlagen',
description:
'Eingereichte Bewerbungsunterlagen inkl. Anschreiben, Lebenslauf, Zeugnisse und Korrespondenz mit Bewerbern.',
affectedGroups: ['Bewerber'],
dataCategories: ['Bewerbungsdaten', 'Qualifikationen', 'Kontaktdaten'],
primaryPurpose:
'Durchfuehrung des Bewerbungsverfahrens und Absicherung gegen Entschaedigungsansprueche nach dem AGG.',
deletionTrigger: 'RETENTION_DRIVER',
retentionDriver: 'AGG_15',
retentionDriverDetail:
'Aufbewahrung fuer 6 Monate nach Absage gemaess 15 Abs. 4 AGG (Frist fuer Geltendmachung von Entschaedigungsanspruechen).',
retentionDuration: 6,
retentionUnit: 'MONTHS',
retentionDescription: '6 Monate nach Absage oder Stellenbesetzung',
startEvent: 'Absage oder endgueltige Stellenbesetzung',
deletionMethod: 'AUTO_DELETE',
deletionMethodDetail:
'Automatische Loeschung aller Bewerbungsunterlagen und zugehoeriger Kommunikation nach Ablauf der 6-Monats-Frist.',
responsibleRole: 'HR-Abteilung',
reviewInterval: 'QUARTERLY',
tags: ['hr', 'bewerbung'],
},
// ==================== 6. Kundenstammdaten ====================
{
templateId: 'kundenstammdaten',
dataObjectName: 'Kundenstammdaten',
description:
'Stammdaten von Kunden inkl. Kontaktdaten, Anschrift, Kundennummer und Kommunikationspraeferenzen.',
affectedGroups: ['Kunden'],
dataCategories: ['Stammdaten', 'Kontaktdaten', 'Adressdaten'],
primaryPurpose:
'Pflege der Kundenbeziehung, Vertragserfuellung und Absicherung gegen Verjaehrung vertraglicher Ansprueche.',
deletionTrigger: 'RETENTION_DRIVER',
retentionDriver: 'BGB_195',
retentionDriverDetail:
'Aufbewahrung fuer die Dauer der regelmaessigen Verjaehrungsfrist gemaess 195 BGB (3 Jahre).',
retentionDuration: 3,
retentionUnit: 'YEARS',
retentionDescription: '3 Jahre nach letzter geschaeftlicher Interaktion',
startEvent: 'Letzte geschaeftliche Interaktion mit dem Kunden',
deletionMethod: 'MANUAL_REVIEW_DELETE',
deletionMethodDetail:
'Manuelle Pruefung durch den Vertrieb vor Loeschung, um sicherzustellen, dass keine aktiven Geschaeftsbeziehungen oder offenen Forderungen bestehen.',
responsibleRole: 'Vertrieb',
reviewInterval: 'ANNUAL',
tags: ['crm', 'kunden'],
},
// ==================== 7. Newsletter-Einwilligungen ====================
{
templateId: 'newsletter-einwilligungen',
dataObjectName: 'Newsletter-Einwilligungen',
description:
'Einwilligungserklaerungen fuer den Newsletter-Versand inkl. Double-Opt-in-Nachweis und Abmeldezeitpunkt.',
affectedGroups: ['Abonnenten'],
dataCategories: ['Einwilligungsdaten', 'E-Mail-Adresse', 'Opt-in-Nachweis'],
primaryPurpose:
'Nachweis der wirksamen Einwilligung zum Newsletter-Versand gemaess Art. 7 DSGVO und Dokumentation des Widerrufs.',
deletionTrigger: 'PURPOSE_END',
retentionDriver: null,
retentionDriverDetail:
'Keine gesetzliche Aufbewahrungspflicht. Daten werden bis zum Widerruf der Einwilligung gespeichert.',
retentionDuration: null,
retentionUnit: null,
retentionDescription: 'Bis zum Widerruf der Einwilligung durch den Abonnenten',
startEvent: 'Widerruf der Einwilligung durch den Abonnenten',
deletionMethod: 'AUTO_DELETE',
deletionMethodDetail:
'Automatische Loeschung der personenbezogenen Daten nach Eingang des Widerrufs. Der Einwilligungsnachweis selbst wird fuer die Dauer der Nachweispflicht aufbewahrt.',
responsibleRole: 'Marketing',
reviewInterval: 'SEMI_ANNUAL',
tags: ['marketing', 'einwilligung'],
},
// ==================== 8. Webserver-Logs ====================
{
templateId: 'webserver-logs',
dataObjectName: 'Webserver-Logs',
description:
'Server-Zugriffsprotokolle inkl. IP-Adressen, Zeitstempel, aufgerufene URLs und HTTP-Statuscodes.',
affectedGroups: ['Website-Besucher'],
dataCategories: ['IP-Adressen', 'Zugriffszeitpunkte', 'User-Agent-Daten'],
primaryPurpose:
'Sicherstellung der IT-Sicherheit, Erkennung von Angriffen und Stoerungen sowie Erfuellung der Protokollierungspflicht nach BSIG.',
deletionTrigger: 'RETENTION_DRIVER',
retentionDriver: 'BSIG',
retentionDriverDetail:
'Aufbewahrung gemaess BSI-Gesetz / IT-Sicherheitsgesetz 2.0 fuer die Analyse von Sicherheitsvorfaellen.',
retentionDuration: 7,
retentionUnit: 'DAYS',
retentionDescription: '7 Tage nach Zeitpunkt des Zugriffs',
startEvent: 'Zeitpunkt des Server-Zugriffs',
deletionMethod: 'AUTO_DELETE',
deletionMethodDetail:
'Automatische Rotation und Loeschung der Logdateien nach 7 Tagen durch den Webserver (logrotate).',
responsibleRole: 'IT-Abteilung',
reviewInterval: 'QUARTERLY',
tags: ['it', 'logs'],
},
// ==================== 9. Videoueberwachung ====================
{
templateId: 'videoueberwachung',
dataObjectName: 'Videoueberwachung',
description:
'Aufnahmen der Videoueberwachung in Geschaeftsraeumen, Eingangsbereichen und Parkplaetzen.',
affectedGroups: ['Besucher', 'Mitarbeiter'],
dataCategories: ['Videodaten', 'Bilddaten', 'Zeitstempel'],
primaryPurpose:
'Schutz des Eigentums und der Sicherheit von Personen sowie Aufklaerung von Vorfaellen in den ueberwachten Bereichen.',
deletionTrigger: 'RETENTION_DRIVER',
retentionDriver: 'BDSG_35',
retentionDriverDetail:
'Unverzuegliche Loeschung nach Zweckwegfall gemaess 35 BDSG bzw. Art. 17 DSGVO. Maximale Speicherdauer 48 Stunden.',
retentionDuration: 2,
retentionUnit: 'DAYS',
retentionDescription: '48 Stunden (2 Tage) nach Aufnahmezeitpunkt',
startEvent: 'Aufnahmezeitpunkt der Videosequenz',
deletionMethod: 'AUTO_DELETE',
deletionMethodDetail:
'Automatisches Ueberschreiben der Aufnahmen durch das Videomanagementsystem nach Ablauf der 48-Stunden-Frist.',
responsibleRole: 'Facility Management',
reviewInterval: 'QUARTERLY',
tags: ['sicherheit', 'video'],
},
// ==================== 10. Gehaltsabrechnungen ====================
{
templateId: 'gehaltsabrechnungen',
dataObjectName: 'Gehaltsabrechnungen',
description:
'Monatliche Gehaltsabrechnungen, Lohnsteuerbescheinigungen und Sozialversicherungsmeldungen.',
affectedGroups: ['Mitarbeiter'],
dataCategories: ['Gehaltsdaten', 'Steuerdaten', 'Sozialversicherungsdaten'],
primaryPurpose:
'Dokumentation der Lohn- und Gehaltszahlungen sowie Erfuellung steuerrechtlicher und sozialversicherungsrechtlicher Aufbewahrungspflichten.',
deletionTrigger: 'RETENTION_DRIVER',
retentionDriver: 'AO_147',
retentionDriverDetail:
'Aufbewahrungspflicht gemaess 147 AO fuer lohnsteuerrelevante Unterlagen und Gehaltsbuchungen.',
retentionDuration: 10,
retentionUnit: 'YEARS',
retentionDescription: '10 Jahre nach Ende des Geschaeftsjahres',
startEvent: 'Ende des Geschaeftsjahres der jeweiligen Abrechnung',
deletionMethod: 'AUTO_DELETE',
deletionMethodDetail:
'Automatische Loeschung der digitalen Gehaltsabrechnungen nach Ablauf der Aufbewahrungsfrist. Papierbelege werden datenschutzkonform vernichtet.',
responsibleRole: 'Lohnbuchhaltung',
reviewInterval: 'ANNUAL',
tags: ['hr', 'steuer'],
},
// ==================== 11. Vertraege ====================
{
templateId: 'vertraege',
dataObjectName: 'Vertraege',
description:
'Geschaeftsvertraege, Rahmenvereinbarungen, Dienstleistungsvertraege und zugehoerige Anlagen und Nachtraege.',
affectedGroups: ['Vertragspartner'],
dataCategories: ['Vertragsdaten', 'Kontaktdaten', 'Konditionen'],
primaryPurpose:
'Dokumentation vertraglicher Vereinbarungen und Sicherung von Beweismitteln fuer die Dauer moeglicher Rechtsstreitigkeiten.',
deletionTrigger: 'RETENTION_DRIVER',
retentionDriver: 'HGB_257',
retentionDriverDetail:
'Aufbewahrungspflicht gemaess 257 HGB fuer handelsrechtlich relevante Vertragsunterlagen.',
retentionDuration: 10,
retentionUnit: 'YEARS',
retentionDescription: '10 Jahre nach Ende der Vertragslaufzeit',
startEvent: 'Ende der Vertragslaufzeit bzw. Vertragsbeendigung',
deletionMethod: 'MANUAL_REVIEW_DELETE',
deletionMethodDetail:
'Manuelle Pruefung durch die Rechtsabteilung vor Loeschung, um sicherzustellen, dass keine laufenden oder angedrohten Rechtsstreitigkeiten bestehen.',
responsibleRole: 'Rechtsabteilung',
reviewInterval: 'ANNUAL',
tags: ['recht', 'vertraege'],
},
// ==================== 12. Zeiterfassungsdaten ====================
{
templateId: 'zeiterfassung',
dataObjectName: 'Zeiterfassungsdaten',
description:
'Arbeitszeitaufzeichnungen inkl. Beginn, Ende, Pausen und Ueberstunden der Beschaeftigten.',
affectedGroups: ['Mitarbeiter'],
dataCategories: ['Arbeitszeiten', 'Pausenzeiten', 'Ueberstunden'],
primaryPurpose:
'Erfuellung der gesetzlichen Aufzeichnungspflicht fuer Arbeitszeiten und Nachweis der Einhaltung des Arbeitszeitgesetzes.',
deletionTrigger: 'RETENTION_DRIVER',
retentionDriver: 'ARBZG_16',
retentionDriverDetail:
'Aufbewahrungspflicht gemaess 16 Abs. 2 ArbZG fuer Aufzeichnungen ueber die Arbeitszeit.',
retentionDuration: 2,
retentionUnit: 'YEARS',
retentionDescription: '2 Jahre nach Ende des Erfassungszeitraums',
startEvent: 'Ende des jeweiligen Erfassungszeitraums',
deletionMethod: 'AUTO_DELETE',
deletionMethodDetail:
'Automatische Loeschung der Zeiterfassungsdaten nach Ablauf der 2-Jahres-Frist im Zeiterfassungssystem.',
responsibleRole: 'HR-Abteilung',
reviewInterval: 'ANNUAL',
tags: ['hr', 'arbzg'],
},
// ==================== 13. Krankmeldungen ====================
{
templateId: 'krankmeldungen',
dataObjectName: 'Krankmeldungen',
description:
'Arbeitsunfaehigkeitsbescheinigungen, Krankmeldungen und zugehoerige Abwesenheitsdokumentationen.',
affectedGroups: ['Mitarbeiter'],
dataCategories: ['Gesundheitsdaten', 'Abwesenheitszeiten', 'AU-Bescheinigungen'],
primaryPurpose:
'Dokumentation von Fehlzeiten, Entgeltfortzahlung im Krankheitsfall und Absicherung gegen Verjaehrung arbeitsrechtlicher Ansprueche.',
deletionTrigger: 'RETENTION_DRIVER',
retentionDriver: 'BGB_195',
retentionDriverDetail:
'Aufbewahrung fuer die Dauer der regelmaessigen Verjaehrungsfrist gemaess 195 BGB zur Absicherung von Erstattungsanspruechen.',
retentionDuration: 3,
retentionUnit: 'YEARS',
retentionDescription: '3 Jahre nach Ende des Beschaeftigungsverhaeltnisses',
startEvent: 'Ende des Beschaeftigungsverhaeltnisses',
deletionMethod: 'MANUAL_REVIEW_DELETE',
deletionMethodDetail:
'Manuelle Pruefung durch die HR-Abteilung vor Loeschung, da Krankmeldungen besondere Kategorien personenbezogener Daten (Gesundheitsdaten) enthalten.',
responsibleRole: 'HR-Abteilung',
reviewInterval: 'ANNUAL',
tags: ['hr', 'gesundheit'],
},
// ==================== 14. Steuererklaerungen ====================
{
templateId: 'steuererklaerungen',
dataObjectName: 'Steuererklaerungen',
description:
'Koerperschaftsteuer-, Gewerbesteuer- und Umsatzsteuererklaerungen inkl. Anlagen und Bescheide.',
affectedGroups: ['Unternehmen'],
dataCategories: ['Steuerdaten', 'Finanzkennzahlen', 'Bescheide'],
primaryPurpose:
'Erfuellung steuerrechtlicher Dokumentationspflichten und Nachweisfuehrung gegenueber den Finanzbehoerden.',
deletionTrigger: 'RETENTION_DRIVER',
retentionDriver: 'AO_147',
retentionDriverDetail:
'Aufbewahrungspflicht gemaess 147 AO fuer Steuererklaerungen und zugehoerige Unterlagen.',
retentionDuration: 10,
retentionUnit: 'YEARS',
retentionDescription: '10 Jahre ab dem jeweiligen Steuerjahr',
startEvent: 'Ende des betreffenden Steuerjahres',
deletionMethod: 'AUTO_DELETE',
deletionMethodDetail:
'Automatische Loeschung nach Ablauf der 10-Jahres-Frist, sofern keine laufende Betriebspruefung oder Einspruchsverfahren vorliegen.',
responsibleRole: 'Steuerberater/Buchhaltung',
reviewInterval: 'ANNUAL',
tags: ['finanzen', 'steuer'],
},
// ==================== 15. Gesellschafterprotokolle ====================
{
templateId: 'protokolle-gesellschafter',
dataObjectName: 'Gesellschafterprotokolle',
description:
'Protokolle der Gesellschafterversammlungen, Beschluesse, Abstimmungsergebnisse und notarielle Urkunden.',
affectedGroups: ['Gesellschafter'],
dataCategories: ['Beschlussdaten', 'Abstimmungsergebnisse', 'Protokolle'],
primaryPurpose:
'Dokumentation gesellschaftsrechtlicher Beschluesse und Erfuellung handelsrechtlicher Aufbewahrungspflichten.',
deletionTrigger: 'RETENTION_DRIVER',
retentionDriver: 'HGB_257',
retentionDriverDetail:
'Aufbewahrungspflicht gemaess 257 HGB fuer Eroeffnungsbilanzen, Jahresabschluesse und zugehoerige Beschluesse.',
retentionDuration: 10,
retentionUnit: 'YEARS',
retentionDescription: '10 Jahre ab Beschlussdatum',
startEvent: 'Datum des jeweiligen Gesellschafterbeschlusses',
deletionMethod: 'PHYSICAL_DESTROY',
deletionMethodDetail:
'Physische Vernichtung der Papieroriginale durch zertifizierten Aktenvernichtungsdienstleister (DIN 66399, Sicherheitsstufe P-4). Digitale Kopien werden parallel geloescht.',
responsibleRole: 'Geschaeftsleitung',
reviewInterval: 'ANNUAL',
tags: ['recht', 'gesellschaft'],
},
// ==================== 16. CRM-Kontakthistorie ====================
{
templateId: 'crm-kontakthistorie',
dataObjectName: 'CRM-Kontakthistorie',
description:
'Kontaktverlauf im CRM-System inkl. Anrufe, E-Mails, Termine, Notizen und Angebotsverlauf.',
affectedGroups: ['Kunden', 'Interessenten'],
dataCategories: ['Kommunikationsdaten', 'Interaktionshistorie', 'Angebotsdaten'],
primaryPurpose:
'Pflege der Kundenbeziehung und Nachverfolgung geschaeftlicher Interaktionen fuer Vertriebs- und Servicezwecke.',
deletionTrigger: 'RETENTION_DRIVER',
retentionDriver: 'BGB_195',
retentionDriverDetail:
'Aufbewahrung fuer die Dauer der regelmaessigen Verjaehrungsfrist gemaess 195 BGB zur Absicherung vertraglicher Ansprueche.',
retentionDuration: 3,
retentionUnit: 'YEARS',
retentionDescription: '3 Jahre nach letztem Kontakt mit dem Kunden oder Interessenten',
startEvent: 'Letzter dokumentierter Kontakt im CRM-System',
deletionMethod: 'ANONYMIZATION',
deletionMethodDetail:
'Anonymisierung der personenbezogenen Daten im CRM-System, sodass statistische Auswertungen weiterhin moeglich sind, aber kein Personenbezug mehr hergestellt werden kann.',
responsibleRole: 'Vertrieb',
reviewInterval: 'SEMI_ANNUAL',
tags: ['crm', 'kunden'],
},
// ==================== 17. Backup-Daten ====================
{
templateId: 'backup-daten',
dataObjectName: 'Backup-Daten',
description:
'Vollstaendige und inkrementelle Sicherungskopien aller Systeme, Datenbanken und Dateisysteme.',
affectedGroups: ['Alle Betroffenengruppen'],
dataCategories: ['Systemsicherungen', 'Datenbankkopien', 'Dateisystemsicherungen'],
primaryPurpose:
'Sicherstellung der Datenwiederherstellung im Katastrophenfall und Gewaehrleistung der Geschaeftskontinuitaet.',
deletionTrigger: 'RETENTION_DRIVER',
retentionDriver: 'BSIG',
retentionDriverDetail:
'Aufbewahrung von Backups fuer 90 Tage gemaess BSI-Grundschutz-Empfehlungen zur Sicherstellung der Wiederherstellbarkeit.',
retentionDuration: 90,
retentionUnit: 'DAYS',
retentionDescription: '90 Tage nach Erstellung des Backups',
startEvent: 'Erstellungsdatum des jeweiligen Backups',
deletionMethod: 'CRYPTO_ERASE',
deletionMethodDetail:
'Kryptographische Loeschung durch Vernichtung der Verschluesselungsschluessel, sodass die verschluesselten Backup-Daten nicht mehr entschluesselt werden koennen.',
responsibleRole: 'IT-Abteilung',
reviewInterval: 'QUARTERLY',
tags: ['it', 'backup'],
},
// ==================== 18. Cookie-Consent-Nachweise ====================
{
templateId: 'cookie-consent-logs',
dataObjectName: 'Cookie-Consent-Nachweise',
description:
'Nachweise ueber Cookie-Einwilligungen der Website-Besucher inkl. Consent-ID, Zeitstempel, gesetzte Praeferenzen und IP-Adresse.',
affectedGroups: ['Website-Besucher'],
dataCategories: ['Consent-Daten', 'IP-Adressen', 'Zeitstempel', 'Praeferenzen'],
primaryPurpose:
'Nachweisfuehrung der Einwilligung in die Cookie-Nutzung gemaess Art. 7 Abs. 1 DSGVO und ePrivacy-Richtlinie.',
deletionTrigger: 'RETENTION_DRIVER',
retentionDriver: 'BGB_195',
retentionDriverDetail:
'Aufbewahrung der Consent-Nachweise fuer die Dauer der regelmaessigen Verjaehrungsfrist gemaess 195 BGB zur Absicherung gegen Abmahnungen.',
retentionDuration: 3,
retentionUnit: 'YEARS',
retentionDescription: '3 Jahre nach Zeitpunkt der Einwilligung',
startEvent: 'Zeitpunkt der Cookie-Einwilligung (Consent-Zeitstempel)',
deletionMethod: 'AUTO_DELETE',
deletionMethodDetail:
'Automatische Loeschung der Consent-Nachweise nach Ablauf der 3-Jahres-Frist durch das Consent-Management-System.',
responsibleRole: 'Datenschutzbeauftragter',
reviewInterval: 'ANNUAL',
tags: ['datenschutz', 'consent'],
},
// ==================== 19. E-Mail-Archivierung ====================
{
templateId: 'email-archivierung',
dataObjectName: 'E-Mail-Archivierung',
description:
'Archivierte geschaeftliche E-Mails inkl. Anhaenge, die als Handelsbriefe oder steuerrelevante Korrespondenz einzustufen sind.',
affectedGroups: ['Mitarbeiter', 'Kunden', 'Lieferanten'],
dataCategories: ['E-Mail-Korrespondenz', 'Anhaenge', 'Metadaten'],
primaryPurpose:
'Erfuellung der handelsrechtlichen Aufbewahrungspflicht fuer geschaeftliche Korrespondenz, die als Handelsbrief einzuordnen ist.',
deletionTrigger: 'RETENTION_DRIVER',
retentionDriver: 'HGB_257',
retentionDriverDetail:
'Aufbewahrungspflicht gemaess 257 HGB fuer empfangene und versandte Handelsbriefe (6 Jahre) bzw. buchhalterisch relevante E-Mails (10 Jahre).',
retentionDuration: 6,
retentionUnit: 'YEARS',
retentionDescription: '6 Jahre nach Versand/Empfang der E-Mail',
startEvent: 'Versand- bzw. Empfangsdatum der E-Mail',
deletionMethod: 'AUTO_DELETE',
deletionMethodDetail:
'Automatische Loeschung durch das E-Mail-Archivierungssystem nach Ablauf der konfigurierten Aufbewahrungsfrist. Vor Loeschung wird geprueft, ob die E-Mail in laufenden Verfahren benoetigt wird.',
responsibleRole: 'IT-Abteilung',
reviewInterval: 'ANNUAL',
tags: ['kommunikation', 'hgb'],
},
// ==================== 20. Zutrittsprotokolle ====================
{
templateId: 'zutrittsprotokolle',
dataObjectName: 'Zutrittsprotokolle',
description:
'Protokolle des Zutrittskontrollsystems inkl. Zeitstempel, Kartennummer, Zutrittsort und Zugangsentscheidung (gewaehrt/verweigert).',
affectedGroups: ['Mitarbeiter', 'Besucher'],
dataCategories: ['Zutrittsdaten', 'Zeitstempel', 'Kartennummern', 'Standortdaten'],
primaryPurpose:
'Sicherstellung der physischen Sicherheit, Nachvollziehbarkeit von Zutritten und Unterstuetzung bei der Aufklaerung von Sicherheitsvorfaellen.',
deletionTrigger: 'RETENTION_DRIVER',
retentionDriver: 'BSIG',
retentionDriverDetail:
'Aufbewahrung gemaess BSI-Grundschutz-Empfehlung fuer Zutrittsprotokolle zur Analyse von Sicherheitsvorfaellen (90 Tage).',
retentionDuration: 90,
retentionUnit: 'DAYS',
retentionDescription: '90 Tage nach Zeitpunkt des Zutritts',
startEvent: 'Zeitpunkt des protokollierten Zutrittsereignisses',
deletionMethod: 'AUTO_DELETE',
deletionMethodDetail:
'Automatische Rotation und Loeschung der Zutrittsprotokolle durch das Zutrittskontrollsystem nach Ablauf der 90-Tage-Frist.',
responsibleRole: 'Facility Management',
reviewInterval: 'QUARTERLY',
tags: ['sicherheit', 'zutritt'],
},
// ==================== 21. Schulungsnachweise ====================
{
templateId: 'schulungsnachweise',
dataObjectName: 'Schulungsnachweise',
description:
'Teilnahmebestaetigungen, Zertifikate und Protokolle von Mitarbeiterschulungen (Datenschutz, Arbeitssicherheit, Compliance).',
affectedGroups: ['Mitarbeiter'],
dataCategories: ['Schulungsdaten', 'Zertifikate', 'Teilnahmelisten'],
primaryPurpose:
'Nachweis der Durchfuehrung gesetzlich vorgeschriebener Schulungen und Dokumentation der Mitarbeiterqualifikation.',
deletionTrigger: 'RETENTION_DRIVER',
retentionDriver: 'CUSTOM',
retentionDriverDetail:
'Aufbewahrung fuer 3 Jahre nach Ende des Beschaeftigungsverhaeltnisses als Nachweis der ordnungsgemaessen Schulungsdurchfuehrung.',
retentionDuration: 3,
retentionUnit: 'YEARS',
retentionDescription: '3 Jahre nach Ende des Beschaeftigungsverhaeltnisses',
startEvent: 'Ende des Beschaeftigungsverhaeltnisses des geschulten Mitarbeiters',
deletionMethod: 'MANUAL_REVIEW_DELETE',
deletionMethodDetail:
'Manuelle Pruefung durch die HR-Abteilung vor Loeschung, da Schulungsnachweise als Compliance-Nachweis in Audits relevant sein koennen.',
responsibleRole: 'HR-Abteilung',
reviewInterval: 'ANNUAL',
tags: ['hr', 'schulung'],
},
// ==================== 22. Betriebsarzt-Dokumentation ====================
{
templateId: 'betriebsarzt-doku',
dataObjectName: 'Betriebsarzt-Dokumentation',
description:
'Ergebnisse arbeitsmedizinischer Vorsorgeuntersuchungen, Eignungsuntersuchungen und arbeitsmedizinische Empfehlungen.',
affectedGroups: ['Mitarbeiter'],
dataCategories: ['Gesundheitsdaten', 'Vorsorgeuntersuchungen', 'Eignungsbefunde'],
primaryPurpose:
'Erfuellung der Dokumentationspflicht fuer arbeitsmedizinische Vorsorge gemaess ArbMedVV und Nachweisfuehrung gegenueber Berufsgenossenschaften.',
deletionTrigger: 'RETENTION_DRIVER',
retentionDriver: 'CUSTOM',
retentionDriverDetail:
'Aufbewahrungspflicht gemaess ArbMedVV (Verordnung zur arbeitsmedizinischen Vorsorge) und Berufsgenossenschaftliche Grundsaetze: bis zu 40 Jahre bei Exposition gegenueber krebserzeugenden Gefahrstoffen.',
retentionDuration: 40,
retentionUnit: 'YEARS',
retentionDescription: '40 Jahre nach letzter Exposition (bei Gefahrstoffen), sonst 10 Jahre nach Ende der Taetigkeit',
startEvent: 'Ende der expositionsrelevanten Taetigkeit bzw. Ende des Beschaeftigungsverhaeltnisses',
deletionMethod: 'PHYSICAL_DESTROY',
deletionMethodDetail:
'Physische Vernichtung der Papierunterlagen durch zertifizierten Aktenvernichtungsdienstleister (DIN 66399, Sicherheitsstufe P-5). Digitale Daten werden kryptographisch geloescht.',
responsibleRole: 'Betriebsarzt / Arbeitsmedizinischer Dienst',
reviewInterval: 'ANNUAL',
tags: ['hr', 'gesundheit'],
},
// ==================== 23. Kundenreklamationen ====================
{
templateId: 'kundenreklamationen',
dataObjectName: 'Kundenreklamationen',
description:
'Reklamationsvorgaenge inkl. Beschwerdeinhalt, Kommunikationsverlauf, Massnahmen und Ergebnis der Reklamationsbearbeitung.',
affectedGroups: ['Kunden'],
dataCategories: ['Reklamationsdaten', 'Kommunikation', 'Massnahmenprotokolle'],
primaryPurpose:
'Dokumentation und Bearbeitung von Kundenreklamationen, Qualitaetssicherung und Absicherung gegen Gewaehrleistungsansprueche.',
deletionTrigger: 'RETENTION_DRIVER',
retentionDriver: 'BGB_195',
retentionDriverDetail:
'Aufbewahrung fuer die Dauer der regelmaessigen Verjaehrungsfrist gemaess 195 BGB (3 Jahre) zur Absicherung gegen Gewaehrleistungs- und Schadensersatzansprueche.',
retentionDuration: 3,
retentionUnit: 'YEARS',
retentionDescription: '3 Jahre nach Abschluss des Reklamationsvorgangs',
startEvent: 'Abschluss des Reklamationsvorgangs (letzte Massnahme)',
deletionMethod: 'ANONYMIZATION',
deletionMethodDetail:
'Anonymisierung der personenbezogenen Daten nach Ablauf der Frist. Anonymisierte Reklamationsstatistiken bleiben fuer die Qualitaetssicherung erhalten.',
responsibleRole: 'Qualitaetsmanagement',
reviewInterval: 'ANNUAL',
tags: ['kunden', 'qualitaet'],
},
// ==================== 24. Lieferantenbewertungen ====================
{
templateId: 'lieferantenbewertungen',
dataObjectName: 'Lieferantenbewertungen',
description:
'Bewertungen und Auditergebnisse von Lieferanten und Auftragsverarbeitern inkl. Qualitaets-, Compliance- und Datenschutz-Bewertungen.',
affectedGroups: ['Lieferanten', 'Auftragsverarbeiter'],
dataCategories: ['Bewertungsdaten', 'Auditberichte', 'Vertragsdaten'],
primaryPurpose:
'Dokumentation der Sorgfaltspflicht bei der Auswahl und Ueberwachung von Auftragsverarbeitern gemaess Art. 28 DSGVO und Qualitaetssicherung in der Lieferkette.',
deletionTrigger: 'RETENTION_DRIVER',
retentionDriver: 'HGB_257',
retentionDriverDetail:
'Aufbewahrung gemaess 257 HGB als handelsrelevante Unterlagen sowie zur Nachweisfuehrung der Sorgfaltspflicht bei der Auftragsverarbeitung.',
retentionDuration: 6,
retentionUnit: 'YEARS',
retentionDescription: '6 Jahre nach Ende der Geschaeftsbeziehung',
startEvent: 'Ende der Geschaeftsbeziehung mit dem Lieferanten/Auftragsverarbeiter',
deletionMethod: 'MANUAL_REVIEW_DELETE',
deletionMethodDetail:
'Manuelle Pruefung durch den Einkauf/Compliance-Abteilung vor Loeschung, um sicherzustellen, dass keine Nachweispflichten aus laufenden Vertraegen oder Audits bestehen.',
responsibleRole: 'Einkauf / Compliance',
reviewInterval: 'ANNUAL',
tags: ['lieferanten', 'einkauf'],
},
// ==================== 25. Social-Media-Marketingdaten ====================
{
templateId: 'social-media-daten',
dataObjectName: 'Social-Media-Marketingdaten',
description:
'Personenbezogene Daten aus Social-Media-Kampagnen inkl. Nutzerinteraktionen, Custom Audiences, Retargeting-Listen und Kampagnen-Analytics.',
affectedGroups: ['Kunden', 'Interessenten', 'Website-Besucher'],
dataCategories: ['Interaktionsdaten', 'Zielgruppendaten', 'Tracking-Daten', 'Profilmerkmale'],
primaryPurpose:
'Durchfuehrung zielgerichteter Marketing-Kampagnen auf Social-Media-Plattformen und Analyse der Kampagneneffektivitaet.',
deletionTrigger: 'PURPOSE_END',
retentionDriver: null,
retentionDriverDetail:
'Keine gesetzliche Aufbewahrungspflicht. Daten werden bis zum Widerruf der Einwilligung bzw. bis zum Ende der Kampagne gespeichert (Art. 6 Abs. 1 lit. a DSGVO).',
retentionDuration: null,
retentionUnit: null,
retentionDescription: 'Bis zum Widerruf der Einwilligung oder Ende des Kampagnenzwecks',
startEvent: 'Widerruf der Einwilligung oder Ende der Marketing-Kampagne',
deletionMethod: 'AUTO_DELETE',
deletionMethodDetail:
'Automatische Loeschung der personenbezogenen Daten in den Social-Media-Werbekonten und internen Systemen nach Zweckwegfall. Custom Audiences werden bei Plattformanbietern geloescht.',
responsibleRole: 'Marketing',
reviewInterval: 'SEMI_ANNUAL',
tags: ['marketing', 'social'],
},
]
// =============================================================================
// HELPER FUNCTIONS
// =============================================================================
/**
* Erstellt eine vollstaendige LoeschfristPolicy aus einem BaselineTemplate.
* Nutzt createEmptyPolicy() als Basis und ueberlagert die Template-Felder.
*/
export function templateToPolicy(template: BaselineTemplate): LoeschfristPolicy {
const base = createEmptyPolicy()
return {
...base,
dataObjectName: template.dataObjectName,
description: template.description,
affectedGroups: [...template.affectedGroups],
dataCategories: [...template.dataCategories],
primaryPurpose: template.primaryPurpose,
deletionTrigger: template.deletionTrigger,
retentionDriver: template.retentionDriver,
retentionDriverDetail: template.retentionDriverDetail,
retentionDuration: template.retentionDuration,
retentionUnit: template.retentionUnit,
retentionDescription: template.retentionDescription,
startEvent: template.startEvent,
deletionMethod: template.deletionMethod,
deletionMethodDetail: template.deletionMethodDetail,
responsibleRole: template.responsibleRole,
reviewInterval: template.reviewInterval,
tags: [...template.tags],
}
}
/**
* Gibt alle Templates zurueck, die einen bestimmten Tag enthalten.
*/
export function getTemplatesByTag(tag: string): BaselineTemplate[] {
return BASELINE_TEMPLATES.filter(t => t.tags.includes(tag))
}
/**
* Findet ein Template anhand seiner templateId.
*/
export function getTemplateById(templateId: string): BaselineTemplate | undefined {
return BASELINE_TEMPLATES.find(t => t.templateId === templateId)
}
/**
* Gibt alle im Katalog verwendeten Tags als sortierte Liste zurueck.
*/
export function getAllTemplateTags(): string[] {
const tags = new Set<string>()
BASELINE_TEMPLATES.forEach(t => t.tags.forEach(tag => tags.add(tag)))
return Array.from(tags).sort()
}

View File

@@ -0,0 +1,202 @@
/**
* Loeschfristen — Finance & Legal Templates
* Buchhaltungsbelege, Rechnungen, Geschaeftsbriefe, Steuererklaerungen,
* Gesellschafterprotokolle, Vertraege, E-Mail-Archivierung, Lieferantenbewertungen
*/
import { BaselineTemplate } from './types'
export const FINANCE_LEGAL_TEMPLATES: BaselineTemplate[] = [
{
templateId: 'buchhaltungsbelege',
dataObjectName: 'Buchhaltungsbelege',
description:
'Buchungsbelege, Kontoauszuege, Kassenbuecher und sonstige Belege der laufenden Buchhaltung.',
affectedGroups: ['Kunden', 'Lieferanten'],
dataCategories: ['Finanzdaten', 'Transaktionsdaten', 'Kontodaten'],
primaryPurpose:
'Ordnungsgemaesse Buchfuehrung und Erfuellung handelsrechtlicher Aufbewahrungspflichten nach HGB.',
deletionTrigger: 'RETENTION_DRIVER',
retentionDriver: 'HGB_257',
retentionDriverDetail:
'Aufbewahrungspflicht gemaess 257 HGB fuer Handelsbuecher und Buchungsbelege.',
retentionDuration: 10,
retentionUnit: 'YEARS',
retentionDescription: '10 Jahre nach Ende des Geschaeftsjahres',
startEvent: 'Ende des Geschaeftsjahres',
deletionMethod: 'MANUAL_REVIEW_DELETE',
deletionMethodDetail:
'Manuelle Pruefung durch die Buchhaltung vor Loeschung, um sicherzustellen, dass keine laufenden Pruefungen oder Rechtsstreitigkeiten bestehen.',
responsibleRole: 'Buchhaltung',
reviewInterval: 'ANNUAL',
tags: ['finanzen', 'hgb'],
},
{
templateId: 'rechnungen',
dataObjectName: 'Rechnungen',
description:
'Eingangs- und Ausgangsrechnungen inkl. Rechnungsanhaenge und rechnungsbegruendende Unterlagen.',
affectedGroups: ['Kunden', 'Lieferanten'],
dataCategories: ['Rechnungsdaten', 'Umsatzsteuerdaten', 'Adressdaten'],
primaryPurpose:
'Dokumentation umsatzsteuerrelevanter Vorgaenge und Erfuellung der Aufbewahrungspflicht nach UStG.',
deletionTrigger: 'RETENTION_DRIVER',
retentionDriver: 'USTG_14B',
retentionDriverDetail:
'Aufbewahrungspflicht gemaess 14b UStG fuer Rechnungen und rechnungsbegruendende Unterlagen.',
retentionDuration: 10,
retentionUnit: 'YEARS',
retentionDescription: '10 Jahre ab Rechnungsdatum',
startEvent: 'Rechnungsdatum',
deletionMethod: 'AUTO_DELETE',
deletionMethodDetail:
'Automatische Loeschung nach Ablauf der 10-Jahres-Frist. Vor Loeschung wird geprueft, ob Rechnungen in laufenden Betriebspruefungen benoetigt werden.',
responsibleRole: 'Buchhaltung',
reviewInterval: 'ANNUAL',
tags: ['finanzen', 'ustg'],
},
{
templateId: 'geschaeftsbriefe',
dataObjectName: 'Geschaeftsbriefe',
description:
'Empfangene und versandte Handelsbriefe, Geschaeftskorrespondenz und geschaeftsrelevante E-Mails.',
affectedGroups: ['Kunden', 'Lieferanten'],
dataCategories: ['Korrespondenz', 'Vertragskommunikation', 'Angebote'],
primaryPurpose:
'Nachweisfuehrung geschaeftlicher Kommunikation und Erfuellung der handelsrechtlichen Aufbewahrungspflicht fuer Handelsbriefe.',
deletionTrigger: 'RETENTION_DRIVER',
retentionDriver: 'HGB_257',
retentionDriverDetail:
'Aufbewahrungspflicht gemaess 257 HGB fuer empfangene und versandte Handelsbriefe (6 Jahre).',
retentionDuration: 6,
retentionUnit: 'YEARS',
retentionDescription: '6 Jahre ab Eingang oder Versand des Geschaeftsbriefes',
startEvent: 'Eingang bzw. Versand des Geschaeftsbriefes',
deletionMethod: 'MANUAL_REVIEW_DELETE',
deletionMethodDetail:
'Manuelle Pruefung durch die Geschaeftsleitung, da Geschaeftsbriefe ggf. als Beweismittel in Rechtsstreitigkeiten dienen koennen.',
responsibleRole: 'Geschaeftsleitung',
reviewInterval: 'ANNUAL',
tags: ['kommunikation', 'hgb'],
},
{
templateId: 'steuererklaerungen',
dataObjectName: 'Steuererklaerungen',
description:
'Koerperschaftsteuer-, Gewerbesteuer- und Umsatzsteuererklaerungen inkl. Anlagen und Bescheide.',
affectedGroups: ['Unternehmen'],
dataCategories: ['Steuerdaten', 'Finanzkennzahlen', 'Bescheide'],
primaryPurpose:
'Erfuellung steuerrechtlicher Dokumentationspflichten und Nachweisfuehrung gegenueber den Finanzbehoerden.',
deletionTrigger: 'RETENTION_DRIVER',
retentionDriver: 'AO_147',
retentionDriverDetail:
'Aufbewahrungspflicht gemaess 147 AO fuer Steuererklaerungen und zugehoerige Unterlagen.',
retentionDuration: 10,
retentionUnit: 'YEARS',
retentionDescription: '10 Jahre ab dem jeweiligen Steuerjahr',
startEvent: 'Ende des betreffenden Steuerjahres',
deletionMethod: 'AUTO_DELETE',
deletionMethodDetail:
'Automatische Loeschung nach Ablauf der 10-Jahres-Frist, sofern keine laufende Betriebspruefung oder Einspruchsverfahren vorliegen.',
responsibleRole: 'Steuerberater/Buchhaltung',
reviewInterval: 'ANNUAL',
tags: ['finanzen', 'steuer'],
},
{
templateId: 'protokolle-gesellschafter',
dataObjectName: 'Gesellschafterprotokolle',
description:
'Protokolle der Gesellschafterversammlungen, Beschluesse, Abstimmungsergebnisse und notarielle Urkunden.',
affectedGroups: ['Gesellschafter'],
dataCategories: ['Beschlussdaten', 'Abstimmungsergebnisse', 'Protokolle'],
primaryPurpose:
'Dokumentation gesellschaftsrechtlicher Beschluesse und Erfuellung handelsrechtlicher Aufbewahrungspflichten.',
deletionTrigger: 'RETENTION_DRIVER',
retentionDriver: 'HGB_257',
retentionDriverDetail:
'Aufbewahrungspflicht gemaess 257 HGB fuer Eroeffnungsbilanzen, Jahresabschluesse und zugehoerige Beschluesse.',
retentionDuration: 10,
retentionUnit: 'YEARS',
retentionDescription: '10 Jahre ab Beschlussdatum',
startEvent: 'Datum des jeweiligen Gesellschafterbeschlusses',
deletionMethod: 'PHYSICAL_DESTROY',
deletionMethodDetail:
'Physische Vernichtung der Papieroriginale durch zertifizierten Aktenvernichtungsdienstleister (DIN 66399, Sicherheitsstufe P-4). Digitale Kopien werden parallel geloescht.',
responsibleRole: 'Geschaeftsleitung',
reviewInterval: 'ANNUAL',
tags: ['recht', 'gesellschaft'],
},
{
templateId: 'vertraege',
dataObjectName: 'Vertraege',
description:
'Geschaeftsvertraege, Rahmenvereinbarungen, Dienstleistungsvertraege und zugehoerige Anlagen und Nachtraege.',
affectedGroups: ['Vertragspartner'],
dataCategories: ['Vertragsdaten', 'Kontaktdaten', 'Konditionen'],
primaryPurpose:
'Dokumentation vertraglicher Vereinbarungen und Sicherung von Beweismitteln fuer die Dauer moeglicher Rechtsstreitigkeiten.',
deletionTrigger: 'RETENTION_DRIVER',
retentionDriver: 'HGB_257',
retentionDriverDetail:
'Aufbewahrungspflicht gemaess 257 HGB fuer handelsrechtlich relevante Vertragsunterlagen.',
retentionDuration: 10,
retentionUnit: 'YEARS',
retentionDescription: '10 Jahre nach Ende der Vertragslaufzeit',
startEvent: 'Ende der Vertragslaufzeit bzw. Vertragsbeendigung',
deletionMethod: 'MANUAL_REVIEW_DELETE',
deletionMethodDetail:
'Manuelle Pruefung durch die Rechtsabteilung vor Loeschung, um sicherzustellen, dass keine laufenden oder angedrohten Rechtsstreitigkeiten bestehen.',
responsibleRole: 'Rechtsabteilung',
reviewInterval: 'ANNUAL',
tags: ['recht', 'vertraege'],
},
{
templateId: 'email-archivierung',
dataObjectName: 'E-Mail-Archivierung',
description:
'Archivierte geschaeftliche E-Mails inkl. Anhaenge, die als Handelsbriefe oder steuerrelevante Korrespondenz einzustufen sind.',
affectedGroups: ['Mitarbeiter', 'Kunden', 'Lieferanten'],
dataCategories: ['E-Mail-Korrespondenz', 'Anhaenge', 'Metadaten'],
primaryPurpose:
'Erfuellung der handelsrechtlichen Aufbewahrungspflicht fuer geschaeftliche Korrespondenz, die als Handelsbrief einzuordnen ist.',
deletionTrigger: 'RETENTION_DRIVER',
retentionDriver: 'HGB_257',
retentionDriverDetail:
'Aufbewahrungspflicht gemaess 257 HGB fuer empfangene und versandte Handelsbriefe (6 Jahre) bzw. buchhalterisch relevante E-Mails (10 Jahre).',
retentionDuration: 6,
retentionUnit: 'YEARS',
retentionDescription: '6 Jahre nach Versand/Empfang der E-Mail',
startEvent: 'Versand- bzw. Empfangsdatum der E-Mail',
deletionMethod: 'AUTO_DELETE',
deletionMethodDetail:
'Automatische Loeschung durch das E-Mail-Archivierungssystem nach Ablauf der konfigurierten Aufbewahrungsfrist. Vor Loeschung wird geprueft, ob die E-Mail in laufenden Verfahren benoetigt wird.',
responsibleRole: 'IT-Abteilung',
reviewInterval: 'ANNUAL',
tags: ['kommunikation', 'hgb'],
},
{
templateId: 'lieferantenbewertungen',
dataObjectName: 'Lieferantenbewertungen',
description:
'Bewertungen und Auditergebnisse von Lieferanten und Auftragsverarbeitern inkl. Qualitaets-, Compliance- und Datenschutz-Bewertungen.',
affectedGroups: ['Lieferanten', 'Auftragsverarbeiter'],
dataCategories: ['Bewertungsdaten', 'Auditberichte', 'Vertragsdaten'],
primaryPurpose:
'Dokumentation der Sorgfaltspflicht bei der Auswahl und Ueberwachung von Auftragsverarbeitern gemaess Art. 28 DSGVO und Qualitaetssicherung in der Lieferkette.',
deletionTrigger: 'RETENTION_DRIVER',
retentionDriver: 'HGB_257',
retentionDriverDetail:
'Aufbewahrung gemaess 257 HGB als handelsrelevante Unterlagen sowie zur Nachweisfuehrung der Sorgfaltspflicht bei der Auftragsverarbeitung.',
retentionDuration: 6,
retentionUnit: 'YEARS',
retentionDescription: '6 Jahre nach Ende der Geschaeftsbeziehung',
startEvent: 'Ende der Geschaeftsbeziehung mit dem Lieferanten/Auftragsverarbeiter',
deletionMethod: 'MANUAL_REVIEW_DELETE',
deletionMethodDetail:
'Manuelle Pruefung durch den Einkauf/Compliance-Abteilung vor Loeschung, um sicherzustellen, dass keine Nachweispflichten aus laufenden Vertraegen oder Audits bestehen.',
responsibleRole: 'Einkauf / Compliance',
reviewInterval: 'ANNUAL',
tags: ['lieferanten', 'einkauf'],
},
]

View File

@@ -0,0 +1,69 @@
/**
* Loeschfristen Baseline-Katalog — Helper Functions
*/
import type { LoeschfristPolicy } from '../loeschfristen-types'
import { createEmptyPolicy } from '../loeschfristen-types'
import type { BaselineTemplate } from './types'
import { FINANCE_LEGAL_TEMPLATES } from './finance-legal'
import { HR_TEMPLATES } from './hr'
import { IT_SECURITY_TEMPLATES } from './it-security'
import { MARKETING_CRM_TEMPLATES } from './marketing-crm'
export const BASELINE_TEMPLATES: BaselineTemplate[] = [
...HR_TEMPLATES,
...FINANCE_LEGAL_TEMPLATES,
...IT_SECURITY_TEMPLATES,
...MARKETING_CRM_TEMPLATES,
]
/**
* Erstellt eine vollstaendige LoeschfristPolicy aus einem BaselineTemplate.
*/
export function templateToPolicy(template: BaselineTemplate): LoeschfristPolicy {
const base = createEmptyPolicy()
return {
...base,
dataObjectName: template.dataObjectName,
description: template.description,
affectedGroups: [...template.affectedGroups],
dataCategories: [...template.dataCategories],
primaryPurpose: template.primaryPurpose,
deletionTrigger: template.deletionTrigger,
retentionDriver: template.retentionDriver,
retentionDriverDetail: template.retentionDriverDetail,
retentionDuration: template.retentionDuration,
retentionUnit: template.retentionUnit,
retentionDescription: template.retentionDescription,
startEvent: template.startEvent,
deletionMethod: template.deletionMethod,
deletionMethodDetail: template.deletionMethodDetail,
responsibleRole: template.responsibleRole,
reviewInterval: template.reviewInterval,
tags: [...template.tags],
}
}
/**
* Gibt alle Templates zurueck, die einen bestimmten Tag enthalten.
*/
export function getTemplatesByTag(tag: string): BaselineTemplate[] {
return BASELINE_TEMPLATES.filter(t => t.tags.includes(tag))
}
/**
* Findet ein Template anhand seiner templateId.
*/
export function getTemplateById(templateId: string): BaselineTemplate | undefined {
return BASELINE_TEMPLATES.find(t => t.templateId === templateId)
}
/**
* Gibt alle im Katalog verwendeten Tags als sortierte Liste zurueck.
*/
export function getAllTemplateTags(): string[] {
const tags = new Set<string>()
BASELINE_TEMPLATES.forEach(t => t.tags.forEach(tag => tags.add(tag)))
return Array.from(tags).sort()
}

View File

@@ -0,0 +1,178 @@
/**
* Loeschfristen — HR Templates
* Personalakten, Bewerbungsunterlagen, Gehaltsabrechnungen, Zeiterfassung,
* Krankmeldungen, Schulungsnachweise, Betriebsarzt-Dokumentation
*/
import { BaselineTemplate } from './types'
export const HR_TEMPLATES: BaselineTemplate[] = [
{
templateId: 'personal-akten',
dataObjectName: 'Personalakten',
description:
'Vollstaendige Personalakten inkl. Arbeitsvertraege, Zeugnisse, Abmahnungen und sonstige beschaeftigungsrelevante Dokumente.',
affectedGroups: ['Mitarbeiter'],
dataCategories: ['Stammdaten', 'Vertragsdaten', 'Gehaltsdaten', 'Zeugnisse'],
primaryPurpose:
'Dokumentation und Nachweisfuehrung des Beschaeftigungsverhaeltnisses sowie Erfuellung steuerrechtlicher Aufbewahrungspflichten.',
deletionTrigger: 'RETENTION_DRIVER',
retentionDriver: 'AO_147',
retentionDriverDetail:
'Aufbewahrungspflicht gemaess 147 AO fuer steuerlich relevante Unterlagen der Personalakte.',
retentionDuration: 10,
retentionUnit: 'YEARS',
retentionDescription: '10 Jahre nach Ende des Beschaeftigungsverhaeltnisses',
startEvent: 'Ende des Beschaeftigungsverhaeltnisses',
deletionMethod: 'AUTO_DELETE',
deletionMethodDetail:
'Automatische Loeschung aller digitalen Personalakten-Dokumente nach Ablauf der Aufbewahrungsfrist. Papierakten werden datenschutzkonform vernichtet.',
responsibleRole: 'HR-Abteilung',
reviewInterval: 'ANNUAL',
tags: ['hr', 'steuer'],
},
{
templateId: 'bewerbungsunterlagen',
dataObjectName: 'Bewerbungsunterlagen',
description:
'Eingereichte Bewerbungsunterlagen inkl. Anschreiben, Lebenslauf, Zeugnisse und Korrespondenz mit Bewerbern.',
affectedGroups: ['Bewerber'],
dataCategories: ['Bewerbungsdaten', 'Qualifikationen', 'Kontaktdaten'],
primaryPurpose:
'Durchfuehrung des Bewerbungsverfahrens und Absicherung gegen Entschaedigungsansprueche nach dem AGG.',
deletionTrigger: 'RETENTION_DRIVER',
retentionDriver: 'AGG_15',
retentionDriverDetail:
'Aufbewahrung fuer 6 Monate nach Absage gemaess 15 Abs. 4 AGG (Frist fuer Geltendmachung von Entschaedigungsanspruechen).',
retentionDuration: 6,
retentionUnit: 'MONTHS',
retentionDescription: '6 Monate nach Absage oder Stellenbesetzung',
startEvent: 'Absage oder endgueltige Stellenbesetzung',
deletionMethod: 'AUTO_DELETE',
deletionMethodDetail:
'Automatische Loeschung aller Bewerbungsunterlagen und zugehoeriger Kommunikation nach Ablauf der 6-Monats-Frist.',
responsibleRole: 'HR-Abteilung',
reviewInterval: 'QUARTERLY',
tags: ['hr', 'bewerbung'],
},
{
templateId: 'gehaltsabrechnungen',
dataObjectName: 'Gehaltsabrechnungen',
description:
'Monatliche Gehaltsabrechnungen, Lohnsteuerbescheinigungen und Sozialversicherungsmeldungen.',
affectedGroups: ['Mitarbeiter'],
dataCategories: ['Gehaltsdaten', 'Steuerdaten', 'Sozialversicherungsdaten'],
primaryPurpose:
'Dokumentation der Lohn- und Gehaltszahlungen sowie Erfuellung steuerrechtlicher und sozialversicherungsrechtlicher Aufbewahrungspflichten.',
deletionTrigger: 'RETENTION_DRIVER',
retentionDriver: 'AO_147',
retentionDriverDetail:
'Aufbewahrungspflicht gemaess 147 AO fuer lohnsteuerrelevante Unterlagen und Gehaltsbuchungen.',
retentionDuration: 10,
retentionUnit: 'YEARS',
retentionDescription: '10 Jahre nach Ende des Geschaeftsjahres',
startEvent: 'Ende des Geschaeftsjahres der jeweiligen Abrechnung',
deletionMethod: 'AUTO_DELETE',
deletionMethodDetail:
'Automatische Loeschung der digitalen Gehaltsabrechnungen nach Ablauf der Aufbewahrungsfrist. Papierbelege werden datenschutzkonform vernichtet.',
responsibleRole: 'Lohnbuchhaltung',
reviewInterval: 'ANNUAL',
tags: ['hr', 'steuer'],
},
{
templateId: 'zeiterfassung',
dataObjectName: 'Zeiterfassungsdaten',
description:
'Arbeitszeitaufzeichnungen inkl. Beginn, Ende, Pausen und Ueberstunden der Beschaeftigten.',
affectedGroups: ['Mitarbeiter'],
dataCategories: ['Arbeitszeiten', 'Pausenzeiten', 'Ueberstunden'],
primaryPurpose:
'Erfuellung der gesetzlichen Aufzeichnungspflicht fuer Arbeitszeiten und Nachweis der Einhaltung des Arbeitszeitgesetzes.',
deletionTrigger: 'RETENTION_DRIVER',
retentionDriver: 'ARBZG_16',
retentionDriverDetail:
'Aufbewahrungspflicht gemaess 16 Abs. 2 ArbZG fuer Aufzeichnungen ueber die Arbeitszeit.',
retentionDuration: 2,
retentionUnit: 'YEARS',
retentionDescription: '2 Jahre nach Ende des Erfassungszeitraums',
startEvent: 'Ende des jeweiligen Erfassungszeitraums',
deletionMethod: 'AUTO_DELETE',
deletionMethodDetail:
'Automatische Loeschung der Zeiterfassungsdaten nach Ablauf der 2-Jahres-Frist im Zeiterfassungssystem.',
responsibleRole: 'HR-Abteilung',
reviewInterval: 'ANNUAL',
tags: ['hr', 'arbzg'],
},
{
templateId: 'krankmeldungen',
dataObjectName: 'Krankmeldungen',
description:
'Arbeitsunfaehigkeitsbescheinigungen, Krankmeldungen und zugehoerige Abwesenheitsdokumentationen.',
affectedGroups: ['Mitarbeiter'],
dataCategories: ['Gesundheitsdaten', 'Abwesenheitszeiten', 'AU-Bescheinigungen'],
primaryPurpose:
'Dokumentation von Fehlzeiten, Entgeltfortzahlung im Krankheitsfall und Absicherung gegen Verjaehrung arbeitsrechtlicher Ansprueche.',
deletionTrigger: 'RETENTION_DRIVER',
retentionDriver: 'BGB_195',
retentionDriverDetail:
'Aufbewahrung fuer die Dauer der regelmaessigen Verjaehrungsfrist gemaess 195 BGB zur Absicherung von Erstattungsanspruechen.',
retentionDuration: 3,
retentionUnit: 'YEARS',
retentionDescription: '3 Jahre nach Ende des Beschaeftigungsverhaeltnisses',
startEvent: 'Ende des Beschaeftigungsverhaeltnisses',
deletionMethod: 'MANUAL_REVIEW_DELETE',
deletionMethodDetail:
'Manuelle Pruefung durch die HR-Abteilung vor Loeschung, da Krankmeldungen besondere Kategorien personenbezogener Daten (Gesundheitsdaten) enthalten.',
responsibleRole: 'HR-Abteilung',
reviewInterval: 'ANNUAL',
tags: ['hr', 'gesundheit'],
},
{
templateId: 'schulungsnachweise',
dataObjectName: 'Schulungsnachweise',
description:
'Teilnahmebestaetigungen, Zertifikate und Protokolle von Mitarbeiterschulungen (Datenschutz, Arbeitssicherheit, Compliance).',
affectedGroups: ['Mitarbeiter'],
dataCategories: ['Schulungsdaten', 'Zertifikate', 'Teilnahmelisten'],
primaryPurpose:
'Nachweis der Durchfuehrung gesetzlich vorgeschriebener Schulungen und Dokumentation der Mitarbeiterqualifikation.',
deletionTrigger: 'RETENTION_DRIVER',
retentionDriver: 'CUSTOM',
retentionDriverDetail:
'Aufbewahrung fuer 3 Jahre nach Ende des Beschaeftigungsverhaeltnisses als Nachweis der ordnungsgemaessen Schulungsdurchfuehrung.',
retentionDuration: 3,
retentionUnit: 'YEARS',
retentionDescription: '3 Jahre nach Ende des Beschaeftigungsverhaeltnisses',
startEvent: 'Ende des Beschaeftigungsverhaeltnisses des geschulten Mitarbeiters',
deletionMethod: 'MANUAL_REVIEW_DELETE',
deletionMethodDetail:
'Manuelle Pruefung durch die HR-Abteilung vor Loeschung, da Schulungsnachweise als Compliance-Nachweis in Audits relevant sein koennen.',
responsibleRole: 'HR-Abteilung',
reviewInterval: 'ANNUAL',
tags: ['hr', 'schulung'],
},
{
templateId: 'betriebsarzt-doku',
dataObjectName: 'Betriebsarzt-Dokumentation',
description:
'Ergebnisse arbeitsmedizinischer Vorsorgeuntersuchungen, Eignungsuntersuchungen und arbeitsmedizinische Empfehlungen.',
affectedGroups: ['Mitarbeiter'],
dataCategories: ['Gesundheitsdaten', 'Vorsorgeuntersuchungen', 'Eignungsbefunde'],
primaryPurpose:
'Erfuellung der Dokumentationspflicht fuer arbeitsmedizinische Vorsorge gemaess ArbMedVV und Nachweisfuehrung gegenueber Berufsgenossenschaften.',
deletionTrigger: 'RETENTION_DRIVER',
retentionDriver: 'CUSTOM',
retentionDriverDetail:
'Aufbewahrungspflicht gemaess ArbMedVV (Verordnung zur arbeitsmedizinischen Vorsorge) und Berufsgenossenschaftliche Grundsaetze: bis zu 40 Jahre bei Exposition gegenueber krebserzeugenden Gefahrstoffen.',
retentionDuration: 40,
retentionUnit: 'YEARS',
retentionDescription: '40 Jahre nach letzter Exposition (bei Gefahrstoffen), sonst 10 Jahre nach Ende der Taetigkeit',
startEvent: 'Ende der expositionsrelevanten Taetigkeit bzw. Ende des Beschaeftigungsverhaeltnisses',
deletionMethod: 'PHYSICAL_DESTROY',
deletionMethodDetail:
'Physische Vernichtung der Papierunterlagen durch zertifizierten Aktenvernichtungsdienstleister (DIN 66399, Sicherheitsstufe P-5). Digitale Daten werden kryptographisch geloescht.',
responsibleRole: 'Betriebsarzt / Arbeitsmedizinischer Dienst',
reviewInterval: 'ANNUAL',
tags: ['hr', 'gesundheit'],
},
]

View File

@@ -0,0 +1,105 @@
/**
* Loeschfristen — IT & Security Templates
* Webserver-Logs, Videoueberwachung, Backup-Daten, Zutrittsprotokolle
*/
import { BaselineTemplate } from './types'
export const IT_SECURITY_TEMPLATES: BaselineTemplate[] = [
{
templateId: 'webserver-logs',
dataObjectName: 'Webserver-Logs',
description:
'Server-Zugriffsprotokolle inkl. IP-Adressen, Zeitstempel, aufgerufene URLs und HTTP-Statuscodes.',
affectedGroups: ['Website-Besucher'],
dataCategories: ['IP-Adressen', 'Zugriffszeitpunkte', 'User-Agent-Daten'],
primaryPurpose:
'Sicherstellung der IT-Sicherheit, Erkennung von Angriffen und Stoerungen sowie Erfuellung der Protokollierungspflicht nach BSIG.',
deletionTrigger: 'RETENTION_DRIVER',
retentionDriver: 'BSIG',
retentionDriverDetail:
'Aufbewahrung gemaess BSI-Gesetz / IT-Sicherheitsgesetz 2.0 fuer die Analyse von Sicherheitsvorfaellen.',
retentionDuration: 7,
retentionUnit: 'DAYS',
retentionDescription: '7 Tage nach Zeitpunkt des Zugriffs',
startEvent: 'Zeitpunkt des Server-Zugriffs',
deletionMethod: 'AUTO_DELETE',
deletionMethodDetail:
'Automatische Rotation und Loeschung der Logdateien nach 7 Tagen durch den Webserver (logrotate).',
responsibleRole: 'IT-Abteilung',
reviewInterval: 'QUARTERLY',
tags: ['it', 'logs'],
},
{
templateId: 'videoueberwachung',
dataObjectName: 'Videoueberwachung',
description:
'Aufnahmen der Videoueberwachung in Geschaeftsraeumen, Eingangsbereichen und Parkplaetzen.',
affectedGroups: ['Besucher', 'Mitarbeiter'],
dataCategories: ['Videodaten', 'Bilddaten', 'Zeitstempel'],
primaryPurpose:
'Schutz des Eigentums und der Sicherheit von Personen sowie Aufklaerung von Vorfaellen in den ueberwachten Bereichen.',
deletionTrigger: 'RETENTION_DRIVER',
retentionDriver: 'BDSG_35',
retentionDriverDetail:
'Unverzuegliche Loeschung nach Zweckwegfall gemaess 35 BDSG bzw. Art. 17 DSGVO. Maximale Speicherdauer 48 Stunden.',
retentionDuration: 2,
retentionUnit: 'DAYS',
retentionDescription: '48 Stunden (2 Tage) nach Aufnahmezeitpunkt',
startEvent: 'Aufnahmezeitpunkt der Videosequenz',
deletionMethod: 'AUTO_DELETE',
deletionMethodDetail:
'Automatisches Ueberschreiben der Aufnahmen durch das Videomanagementsystem nach Ablauf der 48-Stunden-Frist.',
responsibleRole: 'Facility Management',
reviewInterval: 'QUARTERLY',
tags: ['sicherheit', 'video'],
},
{
templateId: 'backup-daten',
dataObjectName: 'Backup-Daten',
description:
'Vollstaendige und inkrementelle Sicherungskopien aller Systeme, Datenbanken und Dateisysteme.',
affectedGroups: ['Alle Betroffenengruppen'],
dataCategories: ['Systemsicherungen', 'Datenbankkopien', 'Dateisystemsicherungen'],
primaryPurpose:
'Sicherstellung der Datenwiederherstellung im Katastrophenfall und Gewaehrleistung der Geschaeftskontinuitaet.',
deletionTrigger: 'RETENTION_DRIVER',
retentionDriver: 'BSIG',
retentionDriverDetail:
'Aufbewahrung von Backups fuer 90 Tage gemaess BSI-Grundschutz-Empfehlungen zur Sicherstellung der Wiederherstellbarkeit.',
retentionDuration: 90,
retentionUnit: 'DAYS',
retentionDescription: '90 Tage nach Erstellung des Backups',
startEvent: 'Erstellungsdatum des jeweiligen Backups',
deletionMethod: 'CRYPTO_ERASE',
deletionMethodDetail:
'Kryptographische Loeschung durch Vernichtung der Verschluesselungsschluessel, sodass die verschluesselten Backup-Daten nicht mehr entschluesselt werden koennen.',
responsibleRole: 'IT-Abteilung',
reviewInterval: 'QUARTERLY',
tags: ['it', 'backup'],
},
{
templateId: 'zutrittsprotokolle',
dataObjectName: 'Zutrittsprotokolle',
description:
'Protokolle des Zutrittskontrollsystems inkl. Zeitstempel, Kartennummer, Zutrittsort und Zugangsentscheidung (gewaehrt/verweigert).',
affectedGroups: ['Mitarbeiter', 'Besucher'],
dataCategories: ['Zutrittsdaten', 'Zeitstempel', 'Kartennummern', 'Standortdaten'],
primaryPurpose:
'Sicherstellung der physischen Sicherheit, Nachvollziehbarkeit von Zutritten und Unterstuetzung bei der Aufklaerung von Sicherheitsvorfaellen.',
deletionTrigger: 'RETENTION_DRIVER',
retentionDriver: 'BSIG',
retentionDriverDetail:
'Aufbewahrung gemaess BSI-Grundschutz-Empfehlung fuer Zutrittsprotokolle zur Analyse von Sicherheitsvorfaellen (90 Tage).',
retentionDuration: 90,
retentionUnit: 'DAYS',
retentionDescription: '90 Tage nach Zeitpunkt des Zutritts',
startEvent: 'Zeitpunkt des protokollierten Zutrittsereignisses',
deletionMethod: 'AUTO_DELETE',
deletionMethodDetail:
'Automatische Rotation und Loeschung der Zutrittsprotokolle durch das Zutrittskontrollsystem nach Ablauf der 90-Tage-Frist.',
responsibleRole: 'Facility Management',
reviewInterval: 'QUARTERLY',
tags: ['sicherheit', 'zutritt'],
},
]

View File

@@ -0,0 +1,154 @@
/**
* Loeschfristen — Marketing & CRM Templates
* Newsletter-Einwilligungen, Kundenstammdaten, CRM-Kontakthistorie,
* Kundenreklamationen, Social-Media-Marketingdaten
*/
import { BaselineTemplate } from './types'
export const MARKETING_CRM_TEMPLATES: BaselineTemplate[] = [
{
templateId: 'newsletter-einwilligungen',
dataObjectName: 'Newsletter-Einwilligungen',
description:
'Einwilligungserklaerungen fuer den Newsletter-Versand inkl. Double-Opt-in-Nachweis und Abmeldezeitpunkt.',
affectedGroups: ['Abonnenten'],
dataCategories: ['Einwilligungsdaten', 'E-Mail-Adresse', 'Opt-in-Nachweis'],
primaryPurpose:
'Nachweis der wirksamen Einwilligung zum Newsletter-Versand gemaess Art. 7 DSGVO und Dokumentation des Widerrufs.',
deletionTrigger: 'PURPOSE_END',
retentionDriver: null,
retentionDriverDetail:
'Keine gesetzliche Aufbewahrungspflicht. Daten werden bis zum Widerruf der Einwilligung gespeichert.',
retentionDuration: null,
retentionUnit: null,
retentionDescription: 'Bis zum Widerruf der Einwilligung durch den Abonnenten',
startEvent: 'Widerruf der Einwilligung durch den Abonnenten',
deletionMethod: 'AUTO_DELETE',
deletionMethodDetail:
'Automatische Loeschung der personenbezogenen Daten nach Eingang des Widerrufs. Der Einwilligungsnachweis selbst wird fuer die Dauer der Nachweispflicht aufbewahrt.',
responsibleRole: 'Marketing',
reviewInterval: 'SEMI_ANNUAL',
tags: ['marketing', 'einwilligung'],
},
{
templateId: 'kundenstammdaten',
dataObjectName: 'Kundenstammdaten',
description:
'Stammdaten von Kunden inkl. Kontaktdaten, Anschrift, Kundennummer und Kommunikationspraeferenzen.',
affectedGroups: ['Kunden'],
dataCategories: ['Stammdaten', 'Kontaktdaten', 'Adressdaten'],
primaryPurpose:
'Pflege der Kundenbeziehung, Vertragserfuellung und Absicherung gegen Verjaehrung vertraglicher Ansprueche.',
deletionTrigger: 'RETENTION_DRIVER',
retentionDriver: 'BGB_195',
retentionDriverDetail:
'Aufbewahrung fuer die Dauer der regelmaessigen Verjaehrungsfrist gemaess 195 BGB (3 Jahre).',
retentionDuration: 3,
retentionUnit: 'YEARS',
retentionDescription: '3 Jahre nach letzter geschaeftlicher Interaktion',
startEvent: 'Letzte geschaeftliche Interaktion mit dem Kunden',
deletionMethod: 'MANUAL_REVIEW_DELETE',
deletionMethodDetail:
'Manuelle Pruefung durch den Vertrieb vor Loeschung, um sicherzustellen, dass keine aktiven Geschaeftsbeziehungen oder offenen Forderungen bestehen.',
responsibleRole: 'Vertrieb',
reviewInterval: 'ANNUAL',
tags: ['crm', 'kunden'],
},
{
templateId: 'crm-kontakthistorie',
dataObjectName: 'CRM-Kontakthistorie',
description:
'Kontaktverlauf im CRM-System inkl. Anrufe, E-Mails, Termine, Notizen und Angebotsverlauf.',
affectedGroups: ['Kunden', 'Interessenten'],
dataCategories: ['Kommunikationsdaten', 'Interaktionshistorie', 'Angebotsdaten'],
primaryPurpose:
'Pflege der Kundenbeziehung und Nachverfolgung geschaeftlicher Interaktionen fuer Vertriebs- und Servicezwecke.',
deletionTrigger: 'RETENTION_DRIVER',
retentionDriver: 'BGB_195',
retentionDriverDetail:
'Aufbewahrung fuer die Dauer der regelmaessigen Verjaehrungsfrist gemaess 195 BGB zur Absicherung vertraglicher Ansprueche.',
retentionDuration: 3,
retentionUnit: 'YEARS',
retentionDescription: '3 Jahre nach letztem Kontakt mit dem Kunden oder Interessenten',
startEvent: 'Letzter dokumentierter Kontakt im CRM-System',
deletionMethod: 'ANONYMIZATION',
deletionMethodDetail:
'Anonymisierung der personenbezogenen Daten im CRM-System, sodass statistische Auswertungen weiterhin moeglich sind, aber kein Personenbezug mehr hergestellt werden kann.',
responsibleRole: 'Vertrieb',
reviewInterval: 'SEMI_ANNUAL',
tags: ['crm', 'kunden'],
},
{
templateId: 'kundenreklamationen',
dataObjectName: 'Kundenreklamationen',
description:
'Reklamationsvorgaenge inkl. Beschwerdeinhalt, Kommunikationsverlauf, Massnahmen und Ergebnis der Reklamationsbearbeitung.',
affectedGroups: ['Kunden'],
dataCategories: ['Reklamationsdaten', 'Kommunikation', 'Massnahmenprotokolle'],
primaryPurpose:
'Dokumentation und Bearbeitung von Kundenreklamationen, Qualitaetssicherung und Absicherung gegen Gewaehrleistungsansprueche.',
deletionTrigger: 'RETENTION_DRIVER',
retentionDriver: 'BGB_195',
retentionDriverDetail:
'Aufbewahrung fuer die Dauer der regelmaessigen Verjaehrungsfrist gemaess 195 BGB (3 Jahre) zur Absicherung gegen Gewaehrleistungs- und Schadensersatzansprueche.',
retentionDuration: 3,
retentionUnit: 'YEARS',
retentionDescription: '3 Jahre nach Abschluss des Reklamationsvorgangs',
startEvent: 'Abschluss des Reklamationsvorgangs (letzte Massnahme)',
deletionMethod: 'ANONYMIZATION',
deletionMethodDetail:
'Anonymisierung der personenbezogenen Daten nach Ablauf der Frist. Anonymisierte Reklamationsstatistiken bleiben fuer die Qualitaetssicherung erhalten.',
responsibleRole: 'Qualitaetsmanagement',
reviewInterval: 'ANNUAL',
tags: ['kunden', 'qualitaet'],
},
{
templateId: 'cookie-consent-logs',
dataObjectName: 'Cookie-Consent-Nachweise',
description:
'Nachweise ueber Cookie-Einwilligungen der Website-Besucher inkl. Consent-ID, Zeitstempel, gesetzte Praeferenzen und IP-Adresse.',
affectedGroups: ['Website-Besucher'],
dataCategories: ['Consent-Daten', 'IP-Adressen', 'Zeitstempel', 'Praeferenzen'],
primaryPurpose:
'Nachweisfuehrung der Einwilligung in die Cookie-Nutzung gemaess Art. 7 Abs. 1 DSGVO und ePrivacy-Richtlinie.',
deletionTrigger: 'RETENTION_DRIVER',
retentionDriver: 'BGB_195',
retentionDriverDetail:
'Aufbewahrung der Consent-Nachweise fuer die Dauer der regelmaessigen Verjaehrungsfrist gemaess 195 BGB zur Absicherung gegen Abmahnungen.',
retentionDuration: 3,
retentionUnit: 'YEARS',
retentionDescription: '3 Jahre nach Zeitpunkt der Einwilligung',
startEvent: 'Zeitpunkt der Cookie-Einwilligung (Consent-Zeitstempel)',
deletionMethod: 'AUTO_DELETE',
deletionMethodDetail:
'Automatische Loeschung der Consent-Nachweise nach Ablauf der 3-Jahres-Frist durch das Consent-Management-System.',
responsibleRole: 'Datenschutzbeauftragter',
reviewInterval: 'ANNUAL',
tags: ['datenschutz', 'consent'],
},
{
templateId: 'social-media-daten',
dataObjectName: 'Social-Media-Marketingdaten',
description:
'Personenbezogene Daten aus Social-Media-Kampagnen inkl. Nutzerinteraktionen, Custom Audiences, Retargeting-Listen und Kampagnen-Analytics.',
affectedGroups: ['Kunden', 'Interessenten', 'Website-Besucher'],
dataCategories: ['Interaktionsdaten', 'Zielgruppendaten', 'Tracking-Daten', 'Profilmerkmale'],
primaryPurpose:
'Durchfuehrung zielgerichteter Marketing-Kampagnen auf Social-Media-Plattformen und Analyse der Kampagneneffektivitaet.',
deletionTrigger: 'PURPOSE_END',
retentionDriver: null,
retentionDriverDetail:
'Keine gesetzliche Aufbewahrungspflicht. Daten werden bis zum Widerruf der Einwilligung bzw. bis zum Ende der Kampagne gespeichert (Art. 6 Abs. 1 lit. a DSGVO).',
retentionDuration: null,
retentionUnit: null,
retentionDescription: 'Bis zum Widerruf der Einwilligung oder Ende des Kampagnenzwecks',
startEvent: 'Widerruf der Einwilligung oder Ende der Marketing-Kampagne',
deletionMethod: 'AUTO_DELETE',
deletionMethodDetail:
'Automatische Loeschung der personenbezogenen Daten in den Social-Media-Werbekonten und internen Systemen nach Zweckwegfall. Custom Audiences werden bei Plattformanbietern geloescht.',
responsibleRole: 'Marketing',
reviewInterval: 'SEMI_ANNUAL',
tags: ['marketing', 'social'],
},
]

View File

@@ -0,0 +1,32 @@
/**
* Loeschfristen Baseline-Katalog — Shared Types
*/
import type {
RetentionDriverType,
DeletionMethodType,
ReviewInterval,
RetentionUnit,
DeletionTriggerLevel,
} from '../loeschfristen-types'
export interface BaselineTemplate {
templateId: string
dataObjectName: string
description: string
affectedGroups: string[]
dataCategories: string[]
primaryPurpose: string
deletionTrigger: DeletionTriggerLevel
retentionDriver: RetentionDriverType | null
retentionDriverDetail: string
retentionDuration: number | null
retentionUnit: RetentionUnit | null
retentionDescription: string
startEvent: string
deletionMethod: DeletionMethodType
deletionMethodDetail: string
responsibleRole: string
reviewInterval: ReviewInterval
tags: string[]
}

View File

@@ -1,879 +1,8 @@
// ============================================================================= // =============================================================================
// Loeschfristen Module - Loeschkonzept Document Generator // Loeschfristen Module - Loeschkonzept Document Generator
// Generates a printable, audit-ready HTML document according to DSGVO Art. 5/17/30 // Barrel re-export — implementation split into loeschfristen-document/
// ============================================================================= // =============================================================================
import type { export type { LoeschkonzeptOrgHeader, LoeschkonzeptRevision } from './loeschfristen-document/types-defaults'
LoeschfristPolicy, export { createDefaultLoeschkonzeptOrgHeader } from './loeschfristen-document/types-defaults'
RetentionDriverType, export { buildLoeschkonzeptHtml } from './loeschfristen-document/html-builder'
} from './loeschfristen-types'
import {
RETENTION_DRIVER_META,
DELETION_METHOD_LABELS,
STATUS_LABELS,
TRIGGER_LABELS,
REVIEW_INTERVAL_LABELS,
formatRetentionDuration,
getEffectiveDeletionTrigger,
getActiveLegalHolds,
} from './loeschfristen-types'
import type { ComplianceCheckResult, ComplianceIssueSeverity } from './loeschfristen-compliance'
// =============================================================================
// TYPES
// =============================================================================
export interface LoeschkonzeptOrgHeader {
organizationName: string
industry: string
dpoName: string
dpoContact: string
responsiblePerson: string
locations: string[]
employeeCount: string
loeschkonzeptVersion: string
lastReviewDate: string
nextReviewDate: string
reviewInterval: string
}
export interface LoeschkonzeptRevision {
version: string
date: string
author: string
changes: string
}
// =============================================================================
// DEFAULTS
// =============================================================================
export function createDefaultLoeschkonzeptOrgHeader(): LoeschkonzeptOrgHeader {
const now = new Date()
const nextYear = new Date()
nextYear.setFullYear(nextYear.getFullYear() + 1)
return {
organizationName: '',
industry: '',
dpoName: '',
dpoContact: '',
responsiblePerson: '',
locations: [],
employeeCount: '',
loeschkonzeptVersion: '1.0',
lastReviewDate: now.toISOString().split('T')[0],
nextReviewDate: nextYear.toISOString().split('T')[0],
reviewInterval: 'Jaehrlich',
}
}
// =============================================================================
// SEVERITY LABELS (for Compliance Status section)
// =============================================================================
const SEVERITY_LABELS_DE: Record<ComplianceIssueSeverity, string> = {
CRITICAL: 'Kritisch',
HIGH: 'Hoch',
MEDIUM: 'Mittel',
LOW: 'Niedrig',
}
const SEVERITY_COLORS: Record<ComplianceIssueSeverity, string> = {
CRITICAL: '#dc2626',
HIGH: '#ea580c',
MEDIUM: '#d97706',
LOW: '#6b7280',
}
// =============================================================================
// HTML DOCUMENT BUILDER
// =============================================================================
export function buildLoeschkonzeptHtml(
policies: LoeschfristPolicy[],
orgHeader: LoeschkonzeptOrgHeader,
vvtActivities: Array<{ id: string; vvt_id?: string; vvtId?: string; name?: string; activity_name?: string }>,
complianceResult: ComplianceCheckResult | null,
revisions: LoeschkonzeptRevision[]
): string {
const today = new Date().toLocaleDateString('de-DE', {
day: '2-digit',
month: '2-digit',
year: 'numeric',
})
const activePolicies = policies.filter(p => p.status !== 'ARCHIVED')
const orgName = orgHeader.organizationName || 'Organisation'
// Collect unique storage locations across all policies
const allStorageLocations = new Set<string>()
for (const p of activePolicies) {
for (const loc of p.storageLocations) {
allStorageLocations.add(loc.name || loc.type)
}
}
// Collect unique responsible roles
const roleMap = new Map<string, string[]>()
for (const p of activePolicies) {
const role = p.responsibleRole || p.responsiblePerson || 'Nicht zugewiesen'
if (!roleMap.has(role)) roleMap.set(role, [])
roleMap.get(role)!.push(p.dataObjectName || p.policyId)
}
// Collect active legal holds
const allActiveLegalHolds: Array<{ policy: string; hold: LoeschfristPolicy['legalHolds'][0] }> = []
for (const p of activePolicies) {
for (const h of getActiveLegalHolds(p)) {
allActiveLegalHolds.push({ policy: p.dataObjectName || p.policyId, hold: h })
}
}
// Build VVT cross-reference data
const vvtRefs: Array<{ policyName: string; policyId: string; vvtId: string; vvtName: string }> = []
for (const p of activePolicies) {
for (const linkedId of p.linkedVVTActivityIds) {
const activity = vvtActivities.find(a => a.id === linkedId)
if (activity) {
vvtRefs.push({
policyName: p.dataObjectName || p.policyId,
policyId: p.policyId,
vvtId: activity.vvt_id || activity.vvtId || linkedId.substring(0, 8),
vvtName: activity.activity_name || activity.name || 'Unbenannte Verarbeitungstaetigkeit',
})
}
}
}
// Build vendor cross-reference data
const vendorRefs: Array<{ policyName: string; policyId: string; vendorId: string; duration: string }> = []
for (const p of activePolicies) {
if (p.linkedVendorIds && p.linkedVendorIds.length > 0) {
for (const vendorId of p.linkedVendorIds) {
vendorRefs.push({
policyName: p.dataObjectName || p.policyId,
policyId: p.policyId,
vendorId,
duration: formatRetentionDuration(p.retentionDuration, p.retentionUnit),
})
}
}
}
// =========================================================================
// HTML Template
// =========================================================================
let html = `<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<title>Loeschkonzept — ${escHtml(orgName)}</title>
<style>
@page { size: A4; margin: 20mm 18mm 22mm 18mm; }
* { margin: 0; padding: 0; box-sizing: border-box; }
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
font-size: 10pt;
line-height: 1.5;
color: #1e293b;
}
/* Cover */
.cover {
min-height: 90vh;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
text-align: center;
page-break-after: always;
}
.cover h1 {
font-size: 28pt;
color: #5b21b6;
margin-bottom: 8px;
font-weight: 700;
}
.cover .subtitle {
font-size: 14pt;
color: #7c3aed;
margin-bottom: 40px;
}
.cover .org-info {
background: #f5f3ff;
border: 1px solid #ddd6fe;
border-radius: 8px;
padding: 24px 40px;
text-align: left;
width: 400px;
margin-bottom: 24px;
}
.cover .org-info div { margin-bottom: 6px; }
.cover .org-info .label { font-weight: 600; color: #5b21b6; display: inline-block; min-width: 160px; }
.cover .legal-ref {
font-size: 9pt;
color: #64748b;
margin-top: 20px;
}
/* TOC */
.toc {
page-break-after: always;
padding-top: 40px;
}
.toc h2 {
font-size: 18pt;
color: #5b21b6;
margin-bottom: 20px;
border-bottom: 2px solid #5b21b6;
padding-bottom: 8px;
}
.toc-entry {
display: flex;
justify-content: space-between;
padding: 6px 0;
border-bottom: 1px dotted #cbd5e1;
font-size: 10pt;
}
.toc-entry .toc-num { font-weight: 600; color: #5b21b6; min-width: 40px; }
/* Sections */
.section {
page-break-inside: avoid;
margin-bottom: 24px;
}
.section-header {
font-size: 14pt;
color: #5b21b6;
font-weight: 700;
margin: 30px 0 12px 0;
border-bottom: 2px solid #ddd6fe;
padding-bottom: 6px;
}
.section-body { margin-bottom: 16px; }
/* Tables */
table {
width: 100%;
border-collapse: collapse;
margin: 10px 0 16px 0;
font-size: 9pt;
}
th, td {
border: 1px solid #e2e8f0;
padding: 6px 8px;
text-align: left;
vertical-align: top;
}
th {
background: #f5f3ff;
color: #5b21b6;
font-weight: 600;
font-size: 8.5pt;
text-transform: uppercase;
letter-spacing: 0.3px;
}
tr:nth-child(even) td { background: #faf5ff; }
/* Detail cards */
.policy-detail {
page-break-inside: avoid;
border: 1px solid #e2e8f0;
border-radius: 6px;
margin-bottom: 16px;
overflow: hidden;
}
.policy-detail-header {
background: #f5f3ff;
padding: 8px 12px;
font-weight: 700;
color: #5b21b6;
border-bottom: 1px solid #ddd6fe;
display: flex;
justify-content: space-between;
}
.policy-detail-body { padding: 0; }
.policy-detail-body table { margin: 0; }
.policy-detail-body th { width: 200px; }
/* Badges */
.badge {
display: inline-block;
padding: 1px 8px;
border-radius: 9999px;
font-size: 8pt;
font-weight: 600;
}
.badge-active { background: #dcfce7; color: #166534; }
.badge-draft { background: #f3f4f6; color: #374151; }
.badge-review { background: #fef9c3; color: #854d0e; }
.badge-critical { background: #fecaca; color: #991b1b; }
.badge-high { background: #fed7aa; color: #9a3412; }
.badge-medium { background: #fef3c7; color: #92400e; }
.badge-low { background: #f3f4f6; color: #4b5563; }
/* Principles */
.principle {
margin-bottom: 10px;
padding-left: 20px;
position: relative;
}
.principle::before {
content: '';
position: absolute;
left: 0;
top: 6px;
width: 10px;
height: 10px;
background: #7c3aed;
border-radius: 50%;
}
.principle strong { color: #5b21b6; }
/* Score */
.score-box {
display: inline-block;
padding: 4px 16px;
border-radius: 8px;
font-size: 18pt;
font-weight: 700;
margin-right: 12px;
}
.score-excellent { background: #dcfce7; color: #166534; }
.score-good { background: #dbeafe; color: #1e40af; }
.score-needs-work { background: #fef3c7; color: #92400e; }
.score-poor { background: #fecaca; color: #991b1b; }
/* Footer */
.page-footer {
position: fixed;
bottom: 0;
left: 0;
right: 0;
padding: 8px 18mm;
font-size: 7.5pt;
color: #94a3b8;
display: flex;
justify-content: space-between;
border-top: 1px solid #e2e8f0;
}
/* Print */
@media print {
body { -webkit-print-color-adjust: exact; print-color-adjust: exact; }
.no-print { display: none !important; }
.page-break { page-break-after: always; }
}
</style>
</head>
<body>
`
// =========================================================================
// Section 0: Cover Page
// =========================================================================
html += `
<div class="cover">
<h1>Loeschkonzept</h1>
<div class="subtitle">gemaess Art. 5 Abs. 1 lit. e, Art. 17, Art. 30 DSGVO</div>
<div class="org-info">
<div><span class="label">Organisation:</span> ${escHtml(orgName)}</div>
${orgHeader.industry ? `<div><span class="label">Branche:</span> ${escHtml(orgHeader.industry)}</div>` : ''}
${orgHeader.dpoName ? `<div><span class="label">Datenschutzbeauftragter:</span> ${escHtml(orgHeader.dpoName)}</div>` : ''}
${orgHeader.dpoContact ? `<div><span class="label">DSB-Kontakt:</span> ${escHtml(orgHeader.dpoContact)}</div>` : ''}
${orgHeader.responsiblePerson ? `<div><span class="label">Verantwortlicher:</span> ${escHtml(orgHeader.responsiblePerson)}</div>` : ''}
${orgHeader.employeeCount ? `<div><span class="label">Mitarbeiter:</span> ${escHtml(orgHeader.employeeCount)}</div>` : ''}
${orgHeader.locations.length > 0 ? `<div><span class="label">Standorte:</span> ${escHtml(orgHeader.locations.join(', '))}</div>` : ''}
</div>
<div class="legal-ref">
Version ${escHtml(orgHeader.loeschkonzeptVersion)} | Stand: ${today}<br/>
Letzte Pruefung: ${formatDateDE(orgHeader.lastReviewDate)} | Naechste Pruefung: ${formatDateDE(orgHeader.nextReviewDate)}<br/>
Pruefintervall: ${escHtml(orgHeader.reviewInterval)}
</div>
</div>
`
// =========================================================================
// Table of Contents
// =========================================================================
const sections = [
'Ziel und Zweck',
'Geltungsbereich',
'Grundprinzipien der Datenspeicherung',
'Loeschregeln-Uebersicht',
'Detaillierte Loeschregeln',
'VVT-Verknuepfung',
'Auftragsverarbeiter mit Loeschpflichten',
'Legal Hold Verfahren',
'Verantwortlichkeiten',
'Pruef- und Revisionszyklus',
'Compliance-Status',
'Aenderungshistorie',
]
html += `
<div class="toc">
<h2>Inhaltsverzeichnis</h2>
${sections.map((s, i) => `<div class="toc-entry"><span><span class="toc-num">${i + 1}.</span> ${escHtml(s)}</span></div>`).join('\n ')}
</div>
`
// =========================================================================
// Section 1: Ziel und Zweck
// =========================================================================
html += `
<div class="section">
<div class="section-header">1. Ziel und Zweck</div>
<div class="section-body">
<p>Dieses Loeschkonzept definiert die systematischen Regeln und Verfahren fuer die Loeschung
personenbezogener Daten bei <strong>${escHtml(orgName)}</strong>. Es dient der Umsetzung
folgender DSGVO-Anforderungen:</p>
<table>
<tr><th>Rechtsgrundlage</th><th>Inhalt</th></tr>
<tr><td><strong>Art. 5 Abs. 1 lit. e DSGVO</strong></td><td>Grundsatz der Speicherbegrenzung — personenbezogene Daten duerfen nur so lange gespeichert werden, wie es fuer die Zwecke der Verarbeitung erforderlich ist.</td></tr>
<tr><td><strong>Art. 17 DSGVO</strong></td><td>Recht auf Loeschung (&bdquo;Recht auf Vergessenwerden&ldquo;) — Betroffene haben das Recht, die Loeschung ihrer Daten zu verlangen.</td></tr>
<tr><td><strong>Art. 30 DSGVO</strong></td><td>Verzeichnis von Verarbeitungstaetigkeiten — vorgesehene Fristen fuer die Loeschung der verschiedenen Datenkategorien muessen dokumentiert werden.</td></tr>
</table>
<p>Das Loeschkonzept ist fester Bestandteil des Datenschutz-Managementsystems und wird
regelmaessig ueberprueft und aktualisiert.</p>
</div>
</div>
`
// =========================================================================
// Section 2: Geltungsbereich
// =========================================================================
const storageListHtml = allStorageLocations.size > 0
? Array.from(allStorageLocations).map(s => `<li>${escHtml(s)}</li>`).join('')
: '<li><em>Keine Speicherorte dokumentiert</em></li>'
html += `
<div class="section">
<div class="section-header">2. Geltungsbereich</div>
<div class="section-body">
<p>Dieses Loeschkonzept gilt fuer alle personenbezogenen Daten, die von <strong>${escHtml(orgName)}</strong>
verarbeitet werden. Es umfasst <strong>${activePolicies.length}</strong> Loeschregeln fuer folgende Systeme und Speicherorte:</p>
<ul style="margin: 8px 0 8px 24px;">
${storageListHtml}
</ul>
<p>Saemtliche Verarbeitungstaetigkeiten, die im Verzeichnis von Verarbeitungstaetigkeiten (VVT)
erfasst sind, werden durch dieses Loeschkonzept abgedeckt.</p>
</div>
</div>
`
// =========================================================================
// Section 3: Grundprinzipien
// =========================================================================
html += `
<div class="section">
<div class="section-header">3. Grundprinzipien der Datenspeicherung</div>
<div class="section-body">
<div class="principle"><strong>Speicherbegrenzung:</strong> Personenbezogene Daten werden nur so lange gespeichert, wie es fuer den jeweiligen Verarbeitungszweck erforderlich ist (Art. 5 Abs. 1 lit. e DSGVO).</div>
<div class="principle"><strong>3-Level-Loeschlogik:</strong> Die Loeschung folgt einer dreistufigen Priorisierung: (1) Zweckende, (2) gesetzliche Aufbewahrungspflichten, (3) Legal Hold — jeweils mit der laengsten Frist als massgeblich.</div>
<div class="principle"><strong>Dokumentationspflicht:</strong> Jede Loeschregel ist dokumentiert mit Rechtsgrundlage, Frist, Loeschmethode und Verantwortlichkeit.</div>
<div class="principle"><strong>Regelmaessige Ueberpruefung:</strong> Alle Loeschregeln werden im definierten Intervall ueberprueft und bei Bedarf angepasst.</div>
<div class="principle"><strong>Datenschutz durch Technikgestaltung:</strong> Loeschmechanismen werden moeglichst automatisiert, um menschliche Fehler zu minimieren (Art. 25 DSGVO).</div>
</div>
</div>
`
// =========================================================================
// Section 4: Loeschregeln-Uebersicht
// =========================================================================
html += `
<div class="section page-break">
<div class="section-header">4. Loeschregeln-Uebersicht</div>
<div class="section-body">
<p>Die folgende Tabelle zeigt eine Uebersicht aller ${activePolicies.length} aktiven Loeschregeln:</p>
<table>
<tr>
<th>LF-Nr.</th>
<th>Datenobjekt</th>
<th>Loeschtrigger</th>
<th>Aufbewahrungsfrist</th>
<th>Loeschmethode</th>
<th>Status</th>
</tr>
`
for (const p of activePolicies) {
const trigger = TRIGGER_LABELS[getEffectiveDeletionTrigger(p)]
const duration = formatRetentionDuration(p.retentionDuration, p.retentionUnit)
const method = DELETION_METHOD_LABELS[p.deletionMethod]
const statusLabel = STATUS_LABELS[p.status]
const statusClass = p.status === 'ACTIVE' ? 'badge-active' : p.status === 'REVIEW_NEEDED' ? 'badge-review' : 'badge-draft'
html += ` <tr>
<td>${escHtml(p.policyId)}</td>
<td>${escHtml(p.dataObjectName)}</td>
<td>${escHtml(trigger)}</td>
<td>${escHtml(duration)}</td>
<td>${escHtml(method)}</td>
<td><span class="badge ${statusClass}">${escHtml(statusLabel)}</span></td>
</tr>
`
}
html += ` </table>
</div>
</div>
`
// =========================================================================
// Section 5: Detaillierte Loeschregeln
// =========================================================================
html += `
<div class="section">
<div class="section-header">5. Detaillierte Loeschregeln</div>
<div class="section-body">
`
for (const p of activePolicies) {
const trigger = TRIGGER_LABELS[getEffectiveDeletionTrigger(p)]
const duration = formatRetentionDuration(p.retentionDuration, p.retentionUnit)
const method = DELETION_METHOD_LABELS[p.deletionMethod]
const statusLabel = STATUS_LABELS[p.status]
const driverLabel = p.retentionDriver ? RETENTION_DRIVER_META[p.retentionDriver]?.label || p.retentionDriver : '-'
const driverStatute = p.retentionDriver ? RETENTION_DRIVER_META[p.retentionDriver]?.statute || '' : ''
const locations = p.storageLocations.map(l => l.name || l.type).join(', ') || '-'
const responsible = [p.responsiblePerson, p.responsibleRole].filter(s => s.trim()).join(' / ') || '-'
const activeHolds = getActiveLegalHolds(p)
html += `
<div class="policy-detail">
<div class="policy-detail-header">
<span>${escHtml(p.policyId)}${escHtml(p.dataObjectName)}</span>
<span class="badge ${p.status === 'ACTIVE' ? 'badge-active' : 'badge-draft'}">${escHtml(statusLabel)}</span>
</div>
<div class="policy-detail-body">
<table>
<tr><th>Beschreibung</th><td>${escHtml(p.description || '-')}</td></tr>
<tr><th>Betroffenengruppen</th><td>${escHtml(p.affectedGroups.join(', ') || '-')}</td></tr>
<tr><th>Datenkategorien</th><td>${escHtml(p.dataCategories.join(', ') || '-')}</td></tr>
<tr><th>Verarbeitungszweck</th><td>${escHtml(p.primaryPurpose || '-')}</td></tr>
<tr><th>Loeschtrigger</th><td>${escHtml(trigger)}</td></tr>
<tr><th>Aufbewahrungstreiber</th><td>${escHtml(driverLabel)}${driverStatute ? ` (${escHtml(driverStatute)})` : ''}</td></tr>
<tr><th>Aufbewahrungsfrist</th><td>${escHtml(duration)}</td></tr>
<tr><th>Startereignis</th><td>${escHtml(p.startEvent || '-')}</td></tr>
<tr><th>Loeschmethode</th><td>${escHtml(method)}</td></tr>
<tr><th>Loeschmethode (Detail)</th><td>${escHtml(p.deletionMethodDetail || '-')}</td></tr>
<tr><th>Speicherorte</th><td>${escHtml(locations)}</td></tr>
<tr><th>Verantwortlich</th><td>${escHtml(responsible)}</td></tr>
<tr><th>Pruefintervall</th><td>${escHtml(REVIEW_INTERVAL_LABELS[p.reviewInterval] || p.reviewInterval)}</td></tr>
${activeHolds.length > 0 ? `<tr><th>Aktive Legal Holds</th><td>${activeHolds.map(h => `${escHtml(h.reason)} (seit ${formatDateDE(h.startDate)})`).join('<br/>')}</td></tr>` : ''}
</table>
</div>
</div>
`
}
html += ` </div>
</div>
`
// =========================================================================
// Section 6: VVT-Verknuepfung
// =========================================================================
html += `
<div class="section page-break">
<div class="section-header">6. VVT-Verknuepfung</div>
<div class="section-body">
<p>Die folgende Tabelle zeigt die Verknuepfung zwischen Loeschregeln und Verarbeitungstaetigkeiten
im VVT (Art. 30 DSGVO):</p>
`
if (vvtRefs.length > 0) {
html += ` <table>
<tr><th>Loeschregel</th><th>LF-Nr.</th><th>VVT-Nr.</th><th>Verarbeitungstaetigkeit</th></tr>
`
for (const ref of vvtRefs) {
html += ` <tr>
<td>${escHtml(ref.policyName)}</td>
<td>${escHtml(ref.policyId)}</td>
<td>${escHtml(ref.vvtId)}</td>
<td>${escHtml(ref.vvtName)}</td>
</tr>
`
}
html += ` </table>
`
} else {
html += ` <p><em>Noch keine VVT-Verknuepfungen dokumentiert. Verknuepfen Sie Ihre Loeschregeln
mit den entsprechenden Verarbeitungstaetigkeiten im Editor-Tab.</em></p>
`
}
html += ` </div>
</div>
`
// =========================================================================
// Section 7: Auftragsverarbeiter mit Loeschpflichten
// =========================================================================
html += `
<div class="section">
<div class="section-header">7. Auftragsverarbeiter mit Loeschpflichten</div>
<div class="section-body">
<p>Die folgende Tabelle zeigt Loeschregeln, die mit Auftragsverarbeitern verknuepft sind.
Diese Verknuepfungen stellen sicher, dass auch bei extern verarbeiteten Daten die Loeschpflichten
eingehalten werden (Art. 28 DSGVO).</p>
`
if (vendorRefs.length > 0) {
html += ` <table>
<tr><th>Loeschregel</th><th>LF-Nr.</th><th>Auftragsverarbeiter (ID)</th><th>Aufbewahrungsfrist</th></tr>
`
for (const ref of vendorRefs) {
html += ` <tr>
<td>${escHtml(ref.policyName)}</td>
<td>${escHtml(ref.policyId)}</td>
<td>${escHtml(ref.vendorId)}</td>
<td>${escHtml(ref.duration)}</td>
</tr>
`
}
html += ` </table>
`
} else {
html += ` <p><em>Noch keine Auftragsverarbeiter mit Loeschregeln verknuepft. Verknuepfen Sie Ihre
Loeschregeln mit den entsprechenden Auftragsverarbeitern im Editor-Tab.</em></p>
`
}
html += ` </div>
</div>
`
// =========================================================================
// Section 8: Legal Hold Verfahren
// =========================================================================
html += `
<div class="section">
<div class="section-header">8. Legal Hold Verfahren</div>
<div class="section-body">
<p>Ein Legal Hold (Aufbewahrungspflicht aufgrund rechtlicher Verfahren) setzt die regulaere
Loeschung aus. Betroffene Daten duerfen trotz abgelaufener Loeschfrist nicht geloescht werden,
bis der Legal Hold aufgehoben wird.</p>
<p><strong>Verfahrensschritte:</strong></p>
<ol style="margin: 8px 0 8px 24px;">
<li>Rechtsabteilung/DSB identifiziert betroffene Datenkategorien</li>
<li>Legal Hold wird im System aktiviert (Status: Aktiv)</li>
<li>Automatische Loeschung wird fuer betroffene Policies ausgesetzt</li>
<li>Regelmaessige Pruefung, ob der Legal Hold noch erforderlich ist</li>
<li>Nach Aufhebung: Regulaere Loeschfristen greifen wieder</li>
</ol>
`
if (allActiveLegalHolds.length > 0) {
html += ` <p><strong>Aktuell aktive Legal Holds (${allActiveLegalHolds.length}):</strong></p>
<table>
<tr><th>Datenobjekt</th><th>Grund</th><th>Rechtsgrundlage</th><th>Seit</th><th>Voraussichtlich bis</th></tr>
`
for (const { policy, hold } of allActiveLegalHolds) {
html += ` <tr>
<td>${escHtml(policy)}</td>
<td>${escHtml(hold.reason)}</td>
<td>${escHtml(hold.legalBasis)}</td>
<td>${formatDateDE(hold.startDate)}</td>
<td>${hold.expectedEndDate ? formatDateDE(hold.expectedEndDate) : 'Unbefristet'}</td>
</tr>
`
}
html += ` </table>
`
} else {
html += ` <p><em>Derzeit sind keine aktiven Legal Holds vorhanden.</em></p>
`
}
html += ` </div>
</div>
`
// =========================================================================
// Section 9: Verantwortlichkeiten
// =========================================================================
html += `
<div class="section">
<div class="section-header">9. Verantwortlichkeiten</div>
<div class="section-body">
<p>Die folgende Rollenmatrix zeigt, welche Organisationseinheiten fuer welche Datenobjekte
die Loeschverantwortung tragen:</p>
<table>
<tr><th>Rolle / Verantwortlich</th><th>Datenobjekte</th><th>Anzahl</th></tr>
`
for (const [role, objects] of roleMap.entries()) {
html += ` <tr>
<td>${escHtml(role)}</td>
<td>${objects.map(o => escHtml(o)).join(', ')}</td>
<td>${objects.length}</td>
</tr>
`
}
html += ` </table>
</div>
</div>
`
// =========================================================================
// Section 10: Pruef- und Revisionszyklus
// =========================================================================
html += `
<div class="section">
<div class="section-header">10. Pruef- und Revisionszyklus</div>
<div class="section-body">
<table>
<tr><th>Eigenschaft</th><th>Wert</th></tr>
<tr><td>Aktuelles Pruefintervall</td><td>${escHtml(orgHeader.reviewInterval)}</td></tr>
<tr><td>Letzte Pruefung</td><td>${formatDateDE(orgHeader.lastReviewDate)}</td></tr>
<tr><td>Naechste Pruefung</td><td>${formatDateDE(orgHeader.nextReviewDate)}</td></tr>
<tr><td>Aktuelle Version</td><td>${escHtml(orgHeader.loeschkonzeptVersion)}</td></tr>
</table>
<p style="margin-top: 8px;">Bei jeder Pruefung wird das Loeschkonzept auf folgende Punkte ueberprueft:</p>
<ul style="margin: 8px 0 8px 24px;">
<li>Vollstaendigkeit aller Loeschregeln (neue Verarbeitungen erfasst?)</li>
<li>Aktualitaet der gesetzlichen Aufbewahrungsfristen</li>
<li>Wirksamkeit der technischen Loeschmechanismen</li>
<li>Einhaltung der definierten Loeschfristen</li>
<li>Angemessenheit der Verantwortlichkeiten</li>
</ul>
</div>
</div>
`
// =========================================================================
// Section 11: Compliance-Status
// =========================================================================
html += `
<div class="section page-break">
<div class="section-header">11. Compliance-Status</div>
<div class="section-body">
`
if (complianceResult) {
const scoreClass = complianceResult.score >= 90 ? 'score-excellent'
: complianceResult.score >= 75 ? 'score-good'
: complianceResult.score >= 50 ? 'score-needs-work'
: 'score-poor'
const scoreLabel = complianceResult.score >= 90 ? 'Ausgezeichnet'
: complianceResult.score >= 75 ? 'Gut'
: complianceResult.score >= 50 ? 'Verbesserungswuerdig'
: 'Mangelhaft'
html += ` <p><span class="score-box ${scoreClass}">${complianceResult.score}/100</span> ${escHtml(scoreLabel)}</p>
<table style="margin-top: 12px;">
<tr><th>Kennzahl</th><th>Wert</th></tr>
<tr><td>Gepruefte Policies</td><td>${complianceResult.stats.total}</td></tr>
<tr><td>Bestanden</td><td>${complianceResult.stats.passed}</td></tr>
<tr><td>Beanstandungen</td><td>${complianceResult.stats.failed}</td></tr>
</table>
`
if (complianceResult.issues.length > 0) {
html += ` <p style="margin-top: 12px;"><strong>Befunde nach Schweregrad:</strong></p>
<table>
<tr><th>Schweregrad</th><th>Anzahl</th><th>Befunde</th></tr>
`
const severityOrder: ComplianceIssueSeverity[] = ['CRITICAL', 'HIGH', 'MEDIUM', 'LOW']
for (const sev of severityOrder) {
const count = complianceResult.stats.bySeverity[sev]
if (count === 0) continue
const issuesForSev = complianceResult.issues.filter(i => i.severity === sev)
html += ` <tr>
<td><span class="badge badge-${sev.toLowerCase()}" style="color: ${SEVERITY_COLORS[sev]}">${SEVERITY_LABELS_DE[sev]}</span></td>
<td>${count}</td>
<td>${issuesForSev.map(i => escHtml(i.title)).join('; ')}</td>
</tr>
`
}
html += ` </table>
`
} else {
html += ` <p style="margin-top: 8px;"><em>Keine Beanstandungen. Alle Policies sind konform.</em></p>
`
}
} else {
html += ` <p><em>Compliance-Check wurde noch nicht ausgefuehrt. Fuehren Sie den Check im
Export-Tab durch, um den Status in das Dokument aufzunehmen.</em></p>
`
}
html += ` </div>
</div>
`
// =========================================================================
// Section 12: Aenderungshistorie
// =========================================================================
html += `
<div class="section">
<div class="section-header">12. Aenderungshistorie</div>
<div class="section-body">
<table>
<tr><th>Version</th><th>Datum</th><th>Autor</th><th>Aenderungen</th></tr>
`
if (revisions.length > 0) {
for (const rev of revisions) {
html += ` <tr>
<td>${escHtml(rev.version)}</td>
<td>${formatDateDE(rev.date)}</td>
<td>${escHtml(rev.author)}</td>
<td>${escHtml(rev.changes)}</td>
</tr>
`
}
} else {
html += ` <tr>
<td>${escHtml(orgHeader.loeschkonzeptVersion)}</td>
<td>${today}</td>
<td>${escHtml(orgHeader.dpoName || orgHeader.responsiblePerson || '-')}</td>
<td>Erstversion des Loeschkonzepts</td>
</tr>
`
}
html += ` </table>
</div>
</div>
`
// =========================================================================
// Footer
// =========================================================================
html += `
<div class="page-footer">
<span>Loeschkonzept — ${escHtml(orgName)}</span>
<span>Stand: ${today} | Version ${escHtml(orgHeader.loeschkonzeptVersion)}</span>
</div>
</body>
</html>`
return html
}
// =============================================================================
// INTERNAL HELPERS
// =============================================================================
function escHtml(str: string): string {
return str
.replace(/&/g, '&amp;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
.replace(/"/g, '&quot;')
}
function formatDateDE(dateStr: string | null | undefined): string {
if (!dateStr) return '-'
try {
const date = new Date(dateStr)
if (isNaN(date.getTime())) return '-'
return date.toLocaleDateString('de-DE', {
day: '2-digit',
month: '2-digit',
year: 'numeric',
})
} catch {
return '-'
}
}

View File

@@ -0,0 +1,26 @@
// =============================================================================
// Loeschfristen Document — Internal Helpers
// =============================================================================
export function escHtml(str: string): string {
return str
.replace(/&/g, '&amp;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
.replace(/"/g, '&quot;')
}
export function formatDateDE(dateStr: string | null | undefined): string {
if (!dateStr) return '-'
try {
const date = new Date(dateStr)
if (isNaN(date.getTime())) return '-'
return date.toLocaleDateString('de-DE', {
day: '2-digit',
month: '2-digit',
year: 'numeric',
})
} catch {
return '-'
}
}

View File

@@ -0,0 +1,603 @@
// =============================================================================
// Loeschfristen Document — HTML Document Builder
// =============================================================================
import type {
LoeschfristPolicy,
} from '../loeschfristen-types'
import {
RETENTION_DRIVER_META,
DELETION_METHOD_LABELS,
STATUS_LABELS,
TRIGGER_LABELS,
REVIEW_INTERVAL_LABELS,
formatRetentionDuration,
getEffectiveDeletionTrigger,
getActiveLegalHolds,
} from '../loeschfristen-types'
import type { ComplianceCheckResult, ComplianceIssueSeverity } from '../loeschfristen-compliance'
import type { LoeschkonzeptOrgHeader, LoeschkonzeptRevision } from './types-defaults'
import { SEVERITY_LABELS_DE, SEVERITY_COLORS } from './types-defaults'
import { escHtml, formatDateDE } from './helpers'
type VVTActivity = { id: string; vvt_id?: string; vvtId?: string; name?: string; activity_name?: string }
export function buildLoeschkonzeptHtml(
policies: LoeschfristPolicy[],
orgHeader: LoeschkonzeptOrgHeader,
vvtActivities: VVTActivity[],
complianceResult: ComplianceCheckResult | null,
revisions: LoeschkonzeptRevision[]
): string {
const today = new Date().toLocaleDateString('de-DE', {
day: '2-digit',
month: '2-digit',
year: 'numeric',
})
const activePolicies = policies.filter(p => p.status !== 'ARCHIVED')
const orgName = orgHeader.organizationName || 'Organisation'
// Collect unique storage locations
const allStorageLocations = new Set<string>()
for (const p of activePolicies) {
for (const loc of p.storageLocations) {
allStorageLocations.add(loc.name || loc.type)
}
}
// Collect unique responsible roles
const roleMap = new Map<string, string[]>()
for (const p of activePolicies) {
const role = p.responsibleRole || p.responsiblePerson || 'Nicht zugewiesen'
if (!roleMap.has(role)) roleMap.set(role, [])
roleMap.get(role)!.push(p.dataObjectName || p.policyId)
}
// Collect active legal holds
const allActiveLegalHolds: Array<{ policy: string; hold: LoeschfristPolicy['legalHolds'][0] }> = []
for (const p of activePolicies) {
for (const h of getActiveLegalHolds(p)) {
allActiveLegalHolds.push({ policy: p.dataObjectName || p.policyId, hold: h })
}
}
// Build VVT cross-reference data
const vvtRefs: Array<{ policyName: string; policyId: string; vvtId: string; vvtName: string }> = []
for (const p of activePolicies) {
for (const linkedId of p.linkedVVTActivityIds) {
const activity = vvtActivities.find(a => a.id === linkedId)
if (activity) {
vvtRefs.push({
policyName: p.dataObjectName || p.policyId,
policyId: p.policyId,
vvtId: activity.vvt_id || activity.vvtId || linkedId.substring(0, 8),
vvtName: activity.activity_name || activity.name || 'Unbenannte Verarbeitungstaetigkeit',
})
}
}
}
// Build vendor cross-reference data
const vendorRefs: Array<{ policyName: string; policyId: string; vendorId: string; duration: string }> = []
for (const p of activePolicies) {
if (p.linkedVendorIds && p.linkedVendorIds.length > 0) {
for (const vendorId of p.linkedVendorIds) {
vendorRefs.push({
policyName: p.dataObjectName || p.policyId,
policyId: p.policyId,
vendorId,
duration: formatRetentionDuration(p.retentionDuration, p.retentionUnit),
})
}
}
}
let html = buildDocumentHeader(orgName)
html += buildCoverAndTOC(orgHeader, orgName, today)
html += buildSections1to5(orgName, orgHeader, activePolicies, allStorageLocations)
html += buildSections6to9(activePolicies, vvtRefs, vendorRefs, allActiveLegalHolds, roleMap)
html += buildSections10to12(orgHeader, complianceResult, revisions, today)
html += `
<div class="page-footer">
<span>Loeschkonzept — ${escHtml(orgName)}</span>
<span>Stand: ${today} | Version ${escHtml(orgHeader.loeschkonzeptVersion)}</span>
</div>
</body>
</html>`
return html
}
function buildDocumentHeader(orgName: string): string {
return `<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<title>Loeschkonzept — ${escHtml(orgName)}</title>
<style>
@page { size: A4; margin: 20mm 18mm 22mm 18mm; }
* { margin: 0; padding: 0; box-sizing: border-box; }
body { font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; font-size: 10pt; line-height: 1.5; color: #1e293b; }
.cover { min-height: 90vh; display: flex; flex-direction: column; justify-content: center; align-items: center; text-align: center; page-break-after: always; }
.cover h1 { font-size: 28pt; color: #5b21b6; margin-bottom: 8px; font-weight: 700; }
.cover .subtitle { font-size: 14pt; color: #7c3aed; margin-bottom: 40px; }
.cover .org-info { background: #f5f3ff; border: 1px solid #ddd6fe; border-radius: 8px; padding: 24px 40px; text-align: left; width: 400px; margin-bottom: 24px; }
.cover .org-info div { margin-bottom: 6px; }
.cover .org-info .label { font-weight: 600; color: #5b21b6; display: inline-block; min-width: 160px; }
.cover .legal-ref { font-size: 9pt; color: #64748b; margin-top: 20px; }
.toc { page-break-after: always; padding-top: 40px; }
.toc h2 { font-size: 18pt; color: #5b21b6; margin-bottom: 20px; border-bottom: 2px solid #5b21b6; padding-bottom: 8px; }
.toc-entry { display: flex; justify-content: space-between; padding: 6px 0; border-bottom: 1px dotted #cbd5e1; font-size: 10pt; }
.toc-entry .toc-num { font-weight: 600; color: #5b21b6; min-width: 40px; }
.section { page-break-inside: avoid; margin-bottom: 24px; }
.section-header { font-size: 14pt; color: #5b21b6; font-weight: 700; margin: 30px 0 12px 0; border-bottom: 2px solid #ddd6fe; padding-bottom: 6px; }
.section-body { margin-bottom: 16px; }
table { width: 100%; border-collapse: collapse; margin: 10px 0 16px 0; font-size: 9pt; }
th, td { border: 1px solid #e2e8f0; padding: 6px 8px; text-align: left; vertical-align: top; }
th { background: #f5f3ff; color: #5b21b6; font-weight: 600; font-size: 8.5pt; text-transform: uppercase; letter-spacing: 0.3px; }
tr:nth-child(even) td { background: #faf5ff; }
.policy-detail { page-break-inside: avoid; border: 1px solid #e2e8f0; border-radius: 6px; margin-bottom: 16px; overflow: hidden; }
.policy-detail-header { background: #f5f3ff; padding: 8px 12px; font-weight: 700; color: #5b21b6; border-bottom: 1px solid #ddd6fe; display: flex; justify-content: space-between; }
.policy-detail-body { padding: 0; }
.policy-detail-body table { margin: 0; }
.policy-detail-body th { width: 200px; }
.badge { display: inline-block; padding: 1px 8px; border-radius: 9999px; font-size: 8pt; font-weight: 600; }
.badge-active { background: #dcfce7; color: #166534; }
.badge-draft { background: #f3f4f6; color: #374151; }
.badge-review { background: #fef9c3; color: #854d0e; }
.badge-critical { background: #fecaca; color: #991b1b; }
.badge-high { background: #fed7aa; color: #9a3412; }
.badge-medium { background: #fef3c7; color: #92400e; }
.badge-low { background: #f3f4f6; color: #4b5563; }
.principle { margin-bottom: 10px; padding-left: 20px; position: relative; }
.principle::before { content: ''; position: absolute; left: 0; top: 6px; width: 10px; height: 10px; background: #7c3aed; border-radius: 50%; }
.principle strong { color: #5b21b6; }
.score-box { display: inline-block; padding: 4px 16px; border-radius: 8px; font-size: 18pt; font-weight: 700; margin-right: 12px; }
.score-excellent { background: #dcfce7; color: #166534; }
.score-good { background: #dbeafe; color: #1e40af; }
.score-needs-work { background: #fef3c7; color: #92400e; }
.score-poor { background: #fecaca; color: #991b1b; }
.page-footer { position: fixed; bottom: 0; left: 0; right: 0; padding: 8px 18mm; font-size: 7.5pt; color: #94a3b8; display: flex; justify-content: space-between; border-top: 1px solid #e2e8f0; }
@media print { body { -webkit-print-color-adjust: exact; print-color-adjust: exact; } .no-print { display: none !important; } .page-break { page-break-after: always; } }
</style>
</head>
<body>
`
}
function buildCoverAndTOC(
orgHeader: LoeschkonzeptOrgHeader,
orgName: string,
today: string
): string {
const sections = [
'Ziel und Zweck', 'Geltungsbereich', 'Grundprinzipien der Datenspeicherung',
'Loeschregeln-Uebersicht', 'Detaillierte Loeschregeln', 'VVT-Verknuepfung',
'Auftragsverarbeiter mit Loeschpflichten', 'Legal Hold Verfahren',
'Verantwortlichkeiten', 'Pruef- und Revisionszyklus', 'Compliance-Status', 'Aenderungshistorie',
]
return `
<div class="cover">
<h1>Loeschkonzept</h1>
<div class="subtitle">gemaess Art. 5 Abs. 1 lit. e, Art. 17, Art. 30 DSGVO</div>
<div class="org-info">
<div><span class="label">Organisation:</span> ${escHtml(orgName)}</div>
${orgHeader.industry ? `<div><span class="label">Branche:</span> ${escHtml(orgHeader.industry)}</div>` : ''}
${orgHeader.dpoName ? `<div><span class="label">Datenschutzbeauftragter:</span> ${escHtml(orgHeader.dpoName)}</div>` : ''}
${orgHeader.dpoContact ? `<div><span class="label">DSB-Kontakt:</span> ${escHtml(orgHeader.dpoContact)}</div>` : ''}
${orgHeader.responsiblePerson ? `<div><span class="label">Verantwortlicher:</span> ${escHtml(orgHeader.responsiblePerson)}</div>` : ''}
${orgHeader.employeeCount ? `<div><span class="label">Mitarbeiter:</span> ${escHtml(orgHeader.employeeCount)}</div>` : ''}
${orgHeader.locations.length > 0 ? `<div><span class="label">Standorte:</span> ${escHtml(orgHeader.locations.join(', '))}</div>` : ''}
</div>
<div class="legal-ref">
Version ${escHtml(orgHeader.loeschkonzeptVersion)} | Stand: ${today}<br/>
Letzte Pruefung: ${formatDateDE(orgHeader.lastReviewDate)} | Naechste Pruefung: ${formatDateDE(orgHeader.nextReviewDate)}<br/>
Pruefintervall: ${escHtml(orgHeader.reviewInterval)}
</div>
</div>
<div class="toc">
<h2>Inhaltsverzeichnis</h2>
${sections.map((s, i) => `<div class="toc-entry"><span><span class="toc-num">${i + 1}.</span> ${escHtml(s)}</span></div>`).join('\n ')}
</div>
`
}
function buildSections1to5(
orgName: string,
orgHeader: LoeschkonzeptOrgHeader,
activePolicies: LoeschfristPolicy[],
allStorageLocations: Set<string>
): string {
const storageListHtml = allStorageLocations.size > 0
? Array.from(allStorageLocations).map(s => `<li>${escHtml(s)}</li>`).join('')
: '<li><em>Keine Speicherorte dokumentiert</em></li>'
return `
<div class="section">
<div class="section-header">1. Ziel und Zweck</div>
<div class="section-body">
<p>Dieses Loeschkonzept definiert die systematischen Regeln und Verfahren fuer die Loeschung
personenbezogener Daten bei <strong>${escHtml(orgName)}</strong>. Es dient der Umsetzung
folgender DSGVO-Anforderungen:</p>
<table>
<tr><th>Rechtsgrundlage</th><th>Inhalt</th></tr>
<tr><td><strong>Art. 5 Abs. 1 lit. e DSGVO</strong></td><td>Grundsatz der Speicherbegrenzung — personenbezogene Daten duerfen nur so lange gespeichert werden, wie es fuer die Zwecke der Verarbeitung erforderlich ist.</td></tr>
<tr><td><strong>Art. 17 DSGVO</strong></td><td>Recht auf Loeschung (&bdquo;Recht auf Vergessenwerden&ldquo;) — Betroffene haben das Recht, die Loeschung ihrer Daten zu verlangen.</td></tr>
<tr><td><strong>Art. 30 DSGVO</strong></td><td>Verzeichnis von Verarbeitungstaetigkeiten — vorgesehene Fristen fuer die Loeschung der verschiedenen Datenkategorien muessen dokumentiert werden.</td></tr>
</table>
<p>Das Loeschkonzept ist fester Bestandteil des Datenschutz-Managementsystems und wird
regelmaessig ueberprueft und aktualisiert.</p>
</div>
</div>
<div class="section">
<div class="section-header">2. Geltungsbereich</div>
<div class="section-body">
<p>Dieses Loeschkonzept gilt fuer alle personenbezogenen Daten, die von <strong>${escHtml(orgName)}</strong>
verarbeitet werden. Es umfasst <strong>${activePolicies.length}</strong> Loeschregeln fuer folgende Systeme und Speicherorte:</p>
<ul style="margin: 8px 0 8px 24px;">${storageListHtml}</ul>
<p>Saemtliche Verarbeitungstaetigkeiten, die im Verzeichnis von Verarbeitungstaetigkeiten (VVT)
erfasst sind, werden durch dieses Loeschkonzept abgedeckt.</p>
</div>
</div>
<div class="section">
<div class="section-header">3. Grundprinzipien der Datenspeicherung</div>
<div class="section-body">
<div class="principle"><strong>Speicherbegrenzung:</strong> Personenbezogene Daten werden nur so lange gespeichert, wie es fuer den jeweiligen Verarbeitungszweck erforderlich ist (Art. 5 Abs. 1 lit. e DSGVO).</div>
<div class="principle"><strong>3-Level-Loeschlogik:</strong> Die Loeschung folgt einer dreistufigen Priorisierung: (1) Zweckende, (2) gesetzliche Aufbewahrungspflichten, (3) Legal Hold — jeweils mit der laengsten Frist als massgeblich.</div>
<div class="principle"><strong>Dokumentationspflicht:</strong> Jede Loeschregel ist dokumentiert mit Rechtsgrundlage, Frist, Loeschmethode und Verantwortlichkeit.</div>
<div class="principle"><strong>Regelmaessige Ueberpruefung:</strong> Alle Loeschregeln werden im definierten Intervall ueberprueft und bei Bedarf angepasst.</div>
<div class="principle"><strong>Datenschutz durch Technikgestaltung:</strong> Loeschmechanismen werden moeglichst automatisiert, um menschliche Fehler zu minimieren (Art. 25 DSGVO).</div>
</div>
</div>
${buildSection4Overview(activePolicies)}
${buildSection5Detail(activePolicies)}
`
}
function buildSection4Overview(activePolicies: LoeschfristPolicy[]): string {
let html = `
<div class="section page-break">
<div class="section-header">4. Loeschregeln-Uebersicht</div>
<div class="section-body">
<p>Die folgende Tabelle zeigt eine Uebersicht aller ${activePolicies.length} aktiven Loeschregeln:</p>
<table>
<tr>
<th>LF-Nr.</th>
<th>Datenobjekt</th>
<th>Loeschtrigger</th>
<th>Aufbewahrungsfrist</th>
<th>Loeschmethode</th>
<th>Status</th>
</tr>
`
for (const p of activePolicies) {
const trigger = TRIGGER_LABELS[getEffectiveDeletionTrigger(p)]
const duration = formatRetentionDuration(p.retentionDuration, p.retentionUnit)
const method = DELETION_METHOD_LABELS[p.deletionMethod]
const statusLabel = STATUS_LABELS[p.status]
const statusClass = p.status === 'ACTIVE' ? 'badge-active' : p.status === 'REVIEW_NEEDED' ? 'badge-review' : 'badge-draft'
html += ` <tr>
<td>${escHtml(p.policyId)}</td>
<td>${escHtml(p.dataObjectName)}</td>
<td>${escHtml(trigger)}</td>
<td>${escHtml(duration)}</td>
<td>${escHtml(method)}</td>
<td><span class="badge ${statusClass}">${escHtml(statusLabel)}</span></td>
</tr>
`
}
html += ` </table>
</div>
</div>
`
return html
}
function buildSection5Detail(activePolicies: LoeschfristPolicy[]): string {
let html = `
<div class="section">
<div class="section-header">5. Detaillierte Loeschregeln</div>
<div class="section-body">
`
for (const p of activePolicies) {
const trigger = TRIGGER_LABELS[getEffectiveDeletionTrigger(p)]
const duration = formatRetentionDuration(p.retentionDuration, p.retentionUnit)
const method = DELETION_METHOD_LABELS[p.deletionMethod]
const statusLabel = STATUS_LABELS[p.status]
const driverLabel = p.retentionDriver ? RETENTION_DRIVER_META[p.retentionDriver]?.label || p.retentionDriver : '-'
const driverStatute = p.retentionDriver ? RETENTION_DRIVER_META[p.retentionDriver]?.statute || '' : ''
const locations = p.storageLocations.map(l => l.name || l.type).join(', ') || '-'
const responsible = [p.responsiblePerson, p.responsibleRole].filter(s => s.trim()).join(' / ') || '-'
const activeHolds = getActiveLegalHolds(p)
html += `
<div class="policy-detail">
<div class="policy-detail-header">
<span>${escHtml(p.policyId)}${escHtml(p.dataObjectName)}</span>
<span class="badge ${p.status === 'ACTIVE' ? 'badge-active' : 'badge-draft'}">${escHtml(statusLabel)}</span>
</div>
<div class="policy-detail-body">
<table>
<tr><th>Beschreibung</th><td>${escHtml(p.description || '-')}</td></tr>
<tr><th>Betroffenengruppen</th><td>${escHtml(p.affectedGroups.join(', ') || '-')}</td></tr>
<tr><th>Datenkategorien</th><td>${escHtml(p.dataCategories.join(', ') || '-')}</td></tr>
<tr><th>Verarbeitungszweck</th><td>${escHtml(p.primaryPurpose || '-')}</td></tr>
<tr><th>Loeschtrigger</th><td>${escHtml(trigger)}</td></tr>
<tr><th>Aufbewahrungstreiber</th><td>${escHtml(driverLabel)}${driverStatute ? ` (${escHtml(driverStatute)})` : ''}</td></tr>
<tr><th>Aufbewahrungsfrist</th><td>${escHtml(duration)}</td></tr>
<tr><th>Startereignis</th><td>${escHtml(p.startEvent || '-')}</td></tr>
<tr><th>Loeschmethode</th><td>${escHtml(method)}</td></tr>
<tr><th>Loeschmethode (Detail)</th><td>${escHtml(p.deletionMethodDetail || '-')}</td></tr>
<tr><th>Speicherorte</th><td>${escHtml(locations)}</td></tr>
<tr><th>Verantwortlich</th><td>${escHtml(responsible)}</td></tr>
<tr><th>Pruefintervall</th><td>${escHtml(REVIEW_INTERVAL_LABELS[p.reviewInterval] || p.reviewInterval)}</td></tr>
${activeHolds.length > 0 ? `<tr><th>Aktive Legal Holds</th><td>${activeHolds.map(h => `${escHtml(h.reason)} (seit ${formatDateDE(h.startDate)})`).join('<br/>')}</td></tr>` : ''}
</table>
</div>
</div>
`
}
html += ` </div>
</div>
`
return html
}
function buildSections6to9(
activePolicies: LoeschfristPolicy[],
vvtRefs: Array<{ policyName: string; policyId: string; vvtId: string; vvtName: string }>,
vendorRefs: Array<{ policyName: string; policyId: string; vendorId: string; duration: string }>,
allActiveLegalHolds: Array<{ policy: string; hold: LoeschfristPolicy['legalHolds'][0] }>,
roleMap: Map<string, string[]>
): string {
let html = `
<div class="section page-break">
<div class="section-header">6. VVT-Verknuepfung</div>
<div class="section-body">
<p>Die folgende Tabelle zeigt die Verknuepfung zwischen Loeschregeln und Verarbeitungstaetigkeiten im VVT (Art. 30 DSGVO):</p>
`
if (vvtRefs.length > 0) {
html += ` <table>
<tr><th>Loeschregel</th><th>LF-Nr.</th><th>VVT-Nr.</th><th>Verarbeitungstaetigkeit</th></tr>
`
for (const ref of vvtRefs) {
html += ` <tr>
<td>${escHtml(ref.policyName)}</td>
<td>${escHtml(ref.policyId)}</td>
<td>${escHtml(ref.vvtId)}</td>
<td>${escHtml(ref.vvtName)}</td>
</tr>
`
}
html += ` </table>
`
} else {
html += ` <p><em>Noch keine VVT-Verknuepfungen dokumentiert.</em></p>
`
}
html += ` </div>
</div>
<div class="section">
<div class="section-header">7. Auftragsverarbeiter mit Loeschpflichten</div>
<div class="section-body">
<p>Die folgende Tabelle zeigt Loeschregeln, die mit Auftragsverarbeitern verknuepft sind (Art. 28 DSGVO).</p>
`
if (vendorRefs.length > 0) {
html += ` <table>
<tr><th>Loeschregel</th><th>LF-Nr.</th><th>Auftragsverarbeiter (ID)</th><th>Aufbewahrungsfrist</th></tr>
`
for (const ref of vendorRefs) {
html += ` <tr>
<td>${escHtml(ref.policyName)}</td>
<td>${escHtml(ref.policyId)}</td>
<td>${escHtml(ref.vendorId)}</td>
<td>${escHtml(ref.duration)}</td>
</tr>
`
}
html += ` </table>
`
} else {
html += ` <p><em>Noch keine Auftragsverarbeiter mit Loeschregeln verknuepft.</em></p>
`
}
html += ` </div>
</div>
<div class="section">
<div class="section-header">8. Legal Hold Verfahren</div>
<div class="section-body">
<p>Ein Legal Hold setzt die regulaere Loeschung aus. Betroffene Daten duerfen trotz abgelaufener Loeschfrist nicht geloescht werden, bis der Legal Hold aufgehoben wird.</p>
<p><strong>Verfahrensschritte:</strong></p>
<ol style="margin: 8px 0 8px 24px;">
<li>Rechtsabteilung/DSB identifiziert betroffene Datenkategorien</li>
<li>Legal Hold wird im System aktiviert (Status: Aktiv)</li>
<li>Automatische Loeschung wird fuer betroffene Policies ausgesetzt</li>
<li>Regelmaessige Pruefung, ob der Legal Hold noch erforderlich ist</li>
<li>Nach Aufhebung: Regulaere Loeschfristen greifen wieder</li>
</ol>
`
if (allActiveLegalHolds.length > 0) {
html += ` <p><strong>Aktuell aktive Legal Holds (${allActiveLegalHolds.length}):</strong></p>
<table>
<tr><th>Datenobjekt</th><th>Grund</th><th>Rechtsgrundlage</th><th>Seit</th><th>Voraussichtlich bis</th></tr>
`
for (const { policy, hold } of allActiveLegalHolds) {
html += ` <tr>
<td>${escHtml(policy)}</td>
<td>${escHtml(hold.reason)}</td>
<td>${escHtml(hold.legalBasis)}</td>
<td>${formatDateDE(hold.startDate)}</td>
<td>${hold.expectedEndDate ? formatDateDE(hold.expectedEndDate) : 'Unbefristet'}</td>
</tr>
`
}
html += ` </table>
`
} else {
html += ` <p><em>Derzeit sind keine aktiven Legal Holds vorhanden.</em></p>
`
}
html += ` </div>
</div>
<div class="section">
<div class="section-header">9. Verantwortlichkeiten</div>
<div class="section-body">
<p>Die folgende Rollenmatrix zeigt, welche Organisationseinheiten fuer welche Datenobjekte die Loeschverantwortung tragen:</p>
<table>
<tr><th>Rolle / Verantwortlich</th><th>Datenobjekte</th><th>Anzahl</th></tr>
`
for (const [role, objects] of roleMap.entries()) {
html += ` <tr>
<td>${escHtml(role)}</td>
<td>${objects.map(o => escHtml(o)).join(', ')}</td>
<td>${objects.length}</td>
</tr>
`
}
html += ` </table>
</div>
</div>
`
return html
}
function buildSections10to12(
orgHeader: LoeschkonzeptOrgHeader,
complianceResult: ComplianceCheckResult | null,
revisions: LoeschkonzeptRevision[],
today: string
): string {
let html = `
<div class="section">
<div class="section-header">10. Pruef- und Revisionszyklus</div>
<div class="section-body">
<table>
<tr><th>Eigenschaft</th><th>Wert</th></tr>
<tr><td>Aktuelles Pruefintervall</td><td>${escHtml(orgHeader.reviewInterval)}</td></tr>
<tr><td>Letzte Pruefung</td><td>${formatDateDE(orgHeader.lastReviewDate)}</td></tr>
<tr><td>Naechste Pruefung</td><td>${formatDateDE(orgHeader.nextReviewDate)}</td></tr>
<tr><td>Aktuelle Version</td><td>${escHtml(orgHeader.loeschkonzeptVersion)}</td></tr>
</table>
<p style="margin-top: 8px;">Bei jeder Pruefung wird das Loeschkonzept auf folgende Punkte ueberprueft:</p>
<ul style="margin: 8px 0 8px 24px;">
<li>Vollstaendigkeit aller Loeschregeln (neue Verarbeitungen erfasst?)</li>
<li>Aktualitaet der gesetzlichen Aufbewahrungsfristen</li>
<li>Wirksamkeit der technischen Loeschmechanismen</li>
<li>Einhaltung der definierten Loeschfristen</li>
<li>Angemessenheit der Verantwortlichkeiten</li>
</ul>
</div>
</div>
`
html += buildSection11Compliance(complianceResult)
html += buildSection12History(revisions, orgHeader, today)
return html
}
function buildSection11Compliance(complianceResult: ComplianceCheckResult | null): string {
let html = `
<div class="section page-break">
<div class="section-header">11. Compliance-Status</div>
<div class="section-body">
`
if (complianceResult) {
const scoreClass = complianceResult.score >= 90 ? 'score-excellent'
: complianceResult.score >= 75 ? 'score-good'
: complianceResult.score >= 50 ? 'score-needs-work'
: 'score-poor'
const scoreLabel = complianceResult.score >= 90 ? 'Ausgezeichnet'
: complianceResult.score >= 75 ? 'Gut'
: complianceResult.score >= 50 ? 'Verbesserungswuerdig'
: 'Mangelhaft'
html += ` <p><span class="score-box ${scoreClass}">${complianceResult.score}/100</span> ${escHtml(scoreLabel)}</p>
<table style="margin-top: 12px;">
<tr><th>Kennzahl</th><th>Wert</th></tr>
<tr><td>Gepruefte Policies</td><td>${complianceResult.stats.total}</td></tr>
<tr><td>Bestanden</td><td>${complianceResult.stats.passed}</td></tr>
<tr><td>Beanstandungen</td><td>${complianceResult.stats.failed}</td></tr>
</table>
`
if (complianceResult.issues.length > 0) {
html += ` <p style="margin-top: 12px;"><strong>Befunde nach Schweregrad:</strong></p>
<table>
<tr><th>Schweregrad</th><th>Anzahl</th><th>Befunde</th></tr>
`
const severityOrder: ComplianceIssueSeverity[] = ['CRITICAL', 'HIGH', 'MEDIUM', 'LOW']
for (const sev of severityOrder) {
const count = complianceResult.stats.bySeverity[sev]
if (count === 0) continue
const issuesForSev = complianceResult.issues.filter(i => i.severity === sev)
html += ` <tr>
<td><span class="badge badge-${sev.toLowerCase()}" style="color: ${SEVERITY_COLORS[sev]}">${SEVERITY_LABELS_DE[sev]}</span></td>
<td>${count}</td>
<td>${issuesForSev.map(i => escHtml(i.title)).join('; ')}</td>
</tr>
`
}
html += ` </table>
`
} else {
html += ` <p style="margin-top: 8px;"><em>Keine Beanstandungen. Alle Policies sind konform.</em></p>
`
}
} else {
html += ` <p><em>Compliance-Check wurde noch nicht ausgefuehrt.</em></p>
`
}
html += ` </div>
</div>
`
return html
}
function buildSection12History(
revisions: LoeschkonzeptRevision[],
orgHeader: LoeschkonzeptOrgHeader,
today: string
): string {
let html = `
<div class="section">
<div class="section-header">12. Aenderungshistorie</div>
<div class="section-body">
<table>
<tr><th>Version</th><th>Datum</th><th>Autor</th><th>Aenderungen</th></tr>
`
if (revisions.length > 0) {
for (const rev of revisions) {
html += ` <tr>
<td>${escHtml(rev.version)}</td>
<td>${formatDateDE(rev.date)}</td>
<td>${escHtml(rev.author)}</td>
<td>${escHtml(rev.changes)}</td>
</tr>
`
}
} else {
html += ` <tr>
<td>${escHtml(orgHeader.loeschkonzeptVersion)}</td>
<td>${today}</td>
<td>${escHtml(orgHeader.dpoName || orgHeader.responsiblePerson || '-')}</td>
<td>Erstversion des Loeschkonzepts</td>
</tr>
`
}
html += ` </table>
</div>
</div>
`
return html
}

View File

@@ -0,0 +1,60 @@
// =============================================================================
// Loeschfristen Document — Types, Defaults & Severity Labels
// =============================================================================
import type { ComplianceIssueSeverity } from '../loeschfristen-compliance'
export interface LoeschkonzeptOrgHeader {
organizationName: string
industry: string
dpoName: string
dpoContact: string
responsiblePerson: string
locations: string[]
employeeCount: string
loeschkonzeptVersion: string
lastReviewDate: string
nextReviewDate: string
reviewInterval: string
}
export interface LoeschkonzeptRevision {
version: string
date: string
author: string
changes: string
}
export function createDefaultLoeschkonzeptOrgHeader(): LoeschkonzeptOrgHeader {
const now = new Date()
const nextYear = new Date()
nextYear.setFullYear(nextYear.getFullYear() + 1)
return {
organizationName: '',
industry: '',
dpoName: '',
dpoContact: '',
responsiblePerson: '',
locations: [],
employeeCount: '',
loeschkonzeptVersion: '1.0',
lastReviewDate: now.toISOString().split('T')[0],
nextReviewDate: nextYear.toISOString().split('T')[0],
reviewInterval: 'Jaehrlich',
}
}
export const SEVERITY_LABELS_DE: Record<ComplianceIssueSeverity, string> = {
CRITICAL: 'Kritisch',
HIGH: 'Hoch',
MEDIUM: 'Mittel',
LOW: 'Niedrig',
}
export const SEVERITY_COLORS: Record<ComplianceIssueSeverity, string> = {
CRITICAL: '#dc2626',
HIGH: '#ea580c',
MEDIUM: '#d97706',
LOW: '#6b7280',
}

View File

@@ -1,915 +1,8 @@
// ============================================================================= // =============================================================================
// Obligations Module - Pflichtenregister Document Generator // Obligations Module - Pflichtenregister Document Generator
// Generates a printable, audit-ready HTML document for the obligation register // Barrel re-export — implementation split into obligations-document/
// ============================================================================= // =============================================================================
import type { Obligation, ObligationComplianceCheckResult, ObligationComplianceIssueSeverity } from './obligations-compliance' export type { ObligationDocumentOrgHeader, ObligationDocumentRevision } from './obligations-document/types-defaults'
import { OBLIGATION_SEVERITY_LABELS_DE, OBLIGATION_SEVERITY_COLORS } from './obligations-compliance' export { createDefaultObligationDocumentOrgHeader } from './obligations-document/types-defaults'
export { buildObligationDocumentHtml } from './obligations-document/html-builder'
// =============================================================================
// TYPES
// =============================================================================
export interface ObligationDocumentOrgHeader {
organizationName: string
industry: string
dpoName: string
dpoContact: string
responsiblePerson: string
legalDepartment: string
documentVersion: string
lastReviewDate: string
nextReviewDate: string
reviewInterval: string
}
export interface ObligationDocumentRevision {
version: string
date: string
author: string
changes: string
}
// =============================================================================
// DEFAULTS
// =============================================================================
export function createDefaultObligationDocumentOrgHeader(): ObligationDocumentOrgHeader {
const now = new Date()
const nextYear = new Date()
nextYear.setFullYear(nextYear.getFullYear() + 1)
return {
organizationName: '',
industry: '',
dpoName: '',
dpoContact: '',
responsiblePerson: '',
legalDepartment: '',
documentVersion: '1.0',
lastReviewDate: now.toISOString().split('T')[0],
nextReviewDate: nextYear.toISOString().split('T')[0],
reviewInterval: 'Jaehrlich',
}
}
// =============================================================================
// STATUS & PRIORITY LABELS
// =============================================================================
const STATUS_LABELS_DE: Record<string, string> = {
'pending': 'Ausstehend',
'in-progress': 'In Bearbeitung',
'completed': 'Abgeschlossen',
'overdue': 'Ueberfaellig',
}
const STATUS_BADGE_CLASSES: Record<string, string> = {
'pending': 'badge-draft',
'in-progress': 'badge-review',
'completed': 'badge-active',
'overdue': 'badge-critical',
}
const PRIORITY_LABELS_DE: Record<string, string> = {
critical: 'Kritisch',
high: 'Hoch',
medium: 'Mittel',
low: 'Niedrig',
}
const PRIORITY_BADGE_CLASSES: Record<string, string> = {
critical: 'badge-critical',
high: 'badge-high',
medium: 'badge-medium',
low: 'badge-low',
}
// =============================================================================
// HTML DOCUMENT BUILDER
// =============================================================================
export function buildObligationDocumentHtml(
obligations: Obligation[],
orgHeader: ObligationDocumentOrgHeader,
complianceResult: ObligationComplianceCheckResult | null,
revisions: ObligationDocumentRevision[]
): string {
const today = new Date().toLocaleDateString('de-DE', {
day: '2-digit',
month: '2-digit',
year: 'numeric',
})
const orgName = orgHeader.organizationName || 'Organisation'
// Group obligations by source (regulation)
const bySource = new Map<string, Obligation[]>()
for (const o of obligations) {
const src = o.source || 'Sonstig'
if (!bySource.has(src)) bySource.set(src, [])
bySource.get(src)!.push(o)
}
// Build role map
const roleMap = new Map<string, Obligation[]>()
for (const o of obligations) {
const role = o.responsible || 'Nicht zugewiesen'
if (!roleMap.has(role)) roleMap.set(role, [])
roleMap.get(role)!.push(o)
}
// Distinct sources
const distinctSources = Array.from(bySource.keys()).sort()
// =========================================================================
// HTML Template
// =========================================================================
let html = `<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<title>Pflichtenregister — ${escHtml(orgName)}</title>
<style>
@page { size: A4; margin: 20mm 18mm 22mm 18mm; }
* { margin: 0; padding: 0; box-sizing: border-box; }
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
font-size: 10pt;
line-height: 1.5;
color: #1e293b;
}
/* Cover */
.cover {
min-height: 90vh;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
text-align: center;
page-break-after: always;
}
.cover h1 {
font-size: 28pt;
color: #5b21b6;
margin-bottom: 8px;
font-weight: 700;
}
.cover .subtitle {
font-size: 14pt;
color: #7c3aed;
margin-bottom: 40px;
}
.cover .org-info {
background: #f5f3ff;
border: 1px solid #ddd6fe;
border-radius: 8px;
padding: 24px 40px;
text-align: left;
width: 400px;
margin-bottom: 24px;
}
.cover .org-info div { margin-bottom: 6px; }
.cover .org-info .label { font-weight: 600; color: #5b21b6; display: inline-block; min-width: 160px; }
.cover .legal-ref {
font-size: 9pt;
color: #64748b;
margin-top: 20px;
}
/* TOC */
.toc {
page-break-after: always;
padding-top: 40px;
}
.toc h2 {
font-size: 18pt;
color: #5b21b6;
margin-bottom: 20px;
border-bottom: 2px solid #5b21b6;
padding-bottom: 8px;
}
.toc-entry {
display: flex;
justify-content: space-between;
padding: 6px 0;
border-bottom: 1px dotted #cbd5e1;
font-size: 10pt;
}
.toc-entry .toc-num { font-weight: 600; color: #5b21b6; min-width: 40px; }
/* Sections */
.section {
page-break-inside: avoid;
margin-bottom: 24px;
}
.section-header {
font-size: 14pt;
color: #5b21b6;
font-weight: 700;
margin: 30px 0 12px 0;
border-bottom: 2px solid #ddd6fe;
padding-bottom: 6px;
}
.section-body { margin-bottom: 16px; }
/* Tables */
table {
width: 100%;
border-collapse: collapse;
margin: 10px 0 16px 0;
font-size: 9pt;
}
th, td {
border: 1px solid #e2e8f0;
padding: 6px 8px;
text-align: left;
vertical-align: top;
}
th {
background: #f5f3ff;
color: #5b21b6;
font-weight: 600;
font-size: 8.5pt;
text-transform: uppercase;
letter-spacing: 0.3px;
}
tr:nth-child(even) td { background: #faf5ff; }
/* Detail cards */
.policy-detail {
page-break-inside: avoid;
border: 1px solid #e2e8f0;
border-radius: 6px;
margin-bottom: 16px;
overflow: hidden;
}
.policy-detail-header {
background: #f5f3ff;
padding: 8px 12px;
font-weight: 700;
color: #5b21b6;
border-bottom: 1px solid #ddd6fe;
display: flex;
justify-content: space-between;
}
.policy-detail-body { padding: 0; }
.policy-detail-body table { margin: 0; }
.policy-detail-body th { width: 200px; }
/* Badges */
.badge {
display: inline-block;
padding: 1px 8px;
border-radius: 9999px;
font-size: 8pt;
font-weight: 600;
}
.badge-active { background: #dcfce7; color: #166534; }
.badge-draft { background: #f3f4f6; color: #374151; }
.badge-review { background: #fef9c3; color: #854d0e; }
.badge-critical { background: #fecaca; color: #991b1b; }
.badge-high { background: #fed7aa; color: #9a3412; }
.badge-medium { background: #fef3c7; color: #92400e; }
.badge-low { background: #f3f4f6; color: #4b5563; }
/* Principles */
.principle {
margin-bottom: 10px;
padding-left: 20px;
position: relative;
}
.principle::before {
content: '';
position: absolute;
left: 0;
top: 6px;
width: 10px;
height: 10px;
background: #7c3aed;
border-radius: 50%;
}
.principle strong { color: #5b21b6; }
/* Score */
.score-box {
display: inline-block;
padding: 4px 16px;
border-radius: 8px;
font-size: 18pt;
font-weight: 700;
margin-right: 12px;
}
.score-excellent { background: #dcfce7; color: #166534; }
.score-good { background: #dbeafe; color: #1e40af; }
.score-needs-work { background: #fef3c7; color: #92400e; }
.score-poor { background: #fecaca; color: #991b1b; }
/* Footer */
.page-footer {
position: fixed;
bottom: 0;
left: 0;
right: 0;
padding: 8px 18mm;
font-size: 7.5pt;
color: #94a3b8;
display: flex;
justify-content: space-between;
border-top: 1px solid #e2e8f0;
}
/* Print */
@media print {
body { -webkit-print-color-adjust: exact; print-color-adjust: exact; }
.no-print { display: none !important; }
.page-break { page-break-after: always; }
}
</style>
</head>
<body>
`
// =========================================================================
// Section 0: Cover Page
// =========================================================================
html += `
<div class="cover">
<h1>Pflichtenregister</h1>
<div class="subtitle">Regulatorische Pflichten — DSGVO, AI Act, NIS2 und weitere</div>
<div class="org-info">
<div><span class="label">Organisation:</span> ${escHtml(orgName)}</div>
${orgHeader.industry ? `<div><span class="label">Branche:</span> ${escHtml(orgHeader.industry)}</div>` : ''}
${orgHeader.dpoName ? `<div><span class="label">DSB:</span> ${escHtml(orgHeader.dpoName)}</div>` : ''}
${orgHeader.dpoContact ? `<div><span class="label">DSB-Kontakt:</span> ${escHtml(orgHeader.dpoContact)}</div>` : ''}
${orgHeader.responsiblePerson ? `<div><span class="label">Verantwortlicher:</span> ${escHtml(orgHeader.responsiblePerson)}</div>` : ''}
${orgHeader.legalDepartment ? `<div><span class="label">Rechtsabteilung:</span> ${escHtml(orgHeader.legalDepartment)}</div>` : ''}
</div>
<div class="legal-ref">
Version ${escHtml(orgHeader.documentVersion)} | Stand: ${today}<br/>
Letzte Pruefung: ${formatDateDE(orgHeader.lastReviewDate)} | Naechste Pruefung: ${formatDateDE(orgHeader.nextReviewDate)}<br/>
Pruefintervall: ${escHtml(orgHeader.reviewInterval)}
</div>
</div>
`
// =========================================================================
// Table of Contents
// =========================================================================
const sections = [
'Ziel und Zweck',
'Geltungsbereich',
'Methodik',
'Regulatorische Grundlagen',
'Pflichtenuebersicht',
'Detaillierte Pflichten',
'Verantwortlichkeiten',
'Fristen und Termine',
'Nachweisverzeichnis',
'Compliance-Status',
'Aenderungshistorie',
]
html += `
<div class="toc">
<h2>Inhaltsverzeichnis</h2>
${sections.map((s, i) => `<div class="toc-entry"><span><span class="toc-num">${i + 1}.</span> ${escHtml(s)}</span></div>`).join('\n ')}
</div>
`
// =========================================================================
// Section 1: Ziel und Zweck
// =========================================================================
html += `
<div class="section">
<div class="section-header">1. Ziel und Zweck</div>
<div class="section-body">
<p>Dieses Pflichtenregister dokumentiert alle regulatorischen Pflichten, denen
<strong>${escHtml(orgName)}</strong> unterliegt. Es dient der systematischen Erfassung,
Ueberwachung und Nachverfolgung aller Compliance-Anforderungen aus den anwendbaren
Regulierungen.</p>
<p style="margin-top: 8px;">Das Register erfuellt folgende Zwecke:</p>
<ul style="margin: 8px 0 8px 24px;">
<li>Vollstaendige Erfassung aller anwendbaren regulatorischen Pflichten</li>
<li>Zuordnung von Verantwortlichkeiten und Fristen</li>
<li>Nachverfolgung des Umsetzungsstatus</li>
<li>Dokumentation von Nachweisen fuer Audits</li>
<li>Identifikation von Compliance-Luecken und Handlungsbedarf</li>
</ul>
<table>
<tr><th>Rechtsrahmen</th><th>Relevanz</th></tr>
<tr><td><strong>DSGVO (EU) 2016/679</strong></td><td>Datenschutz-Grundverordnung — Kernregulierung fuer personenbezogene Daten</td></tr>
<tr><td><strong>AI Act (EU) 2024/1689</strong></td><td>KI-Verordnung — Anforderungen an KI-Systeme nach Risikoklasse</td></tr>
<tr><td><strong>NIS2 (EU) 2022/2555</strong></td><td>Netzwerk- und Informationssicherheit — Cybersicherheitspflichten</td></tr>
<tr><td><strong>BDSG</strong></td><td>Bundesdatenschutzgesetz — Nationale Ergaenzung zur DSGVO</td></tr>
</table>
</div>
</div>
`
// =========================================================================
// Section 2: Geltungsbereich
// =========================================================================
html += `
<div class="section">
<div class="section-header">2. Geltungsbereich</div>
<div class="section-body">
<p>Dieses Pflichtenregister gilt fuer alle Geschaeftsprozesse und IT-Systeme von
<strong>${escHtml(orgName)}</strong>${orgHeader.industry ? ` (Branche: ${escHtml(orgHeader.industry)})` : ''}.</p>
<p style="margin-top: 8px;">Anwendbare Regulierungen:</p>
<table>
<tr><th>Regulierung</th><th>Anzahl Pflichten</th><th>Status</th></tr>
`
for (const [source, obls] of bySource.entries()) {
const completed = obls.filter(o => o.status === 'completed').length
const pct = obls.length > 0 ? Math.round((completed / obls.length) * 100) : 0
html += ` <tr>
<td>${escHtml(source)}</td>
<td>${obls.length}</td>
<td>${completed}/${obls.length} abgeschlossen (${pct}%)</td>
</tr>
`
}
html += ` </table>
<p>Insgesamt umfasst dieses Register <strong>${obligations.length}</strong> Pflichten aus
<strong>${distinctSources.length}</strong> Regulierungen.</p>
</div>
</div>
`
// =========================================================================
// Section 3: Methodik
// =========================================================================
html += `
<div class="section">
<div class="section-header">3. Methodik</div>
<div class="section-body">
<p>Die Identifikation und Bewertung der Pflichten erfolgt in drei Schritten:</p>
<div class="principle"><strong>Pflicht-Identifikation:</strong> Systematische Analyse aller anwendbaren Regulierungen und Extraktion der einzelnen Pflichten mit Artikel-Referenz, Beschreibung und Zielgruppe.</div>
<div class="principle"><strong>Bewertung und Priorisierung:</strong> Jede Pflicht wird nach Prioritaet (kritisch, hoch, mittel, niedrig) und Dringlichkeit (Frist) bewertet. Die Bewertung basiert auf dem Risikopotenzial bei Nichterfuellung.</div>
<div class="principle"><strong>Ueberwachung und Nachverfolgung:</strong> Regelmaessige Pruefung des Umsetzungsstatus, Aktualisierung der Fristen und Dokumentation von Nachweisen.</div>
<p style="margin-top: 12px;">Die Pflichten werden ueber einen automatisierten Compliance-Check geprueft, der
11 Kriterien umfasst (siehe Abschnitt 10: Compliance-Status).</p>
</div>
</div>
`
// =========================================================================
// Section 4: Regulatorische Grundlagen
// =========================================================================
html += `
<div class="section page-break">
<div class="section-header">4. Regulatorische Grundlagen</div>
<div class="section-body">
<p>Die folgende Tabelle zeigt die regulatorischen Grundlagen mit Artikelzahl und Umsetzungsstatus:</p>
<table>
<tr>
<th>Regulierung</th>
<th>Pflichten</th>
<th>Kritisch</th>
<th>Hoch</th>
<th>Mittel</th>
<th>Niedrig</th>
<th>Abgeschlossen</th>
</tr>
`
for (const [source, obls] of bySource.entries()) {
const critical = obls.filter(o => o.priority === 'critical').length
const high = obls.filter(o => o.priority === 'high').length
const medium = obls.filter(o => o.priority === 'medium').length
const low = obls.filter(o => o.priority === 'low').length
const completed = obls.filter(o => o.status === 'completed').length
html += ` <tr>
<td><strong>${escHtml(source)}</strong></td>
<td>${obls.length}</td>
<td>${critical}</td>
<td>${high}</td>
<td>${medium}</td>
<td>${low}</td>
<td>${completed}</td>
</tr>
`
}
// Totals row
const totalCritical = obligations.filter(o => o.priority === 'critical').length
const totalHigh = obligations.filter(o => o.priority === 'high').length
const totalMedium = obligations.filter(o => o.priority === 'medium').length
const totalLow = obligations.filter(o => o.priority === 'low').length
const totalCompleted = obligations.filter(o => o.status === 'completed').length
html += ` <tr style="font-weight: 700; background: #f5f3ff;">
<td>Gesamt</td>
<td>${obligations.length}</td>
<td>${totalCritical}</td>
<td>${totalHigh}</td>
<td>${totalMedium}</td>
<td>${totalLow}</td>
<td>${totalCompleted}</td>
</tr>
`
html += ` </table>
</div>
</div>
`
// =========================================================================
// Section 5: Pflichtenuebersicht
// =========================================================================
html += `
<div class="section">
<div class="section-header">5. Pflichtenuebersicht</div>
<div class="section-body">
<p>Uebersicht aller ${obligations.length} Pflichten nach Regulierung und Status:</p>
<table>
<tr>
<th>Regulierung</th>
<th>Gesamt</th>
<th>Ausstehend</th>
<th>In Bearbeitung</th>
<th>Abgeschlossen</th>
<th>Ueberfaellig</th>
</tr>
`
for (const [source, obls] of bySource.entries()) {
const pending = obls.filter(o => o.status === 'pending').length
const inProgress = obls.filter(o => o.status === 'in-progress').length
const completed = obls.filter(o => o.status === 'completed').length
const overdue = obls.filter(o => o.status === 'overdue').length
html += ` <tr>
<td>${escHtml(source)}</td>
<td>${obls.length}</td>
<td>${pending}</td>
<td>${inProgress}</td>
<td>${completed}</td>
<td>${overdue > 0 ? `<span class="badge badge-critical">${overdue}</span>` : '0'}</td>
</tr>
`
}
html += ` </table>
</div>
</div>
`
// =========================================================================
// Section 6: Detaillierte Pflichten
// =========================================================================
html += `
<div class="section">
<div class="section-header">6. Detaillierte Pflichten</div>
<div class="section-body">
`
for (const [source, obls] of bySource.entries()) {
// Sort by priority (critical first) then by title
const priorityOrder: Record<string, number> = { critical: 0, high: 1, medium: 2, low: 3 }
const sorted = [...obls].sort((a, b) => {
const pa = priorityOrder[a.priority] ?? 2
const pb = priorityOrder[b.priority] ?? 2
if (pa !== pb) return pa - pb
return a.title.localeCompare(b.title)
})
html += ` <h3 style="color: #5b21b6; margin: 20px 0 10px 0; font-size: 11pt;">${escHtml(source)} <span style="font-weight: 400; font-size: 9pt; color: #64748b;">(${sorted.length} Pflichten)</span></h3>
`
for (const o of sorted) {
const statusLabel = STATUS_LABELS_DE[o.status] || o.status
const statusBadge = STATUS_BADGE_CLASSES[o.status] || 'badge-draft'
const priorityLabel = PRIORITY_LABELS_DE[o.priority] || o.priority
const priorityBadge = PRIORITY_BADGE_CLASSES[o.priority] || 'badge-draft'
const deadlineStr = o.deadline ? formatDateDE(o.deadline) : '—'
const evidenceStr = o.evidence && o.evidence.length > 0
? o.evidence.map(e => escHtml(e)).join(', ')
: '<em style="color: #d97706;">Kein Nachweis</em>'
const systemsStr = o.linked_systems && o.linked_systems.length > 0
? o.linked_systems.map(s => escHtml(s)).join(', ')
: '—'
html += `
<div class="policy-detail">
<div class="policy-detail-header">
<span>${escHtml(o.title)}</span>
<span class="badge ${statusBadge}">${escHtml(statusLabel)}</span>
</div>
<div class="policy-detail-body">
<table>
<tr><th>Rechtsquelle</th><td>${escHtml(o.source)} ${escHtml(o.source_article || '')}</td></tr>
<tr><th>Beschreibung</th><td>${escHtml(o.description || '—')}</td></tr>
<tr><th>Prioritaet</th><td><span class="badge ${priorityBadge}">${escHtml(priorityLabel)}</span></td></tr>
<tr><th>Status</th><td><span class="badge ${statusBadge}">${escHtml(statusLabel)}</span></td></tr>
<tr><th>Verantwortlich</th><td>${escHtml(o.responsible || '—')}</td></tr>
<tr><th>Frist</th><td>${deadlineStr}</td></tr>
<tr><th>Nachweise</th><td>${evidenceStr}</td></tr>
<tr><th>Betroffene Systeme</th><td>${systemsStr}</td></tr>
${o.linked_vendor_ids && o.linked_vendor_ids.length > 0 ? `<tr><th>Auftragsverarbeiter</th><td>${o.linked_vendor_ids.map(id => escHtml(id)).join(', ')}</td></tr>` : ''}
${o.notes ? `<tr><th>Notizen</th><td>${escHtml(o.notes)}</td></tr>` : ''}
</table>
</div>
</div>
`
}
}
html += ` </div>
</div>
`
// =========================================================================
// Section 7: Verantwortlichkeiten
// =========================================================================
html += `
<div class="section page-break">
<div class="section-header">7. Verantwortlichkeiten</div>
<div class="section-body">
<p>Die folgende Rollenmatrix zeigt, welche Personen oder Abteilungen fuer welche Pflichten
die Umsetzungsverantwortung tragen:</p>
<table>
<tr><th>Verantwortlich</th><th>Pflichten</th><th>Anzahl</th><th>Davon offen</th></tr>
`
for (const [role, obls] of roleMap.entries()) {
const openCount = obls.filter(o => o.status !== 'completed').length
const titles = obls.slice(0, 5).map(o => escHtml(o.title))
const suffix = obls.length > 5 ? `, ... (+${obls.length - 5})` : ''
html += ` <tr>
<td>${escHtml(role)}</td>
<td>${titles.join('; ')}${suffix}</td>
<td>${obls.length}</td>
<td>${openCount}</td>
</tr>
`
}
html += ` </table>
</div>
</div>
`
// =========================================================================
// Section 8: Fristen und Termine
// =========================================================================
const now = new Date()
const withDeadline = obligations
.filter(o => o.deadline && o.status !== 'completed')
.sort((a, b) => new Date(a.deadline!).getTime() - new Date(b.deadline!).getTime())
const overdue = withDeadline.filter(o => new Date(o.deadline!) < now)
const upcoming = withDeadline.filter(o => new Date(o.deadline!) >= now)
html += `
<div class="section">
<div class="section-header">8. Fristen und Termine</div>
<div class="section-body">
`
if (overdue.length > 0) {
html += ` <h4 style="color: #dc2626; margin-bottom: 8px;">Ueberfaellige Pflichten (${overdue.length})</h4>
<table>
<tr><th>Pflicht</th><th>Regulierung</th><th>Frist</th><th>Tage ueberfaellig</th><th>Prioritaet</th></tr>
`
for (const o of overdue) {
const days = daysBetween(new Date(o.deadline!), now)
html += ` <tr>
<td>${escHtml(o.title)}</td>
<td>${escHtml(o.source)}</td>
<td>${formatDateDE(o.deadline)}</td>
<td><span class="badge badge-critical">${days} Tage</span></td>
<td><span class="badge ${PRIORITY_BADGE_CLASSES[o.priority] || 'badge-draft'}">${escHtml(PRIORITY_LABELS_DE[o.priority] || o.priority)}</span></td>
</tr>
`
}
html += ` </table>
`
}
if (upcoming.length > 0) {
html += ` <h4 style="color: #5b21b6; margin: 16px 0 8px 0;">Anstehende Fristen (${upcoming.length})</h4>
<table>
<tr><th>Pflicht</th><th>Regulierung</th><th>Frist</th><th>Verbleibend</th><th>Verantwortlich</th></tr>
`
for (const o of upcoming.slice(0, 20)) {
const days = daysBetween(now, new Date(o.deadline!))
html += ` <tr>
<td>${escHtml(o.title)}</td>
<td>${escHtml(o.source)}</td>
<td>${formatDateDE(o.deadline)}</td>
<td>${days} Tage</td>
<td>${escHtml(o.responsible || '—')}</td>
</tr>
`
}
if (upcoming.length > 20) {
html += ` <tr><td colspan="5" style="text-align: center; color: #64748b;">... und ${upcoming.length - 20} weitere</td></tr>
`
}
html += ` </table>
`
}
if (withDeadline.length === 0) {
html += ` <p><em>Keine offenen Pflichten mit Fristen vorhanden.</em></p>
`
}
html += ` </div>
</div>
`
// =========================================================================
// Section 9: Nachweisverzeichnis
// =========================================================================
const withEvidence = obligations.filter(o => o.evidence && o.evidence.length > 0)
const withoutEvidence = obligations.filter(o => !o.evidence || o.evidence.length === 0)
html += `
<div class="section page-break">
<div class="section-header">9. Nachweisverzeichnis</div>
<div class="section-body">
<p>${withEvidence.length} von ${obligations.length} Pflichten haben Nachweise hinterlegt.</p>
`
if (withEvidence.length > 0) {
html += ` <table>
<tr><th>Pflicht</th><th>Regulierung</th><th>Nachweise</th><th>Status</th></tr>
`
for (const o of withEvidence) {
html += ` <tr>
<td>${escHtml(o.title)}</td>
<td>${escHtml(o.source)}</td>
<td>${o.evidence!.map(e => escHtml(e)).join(', ')}</td>
<td><span class="badge ${STATUS_BADGE_CLASSES[o.status] || 'badge-draft'}">${escHtml(STATUS_LABELS_DE[o.status] || o.status)}</span></td>
</tr>
`
}
html += ` </table>
`
}
if (withoutEvidence.length > 0) {
html += ` <p style="margin-top: 12px;"><strong>Pflichten ohne Nachweise (${withoutEvidence.length}):</strong></p>
<ul style="margin: 4px 0 8px 24px; font-size: 9pt; color: #d97706;">
`
for (const o of withoutEvidence.slice(0, 15)) {
html += ` <li>${escHtml(o.title)} (${escHtml(o.source)})</li>
`
}
if (withoutEvidence.length > 15) {
html += ` <li>... und ${withoutEvidence.length - 15} weitere</li>
`
}
html += ` </ul>
`
}
html += ` </div>
</div>
`
// =========================================================================
// Section 10: Compliance-Status
// =========================================================================
html += `
<div class="section">
<div class="section-header">10. Compliance-Status</div>
<div class="section-body">
`
if (complianceResult) {
const scoreClass = complianceResult.score >= 90 ? 'score-excellent'
: complianceResult.score >= 75 ? 'score-good'
: complianceResult.score >= 50 ? 'score-needs-work'
: 'score-poor'
const scoreLabel = complianceResult.score >= 90 ? 'Ausgezeichnet'
: complianceResult.score >= 75 ? 'Gut'
: complianceResult.score >= 50 ? 'Verbesserungswuerdig'
: 'Mangelhaft'
html += ` <p><span class="score-box ${scoreClass}">${complianceResult.score}/100</span> ${escHtml(scoreLabel)}</p>
<table style="margin-top: 12px;">
<tr><th>Kennzahl</th><th>Wert</th></tr>
<tr><td>Geprueft am</td><td>${formatDateDE(complianceResult.checkedAt)}</td></tr>
<tr><td>Befunde gesamt</td><td>${complianceResult.summary.total}</td></tr>
<tr><td>Kritisch</td><td>${complianceResult.summary.critical}</td></tr>
<tr><td>Hoch</td><td>${complianceResult.summary.high}</td></tr>
<tr><td>Mittel</td><td>${complianceResult.summary.medium}</td></tr>
<tr><td>Niedrig</td><td>${complianceResult.summary.low}</td></tr>
</table>
`
if (complianceResult.issues.length > 0) {
html += ` <p style="margin-top: 12px;"><strong>Befunde nach Schweregrad:</strong></p>
<table>
<tr><th>Schweregrad</th><th>Befund</th><th>Betroffene Pflichten</th><th>Empfehlung</th></tr>
`
const severityOrder: ObligationComplianceIssueSeverity[] = ['CRITICAL', 'HIGH', 'MEDIUM', 'LOW']
for (const sev of severityOrder) {
const issuesForSev = complianceResult.issues.filter(i => i.severity === sev)
for (const issue of issuesForSev) {
html += ` <tr>
<td><span class="badge badge-${sev.toLowerCase()}" style="color: ${OBLIGATION_SEVERITY_COLORS[sev]}">${OBLIGATION_SEVERITY_LABELS_DE[sev]}</span></td>
<td>${escHtml(issue.message)}</td>
<td>${issue.affectedObligations.length > 0 ? issue.affectedObligations.length + ' Pflicht(en)' : '—'}</td>
<td>${escHtml(issue.recommendation)}</td>
</tr>
`
}
}
html += ` </table>
`
} else {
html += ` <p style="margin-top: 8px;"><em>Keine Beanstandungen. Alle Pflichten sind konform.</em></p>
`
}
} else {
html += ` <p><em>Compliance-Check wurde noch nicht ausgefuehrt. Fuehren Sie den Check im
Pflichtenregister-Tab durch, um den Status in das Dokument aufzunehmen.</em></p>
`
}
html += ` </div>
</div>
`
// =========================================================================
// Section 11: Aenderungshistorie
// =========================================================================
html += `
<div class="section">
<div class="section-header">11. Aenderungshistorie</div>
<div class="section-body">
<table>
<tr><th>Version</th><th>Datum</th><th>Autor</th><th>Aenderungen</th></tr>
`
if (revisions.length > 0) {
for (const rev of revisions) {
html += ` <tr>
<td>${escHtml(rev.version)}</td>
<td>${formatDateDE(rev.date)}</td>
<td>${escHtml(rev.author)}</td>
<td>${escHtml(rev.changes)}</td>
</tr>
`
}
} else {
html += ` <tr>
<td>${escHtml(orgHeader.documentVersion)}</td>
<td>${today}</td>
<td>${escHtml(orgHeader.dpoName || orgHeader.responsiblePerson || '—')}</td>
<td>Erstversion des Pflichtenregisters</td>
</tr>
`
}
html += ` </table>
</div>
</div>
`
// =========================================================================
// Footer
// =========================================================================
html += `
<div class="page-footer">
<span>Pflichtenregister — ${escHtml(orgName)}</span>
<span>Stand: ${today} | Version ${escHtml(orgHeader.documentVersion)}</span>
</div>
</body>
</html>`
return html
}
// =============================================================================
// INTERNAL HELPERS
// =============================================================================
function escHtml(str: string): string {
return str
.replace(/&/g, '&amp;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
.replace(/"/g, '&quot;')
}
function formatDateDE(dateStr: string | null | undefined): string {
if (!dateStr) return '—'
try {
const date = new Date(dateStr)
if (isNaN(date.getTime())) return '—'
return date.toLocaleDateString('de-DE', {
day: '2-digit',
month: '2-digit',
year: 'numeric',
})
} catch {
return '—'
}
}
function daysBetween(earlier: Date, later: Date): number {
const diffMs = later.getTime() - earlier.getTime()
return Math.floor(diffMs / (1000 * 60 * 60 * 24))
}

View File

@@ -0,0 +1,31 @@
// =============================================================================
// Obligations Document — Internal Helpers
// =============================================================================
export function escHtml(str: string): string {
return str
.replace(/&/g, '&amp;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
.replace(/"/g, '&quot;')
}
export function formatDateDE(dateStr: string | null | undefined): string {
if (!dateStr) return '—'
try {
const date = new Date(dateStr)
if (isNaN(date.getTime())) return '—'
return date.toLocaleDateString('de-DE', {
day: '2-digit',
month: '2-digit',
year: 'numeric',
})
} catch {
return '—'
}
}
export function daysBetween(earlier: Date, later: Date): number {
const diffMs = later.getTime() - earlier.getTime()
return Math.floor(diffMs / (1000 * 60 * 60 * 24))
}

View File

@@ -0,0 +1,620 @@
// =============================================================================
// Obligations Document — HTML Document Builder
// =============================================================================
import type { Obligation, ObligationComplianceCheckResult, ObligationComplianceIssueSeverity } from '../obligations-compliance'
import { OBLIGATION_SEVERITY_LABELS_DE, OBLIGATION_SEVERITY_COLORS } from '../obligations-compliance'
import type { ObligationDocumentOrgHeader, ObligationDocumentRevision } from './types-defaults'
import {
STATUS_LABELS_DE,
STATUS_BADGE_CLASSES,
PRIORITY_LABELS_DE,
PRIORITY_BADGE_CLASSES,
} from './types-defaults'
import { escHtml, formatDateDE, daysBetween } from './helpers'
import { getDocumentStyles } from './html-styles'
export function buildObligationDocumentHtml(
obligations: Obligation[],
orgHeader: ObligationDocumentOrgHeader,
complianceResult: ObligationComplianceCheckResult | null,
revisions: ObligationDocumentRevision[]
): string {
const today = new Date().toLocaleDateString('de-DE', {
day: '2-digit',
month: '2-digit',
year: 'numeric',
})
const orgName = orgHeader.organizationName || 'Organisation'
// Group obligations by source (regulation)
const bySource = new Map<string, Obligation[]>()
for (const o of obligations) {
const src = o.source || 'Sonstig'
if (!bySource.has(src)) bySource.set(src, [])
bySource.get(src)!.push(o)
}
// Build role map
const roleMap = new Map<string, Obligation[]>()
for (const o of obligations) {
const role = o.responsible || 'Nicht zugewiesen'
if (!roleMap.has(role)) roleMap.set(role, [])
roleMap.get(role)!.push(o)
}
const distinctSources = Array.from(bySource.keys()).sort()
let html = getDocumentStyles(`Pflichtenregister — ${escHtml(orgName)}`)
html += buildCoverPage(orgHeader, orgName, today)
html += buildTOC()
html += buildSection1(orgName)
html += buildSection2(orgName, orgHeader, bySource, obligations, distinctSources)
html += buildSection3()
html += buildSection4(bySource, obligations)
html += buildSection5(bySource)
html += buildSection6(bySource)
html += buildSection7(roleMap)
html += buildSection8(obligations, today)
html += buildSection9(obligations)
html += buildSection10(complianceResult)
html += buildSection11(revisions, orgHeader, today)
html += buildFooter(orgName, today, orgHeader.documentVersion)
return html
}
function buildCoverPage(
orgHeader: ObligationDocumentOrgHeader,
orgName: string,
today: string
): string {
return `
<div class="cover">
<h1>Pflichtenregister</h1>
<div class="subtitle">Regulatorische Pflichten — DSGVO, AI Act, NIS2 und weitere</div>
<div class="org-info">
<div><span class="label">Organisation:</span> ${escHtml(orgName)}</div>
${orgHeader.industry ? `<div><span class="label">Branche:</span> ${escHtml(orgHeader.industry)}</div>` : ''}
${orgHeader.dpoName ? `<div><span class="label">DSB:</span> ${escHtml(orgHeader.dpoName)}</div>` : ''}
${orgHeader.dpoContact ? `<div><span class="label">DSB-Kontakt:</span> ${escHtml(orgHeader.dpoContact)}</div>` : ''}
${orgHeader.responsiblePerson ? `<div><span class="label">Verantwortlicher:</span> ${escHtml(orgHeader.responsiblePerson)}</div>` : ''}
${orgHeader.legalDepartment ? `<div><span class="label">Rechtsabteilung:</span> ${escHtml(orgHeader.legalDepartment)}</div>` : ''}
</div>
<div class="legal-ref">
Version ${escHtml(orgHeader.documentVersion)} | Stand: ${today}<br/>
Letzte Pruefung: ${formatDateDE(orgHeader.lastReviewDate)} | Naechste Pruefung: ${formatDateDE(orgHeader.nextReviewDate)}<br/>
Pruefintervall: ${escHtml(orgHeader.reviewInterval)}
</div>
</div>
`
}
function buildTOC(): string {
const sections = [
'Ziel und Zweck',
'Geltungsbereich',
'Methodik',
'Regulatorische Grundlagen',
'Pflichtenuebersicht',
'Detaillierte Pflichten',
'Verantwortlichkeiten',
'Fristen und Termine',
'Nachweisverzeichnis',
'Compliance-Status',
'Aenderungshistorie',
]
return `
<div class="toc">
<h2>Inhaltsverzeichnis</h2>
${sections.map((s, i) => `<div class="toc-entry"><span><span class="toc-num">${i + 1}.</span> ${escHtml(s)}</span></div>`).join('\n ')}
</div>
`
}
function buildSection1(orgName: string): string {
return `
<div class="section">
<div class="section-header">1. Ziel und Zweck</div>
<div class="section-body">
<p>Dieses Pflichtenregister dokumentiert alle regulatorischen Pflichten, denen
<strong>${escHtml(orgName)}</strong> unterliegt. Es dient der systematischen Erfassung,
Ueberwachung und Nachverfolgung aller Compliance-Anforderungen aus den anwendbaren
Regulierungen.</p>
<p style="margin-top: 8px;">Das Register erfuellt folgende Zwecke:</p>
<ul style="margin: 8px 0 8px 24px;">
<li>Vollstaendige Erfassung aller anwendbaren regulatorischen Pflichten</li>
<li>Zuordnung von Verantwortlichkeiten und Fristen</li>
<li>Nachverfolgung des Umsetzungsstatus</li>
<li>Dokumentation von Nachweisen fuer Audits</li>
<li>Identifikation von Compliance-Luecken und Handlungsbedarf</li>
</ul>
<table>
<tr><th>Rechtsrahmen</th><th>Relevanz</th></tr>
<tr><td><strong>DSGVO (EU) 2016/679</strong></td><td>Datenschutz-Grundverordnung — Kernregulierung fuer personenbezogene Daten</td></tr>
<tr><td><strong>AI Act (EU) 2024/1689</strong></td><td>KI-Verordnung — Anforderungen an KI-Systeme nach Risikoklasse</td></tr>
<tr><td><strong>NIS2 (EU) 2022/2555</strong></td><td>Netzwerk- und Informationssicherheit — Cybersicherheitspflichten</td></tr>
<tr><td><strong>BDSG</strong></td><td>Bundesdatenschutzgesetz — Nationale Ergaenzung zur DSGVO</td></tr>
</table>
</div>
</div>
`
}
function buildSection2(
orgName: string,
orgHeader: ObligationDocumentOrgHeader,
bySource: Map<string, Obligation[]>,
obligations: Obligation[],
distinctSources: string[]
): string {
let html = `
<div class="section">
<div class="section-header">2. Geltungsbereich</div>
<div class="section-body">
<p>Dieses Pflichtenregister gilt fuer alle Geschaeftsprozesse und IT-Systeme von
<strong>${escHtml(orgName)}</strong>${orgHeader.industry ? ` (Branche: ${escHtml(orgHeader.industry)})` : ''}.</p>
<p style="margin-top: 8px;">Anwendbare Regulierungen:</p>
<table>
<tr><th>Regulierung</th><th>Anzahl Pflichten</th><th>Status</th></tr>
`
for (const [source, obls] of bySource.entries()) {
const completed = obls.filter(o => o.status === 'completed').length
const pct = obls.length > 0 ? Math.round((completed / obls.length) * 100) : 0
html += ` <tr>
<td>${escHtml(source)}</td>
<td>${obls.length}</td>
<td>${completed}/${obls.length} abgeschlossen (${pct}%)</td>
</tr>
`
}
html += ` </table>
<p>Insgesamt umfasst dieses Register <strong>${obligations.length}</strong> Pflichten aus
<strong>${distinctSources.length}</strong> Regulierungen.</p>
</div>
</div>
`
return html
}
function buildSection3(): string {
return `
<div class="section">
<div class="section-header">3. Methodik</div>
<div class="section-body">
<p>Die Identifikation und Bewertung der Pflichten erfolgt in drei Schritten:</p>
<div class="principle"><strong>Pflicht-Identifikation:</strong> Systematische Analyse aller anwendbaren Regulierungen und Extraktion der einzelnen Pflichten mit Artikel-Referenz, Beschreibung und Zielgruppe.</div>
<div class="principle"><strong>Bewertung und Priorisierung:</strong> Jede Pflicht wird nach Prioritaet (kritisch, hoch, mittel, niedrig) und Dringlichkeit (Frist) bewertet. Die Bewertung basiert auf dem Risikopotenzial bei Nichterfuellung.</div>
<div class="principle"><strong>Ueberwachung und Nachverfolgung:</strong> Regelmaessige Pruefung des Umsetzungsstatus, Aktualisierung der Fristen und Dokumentation von Nachweisen.</div>
<p style="margin-top: 12px;">Die Pflichten werden ueber einen automatisierten Compliance-Check geprueft, der
11 Kriterien umfasst (siehe Abschnitt 10: Compliance-Status).</p>
</div>
</div>
`
}
function buildSection4(bySource: Map<string, Obligation[]>, obligations: Obligation[]): string {
const totalCritical = obligations.filter(o => o.priority === 'critical').length
const totalHigh = obligations.filter(o => o.priority === 'high').length
const totalMedium = obligations.filter(o => o.priority === 'medium').length
const totalLow = obligations.filter(o => o.priority === 'low').length
const totalCompleted = obligations.filter(o => o.status === 'completed').length
let html = `
<div class="section page-break">
<div class="section-header">4. Regulatorische Grundlagen</div>
<div class="section-body">
<p>Die folgende Tabelle zeigt die regulatorischen Grundlagen mit Artikelzahl und Umsetzungsstatus:</p>
<table>
<tr>
<th>Regulierung</th>
<th>Pflichten</th>
<th>Kritisch</th>
<th>Hoch</th>
<th>Mittel</th>
<th>Niedrig</th>
<th>Abgeschlossen</th>
</tr>
`
for (const [source, obls] of bySource.entries()) {
const critical = obls.filter(o => o.priority === 'critical').length
const high = obls.filter(o => o.priority === 'high').length
const medium = obls.filter(o => o.priority === 'medium').length
const low = obls.filter(o => o.priority === 'low').length
const completed = obls.filter(o => o.status === 'completed').length
html += ` <tr>
<td><strong>${escHtml(source)}</strong></td>
<td>${obls.length}</td>
<td>${critical}</td>
<td>${high}</td>
<td>${medium}</td>
<td>${low}</td>
<td>${completed}</td>
</tr>
`
}
html += ` <tr style="font-weight: 700; background: #f5f3ff;">
<td>Gesamt</td>
<td>${obligations.length}</td>
<td>${totalCritical}</td>
<td>${totalHigh}</td>
<td>${totalMedium}</td>
<td>${totalLow}</td>
<td>${totalCompleted}</td>
</tr>
</table>
</div>
</div>
`
return html
}
function buildSection5(bySource: Map<string, Obligation[]>): string {
let html = `
<div class="section">
<div class="section-header">5. Pflichtenuebersicht</div>
<div class="section-body">
<p>Uebersicht aller Pflichten nach Regulierung und Status:</p>
<table>
<tr>
<th>Regulierung</th>
<th>Gesamt</th>
<th>Ausstehend</th>
<th>In Bearbeitung</th>
<th>Abgeschlossen</th>
<th>Ueberfaellig</th>
</tr>
`
for (const [source, obls] of bySource.entries()) {
const pending = obls.filter(o => o.status === 'pending').length
const inProgress = obls.filter(o => o.status === 'in-progress').length
const completed = obls.filter(o => o.status === 'completed').length
const overdue = obls.filter(o => o.status === 'overdue').length
html += ` <tr>
<td>${escHtml(source)}</td>
<td>${obls.length}</td>
<td>${pending}</td>
<td>${inProgress}</td>
<td>${completed}</td>
<td>${overdue > 0 ? `<span class="badge badge-critical">${overdue}</span>` : '0'}</td>
</tr>
`
}
html += ` </table>
</div>
</div>
`
return html
}
function buildSection6(bySource: Map<string, Obligation[]>): string {
const priorityOrder: Record<string, number> = { critical: 0, high: 1, medium: 2, low: 3 }
let html = `
<div class="section">
<div class="section-header">6. Detaillierte Pflichten</div>
<div class="section-body">
`
for (const [source, obls] of bySource.entries()) {
const sorted = [...obls].sort((a, b) => {
const pa = priorityOrder[a.priority] ?? 2
const pb = priorityOrder[b.priority] ?? 2
if (pa !== pb) return pa - pb
return a.title.localeCompare(b.title)
})
html += ` <h3 style="color: #5b21b6; margin: 20px 0 10px 0; font-size: 11pt;">${escHtml(source)} <span style="font-weight: 400; font-size: 9pt; color: #64748b;">(${sorted.length} Pflichten)</span></h3>
`
for (const o of sorted) {
const statusLabel = STATUS_LABELS_DE[o.status] || o.status
const statusBadge = STATUS_BADGE_CLASSES[o.status] || 'badge-draft'
const priorityLabel = PRIORITY_LABELS_DE[o.priority] || o.priority
const priorityBadge = PRIORITY_BADGE_CLASSES[o.priority] || 'badge-draft'
const deadlineStr = o.deadline ? formatDateDE(o.deadline) : '—'
const evidenceStr = o.evidence && o.evidence.length > 0
? o.evidence.map(e => escHtml(e)).join(', ')
: '<em style="color: #d97706;">Kein Nachweis</em>'
const systemsStr = o.linked_systems && o.linked_systems.length > 0
? o.linked_systems.map(s => escHtml(s)).join(', ')
: '—'
html += `
<div class="policy-detail">
<div class="policy-detail-header">
<span>${escHtml(o.title)}</span>
<span class="badge ${statusBadge}">${escHtml(statusLabel)}</span>
</div>
<div class="policy-detail-body">
<table>
<tr><th>Rechtsquelle</th><td>${escHtml(o.source)} ${escHtml(o.source_article || '')}</td></tr>
<tr><th>Beschreibung</th><td>${escHtml(o.description || '—')}</td></tr>
<tr><th>Prioritaet</th><td><span class="badge ${priorityBadge}">${escHtml(priorityLabel)}</span></td></tr>
<tr><th>Status</th><td><span class="badge ${statusBadge}">${escHtml(statusLabel)}</span></td></tr>
<tr><th>Verantwortlich</th><td>${escHtml(o.responsible || '—')}</td></tr>
<tr><th>Frist</th><td>${deadlineStr}</td></tr>
<tr><th>Nachweise</th><td>${evidenceStr}</td></tr>
<tr><th>Betroffene Systeme</th><td>${systemsStr}</td></tr>
${o.linked_vendor_ids && o.linked_vendor_ids.length > 0 ? `<tr><th>Auftragsverarbeiter</th><td>${o.linked_vendor_ids.map(id => escHtml(id)).join(', ')}</td></tr>` : ''}
${o.notes ? `<tr><th>Notizen</th><td>${escHtml(o.notes)}</td></tr>` : ''}
</table>
</div>
</div>
`
}
}
html += ` </div>
</div>
`
return html
}
function buildSection7(roleMap: Map<string, Obligation[]>): string {
let html = `
<div class="section page-break">
<div class="section-header">7. Verantwortlichkeiten</div>
<div class="section-body">
<p>Die folgende Rollenmatrix zeigt, welche Personen oder Abteilungen fuer welche Pflichten
die Umsetzungsverantwortung tragen:</p>
<table>
<tr><th>Verantwortlich</th><th>Pflichten</th><th>Anzahl</th><th>Davon offen</th></tr>
`
for (const [role, obls] of roleMap.entries()) {
const openCount = obls.filter(o => o.status !== 'completed').length
const titles = obls.slice(0, 5).map(o => escHtml(o.title))
const suffix = obls.length > 5 ? `, ... (+${obls.length - 5})` : ''
html += ` <tr>
<td>${escHtml(role)}</td>
<td>${titles.join('; ')}${suffix}</td>
<td>${obls.length}</td>
<td>${openCount}</td>
</tr>
`
}
html += ` </table>
</div>
</div>
`
return html
}
function buildSection8(obligations: Obligation[], _today: string): string {
const now = new Date()
const withDeadline = obligations
.filter(o => o.deadline && o.status !== 'completed')
.sort((a, b) => new Date(a.deadline!).getTime() - new Date(b.deadline!).getTime())
const overdue = withDeadline.filter(o => new Date(o.deadline!) < now)
const upcoming = withDeadline.filter(o => new Date(o.deadline!) >= now)
let html = `
<div class="section">
<div class="section-header">8. Fristen und Termine</div>
<div class="section-body">
`
if (overdue.length > 0) {
html += ` <h4 style="color: #dc2626; margin-bottom: 8px;">Ueberfaellige Pflichten (${overdue.length})</h4>
<table>
<tr><th>Pflicht</th><th>Regulierung</th><th>Frist</th><th>Tage ueberfaellig</th><th>Prioritaet</th></tr>
`
for (const o of overdue) {
const days = daysBetween(new Date(o.deadline!), now)
html += ` <tr>
<td>${escHtml(o.title)}</td>
<td>${escHtml(o.source)}</td>
<td>${formatDateDE(o.deadline)}</td>
<td><span class="badge badge-critical">${days} Tage</span></td>
<td><span class="badge ${PRIORITY_BADGE_CLASSES[o.priority] || 'badge-draft'}">${escHtml(PRIORITY_LABELS_DE[o.priority] || o.priority)}</span></td>
</tr>
`
}
html += ` </table>
`
}
if (upcoming.length > 0) {
html += ` <h4 style="color: #5b21b6; margin: 16px 0 8px 0;">Anstehende Fristen (${upcoming.length})</h4>
<table>
<tr><th>Pflicht</th><th>Regulierung</th><th>Frist</th><th>Verbleibend</th><th>Verantwortlich</th></tr>
`
for (const o of upcoming.slice(0, 20)) {
const days = daysBetween(now, new Date(o.deadline!))
html += ` <tr>
<td>${escHtml(o.title)}</td>
<td>${escHtml(o.source)}</td>
<td>${formatDateDE(o.deadline)}</td>
<td>${days} Tage</td>
<td>${escHtml(o.responsible || '—')}</td>
</tr>
`
}
if (upcoming.length > 20) {
html += ` <tr><td colspan="5" style="text-align: center; color: #64748b;">... und ${upcoming.length - 20} weitere</td></tr>
`
}
html += ` </table>
`
}
if (withDeadline.length === 0) {
html += ` <p><em>Keine offenen Pflichten mit Fristen vorhanden.</em></p>
`
}
html += ` </div>
</div>
`
return html
}
function buildSection9(obligations: Obligation[]): string {
const withEvidence = obligations.filter(o => o.evidence && o.evidence.length > 0)
const withoutEvidence = obligations.filter(o => !o.evidence || o.evidence.length === 0)
let html = `
<div class="section page-break">
<div class="section-header">9. Nachweisverzeichnis</div>
<div class="section-body">
<p>${withEvidence.length} von ${obligations.length} Pflichten haben Nachweise hinterlegt.</p>
`
if (withEvidence.length > 0) {
html += ` <table>
<tr><th>Pflicht</th><th>Regulierung</th><th>Nachweise</th><th>Status</th></tr>
`
for (const o of withEvidence) {
html += ` <tr>
<td>${escHtml(o.title)}</td>
<td>${escHtml(o.source)}</td>
<td>${o.evidence!.map(e => escHtml(e)).join(', ')}</td>
<td><span class="badge ${STATUS_BADGE_CLASSES[o.status] || 'badge-draft'}">${escHtml(STATUS_LABELS_DE[o.status] || o.status)}</span></td>
</tr>
`
}
html += ` </table>
`
}
if (withoutEvidence.length > 0) {
html += ` <p style="margin-top: 12px;"><strong>Pflichten ohne Nachweise (${withoutEvidence.length}):</strong></p>
<ul style="margin: 4px 0 8px 24px; font-size: 9pt; color: #d97706;">
`
for (const o of withoutEvidence.slice(0, 15)) {
html += ` <li>${escHtml(o.title)} (${escHtml(o.source)})</li>
`
}
if (withoutEvidence.length > 15) {
html += ` <li>... und ${withoutEvidence.length - 15} weitere</li>
`
}
html += ` </ul>
`
}
html += ` </div>
</div>
`
return html
}
function buildSection10(complianceResult: ObligationComplianceCheckResult | null): string {
let html = `
<div class="section">
<div class="section-header">10. Compliance-Status</div>
<div class="section-body">
`
if (complianceResult) {
const scoreClass = complianceResult.score >= 90 ? 'score-excellent'
: complianceResult.score >= 75 ? 'score-good'
: complianceResult.score >= 50 ? 'score-needs-work'
: 'score-poor'
const scoreLabel = complianceResult.score >= 90 ? 'Ausgezeichnet'
: complianceResult.score >= 75 ? 'Gut'
: complianceResult.score >= 50 ? 'Verbesserungswuerdig'
: 'Mangelhaft'
html += ` <p><span class="score-box ${scoreClass}">${complianceResult.score}/100</span> ${escHtml(scoreLabel)}</p>
<table style="margin-top: 12px;">
<tr><th>Kennzahl</th><th>Wert</th></tr>
<tr><td>Geprueft am</td><td>${formatDateDE(complianceResult.checkedAt)}</td></tr>
<tr><td>Befunde gesamt</td><td>${complianceResult.summary.total}</td></tr>
<tr><td>Kritisch</td><td>${complianceResult.summary.critical}</td></tr>
<tr><td>Hoch</td><td>${complianceResult.summary.high}</td></tr>
<tr><td>Mittel</td><td>${complianceResult.summary.medium}</td></tr>
<tr><td>Niedrig</td><td>${complianceResult.summary.low}</td></tr>
</table>
`
if (complianceResult.issues.length > 0) {
html += ` <p style="margin-top: 12px;"><strong>Befunde nach Schweregrad:</strong></p>
<table>
<tr><th>Schweregrad</th><th>Befund</th><th>Betroffene Pflichten</th><th>Empfehlung</th></tr>
`
const severityOrder: ObligationComplianceIssueSeverity[] = ['CRITICAL', 'HIGH', 'MEDIUM', 'LOW']
for (const sev of severityOrder) {
const issuesForSev = complianceResult.issues.filter(i => i.severity === sev)
for (const issue of issuesForSev) {
html += ` <tr>
<td><span class="badge badge-${sev.toLowerCase()}" style="color: ${OBLIGATION_SEVERITY_COLORS[sev]}">${OBLIGATION_SEVERITY_LABELS_DE[sev]}</span></td>
<td>${escHtml(issue.message)}</td>
<td>${issue.affectedObligations.length > 0 ? issue.affectedObligations.length + ' Pflicht(en)' : '—'}</td>
<td>${escHtml(issue.recommendation)}</td>
</tr>
`
}
}
html += ` </table>
`
} else {
html += ` <p style="margin-top: 8px;"><em>Keine Beanstandungen. Alle Pflichten sind konform.</em></p>
`
}
} else {
html += ` <p><em>Compliance-Check wurde noch nicht ausgefuehrt. Fuehren Sie den Check im
Pflichtenregister-Tab durch, um den Status in das Dokument aufzunehmen.</em></p>
`
}
html += ` </div>
</div>
`
return html
}
function buildSection11(
revisions: ObligationDocumentRevision[],
orgHeader: ObligationDocumentOrgHeader,
today: string
): string {
let html = `
<div class="section">
<div class="section-header">11. Aenderungshistorie</div>
<div class="section-body">
<table>
<tr><th>Version</th><th>Datum</th><th>Autor</th><th>Aenderungen</th></tr>
`
if (revisions.length > 0) {
for (const rev of revisions) {
html += ` <tr>
<td>${escHtml(rev.version)}</td>
<td>${formatDateDE(rev.date)}</td>
<td>${escHtml(rev.author)}</td>
<td>${escHtml(rev.changes)}</td>
</tr>
`
}
} else {
html += ` <tr>
<td>${escHtml(orgHeader.documentVersion)}</td>
<td>${today}</td>
<td>${escHtml(orgHeader.dpoName || orgHeader.responsiblePerson || '—')}</td>
<td>Erstversion des Pflichtenregisters</td>
</tr>
`
}
html += ` </table>
</div>
</div>
`
return html
}
function buildFooter(orgName: string, today: string, version: string): string {
return `
<div class="page-footer">
<span>Pflichtenregister — ${escHtml(orgName)}</span>
<span>Stand: ${today} | Version ${escHtml(version)}</span>
</div>
</body>
</html>`
}

View File

@@ -0,0 +1,207 @@
// =============================================================================
// Obligations Document — HTML Sections 15 (cover, TOC, purpose, scope, method, sources, overview)
// =============================================================================
import type { Obligation } from '../obligations-compliance'
import type { ObligationDocumentOrgHeader } from './types-defaults'
import { escHtml, formatDateDE } from './helpers'
export function buildCoverPage(
orgHeader: ObligationDocumentOrgHeader,
orgName: string,
today: string
): string {
return `
<div class="cover">
<h1>Pflichtenregister</h1>
<div class="subtitle">Regulatorische Pflichten — DSGVO, AI Act, NIS2 und weitere</div>
<div class="org-info">
<div><span class="label">Organisation:</span> ${escHtml(orgName)}</div>
${orgHeader.industry ? `<div><span class="label">Branche:</span> ${escHtml(orgHeader.industry)}</div>` : ''}
${orgHeader.dpoName ? `<div><span class="label">DSB:</span> ${escHtml(orgHeader.dpoName)}</div>` : ''}
${orgHeader.dpoContact ? `<div><span class="label">DSB-Kontakt:</span> ${escHtml(orgHeader.dpoContact)}</div>` : ''}
${orgHeader.responsiblePerson ? `<div><span class="label">Verantwortlicher:</span> ${escHtml(orgHeader.responsiblePerson)}</div>` : ''}
${orgHeader.legalDepartment ? `<div><span class="label">Rechtsabteilung:</span> ${escHtml(orgHeader.legalDepartment)}</div>` : ''}
</div>
<div class="legal-ref">
Version ${escHtml(orgHeader.documentVersion)} | Stand: ${today}<br/>
Letzte Pruefung: ${formatDateDE(orgHeader.lastReviewDate)} | Naechste Pruefung: ${formatDateDE(orgHeader.nextReviewDate)}<br/>
Pruefintervall: ${escHtml(orgHeader.reviewInterval)}
</div>
</div>
`
}
export function buildTOC(): string {
const sections = [
'Ziel und Zweck', 'Geltungsbereich', 'Methodik', 'Regulatorische Grundlagen',
'Pflichtenuebersicht', 'Detaillierte Pflichten', 'Verantwortlichkeiten',
'Fristen und Termine', 'Nachweisverzeichnis', 'Compliance-Status', 'Aenderungshistorie',
]
return `
<div class="toc">
<h2>Inhaltsverzeichnis</h2>
${sections.map((s, i) => `<div class="toc-entry"><span><span class="toc-num">${i + 1}.</span> ${escHtml(s)}</span></div>`).join('\n ')}
</div>
`
}
export function buildSection1(orgName: string): string {
return `
<div class="section">
<div class="section-header">1. Ziel und Zweck</div>
<div class="section-body">
<p>Dieses Pflichtenregister dokumentiert alle regulatorischen Pflichten, denen
<strong>${escHtml(orgName)}</strong> unterliegt. Es dient der systematischen Erfassung,
Ueberwachung und Nachverfolgung aller Compliance-Anforderungen aus den anwendbaren
Regulierungen.</p>
<p style="margin-top: 8px;">Das Register erfuellt folgende Zwecke:</p>
<ul style="margin: 8px 0 8px 24px;">
<li>Vollstaendige Erfassung aller anwendbaren regulatorischen Pflichten</li>
<li>Zuordnung von Verantwortlichkeiten und Fristen</li>
<li>Nachverfolgung des Umsetzungsstatus</li>
<li>Dokumentation von Nachweisen fuer Audits</li>
<li>Identifikation von Compliance-Luecken und Handlungsbedarf</li>
</ul>
<table>
<tr><th>Rechtsrahmen</th><th>Relevanz</th></tr>
<tr><td><strong>DSGVO (EU) 2016/679</strong></td><td>Datenschutz-Grundverordnung — Kernregulierung fuer personenbezogene Daten</td></tr>
<tr><td><strong>AI Act (EU) 2024/1689</strong></td><td>KI-Verordnung — Anforderungen an KI-Systeme nach Risikoklasse</td></tr>
<tr><td><strong>NIS2 (EU) 2022/2555</strong></td><td>Netzwerk- und Informationssicherheit — Cybersicherheitspflichten</td></tr>
<tr><td><strong>BDSG</strong></td><td>Bundesdatenschutzgesetz — Nationale Ergaenzung zur DSGVO</td></tr>
</table>
</div>
</div>
`
}
export function buildSection2(
orgName: string,
orgHeader: ObligationDocumentOrgHeader,
bySource: Map<string, Obligation[]>,
obligations: Obligation[],
distinctSources: string[]
): string {
let html = `
<div class="section">
<div class="section-header">2. Geltungsbereich</div>
<div class="section-body">
<p>Dieses Pflichtenregister gilt fuer alle Geschaeftsprozesse und IT-Systeme von
<strong>${escHtml(orgName)}</strong>${orgHeader.industry ? ` (Branche: ${escHtml(orgHeader.industry)})` : ''}.</p>
<p style="margin-top: 8px;">Anwendbare Regulierungen:</p>
<table>
<tr><th>Regulierung</th><th>Anzahl Pflichten</th><th>Status</th></tr>
`
for (const [source, obls] of bySource.entries()) {
const completed = obls.filter(o => o.status === 'completed').length
const pct = obls.length > 0 ? Math.round((completed / obls.length) * 100) : 0
html += ` <tr>
<td>${escHtml(source)}</td>
<td>${obls.length}</td>
<td>${completed}/${obls.length} abgeschlossen (${pct}%)</td>
</tr>
`
}
html += ` </table>
<p>Insgesamt umfasst dieses Register <strong>${obligations.length}</strong> Pflichten aus
<strong>${distinctSources.length}</strong> Regulierungen.</p>
</div>
</div>
`
return html
}
export function buildSection3(): string {
return `
<div class="section">
<div class="section-header">3. Methodik</div>
<div class="section-body">
<p>Die Identifikation und Bewertung der Pflichten erfolgt in drei Schritten:</p>
<div class="principle"><strong>Pflicht-Identifikation:</strong> Systematische Analyse aller anwendbaren Regulierungen und Extraktion der einzelnen Pflichten mit Artikel-Referenz, Beschreibung und Zielgruppe.</div>
<div class="principle"><strong>Bewertung und Priorisierung:</strong> Jede Pflicht wird nach Prioritaet (kritisch, hoch, mittel, niedrig) und Dringlichkeit (Frist) bewertet. Die Bewertung basiert auf dem Risikopotenzial bei Nichterfuellung.</div>
<div class="principle"><strong>Ueberwachung und Nachverfolgung:</strong> Regelmaessige Pruefung des Umsetzungsstatus, Aktualisierung der Fristen und Dokumentation von Nachweisen.</div>
<p style="margin-top: 12px;">Die Pflichten werden ueber einen automatisierten Compliance-Check geprueft, der
11 Kriterien umfasst (siehe Abschnitt 10: Compliance-Status).</p>
</div>
</div>
`
}
export function buildSection4(bySource: Map<string, Obligation[]>, obligations: Obligation[]): string {
const totalCritical = obligations.filter(o => o.priority === 'critical').length
const totalHigh = obligations.filter(o => o.priority === 'high').length
const totalMedium = obligations.filter(o => o.priority === 'medium').length
const totalLow = obligations.filter(o => o.priority === 'low').length
const totalCompleted = obligations.filter(o => o.status === 'completed').length
let html = `
<div class="section page-break">
<div class="section-header">4. Regulatorische Grundlagen</div>
<div class="section-body">
<p>Die folgende Tabelle zeigt die regulatorischen Grundlagen mit Artikelzahl und Umsetzungsstatus:</p>
<table>
<tr>
<th>Regulierung</th><th>Pflichten</th><th>Kritisch</th>
<th>Hoch</th><th>Mittel</th><th>Niedrig</th><th>Abgeschlossen</th>
</tr>
`
for (const [source, obls] of bySource.entries()) {
const critical = obls.filter(o => o.priority === 'critical').length
const high = obls.filter(o => o.priority === 'high').length
const medium = obls.filter(o => o.priority === 'medium').length
const low = obls.filter(o => o.priority === 'low').length
const completed = obls.filter(o => o.status === 'completed').length
html += ` <tr>
<td><strong>${escHtml(source)}</strong></td>
<td>${obls.length}</td><td>${critical}</td><td>${high}</td>
<td>${medium}</td><td>${low}</td><td>${completed}</td>
</tr>
`
}
html += ` <tr style="font-weight: 700; background: #f5f3ff;">
<td>Gesamt</td>
<td>${obligations.length}</td><td>${totalCritical}</td><td>${totalHigh}</td>
<td>${totalMedium}</td><td>${totalLow}</td><td>${totalCompleted}</td>
</tr>
</table>
</div>
</div>
`
return html
}
export function buildSection5(bySource: Map<string, Obligation[]>): string {
let html = `
<div class="section">
<div class="section-header">5. Pflichtenuebersicht</div>
<div class="section-body">
<p>Uebersicht aller Pflichten nach Regulierung und Status:</p>
<table>
<tr>
<th>Regulierung</th><th>Gesamt</th><th>Ausstehend</th>
<th>In Bearbeitung</th><th>Abgeschlossen</th><th>Ueberfaellig</th>
</tr>
`
for (const [source, obls] of bySource.entries()) {
const pending = obls.filter(o => o.status === 'pending').length
const inProgress = obls.filter(o => o.status === 'in-progress').length
const completed = obls.filter(o => o.status === 'completed').length
const overdue = obls.filter(o => o.status === 'overdue').length
html += ` <tr>
<td>${escHtml(source)}</td><td>${obls.length}</td><td>${pending}</td>
<td>${inProgress}</td><td>${completed}</td>
<td>${overdue > 0 ? `<span class="badge badge-critical">${overdue}</span>` : '0'}</td>
</tr>
`
}
html += ` </table>
</div>
</div>
`
return html
}

View File

@@ -0,0 +1,211 @@
// =============================================================================
// Obligations Document — Shared HTML/CSS Styles
// =============================================================================
export function getDocumentStyles(title: string): string {
return `<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<title>${title}</title>
<style>
@page { size: A4; margin: 20mm 18mm 22mm 18mm; }
* { margin: 0; padding: 0; box-sizing: border-box; }
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
font-size: 10pt;
line-height: 1.5;
color: #1e293b;
}
/* Cover */
.cover {
min-height: 90vh;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
text-align: center;
page-break-after: always;
}
.cover h1 {
font-size: 28pt;
color: #5b21b6;
margin-bottom: 8px;
font-weight: 700;
}
.cover .subtitle {
font-size: 14pt;
color: #7c3aed;
margin-bottom: 40px;
}
.cover .org-info {
background: #f5f3ff;
border: 1px solid #ddd6fe;
border-radius: 8px;
padding: 24px 40px;
text-align: left;
width: 400px;
margin-bottom: 24px;
}
.cover .org-info div { margin-bottom: 6px; }
.cover .org-info .label { font-weight: 600; color: #5b21b6; display: inline-block; min-width: 160px; }
.cover .legal-ref {
font-size: 9pt;
color: #64748b;
margin-top: 20px;
}
/* TOC */
.toc {
page-break-after: always;
padding-top: 40px;
}
.toc h2 {
font-size: 18pt;
color: #5b21b6;
margin-bottom: 20px;
border-bottom: 2px solid #5b21b6;
padding-bottom: 8px;
}
.toc-entry {
display: flex;
justify-content: space-between;
padding: 6px 0;
border-bottom: 1px dotted #cbd5e1;
font-size: 10pt;
}
.toc-entry .toc-num { font-weight: 600; color: #5b21b6; min-width: 40px; }
/* Sections */
.section {
page-break-inside: avoid;
margin-bottom: 24px;
}
.section-header {
font-size: 14pt;
color: #5b21b6;
font-weight: 700;
margin: 30px 0 12px 0;
border-bottom: 2px solid #ddd6fe;
padding-bottom: 6px;
}
.section-body { margin-bottom: 16px; }
/* Tables */
table {
width: 100%;
border-collapse: collapse;
margin: 10px 0 16px 0;
font-size: 9pt;
}
th, td {
border: 1px solid #e2e8f0;
padding: 6px 8px;
text-align: left;
vertical-align: top;
}
th {
background: #f5f3ff;
color: #5b21b6;
font-weight: 600;
font-size: 8.5pt;
text-transform: uppercase;
letter-spacing: 0.3px;
}
tr:nth-child(even) td { background: #faf5ff; }
/* Detail cards */
.policy-detail {
page-break-inside: avoid;
border: 1px solid #e2e8f0;
border-radius: 6px;
margin-bottom: 16px;
overflow: hidden;
}
.policy-detail-header {
background: #f5f3ff;
padding: 8px 12px;
font-weight: 700;
color: #5b21b6;
border-bottom: 1px solid #ddd6fe;
display: flex;
justify-content: space-between;
}
.policy-detail-body { padding: 0; }
.policy-detail-body table { margin: 0; }
.policy-detail-body th { width: 200px; }
/* Badges */
.badge {
display: inline-block;
padding: 1px 8px;
border-radius: 9999px;
font-size: 8pt;
font-weight: 600;
}
.badge-active { background: #dcfce7; color: #166534; }
.badge-draft { background: #f3f4f6; color: #374151; }
.badge-review { background: #fef9c3; color: #854d0e; }
.badge-critical { background: #fecaca; color: #991b1b; }
.badge-high { background: #fed7aa; color: #9a3412; }
.badge-medium { background: #fef3c7; color: #92400e; }
.badge-low { background: #f3f4f6; color: #4b5563; }
/* Principles */
.principle {
margin-bottom: 10px;
padding-left: 20px;
position: relative;
}
.principle::before {
content: '';
position: absolute;
left: 0;
top: 6px;
width: 10px;
height: 10px;
background: #7c3aed;
border-radius: 50%;
}
.principle strong { color: #5b21b6; }
/* Score */
.score-box {
display: inline-block;
padding: 4px 16px;
border-radius: 8px;
font-size: 18pt;
font-weight: 700;
margin-right: 12px;
}
.score-excellent { background: #dcfce7; color: #166534; }
.score-good { background: #dbeafe; color: #1e40af; }
.score-needs-work { background: #fef3c7; color: #92400e; }
.score-poor { background: #fecaca; color: #991b1b; }
/* Footer */
.page-footer {
position: fixed;
bottom: 0;
left: 0;
right: 0;
padding: 8px 18mm;
font-size: 7.5pt;
color: #94a3b8;
display: flex;
justify-content: space-between;
border-top: 1px solid #e2e8f0;
}
/* Print */
@media print {
body { -webkit-print-color-adjust: exact; print-color-adjust: exact; }
.no-print { display: none !important; }
.page-break { page-break-after: always; }
}
</style>
</head>
<body>
`
}

View File

@@ -0,0 +1,70 @@
// =============================================================================
// Obligations Document — Types, Defaults & Status/Priority Labels
// =============================================================================
export interface ObligationDocumentOrgHeader {
organizationName: string
industry: string
dpoName: string
dpoContact: string
responsiblePerson: string
legalDepartment: string
documentVersion: string
lastReviewDate: string
nextReviewDate: string
reviewInterval: string
}
export interface ObligationDocumentRevision {
version: string
date: string
author: string
changes: string
}
export function createDefaultObligationDocumentOrgHeader(): ObligationDocumentOrgHeader {
const now = new Date()
const nextYear = new Date()
nextYear.setFullYear(nextYear.getFullYear() + 1)
return {
organizationName: '',
industry: '',
dpoName: '',
dpoContact: '',
responsiblePerson: '',
legalDepartment: '',
documentVersion: '1.0',
lastReviewDate: now.toISOString().split('T')[0],
nextReviewDate: nextYear.toISOString().split('T')[0],
reviewInterval: 'Jaehrlich',
}
}
export const STATUS_LABELS_DE: Record<string, string> = {
'pending': 'Ausstehend',
'in-progress': 'In Bearbeitung',
'completed': 'Abgeschlossen',
'overdue': 'Ueberfaellig',
}
export const STATUS_BADGE_CLASSES: Record<string, string> = {
'pending': 'badge-draft',
'in-progress': 'badge-review',
'completed': 'badge-active',
'overdue': 'badge-critical',
}
export const PRIORITY_LABELS_DE: Record<string, string> = {
critical: 'Kritisch',
high: 'Hoch',
medium: 'Mittel',
low: 'Niedrig',
}
export const PRIORITY_BADGE_CLASSES: Record<string, string> = {
critical: 'badge-critical',
high: 'badge-high',
medium: 'badge-medium',
low: 'badge-low',
}

View File

@@ -0,0 +1,328 @@
// =============================================================================
// TOM Compliance Checks — Per-TOM and Aggregate checks
//
// Barrel-split from tom-compliance.ts. Do NOT import directly; use tom-compliance.ts.
// =============================================================================
import type {
TOMGeneratorState,
DerivedTOM,
RiskProfile,
DataProfile,
ControlCategory,
} from './tom-generator/types'
import { getControlById } from './tom-generator/controls/loader'
import { SDM_CATEGORY_MAPPING } from './tom-generator/types'
import type { TOMComplianceIssue, TOMComplianceIssueType, TOMComplianceIssueSeverity } from './tom-compliance'
// =============================================================================
// HELPERS
// =============================================================================
let issueCounter = 0
export function resetIssueCounter(): void {
issueCounter = 0
}
export function createIssue(
controlId: string,
controlName: string,
type: TOMComplianceIssueType,
severity: TOMComplianceIssueSeverity,
title: string,
description: string,
recommendation: string
): TOMComplianceIssue {
issueCounter++
const id = `TCI-${Date.now()}-${String(issueCounter).padStart(4, '0')}`
return { id, controlId, controlName, type, severity, title, description, recommendation }
}
function daysBetween(date: Date, now: Date): number {
const diffMs = now.getTime() - date.getTime()
return Math.floor(diffMs / (1000 * 60 * 60 * 24))
}
// =============================================================================
// PER-TOM CHECKS (1-3, 11)
// =============================================================================
/**
* Check 1: MISSING_RESPONSIBLE (MEDIUM)
*/
export function checkMissingResponsible(tom: DerivedTOM): TOMComplianceIssue | null {
if (tom.applicability !== 'REQUIRED') return null
if (!tom.responsiblePerson && !tom.responsibleDepartment) {
return createIssue(
tom.controlId, tom.name, 'MISSING_RESPONSIBLE', 'MEDIUM',
'Keine verantwortliche Person/Abteilung',
`Die TOM "${tom.name}" ist als REQUIRED eingestuft, hat aber weder eine verantwortliche Person noch eine verantwortliche Abteilung zugewiesen. Ohne klare Verantwortlichkeit kann die Massnahme nicht zuverlaessig umgesetzt und gepflegt werden.`,
'Weisen Sie eine verantwortliche Person oder Abteilung zu, die fuer die Umsetzung und regelmaessige Pruefung dieser Massnahme zustaendig ist.'
)
}
return null
}
/**
* Check 2: OVERDUE_REVIEW (MEDIUM)
*/
export function checkOverdueReview(tom: DerivedTOM): TOMComplianceIssue | null {
if (!tom.reviewDate) return null
const reviewDate = new Date(tom.reviewDate)
const now = new Date()
if (reviewDate < now) {
const overdueDays = daysBetween(reviewDate, now)
return createIssue(
tom.controlId, tom.name, 'OVERDUE_REVIEW', 'MEDIUM',
'Ueberfaellige Pruefung',
`Die TOM "${tom.name}" haette am ${reviewDate.toLocaleDateString('de-DE')} geprueft werden muessen. Die Pruefung ist ${overdueDays} Tag(e) ueberfaellig. Gemaess Art. 32 Abs. 1 lit. d DSGVO ist eine regelmaessige Ueberpruefung der Wirksamkeit von TOMs erforderlich.`,
'Fuehren Sie umgehend eine Wirksamkeitspruefung dieser Massnahme durch und aktualisieren Sie das naechste Pruefungsdatum.'
)
}
return null
}
/**
* Check 3: MISSING_EVIDENCE (HIGH)
*/
export function checkMissingEvidence(tom: DerivedTOM): TOMComplianceIssue | null {
if (tom.implementationStatus !== 'IMPLEMENTED') return null
if (tom.linkedEvidence.length > 0) return null
const control = getControlById(tom.controlId)
if (!control || control.evidenceRequirements.length === 0) return null
return createIssue(
tom.controlId, tom.name, 'MISSING_EVIDENCE', 'HIGH',
'Kein Nachweis hinterlegt',
`Die TOM "${tom.name}" ist als IMPLEMENTED markiert, hat aber keine verknuepften Nachweisdokumente. Der Control erfordert ${control.evidenceRequirements.length} Nachweis(e): ${control.evidenceRequirements.join(', ')}. Ohne Nachweise ist die Umsetzung nicht auditfaehig.`,
'Laden Sie die erforderlichen Nachweisdokumente hoch und verknuepfen Sie sie mit dieser Massnahme.'
)
}
/**
* Check 11: STALE_NOT_IMPLEMENTED (LOW)
*/
export function checkStaleNotImplemented(tom: DerivedTOM, state: TOMGeneratorState): TOMComplianceIssue | null {
if (tom.applicability !== 'REQUIRED') return null
if (tom.implementationStatus !== 'NOT_IMPLEMENTED') return null
if (tom.implementationDate !== null) return null
const referenceDate = state.createdAt ? new Date(state.createdAt) : (state.updatedAt ? new Date(state.updatedAt) : null)
if (!referenceDate) return null
const ageInDays = daysBetween(referenceDate, new Date())
if (ageInDays <= 90) return null
return createIssue(
tom.controlId, tom.name, 'STALE_NOT_IMPLEMENTED', 'LOW',
'Langfristig nicht umgesetzte Pflichtmassnahme',
`Die TOM "${tom.name}" ist als REQUIRED eingestuft, aber seit ${ageInDays} Tagen nicht umgesetzt. Pflichtmassnahmen, die laenger als 90 Tage nicht implementiert werden, deuten auf organisatorische Blockaden oder unzureichende Priorisierung hin.`,
'Pruefen Sie, ob die Massnahme weiterhin erforderlich ist, und erstellen Sie einen konkreten Umsetzungsplan mit Verantwortlichkeiten und Fristen.'
)
}
// =============================================================================
// AGGREGATE CHECKS (4-10)
// =============================================================================
/**
* Check 4: INCOMPLETE_CATEGORY (HIGH)
*/
export function checkIncompleteCategory(toms: DerivedTOM[]): TOMComplianceIssue[] {
const issues: TOMComplianceIssue[] = []
const categoryMap = new Map<ControlCategory, DerivedTOM[]>()
for (const tom of toms) {
const control = getControlById(tom.controlId)
if (!control) continue
const category = control.category
if (!categoryMap.has(category)) categoryMap.set(category, [])
categoryMap.get(category)!.push(tom)
}
for (const [category, categoryToms] of Array.from(categoryMap.entries())) {
const requiredToms = categoryToms.filter((t: DerivedTOM) => t.applicability === 'REQUIRED')
if (requiredToms.length === 0) continue
const allNotImplemented = requiredToms.every((t: DerivedTOM) => t.implementationStatus === 'NOT_IMPLEMENTED')
if (allNotImplemented) {
issues.push(createIssue(
category, category, 'INCOMPLETE_CATEGORY', 'HIGH',
`Kategorie "${category}" vollstaendig ohne Umsetzung`,
`Alle ${requiredToms.length} Pflichtmassnahme(n) in der Kategorie "${category}" sind nicht umgesetzt. Eine vollstaendig unabgedeckte Kategorie stellt eine erhebliche Luecke im TOM-Konzept dar.`,
`Setzen Sie mindestens die wichtigsten Massnahmen in der Kategorie "${category}" um, um eine Grundabdeckung sicherzustellen.`
))
}
}
return issues
}
/**
* Check 5: NO_ENCRYPTION_MEASURES (CRITICAL)
*/
export function checkNoEncryption(toms: DerivedTOM[]): TOMComplianceIssue | null {
const hasImplementedEncryption = toms.some((tom) => {
const control = getControlById(tom.controlId)
return control?.category === 'ENCRYPTION' && tom.implementationStatus === 'IMPLEMENTED'
})
if (!hasImplementedEncryption) {
return createIssue(
'ENCRYPTION', 'Verschluesselung', 'NO_ENCRYPTION_MEASURES', 'CRITICAL',
'Keine Verschluesselungsmassnahmen umgesetzt',
'Es ist keine einzige Verschluesselungsmassnahme als IMPLEMENTED markiert. Art. 32 Abs. 1 lit. a DSGVO nennt Verschluesselung explizit als geeignete technische Massnahme. Ohne Verschluesselung sind personenbezogene Daten bei Zugriff oder Verlust ungeschuetzt.',
'Implementieren Sie umgehend Verschluesselungsmassnahmen fuer Daten im Ruhezustand (Encryption at Rest) und waehrend der Uebertragung (Encryption in Transit).'
)
}
return null
}
/**
* Check 6: NO_PSEUDONYMIZATION (MEDIUM)
*/
export function checkNoPseudonymization(toms: DerivedTOM[], dataProfile: DataProfile | null): TOMComplianceIssue | null {
if (!dataProfile || !dataProfile.hasSpecialCategories) return null
const hasImplementedPseudonymization = toms.some((tom) => {
const control = getControlById(tom.controlId)
return control?.category === 'PSEUDONYMIZATION' && tom.implementationStatus === 'IMPLEMENTED'
})
if (!hasImplementedPseudonymization) {
return createIssue(
'PSEUDONYMIZATION', 'Pseudonymisierung', 'NO_PSEUDONYMIZATION', 'MEDIUM',
'Keine Pseudonymisierung bei besonderen Datenkategorien',
'Das Datenprofil enthaelt besondere Kategorien personenbezogener Daten (Art. 9 DSGVO), aber keine Pseudonymisierungsmassnahme ist umgesetzt. Art. 32 Abs. 1 lit. a DSGVO empfiehlt Pseudonymisierung ausdruecklich als Schutzmassnahme.',
'Implementieren Sie Pseudonymisierungsmassnahmen fuer die Verarbeitung besonderer Datenkategorien, um das Risiko fuer betroffene Personen zu minimieren.'
)
}
return null
}
/**
* Check 7: MISSING_AVAILABILITY (HIGH)
*/
export function checkMissingAvailability(toms: DerivedTOM[], state: TOMGeneratorState): TOMComplianceIssue | null {
const hasAvailabilityOrRecovery = toms.some((tom) => {
const control = getControlById(tom.controlId)
return (
(control?.category === 'AVAILABILITY' || control?.category === 'RECOVERY') &&
tom.implementationStatus === 'IMPLEMENTED'
)
})
const hasDRPlan = state.securityProfile?.hasDRPlan ?? false
if (!hasAvailabilityOrRecovery && !hasDRPlan) {
return createIssue(
'AVAILABILITY', 'Verfuegbarkeit / Wiederherstellbarkeit', 'MISSING_AVAILABILITY', 'HIGH',
'Keine Verfuegbarkeits- oder Wiederherstellungsmassnahmen',
'Weder Verfuegbarkeits- noch Wiederherstellungsmassnahmen sind umgesetzt, und es existiert kein Disaster-Recovery-Plan im Security-Profil. Art. 32 Abs. 1 lit. b und c DSGVO verlangen die Faehigkeit zur raschen Wiederherstellung der Verfuegbarkeit personenbezogener Daten.',
'Implementieren Sie Backup-Konzepte, Redundanzloesungen und einen Disaster-Recovery-Plan, um die Verfuegbarkeit und Wiederherstellbarkeit sicherzustellen.'
)
}
return null
}
/**
* Check 8: NO_REVIEW_PROCESS (MEDIUM)
*/
export function checkNoReviewProcess(toms: DerivedTOM[]): TOMComplianceIssue | null {
const hasImplementedReview = toms.some((tom) => {
const control = getControlById(tom.controlId)
return control?.category === 'REVIEW' && tom.implementationStatus === 'IMPLEMENTED'
})
if (!hasImplementedReview) {
return createIssue(
'REVIEW', 'Ueberpruefung & Bewertung', 'NO_REVIEW_PROCESS', 'MEDIUM',
'Kein Verfahren zur regelmaessigen Ueberpruefung',
'Es ist keine Ueberpruefungsmassnahme als IMPLEMENTED markiert. Art. 32 Abs. 1 lit. d DSGVO verlangt ein Verfahren zur regelmaessigen Ueberpruefung, Bewertung und Evaluierung der Wirksamkeit der technischen und organisatorischen Massnahmen.',
'Implementieren Sie einen regelmaessigen Review-Prozess (z.B. quartalsweise TOM-Audits, jaehrliche Wirksamkeitspruefung) und dokumentieren Sie die Ergebnisse.'
)
}
return null
}
/**
* Check 9: UNCOVERED_SDM_GOAL (HIGH)
*/
export function checkUncoveredSDMGoal(toms: DerivedTOM[]): TOMComplianceIssue[] {
const issues: TOMComplianceIssue[] = []
const sdmGoals = [
'Verfuegbarkeit', 'Integritaet', 'Vertraulichkeit',
'Nichtverkettung', 'Intervenierbarkeit', 'Transparenz', 'Datenminimierung',
] as const
const goalToCategoriesMap = new Map<string, ControlCategory[]>()
for (const goal of sdmGoals) goalToCategoriesMap.set(goal, [])
for (const [category, goals] of Object.entries(SDM_CATEGORY_MAPPING)) {
for (const goal of goals) {
const existing = goalToCategoriesMap.get(goal)
if (existing) existing.push(category as ControlCategory)
}
}
const implementedCategories = new Set<ControlCategory>()
for (const tom of toms) {
if (tom.implementationStatus !== 'IMPLEMENTED') continue
const control = getControlById(tom.controlId)
if (control) implementedCategories.add(control.category)
}
for (const goal of sdmGoals) {
const coveringCategories = goalToCategoriesMap.get(goal) ?? []
const hasCoverage = coveringCategories.some((cat) => implementedCategories.has(cat))
if (!hasCoverage) {
issues.push(createIssue(
`SDM-${goal}`, goal, 'UNCOVERED_SDM_GOAL', 'HIGH',
`SDM-Gewaehrleistungsziel "${goal}" nicht abgedeckt`,
`Das Gewaehrleistungsziel "${goal}" des Standard-Datenschutzmodells (SDM) ist durch keine umgesetzte Massnahme abgedeckt. Zugehoerige Kategorien (${coveringCategories.join(', ')}) haben keine IMPLEMENTED Controls. Das SDM ist die anerkannte Methodik zur Umsetzung der DSGVO-Anforderungen.`,
`Setzen Sie mindestens eine Massnahme aus den Kategorien ${coveringCategories.join(', ')} um, um das SDM-Ziel "${goal}" abzudecken.`
))
}
}
return issues
}
/**
* Check 10: HIGH_RISK_WITHOUT_MEASURES (CRITICAL)
*/
export function checkHighRiskWithoutMeasures(toms: DerivedTOM[], riskProfile: RiskProfile | null): TOMComplianceIssue | null {
if (!riskProfile || riskProfile.protectionLevel !== 'VERY_HIGH') return null
const requiredToms = toms.filter((t) => t.applicability === 'REQUIRED')
if (requiredToms.length === 0) return null
const implementedCount = requiredToms.filter((t) => t.implementationStatus === 'IMPLEMENTED').length
const implementationRate = implementedCount / requiredToms.length
if (implementationRate < 0.5) {
const percentage = Math.round(implementationRate * 100)
return createIssue(
'RISK-PROFILE', 'Risikoprofil VERY_HIGH', 'HIGH_RISK_WITHOUT_MEASURES', 'CRITICAL',
'Sehr hoher Schutzbedarf bei niedriger Umsetzungsrate',
`Der Schutzbedarf ist als VERY_HIGH eingestuft, aber nur ${implementedCount} von ${requiredToms.length} Pflichtmassnahmen (${percentage}%) sind umgesetzt. Bei sehr hohem Schutzbedarf muessen mindestens 50% der Pflichtmassnahmen implementiert sein, um ein angemessenes Schutzniveau gemaess Art. 32 DSGVO zu gewaehrleisten.`,
'Priorisieren Sie die Umsetzung der verbleibenden Pflichtmassnahmen. Beginnen Sie mit CRITICAL- und HIGH-Priority Controls. Erwaeegen Sie einen Umsetzungsplan mit klaren Meilensteinen.'
)
}
return null
}

View File

@@ -2,19 +2,26 @@
// TOM Module - Compliance Check Engine // TOM Module - Compliance Check Engine
// Prueft Technische und Organisatorische Massnahmen auf Vollstaendigkeit, // Prueft Technische und Organisatorische Massnahmen auf Vollstaendigkeit,
// Konsistenz und DSGVO-Konformitaet (Art. 32 DSGVO) // Konsistenz und DSGVO-Konformitaet (Art. 32 DSGVO)
//
// Check functions live in tom-compliance-checks.ts (barrel split).
// ============================================================================= // =============================================================================
import type { import type { TOMGeneratorState } from './tom-generator/types'
TOMGeneratorState,
DerivedTOM,
RiskProfile,
DataProfile,
ControlCategory,
ImplementationStatus,
} from './tom-generator/types'
import { getControlById, getControlsByCategory, getAllCategories } from './tom-generator/controls/loader' import {
import { SDM_CATEGORY_MAPPING } from './tom-generator/types' resetIssueCounter,
checkMissingResponsible,
checkOverdueReview,
checkMissingEvidence,
checkStaleNotImplemented,
checkIncompleteCategory,
checkNoEncryption,
checkNoPseudonymization,
checkMissingAvailability,
checkNoReviewProcess,
checkUncoveredSDMGoal,
checkHighRiskWithoutMeasures,
} from './tom-compliance-checks'
// ============================================================================= // =============================================================================
// TYPES // TYPES
@@ -75,386 +82,6 @@ export const TOM_SEVERITY_COLORS: Record<TOMComplianceIssueSeverity, string> = {
LOW: '#6b7280', LOW: '#6b7280',
} }
// =============================================================================
// HELPERS
// =============================================================================
let issueCounter = 0
function createIssueId(): string {
issueCounter++
return `TCI-${Date.now()}-${String(issueCounter).padStart(4, '0')}`
}
function createIssue(
controlId: string,
controlName: string,
type: TOMComplianceIssueType,
severity: TOMComplianceIssueSeverity,
title: string,
description: string,
recommendation: string
): TOMComplianceIssue {
return { id: createIssueId(), controlId, controlName, type, severity, title, description, recommendation }
}
function daysBetween(date: Date, now: Date): number {
const diffMs = now.getTime() - date.getTime()
return Math.floor(diffMs / (1000 * 60 * 60 * 24))
}
// =============================================================================
// PER-TOM CHECKS (1-3, 11)
// =============================================================================
/**
* Check 1: MISSING_RESPONSIBLE (MEDIUM)
* REQUIRED TOM without responsiblePerson AND responsibleDepartment.
*/
function checkMissingResponsible(tom: DerivedTOM): TOMComplianceIssue | null {
if (tom.applicability !== 'REQUIRED') return null
if (!tom.responsiblePerson && !tom.responsibleDepartment) {
return createIssue(
tom.controlId,
tom.name,
'MISSING_RESPONSIBLE',
'MEDIUM',
'Keine verantwortliche Person/Abteilung',
`Die TOM "${tom.name}" ist als REQUIRED eingestuft, hat aber weder eine verantwortliche Person noch eine verantwortliche Abteilung zugewiesen. Ohne klare Verantwortlichkeit kann die Massnahme nicht zuverlaessig umgesetzt und gepflegt werden.`,
'Weisen Sie eine verantwortliche Person oder Abteilung zu, die fuer die Umsetzung und regelmaessige Pruefung dieser Massnahme zustaendig ist.'
)
}
return null
}
/**
* Check 2: OVERDUE_REVIEW (MEDIUM)
* TOM with reviewDate in the past.
*/
function checkOverdueReview(tom: DerivedTOM): TOMComplianceIssue | null {
if (!tom.reviewDate) return null
const reviewDate = new Date(tom.reviewDate)
const now = new Date()
if (reviewDate < now) {
const overdueDays = daysBetween(reviewDate, now)
return createIssue(
tom.controlId,
tom.name,
'OVERDUE_REVIEW',
'MEDIUM',
'Ueberfaellige Pruefung',
`Die TOM "${tom.name}" haette am ${reviewDate.toLocaleDateString('de-DE')} geprueft werden muessen. Die Pruefung ist ${overdueDays} Tag(e) ueberfaellig. Gemaess Art. 32 Abs. 1 lit. d DSGVO ist eine regelmaessige Ueberpruefung der Wirksamkeit von TOMs erforderlich.`,
'Fuehren Sie umgehend eine Wirksamkeitspruefung dieser Massnahme durch und aktualisieren Sie das naechste Pruefungsdatum.'
)
}
return null
}
/**
* Check 3: MISSING_EVIDENCE (HIGH)
* IMPLEMENTED TOM where linkedEvidence is empty but the control has evidenceRequirements.
*/
function checkMissingEvidence(tom: DerivedTOM): TOMComplianceIssue | null {
if (tom.implementationStatus !== 'IMPLEMENTED') return null
if (tom.linkedEvidence.length > 0) return null
const control = getControlById(tom.controlId)
if (!control || control.evidenceRequirements.length === 0) return null
return createIssue(
tom.controlId,
tom.name,
'MISSING_EVIDENCE',
'HIGH',
'Kein Nachweis hinterlegt',
`Die TOM "${tom.name}" ist als IMPLEMENTED markiert, hat aber keine verknuepften Nachweisdokumente. Der Control erfordert ${control.evidenceRequirements.length} Nachweis(e): ${control.evidenceRequirements.join(', ')}. Ohne Nachweise ist die Umsetzung nicht auditfaehig.`,
'Laden Sie die erforderlichen Nachweisdokumente hoch und verknuepfen Sie sie mit dieser Massnahme.'
)
}
/**
* Check 11: STALE_NOT_IMPLEMENTED (LOW)
* REQUIRED TOM that has been NOT_IMPLEMENTED for >90 days.
* Uses implementationDate === null and state.createdAt / state.updatedAt as reference.
*/
function checkStaleNotImplemented(tom: DerivedTOM, state: TOMGeneratorState): TOMComplianceIssue | null {
if (tom.applicability !== 'REQUIRED') return null
if (tom.implementationStatus !== 'NOT_IMPLEMENTED') return null
if (tom.implementationDate !== null) return null
const referenceDate = state.createdAt ? new Date(state.createdAt) : (state.updatedAt ? new Date(state.updatedAt) : null)
if (!referenceDate) return null
const ageInDays = daysBetween(referenceDate, new Date())
if (ageInDays <= 90) return null
return createIssue(
tom.controlId,
tom.name,
'STALE_NOT_IMPLEMENTED',
'LOW',
'Langfristig nicht umgesetzte Pflichtmassnahme',
`Die TOM "${tom.name}" ist als REQUIRED eingestuft, aber seit ${ageInDays} Tagen nicht umgesetzt. Pflichtmassnahmen, die laenger als 90 Tage nicht implementiert werden, deuten auf organisatorische Blockaden oder unzureichende Priorisierung hin.`,
'Pruefen Sie, ob die Massnahme weiterhin erforderlich ist, und erstellen Sie einen konkreten Umsetzungsplan mit Verantwortlichkeiten und Fristen.'
)
}
// =============================================================================
// AGGREGATE CHECKS (4-10)
// =============================================================================
/**
* Check 4: INCOMPLETE_CATEGORY (HIGH)
* Category where ALL applicable (REQUIRED) controls are NOT_IMPLEMENTED.
*/
function checkIncompleteCategory(toms: DerivedTOM[]): TOMComplianceIssue[] {
const issues: TOMComplianceIssue[] = []
// Group applicable TOMs by category
const categoryMap = new Map<ControlCategory, DerivedTOM[]>()
for (const tom of toms) {
const control = getControlById(tom.controlId)
if (!control) continue
const category = control.category
if (!categoryMap.has(category)) {
categoryMap.set(category, [])
}
categoryMap.get(category)!.push(tom)
}
for (const [category, categoryToms] of Array.from(categoryMap.entries())) {
// Only check categories that have at least one REQUIRED control
const requiredToms = categoryToms.filter((t: DerivedTOM) => t.applicability === 'REQUIRED')
if (requiredToms.length === 0) continue
const allNotImplemented = requiredToms.every((t: DerivedTOM) => t.implementationStatus === 'NOT_IMPLEMENTED')
if (allNotImplemented) {
issues.push(
createIssue(
category,
category,
'INCOMPLETE_CATEGORY',
'HIGH',
`Kategorie "${category}" vollstaendig ohne Umsetzung`,
`Alle ${requiredToms.length} Pflichtmassnahme(n) in der Kategorie "${category}" sind nicht umgesetzt. Eine vollstaendig unabgedeckte Kategorie stellt eine erhebliche Luecke im TOM-Konzept dar.`,
`Setzen Sie mindestens die wichtigsten Massnahmen in der Kategorie "${category}" um, um eine Grundabdeckung sicherzustellen.`
)
)
}
}
return issues
}
/**
* Check 5: NO_ENCRYPTION_MEASURES (CRITICAL)
* No ENCRYPTION control with status IMPLEMENTED.
*/
function checkNoEncryption(toms: DerivedTOM[]): TOMComplianceIssue | null {
const hasImplementedEncryption = toms.some((tom) => {
const control = getControlById(tom.controlId)
return control?.category === 'ENCRYPTION' && tom.implementationStatus === 'IMPLEMENTED'
})
if (!hasImplementedEncryption) {
return createIssue(
'ENCRYPTION',
'Verschluesselung',
'NO_ENCRYPTION_MEASURES',
'CRITICAL',
'Keine Verschluesselungsmassnahmen umgesetzt',
'Es ist keine einzige Verschluesselungsmassnahme als IMPLEMENTED markiert. Art. 32 Abs. 1 lit. a DSGVO nennt Verschluesselung explizit als geeignete technische Massnahme. Ohne Verschluesselung sind personenbezogene Daten bei Zugriff oder Verlust ungeschuetzt.',
'Implementieren Sie umgehend Verschluesselungsmassnahmen fuer Daten im Ruhezustand (Encryption at Rest) und waehrend der Uebertragung (Encryption in Transit).'
)
}
return null
}
/**
* Check 6: NO_PSEUDONYMIZATION (MEDIUM)
* DataProfile has special categories (Art. 9) but no PSEUDONYMIZATION control implemented.
*/
function checkNoPseudonymization(toms: DerivedTOM[], dataProfile: DataProfile | null): TOMComplianceIssue | null {
if (!dataProfile || !dataProfile.hasSpecialCategories) return null
const hasImplementedPseudonymization = toms.some((tom) => {
const control = getControlById(tom.controlId)
return control?.category === 'PSEUDONYMIZATION' && tom.implementationStatus === 'IMPLEMENTED'
})
if (!hasImplementedPseudonymization) {
return createIssue(
'PSEUDONYMIZATION',
'Pseudonymisierung',
'NO_PSEUDONYMIZATION',
'MEDIUM',
'Keine Pseudonymisierung bei besonderen Datenkategorien',
'Das Datenprofil enthaelt besondere Kategorien personenbezogener Daten (Art. 9 DSGVO), aber keine Pseudonymisierungsmassnahme ist umgesetzt. Art. 32 Abs. 1 lit. a DSGVO empfiehlt Pseudonymisierung ausdruecklich als Schutzmassnahme.',
'Implementieren Sie Pseudonymisierungsmassnahmen fuer die Verarbeitung besonderer Datenkategorien, um das Risiko fuer betroffene Personen zu minimieren.'
)
}
return null
}
/**
* Check 7: MISSING_AVAILABILITY (HIGH)
* No AVAILABILITY or RECOVERY control implemented AND no DR plan in securityProfile.
*/
function checkMissingAvailability(toms: DerivedTOM[], state: TOMGeneratorState): TOMComplianceIssue | null {
const hasAvailabilityOrRecovery = toms.some((tom) => {
const control = getControlById(tom.controlId)
return (
(control?.category === 'AVAILABILITY' || control?.category === 'RECOVERY') &&
tom.implementationStatus === 'IMPLEMENTED'
)
})
const hasDRPlan = state.securityProfile?.hasDRPlan ?? false
if (!hasAvailabilityOrRecovery && !hasDRPlan) {
return createIssue(
'AVAILABILITY',
'Verfuegbarkeit / Wiederherstellbarkeit',
'MISSING_AVAILABILITY',
'HIGH',
'Keine Verfuegbarkeits- oder Wiederherstellungsmassnahmen',
'Weder Verfuegbarkeits- noch Wiederherstellungsmassnahmen sind umgesetzt, und es existiert kein Disaster-Recovery-Plan im Security-Profil. Art. 32 Abs. 1 lit. b und c DSGVO verlangen die Faehigkeit zur raschen Wiederherstellung der Verfuegbarkeit personenbezogener Daten.',
'Implementieren Sie Backup-Konzepte, Redundanzloesungen und einen Disaster-Recovery-Plan, um die Verfuegbarkeit und Wiederherstellbarkeit sicherzustellen.'
)
}
return null
}
/**
* Check 8: NO_REVIEW_PROCESS (MEDIUM)
* No REVIEW control implemented (Art. 32 Abs. 1 lit. d requires periodic review).
*/
function checkNoReviewProcess(toms: DerivedTOM[]): TOMComplianceIssue | null {
const hasImplementedReview = toms.some((tom) => {
const control = getControlById(tom.controlId)
return control?.category === 'REVIEW' && tom.implementationStatus === 'IMPLEMENTED'
})
if (!hasImplementedReview) {
return createIssue(
'REVIEW',
'Ueberpruefung & Bewertung',
'NO_REVIEW_PROCESS',
'MEDIUM',
'Kein Verfahren zur regelmaessigen Ueberpruefung',
'Es ist keine Ueberpruefungsmassnahme als IMPLEMENTED markiert. Art. 32 Abs. 1 lit. d DSGVO verlangt ein Verfahren zur regelmaessigen Ueberpruefung, Bewertung und Evaluierung der Wirksamkeit der technischen und organisatorischen Massnahmen.',
'Implementieren Sie einen regelmaessigen Review-Prozess (z.B. quartalsweise TOM-Audits, jaehrliche Wirksamkeitspruefung) und dokumentieren Sie die Ergebnisse.'
)
}
return null
}
/**
* Check 9: UNCOVERED_SDM_GOAL (HIGH)
* SDM goal with 0% coverage — no implemented control maps to it via SDM_CATEGORY_MAPPING.
*/
function checkUncoveredSDMGoal(toms: DerivedTOM[]): TOMComplianceIssue[] {
const issues: TOMComplianceIssue[] = []
// Build reverse mapping: SDM goal -> ControlCategories that cover it
const sdmGoals = [
'Verfuegbarkeit',
'Integritaet',
'Vertraulichkeit',
'Nichtverkettung',
'Intervenierbarkeit',
'Transparenz',
'Datenminimierung',
] as const
const goalToCategoriesMap = new Map<string, ControlCategory[]>()
for (const goal of sdmGoals) {
goalToCategoriesMap.set(goal, [])
}
// Build reverse lookup from SDM_CATEGORY_MAPPING
for (const [category, goals] of Object.entries(SDM_CATEGORY_MAPPING)) {
for (const goal of goals) {
const existing = goalToCategoriesMap.get(goal)
if (existing) {
existing.push(category as ControlCategory)
}
}
}
// Collect implemented categories
const implementedCategories = new Set<ControlCategory>()
for (const tom of toms) {
if (tom.implementationStatus !== 'IMPLEMENTED') continue
const control = getControlById(tom.controlId)
if (control) {
implementedCategories.add(control.category)
}
}
// Check each SDM goal
for (const goal of sdmGoals) {
const coveringCategories = goalToCategoriesMap.get(goal) ?? []
const hasCoverage = coveringCategories.some((cat) => implementedCategories.has(cat))
if (!hasCoverage) {
issues.push(
createIssue(
`SDM-${goal}`,
goal,
'UNCOVERED_SDM_GOAL',
'HIGH',
`SDM-Gewaehrleistungsziel "${goal}" nicht abgedeckt`,
`Das Gewaehrleistungsziel "${goal}" des Standard-Datenschutzmodells (SDM) ist durch keine umgesetzte Massnahme abgedeckt. Zugehoerige Kategorien (${coveringCategories.join(', ')}) haben keine IMPLEMENTED Controls. Das SDM ist die anerkannte Methodik zur Umsetzung der DSGVO-Anforderungen.`,
`Setzen Sie mindestens eine Massnahme aus den Kategorien ${coveringCategories.join(', ')} um, um das SDM-Ziel "${goal}" abzudecken.`
)
)
}
}
return issues
}
/**
* Check 10: HIGH_RISK_WITHOUT_MEASURES (CRITICAL)
* Protection level VERY_HIGH but < 50% of REQUIRED controls implemented.
*/
function checkHighRiskWithoutMeasures(toms: DerivedTOM[], riskProfile: RiskProfile | null): TOMComplianceIssue | null {
if (!riskProfile || riskProfile.protectionLevel !== 'VERY_HIGH') return null
const requiredToms = toms.filter((t) => t.applicability === 'REQUIRED')
if (requiredToms.length === 0) return null
const implementedCount = requiredToms.filter((t) => t.implementationStatus === 'IMPLEMENTED').length
const implementationRate = implementedCount / requiredToms.length
if (implementationRate < 0.5) {
const percentage = Math.round(implementationRate * 100)
return createIssue(
'RISK-PROFILE',
'Risikoprofil VERY_HIGH',
'HIGH_RISK_WITHOUT_MEASURES',
'CRITICAL',
'Sehr hoher Schutzbedarf bei niedriger Umsetzungsrate',
`Der Schutzbedarf ist als VERY_HIGH eingestuft, aber nur ${implementedCount} von ${requiredToms.length} Pflichtmassnahmen (${percentage}%) sind umgesetzt. Bei sehr hohem Schutzbedarf muessen mindestens 50% der Pflichtmassnahmen implementiert sein, um ein angemessenes Schutzniveau gemaess Art. 32 DSGVO zu gewaehrleisten.`,
'Priorisieren Sie die Umsetzung der verbleibenden Pflichtmassnahmen. Beginnen Sie mit CRITICAL- und HIGH-Priority Controls. Erwaeegen Sie einen Umsetzungsplan mit klaren Meilensteinen.'
)
}
return null
}
// ============================================================================= // =============================================================================
// MAIN COMPLIANCE CHECK // MAIN COMPLIANCE CHECK
// ============================================================================= // =============================================================================
@@ -467,7 +94,7 @@ function checkHighRiskWithoutMeasures(toms: DerivedTOM[], riskProfile: RiskProfi
*/ */
export function runTOMComplianceCheck(state: TOMGeneratorState): TOMComplianceCheckResult { export function runTOMComplianceCheck(state: TOMGeneratorState): TOMComplianceCheckResult {
// Reset counter for deterministic IDs within a single check run // Reset counter for deterministic IDs within a single check run
issueCounter = 0 resetIssueCounter()
const issues: TOMComplianceIssue[] = [] const issues: TOMComplianceIssue[] = []
@@ -513,10 +140,7 @@ export function runTOMComplianceCheck(state: TOMGeneratorState): TOMComplianceCh
// Calculate score // Calculate score
const bySeverity: Record<TOMComplianceIssueSeverity, number> = { const bySeverity: Record<TOMComplianceIssueSeverity, number> = {
LOW: 0, LOW: 0, MEDIUM: 0, HIGH: 0, CRITICAL: 0,
MEDIUM: 0,
HIGH: 0,
CRITICAL: 0,
} }
for (const issue of issues) { for (const issue of issues) {

View File

@@ -1,906 +1,8 @@
// ============================================================================= // =============================================================================
// TOM Module - TOM-Dokumentation Document Generator // TOM Module - TOM-Dokumentation Document Generator
// Generates a printable, audit-ready HTML document according to DSGVO Art. 32 // Barrel re-export — implementation split into tom-document/
// ============================================================================= // =============================================================================
import type { export type { TOMDocumentOrgHeader, TOMDocumentRevision } from './tom-document/types-defaults'
TOMGeneratorState, export { createDefaultTOMDocumentOrgHeader } from './tom-document/types-defaults'
DerivedTOM, export { buildTOMDocumentHtml } from './tom-document/html-builder'
CompanyProfile,
RiskProfile,
ControlCategory,
} from './tom-generator/types'
import { SDM_CATEGORY_MAPPING } from './tom-generator/types'
import {
getControlById,
getControlsByCategory,
getAllCategories,
getCategoryMetadata,
} from './tom-generator/controls/loader'
import type { TOMComplianceCheckResult, TOMComplianceIssueSeverity } from './tom-compliance'
// =============================================================================
// TYPES
// =============================================================================
export interface TOMDocumentOrgHeader {
organizationName: string
industry: string
dpoName: string
dpoContact: string
responsiblePerson: string
itSecurityContact: string
locations: string[]
employeeCount: string
documentVersion: string
lastReviewDate: string
nextReviewDate: string
reviewInterval: string
}
export interface TOMDocumentRevision {
version: string
date: string
author: string
changes: string
}
// =============================================================================
// DEFAULTS
// =============================================================================
export function createDefaultTOMDocumentOrgHeader(): TOMDocumentOrgHeader {
const now = new Date()
const nextYear = new Date()
nextYear.setFullYear(nextYear.getFullYear() + 1)
return {
organizationName: '',
industry: '',
dpoName: '',
dpoContact: '',
responsiblePerson: '',
itSecurityContact: '',
locations: [],
employeeCount: '',
documentVersion: '1.0',
lastReviewDate: now.toISOString().split('T')[0],
nextReviewDate: nextYear.toISOString().split('T')[0],
reviewInterval: 'Jaehrlich',
}
}
// =============================================================================
// SEVERITY LABELS (for Compliance Status section)
// =============================================================================
const SEVERITY_LABELS_DE: Record<TOMComplianceIssueSeverity, string> = {
CRITICAL: 'Kritisch',
HIGH: 'Hoch',
MEDIUM: 'Mittel',
LOW: 'Niedrig',
}
const SEVERITY_COLORS: Record<TOMComplianceIssueSeverity, string> = {
CRITICAL: '#dc2626',
HIGH: '#ea580c',
MEDIUM: '#d97706',
LOW: '#6b7280',
}
// =============================================================================
// CATEGORY LABELS (German)
// =============================================================================
const CATEGORY_LABELS_DE: Record<ControlCategory, string> = {
ACCESS_CONTROL: 'Zutrittskontrolle',
ADMISSION_CONTROL: 'Zugangskontrolle',
ACCESS_AUTHORIZATION: 'Zugriffskontrolle',
TRANSFER_CONTROL: 'Weitergabekontrolle',
INPUT_CONTROL: 'Eingabekontrolle',
ORDER_CONTROL: 'Auftragskontrolle',
AVAILABILITY: 'Verfuegbarkeit',
SEPARATION: 'Trennbarkeit',
ENCRYPTION: 'Verschluesselung',
PSEUDONYMIZATION: 'Pseudonymisierung',
RESILIENCE: 'Belastbarkeit',
RECOVERY: 'Wiederherstellbarkeit',
REVIEW: 'Ueberpruefung & Bewertung',
}
// =============================================================================
// STATUS & APPLICABILITY LABELS
// =============================================================================
const STATUS_LABELS_DE: Record<string, string> = {
IMPLEMENTED: 'Umgesetzt',
PARTIAL: 'Teilweise umgesetzt',
NOT_IMPLEMENTED: 'Nicht umgesetzt',
}
const STATUS_BADGE_CLASSES: Record<string, string> = {
IMPLEMENTED: 'badge-active',
PARTIAL: 'badge-review',
NOT_IMPLEMENTED: 'badge-critical',
}
const APPLICABILITY_LABELS_DE: Record<string, string> = {
REQUIRED: 'Erforderlich',
RECOMMENDED: 'Empfohlen',
OPTIONAL: 'Optional',
NOT_APPLICABLE: 'Nicht anwendbar',
}
// =============================================================================
// HTML DOCUMENT BUILDER
// =============================================================================
export function buildTOMDocumentHtml(
derivedTOMs: DerivedTOM[],
orgHeader: TOMDocumentOrgHeader,
companyProfile: CompanyProfile | null,
riskProfile: RiskProfile | null,
complianceResult: TOMComplianceCheckResult | null,
revisions: TOMDocumentRevision[]
): string {
const today = new Date().toLocaleDateString('de-DE', {
day: '2-digit',
month: '2-digit',
year: 'numeric',
})
const orgName = orgHeader.organizationName || 'Organisation'
// Filter out NOT_APPLICABLE TOMs for display
const applicableTOMs = derivedTOMs.filter(t => t.applicability !== 'NOT_APPLICABLE')
// Group TOMs by category via control library lookup
const tomsByCategory = new Map<ControlCategory, DerivedTOM[]>()
for (const tom of applicableTOMs) {
const control = getControlById(tom.controlId)
const cat = control?.category || 'REVIEW'
if (!tomsByCategory.has(cat)) tomsByCategory.set(cat, [])
tomsByCategory.get(cat)!.push(tom)
}
// Build role map: role/department → list of control codes
const roleMap = new Map<string, string[]>()
for (const tom of applicableTOMs) {
const role = tom.responsiblePerson || tom.responsibleDepartment || 'Nicht zugewiesen'
if (!roleMap.has(role)) roleMap.set(role, [])
const control = getControlById(tom.controlId)
roleMap.get(role)!.push(control?.code || tom.controlId)
}
// =========================================================================
// HTML Template
// =========================================================================
let html = `<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<title>TOM-Dokumentation — ${escHtml(orgName)}</title>
<style>
@page { size: A4; margin: 20mm 18mm 22mm 18mm; }
* { margin: 0; padding: 0; box-sizing: border-box; }
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
font-size: 10pt;
line-height: 1.5;
color: #1e293b;
}
/* Cover */
.cover {
min-height: 90vh;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
text-align: center;
page-break-after: always;
}
.cover h1 {
font-size: 28pt;
color: #5b21b6;
margin-bottom: 8px;
font-weight: 700;
}
.cover .subtitle {
font-size: 14pt;
color: #7c3aed;
margin-bottom: 40px;
}
.cover .org-info {
background: #f5f3ff;
border: 1px solid #ddd6fe;
border-radius: 8px;
padding: 24px 40px;
text-align: left;
width: 400px;
margin-bottom: 24px;
}
.cover .org-info div { margin-bottom: 6px; }
.cover .org-info .label { font-weight: 600; color: #5b21b6; display: inline-block; min-width: 160px; }
.cover .legal-ref {
font-size: 9pt;
color: #64748b;
margin-top: 20px;
}
/* TOC */
.toc {
page-break-after: always;
padding-top: 40px;
}
.toc h2 {
font-size: 18pt;
color: #5b21b6;
margin-bottom: 20px;
border-bottom: 2px solid #5b21b6;
padding-bottom: 8px;
}
.toc-entry {
display: flex;
justify-content: space-between;
padding: 6px 0;
border-bottom: 1px dotted #cbd5e1;
font-size: 10pt;
}
.toc-entry .toc-num { font-weight: 600; color: #5b21b6; min-width: 40px; }
/* Sections */
.section {
page-break-inside: avoid;
margin-bottom: 24px;
}
.section-header {
font-size: 14pt;
color: #5b21b6;
font-weight: 700;
margin: 30px 0 12px 0;
border-bottom: 2px solid #ddd6fe;
padding-bottom: 6px;
}
.section-body { margin-bottom: 16px; }
/* Tables */
table {
width: 100%;
border-collapse: collapse;
margin: 10px 0 16px 0;
font-size: 9pt;
}
th, td {
border: 1px solid #e2e8f0;
padding: 6px 8px;
text-align: left;
vertical-align: top;
}
th {
background: #f5f3ff;
color: #5b21b6;
font-weight: 600;
font-size: 8.5pt;
text-transform: uppercase;
letter-spacing: 0.3px;
}
tr:nth-child(even) td { background: #faf5ff; }
/* Detail cards */
.policy-detail {
page-break-inside: avoid;
border: 1px solid #e2e8f0;
border-radius: 6px;
margin-bottom: 16px;
overflow: hidden;
}
.policy-detail-header {
background: #f5f3ff;
padding: 8px 12px;
font-weight: 700;
color: #5b21b6;
border-bottom: 1px solid #ddd6fe;
display: flex;
justify-content: space-between;
}
.policy-detail-body { padding: 0; }
.policy-detail-body table { margin: 0; }
.policy-detail-body th { width: 200px; }
/* Badges */
.badge {
display: inline-block;
padding: 1px 8px;
border-radius: 9999px;
font-size: 8pt;
font-weight: 600;
}
.badge-active { background: #dcfce7; color: #166534; }
.badge-draft { background: #f3f4f6; color: #374151; }
.badge-review { background: #fef9c3; color: #854d0e; }
.badge-critical { background: #fecaca; color: #991b1b; }
.badge-high { background: #fed7aa; color: #9a3412; }
.badge-medium { background: #fef3c7; color: #92400e; }
.badge-low { background: #f3f4f6; color: #4b5563; }
/* Principles */
.principle {
margin-bottom: 10px;
padding-left: 20px;
position: relative;
}
.principle::before {
content: '';
position: absolute;
left: 0;
top: 6px;
width: 10px;
height: 10px;
background: #7c3aed;
border-radius: 50%;
}
.principle strong { color: #5b21b6; }
/* Score */
.score-box {
display: inline-block;
padding: 4px 16px;
border-radius: 8px;
font-size: 18pt;
font-weight: 700;
margin-right: 12px;
}
.score-excellent { background: #dcfce7; color: #166534; }
.score-good { background: #dbeafe; color: #1e40af; }
.score-needs-work { background: #fef3c7; color: #92400e; }
.score-poor { background: #fecaca; color: #991b1b; }
/* Footer */
.page-footer {
position: fixed;
bottom: 0;
left: 0;
right: 0;
padding: 8px 18mm;
font-size: 7.5pt;
color: #94a3b8;
display: flex;
justify-content: space-between;
border-top: 1px solid #e2e8f0;
}
/* Print */
@media print {
body { -webkit-print-color-adjust: exact; print-color-adjust: exact; }
.no-print { display: none !important; }
.page-break { page-break-after: always; }
}
</style>
</head>
<body>
`
// =========================================================================
// Section 0: Cover Page
// =========================================================================
html += `
<div class="cover">
<h1>TOM-Dokumentation</h1>
<div class="subtitle">Technische und Organisatorische Massnahmen gemaess Art. 32 DSGVO</div>
<div class="org-info">
<div><span class="label">Organisation:</span> ${escHtml(orgName)}</div>
${orgHeader.industry ? `<div><span class="label">Branche:</span> ${escHtml(orgHeader.industry)}</div>` : ''}
${orgHeader.dpoName ? `<div><span class="label">DSB:</span> ${escHtml(orgHeader.dpoName)}</div>` : ''}
${orgHeader.dpoContact ? `<div><span class="label">DSB-Kontakt:</span> ${escHtml(orgHeader.dpoContact)}</div>` : ''}
${orgHeader.responsiblePerson ? `<div><span class="label">Verantwortlicher:</span> ${escHtml(orgHeader.responsiblePerson)}</div>` : ''}
${orgHeader.itSecurityContact ? `<div><span class="label">IT-Sicherheit:</span> ${escHtml(orgHeader.itSecurityContact)}</div>` : ''}
${orgHeader.employeeCount ? `<div><span class="label">Mitarbeiter:</span> ${escHtml(orgHeader.employeeCount)}</div>` : ''}
${orgHeader.locations.length > 0 ? `<div><span class="label">Standorte:</span> ${escHtml(orgHeader.locations.join(', '))}</div>` : ''}
</div>
<div class="legal-ref">
Version ${escHtml(orgHeader.documentVersion)} | Stand: ${today}<br/>
Letzte Pruefung: ${formatDateDE(orgHeader.lastReviewDate)} | Naechste Pruefung: ${formatDateDE(orgHeader.nextReviewDate)}<br/>
Pruefintervall: ${escHtml(orgHeader.reviewInterval)}
</div>
</div>
`
// =========================================================================
// Table of Contents
// =========================================================================
const sections = [
'Ziel und Zweck',
'Geltungsbereich',
'Grundprinzipien Art. 32',
'Schutzbedarf und Risikoanalyse',
'Massnahmen-Uebersicht',
'Detaillierte Massnahmen',
'SDM Gewaehrleistungsziele',
'Verantwortlichkeiten',
'Pruef- und Revisionszyklus',
'Compliance-Status',
'Aenderungshistorie',
]
html += `
<div class="toc">
<h2>Inhaltsverzeichnis</h2>
${sections.map((s, i) => `<div class="toc-entry"><span><span class="toc-num">${i + 1}.</span> ${escHtml(s)}</span></div>`).join('\n ')}
</div>
`
// =========================================================================
// Section 1: Ziel und Zweck
// =========================================================================
html += `
<div class="section">
<div class="section-header">1. Ziel und Zweck</div>
<div class="section-body">
<p>Diese TOM-Dokumentation beschreibt die technischen und organisatorischen Massnahmen
zum Schutz personenbezogener Daten bei <strong>${escHtml(orgName)}</strong>. Sie dient
der Umsetzung folgender DSGVO-Anforderungen:</p>
<table>
<tr><th>Rechtsgrundlage</th><th>Inhalt</th></tr>
<tr><td><strong>Art. 32 Abs. 1 lit. a DSGVO</strong></td><td>Pseudonymisierung und Verschluesselung personenbezogener Daten</td></tr>
<tr><td><strong>Art. 32 Abs. 1 lit. b DSGVO</strong></td><td>Faehigkeit, die Vertraulichkeit, Integritaet, Verfuegbarkeit und Belastbarkeit der Systeme und Dienste im Zusammenhang mit der Verarbeitung auf Dauer sicherzustellen</td></tr>
<tr><td><strong>Art. 32 Abs. 1 lit. c DSGVO</strong></td><td>Faehigkeit, die Verfuegbarkeit der personenbezogenen Daten und den Zugang zu ihnen bei einem physischen oder technischen Zwischenfall rasch wiederherzustellen</td></tr>
<tr><td><strong>Art. 32 Abs. 1 lit. d DSGVO</strong></td><td>Verfahren zur regelmaessigen Ueberpruefung, Bewertung und Evaluierung der Wirksamkeit der technischen und organisatorischen Massnahmen</td></tr>
</table>
<p>Die TOM-Dokumentation ist fester Bestandteil des Datenschutz-Managementsystems und wird
regelmaessig ueberprueft und aktualisiert.</p>
</div>
</div>
`
// =========================================================================
// Section 2: Geltungsbereich
// =========================================================================
const industryInfo = companyProfile?.industry || orgHeader.industry || ''
const hostingInfo = companyProfile ? `Unternehmen: ${escHtml(companyProfile.name || orgName)}, Groesse: ${escHtml(companyProfile.size || '-')}` : ''
html += `
<div class="section">
<div class="section-header">2. Geltungsbereich</div>
<div class="section-body">
<p>Diese TOM-Dokumentation gilt fuer alle IT-Systeme, Anwendungen und Verarbeitungsprozesse
von <strong>${escHtml(orgName)}</strong>${industryInfo ? ` (Branche: ${escHtml(industryInfo)})` : ''}.</p>
${hostingInfo ? `<p>${hostingInfo}</p>` : ''}
${orgHeader.locations.length > 0 ? `<p>Standorte: ${escHtml(orgHeader.locations.join(', '))}</p>` : ''}
<p>Die dokumentierten Massnahmen stammen aus zwei Quellen:</p>
<ul style="margin: 8px 0 8px 24px;">
<li><strong>Embedded Library (TOM-xxx):</strong> Integrierte Kontrollbibliothek mit spezifischen Massnahmen fuer Art. 32 DSGVO</li>
<li><strong>Canonical Control Library (CP-CLIB):</strong> Uebergreifende Kontrollbibliothek mit framework-uebergreifenden Massnahmen</li>
</ul>
<p>Insgesamt umfasst dieses Dokument <strong>${applicableTOMs.length}</strong> anwendbare Massnahmen
in <strong>${tomsByCategory.size}</strong> Kategorien.</p>
</div>
</div>
`
// =========================================================================
// Section 3: Grundprinzipien Art. 32
// =========================================================================
html += `
<div class="section">
<div class="section-header">3. Grundprinzipien Art. 32</div>
<div class="section-body">
<div class="principle"><strong>Vertraulichkeit:</strong> Schutz personenbezogener Daten vor unbefugter Kenntnisnahme durch Zutrittskontrolle, Zugangskontrolle, Zugriffskontrolle und Verschluesselung (Art. 32 Abs. 1 lit. b DSGVO).</div>
<div class="principle"><strong>Integritaet:</strong> Sicherstellung, dass personenbezogene Daten nicht unbefugt oder unbeabsichtigt veraendert werden koennen, durch Eingabekontrolle, Weitergabekontrolle und Protokollierung (Art. 32 Abs. 1 lit. b DSGVO).</div>
<div class="principle"><strong>Verfuegbarkeit und Belastbarkeit:</strong> Gewaehrleistung, dass Systeme und Dienste bei Lastspitzen und Stoerungen zuverlaessig funktionieren, durch Backup, Redundanz und Disaster Recovery (Art. 32 Abs. 1 lit. b DSGVO).</div>
<div class="principle"><strong>Rasche Wiederherstellbarkeit:</strong> Faehigkeit, nach einem physischen oder technischen Zwischenfall Daten und Systeme schnell wiederherzustellen, durch getestete Recovery-Prozesse (Art. 32 Abs. 1 lit. c DSGVO).</div>
<div class="principle"><strong>Regelmaessige Wirksamkeitspruefung:</strong> Verfahren zur regelmaessigen Ueberpruefung, Bewertung und Evaluierung der Wirksamkeit aller technischen und organisatorischen Massnahmen (Art. 32 Abs. 1 lit. d DSGVO).</div>
</div>
</div>
`
// =========================================================================
// Section 4: Schutzbedarf und Risikoanalyse
// =========================================================================
html += `
<div class="section">
<div class="section-header">4. Schutzbedarf und Risikoanalyse</div>
<div class="section-body">
`
if (riskProfile) {
html += ` <p>Die folgende Schutzbedarfsanalyse bildet die Grundlage fuer die Auswahl und Priorisierung
der technischen und organisatorischen Massnahmen:</p>
<table>
<tr><th>Kriterium</th><th>Bewertung</th></tr>
<tr><td>Vertraulichkeit</td><td>${riskProfile.ciaAssessment.confidentiality}/5</td></tr>
<tr><td>Integritaet</td><td>${riskProfile.ciaAssessment.integrity}/5</td></tr>
<tr><td>Verfuegbarkeit</td><td>${riskProfile.ciaAssessment.availability}/5</td></tr>
<tr><td>Schutzniveau</td><td><strong>${escHtml(riskProfile.protectionLevel)}</strong></td></tr>
<tr><td>DSFA-Pflicht</td><td>${riskProfile.dsfaRequired ? 'Ja' : 'Nein'}</td></tr>
${riskProfile.specialRisks.length > 0 ? `<tr><td>Spezialrisiken</td><td>${escHtml(riskProfile.specialRisks.join(', '))}</td></tr>` : ''}
${riskProfile.regulatoryRequirements.length > 0 ? `<tr><td>Regulatorische Anforderungen</td><td>${escHtml(riskProfile.regulatoryRequirements.join(', '))}</td></tr>` : ''}
</table>
`
} else {
html += ` <p><em>Die Schutzbedarfsanalyse wurde noch nicht durchgefuehrt. Fuehren Sie den
Risiko-Wizard im TOM-Generator durch, um den Schutzbedarf zu ermitteln.</em></p>
`
}
html += ` </div>
</div>
`
// =========================================================================
// Section 5: Massnahmen-Uebersicht
// =========================================================================
html += `
<div class="section page-break">
<div class="section-header">5. Massnahmen-Uebersicht</div>
<div class="section-body">
<p>Die folgende Tabelle zeigt eine Uebersicht aller ${applicableTOMs.length} anwendbaren Massnahmen
nach Kategorie:</p>
<table>
<tr>
<th>Kategorie</th>
<th>Gesamt</th>
<th>Umgesetzt</th>
<th>Teilweise</th>
<th>Offen</th>
</tr>
`
const allCategories = getAllCategories()
for (const cat of allCategories) {
const tomsInCat = tomsByCategory.get(cat)
if (!tomsInCat || tomsInCat.length === 0) continue
const implemented = tomsInCat.filter(t => t.implementationStatus === 'IMPLEMENTED').length
const partial = tomsInCat.filter(t => t.implementationStatus === 'PARTIAL').length
const notImpl = tomsInCat.filter(t => t.implementationStatus === 'NOT_IMPLEMENTED').length
const catLabel = CATEGORY_LABELS_DE[cat] || cat
html += ` <tr>
<td>${escHtml(catLabel)}</td>
<td>${tomsInCat.length}</td>
<td>${implemented}</td>
<td>${partial}</td>
<td>${notImpl}</td>
</tr>
`
}
html += ` </table>
</div>
</div>
`
// =========================================================================
// Section 6: Detaillierte Massnahmen
// =========================================================================
html += `
<div class="section">
<div class="section-header">6. Detaillierte Massnahmen</div>
<div class="section-body">
`
for (const cat of allCategories) {
const tomsInCat = tomsByCategory.get(cat)
if (!tomsInCat || tomsInCat.length === 0) continue
const catLabel = CATEGORY_LABELS_DE[cat] || cat
const catMeta = getCategoryMetadata(cat)
const gdprRef = catMeta?.gdprReference || ''
html += ` <h3 style="color: #5b21b6; margin: 20px 0 10px 0; font-size: 11pt;">${escHtml(catLabel)}${gdprRef ? ` <span style="font-weight: 400; font-size: 9pt; color: #64748b;">(${escHtml(gdprRef)})</span>` : ''}</h3>
`
// Sort TOMs by control code
const sortedTOMs = [...tomsInCat].sort((a, b) => {
const codeA = getControlById(a.controlId)?.code || a.controlId
const codeB = getControlById(b.controlId)?.code || b.controlId
return codeA.localeCompare(codeB)
})
for (const tom of sortedTOMs) {
const control = getControlById(tom.controlId)
const code = control?.code || tom.controlId
const nameDE = control?.name?.de || tom.name
const descDE = control?.description?.de || tom.description
const typeLabel = control?.type === 'TECHNICAL' ? 'Technisch' : control?.type === 'ORGANIZATIONAL' ? 'Organisatorisch' : '-'
const statusLabel = STATUS_LABELS_DE[tom.implementationStatus] || tom.implementationStatus
const statusBadge = STATUS_BADGE_CLASSES[tom.implementationStatus] || 'badge-draft'
const applicabilityLabel = APPLICABILITY_LABELS_DE[tom.applicability] || tom.applicability
const responsible = [tom.responsiblePerson, tom.responsibleDepartment].filter(s => s && s.trim()).join(' / ') || '-'
const implDate = tom.implementationDate ? formatDateDE(typeof tom.implementationDate === 'string' ? tom.implementationDate : tom.implementationDate.toISOString()) : '-'
const reviewDate = tom.reviewDate ? formatDateDE(typeof tom.reviewDate === 'string' ? tom.reviewDate : tom.reviewDate.toISOString()) : '-'
// Evidence
const evidenceInfo = tom.linkedEvidence.length > 0
? tom.linkedEvidence.join(', ')
: tom.evidenceGaps.length > 0
? `<em style="color: #d97706;">Fehlend: ${escHtml(tom.evidenceGaps.join(', '))}</em>`
: '-'
// Framework mappings
let mappingsHtml = '-'
if (control?.mappings && control.mappings.length > 0) {
mappingsHtml = control.mappings.map(m => `${escHtml(m.framework)}: ${escHtml(m.reference)}`).join('<br/>')
}
html += `
<div class="policy-detail">
<div class="policy-detail-header">
<span>${escHtml(code)}${escHtml(nameDE)}</span>
<span class="badge ${statusBadge}">${escHtml(statusLabel)}</span>
</div>
<div class="policy-detail-body">
<table>
<tr><th>Beschreibung</th><td>${escHtml(descDE)}</td></tr>
<tr><th>Massnahmentyp</th><td>${escHtml(typeLabel)}</td></tr>
<tr><th>Anwendbarkeit</th><td>${escHtml(applicabilityLabel)}${tom.applicabilityReason ? `${escHtml(tom.applicabilityReason)}` : ''}</td></tr>
<tr><th>Umsetzungsstatus</th><td><span class="badge ${statusBadge}">${escHtml(statusLabel)}</span></td></tr>
<tr><th>Verantwortlich</th><td>${escHtml(responsible)}</td></tr>
<tr><th>Umsetzungsdatum</th><td>${implDate}</td></tr>
<tr><th>Naechste Pruefung</th><td>${reviewDate}</td></tr>
<tr><th>Evidence</th><td>${evidenceInfo}</td></tr>
<tr><th>Framework-Mappings</th><td>${mappingsHtml}</td></tr>
</table>
</div>
</div>
`
}
}
html += ` </div>
</div>
`
// =========================================================================
// Section 7: SDM Gewaehrleistungsziele
// =========================================================================
const sdmGoals: Array<{ goal: string; categories: ControlCategory[] }> = []
const allSDMGoals = [
'Verfuegbarkeit',
'Integritaet',
'Vertraulichkeit',
'Nichtverkettung',
'Intervenierbarkeit',
'Transparenz',
'Datenminimierung',
] as const
for (const goal of allSDMGoals) {
const cats: ControlCategory[] = []
for (const [cat, goals] of Object.entries(SDM_CATEGORY_MAPPING)) {
if (goals.includes(goal)) {
cats.push(cat as ControlCategory)
}
}
sdmGoals.push({ goal, categories: cats })
}
html += `
<div class="section page-break">
<div class="section-header">7. SDM Gewaehrleistungsziele</div>
<div class="section-body">
<p>Die folgende Tabelle zeigt die Abdeckung der sieben Gewaehrleistungsziele des
Standard-Datenschutzmodells (SDM) durch die implementierten Massnahmen:</p>
<table>
<tr>
<th>Gewaehrleistungsziel</th>
<th>Abgedeckt</th>
<th>Gesamt</th>
<th>Abdeckung (%)</th>
</tr>
`
for (const { goal, categories } of sdmGoals) {
let totalInGoal = 0
let implementedInGoal = 0
for (const cat of categories) {
const tomsInCat = tomsByCategory.get(cat) || []
totalInGoal += tomsInCat.length
implementedInGoal += tomsInCat.filter(t => t.implementationStatus === 'IMPLEMENTED').length
}
const percentage = totalInGoal > 0 ? Math.round((implementedInGoal / totalInGoal) * 100) : 0
html += ` <tr>
<td>${escHtml(goal)}</td>
<td>${implementedInGoal}</td>
<td>${totalInGoal}</td>
<td>${percentage}%</td>
</tr>
`
}
html += ` </table>
</div>
</div>
`
// =========================================================================
// Section 8: Verantwortlichkeiten
// =========================================================================
html += `
<div class="section">
<div class="section-header">8. Verantwortlichkeiten</div>
<div class="section-body">
<p>Die folgende Rollenmatrix zeigt, welche Personen oder Abteilungen fuer welche Massnahmen
die Umsetzungsverantwortung tragen:</p>
<table>
<tr><th>Rolle / Verantwortlich</th><th>Massnahmen</th><th>Anzahl</th></tr>
`
for (const [role, controls] of roleMap.entries()) {
html += ` <tr>
<td>${escHtml(role)}</td>
<td>${controls.map(c => escHtml(c)).join(', ')}</td>
<td>${controls.length}</td>
</tr>
`
}
html += ` </table>
</div>
</div>
`
// =========================================================================
// Section 9: Pruef- und Revisionszyklus
// =========================================================================
html += `
<div class="section">
<div class="section-header">9. Pruef- und Revisionszyklus</div>
<div class="section-body">
<table>
<tr><th>Eigenschaft</th><th>Wert</th></tr>
<tr><td>Aktuelles Pruefintervall</td><td>${escHtml(orgHeader.reviewInterval)}</td></tr>
<tr><td>Letzte Pruefung</td><td>${formatDateDE(orgHeader.lastReviewDate)}</td></tr>
<tr><td>Naechste Pruefung</td><td>${formatDateDE(orgHeader.nextReviewDate)}</td></tr>
<tr><td>Aktuelle Version</td><td>${escHtml(orgHeader.documentVersion)}</td></tr>
</table>
<p style="margin-top: 8px;">Bei jeder Pruefung wird die TOM-Dokumentation auf folgende Punkte ueberprueft:</p>
<ul style="margin: 8px 0 8px 24px;">
<li>Vollstaendigkeit aller Massnahmen (neue Systeme oder Verarbeitungen erfasst?)</li>
<li>Aktualitaet des Umsetzungsstatus (Aenderungen seit letzter Pruefung?)</li>
<li>Wirksamkeit der technischen Massnahmen (Penetration-Tests, Audit-Ergebnisse)</li>
<li>Angemessenheit der organisatorischen Massnahmen (Schulungen, Richtlinien aktuell?)</li>
<li>Abdeckung aller SDM-Gewaehrleistungsziele</li>
<li>Zuordnung von Verantwortlichkeiten zu allen Massnahmen</li>
</ul>
</div>
</div>
`
// =========================================================================
// Section 10: Compliance-Status
// =========================================================================
html += `
<div class="section page-break">
<div class="section-header">10. Compliance-Status</div>
<div class="section-body">
`
if (complianceResult) {
const scoreClass = complianceResult.score >= 90 ? 'score-excellent'
: complianceResult.score >= 75 ? 'score-good'
: complianceResult.score >= 50 ? 'score-needs-work'
: 'score-poor'
const scoreLabel = complianceResult.score >= 90 ? 'Ausgezeichnet'
: complianceResult.score >= 75 ? 'Gut'
: complianceResult.score >= 50 ? 'Verbesserungswuerdig'
: 'Mangelhaft'
html += ` <p><span class="score-box ${scoreClass}">${complianceResult.score}/100</span> ${escHtml(scoreLabel)}</p>
<table style="margin-top: 12px;">
<tr><th>Kennzahl</th><th>Wert</th></tr>
<tr><td>Gepruefte Massnahmen</td><td>${complianceResult.stats.total}</td></tr>
<tr><td>Bestanden</td><td>${complianceResult.stats.passed}</td></tr>
<tr><td>Beanstandungen</td><td>${complianceResult.stats.failed}</td></tr>
</table>
`
if (complianceResult.issues.length > 0) {
html += ` <p style="margin-top: 12px;"><strong>Befunde nach Schweregrad:</strong></p>
<table>
<tr><th>Schweregrad</th><th>Anzahl</th><th>Befunde</th></tr>
`
const severityOrder: TOMComplianceIssueSeverity[] = ['CRITICAL', 'HIGH', 'MEDIUM', 'LOW']
for (const sev of severityOrder) {
const count = complianceResult.stats.bySeverity[sev]
if (count === 0) continue
const issuesForSev = complianceResult.issues.filter(i => i.severity === sev)
html += ` <tr>
<td><span class="badge badge-${sev.toLowerCase()}" style="color: ${SEVERITY_COLORS[sev]}">${SEVERITY_LABELS_DE[sev]}</span></td>
<td>${count}</td>
<td>${issuesForSev.map(i => escHtml(i.title)).join('; ')}</td>
</tr>
`
}
html += ` </table>
`
} else {
html += ` <p style="margin-top: 8px;"><em>Keine Beanstandungen. Alle Massnahmen sind konform.</em></p>
`
}
} else {
html += ` <p><em>Compliance-Check wurde noch nicht ausgefuehrt. Fuehren Sie den Check im
Export-Tab durch, um den Status in das Dokument aufzunehmen.</em></p>
`
}
html += ` </div>
</div>
`
// =========================================================================
// Section 11: Aenderungshistorie
// =========================================================================
html += `
<div class="section">
<div class="section-header">11. Aenderungshistorie</div>
<div class="section-body">
<table>
<tr><th>Version</th><th>Datum</th><th>Autor</th><th>Aenderungen</th></tr>
`
if (revisions.length > 0) {
for (const rev of revisions) {
html += ` <tr>
<td>${escHtml(rev.version)}</td>
<td>${formatDateDE(rev.date)}</td>
<td>${escHtml(rev.author)}</td>
<td>${escHtml(rev.changes)}</td>
</tr>
`
}
} else {
html += ` <tr>
<td>${escHtml(orgHeader.documentVersion)}</td>
<td>${today}</td>
<td>${escHtml(orgHeader.dpoName || orgHeader.responsiblePerson || '-')}</td>
<td>Erstversion der TOM-Dokumentation</td>
</tr>
`
}
html += ` </table>
</div>
</div>
`
// =========================================================================
// Footer
// =========================================================================
html += `
<div class="page-footer">
<span>TOM-Dokumentation — ${escHtml(orgName)}</span>
<span>Stand: ${today} | Version ${escHtml(orgHeader.documentVersion)}</span>
</div>
</body>
</html>`
return html
}
// =============================================================================
// INTERNAL HELPERS
// =============================================================================
function escHtml(str: string): string {
return str
.replace(/&/g, '&amp;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
.replace(/"/g, '&quot;')
}
function formatDateDE(dateStr: string | null | undefined): string {
if (!dateStr) return '-'
try {
const date = new Date(dateStr)
if (isNaN(date.getTime())) return '-'
return date.toLocaleDateString('de-DE', {
day: '2-digit',
month: '2-digit',
year: 'numeric',
})
} catch {
return '-'
}
}

View File

@@ -0,0 +1,26 @@
// =============================================================================
// TOM Document — Internal Helpers
// =============================================================================
export function escHtml(str: string): string {
return str
.replace(/&/g, '&amp;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
.replace(/"/g, '&quot;')
}
export function formatDateDE(dateStr: string | null | undefined): string {
if (!dateStr) return '-'
try {
const date = new Date(dateStr)
if (isNaN(date.getTime())) return '-'
return date.toLocaleDateString('de-DE', {
day: '2-digit',
month: '2-digit',
year: 'numeric',
})
} catch {
return '-'
}
}

View File

@@ -0,0 +1,82 @@
// =============================================================================
// TOM Document — HTML Document Builder (main entry point)
// =============================================================================
import type {
TOMGeneratorState,
DerivedTOM,
CompanyProfile,
RiskProfile,
ControlCategory,
} from '../tom-generator/types'
import { SDM_CATEGORY_MAPPING } from '../tom-generator/types'
import {
getControlById,
getAllCategories,
} from '../tom-generator/controls/loader'
import type { TOMComplianceCheckResult } from '../tom-compliance'
import type { TOMDocumentOrgHeader, TOMDocumentRevision } from './types-defaults'
import { CATEGORY_LABELS_DE } from './types-defaults'
import { escHtml, formatDateDE } from './helpers'
import { buildDocumentStyles } from './html-styles'
import { buildSections1to6 } from './html-sections-1-6'
import { buildSections7to11 } from './html-sections-7-11'
export function buildTOMDocumentHtml(
derivedTOMs: DerivedTOM[],
orgHeader: TOMDocumentOrgHeader,
companyProfile: CompanyProfile | null,
riskProfile: RiskProfile | null,
complianceResult: TOMComplianceCheckResult | null,
revisions: TOMDocumentRevision[]
): string {
const today = new Date().toLocaleDateString('de-DE', {
day: '2-digit',
month: '2-digit',
year: 'numeric',
})
const orgName = orgHeader.organizationName || 'Organisation'
const applicableTOMs = derivedTOMs.filter(t => t.applicability !== 'NOT_APPLICABLE')
// Group TOMs by category
const tomsByCategory = new Map<ControlCategory, DerivedTOM[]>()
for (const tom of applicableTOMs) {
const control = getControlById(tom.controlId)
const cat = control?.category || 'REVIEW'
if (!tomsByCategory.has(cat)) tomsByCategory.set(cat, [])
tomsByCategory.get(cat)!.push(tom)
}
// Build role map
const roleMap = new Map<string, string[]>()
for (const tom of applicableTOMs) {
const role = tom.responsiblePerson || tom.responsibleDepartment || 'Nicht zugewiesen'
if (!roleMap.has(role)) roleMap.set(role, [])
const control = getControlById(tom.controlId)
roleMap.get(role)!.push(control?.code || tom.controlId)
}
let html = buildDocumentStyles(escHtml(orgName))
html += buildSections1to6(
orgName, orgHeader, companyProfile, riskProfile,
applicableTOMs, tomsByCategory, today
)
html += buildSections7to11(
orgName, orgHeader, tomsByCategory, roleMap,
complianceResult, revisions, today
)
html += `
<div class="page-footer">
<span>TOM-Dokumentation — ${escHtml(orgName)}</span>
<span>Stand: ${today} | Version ${escHtml(orgHeader.documentVersion)}</span>
</div>
</body>
</html>`
return html
}

View File

@@ -0,0 +1,306 @@
// =============================================================================
// TOM Document — HTML Sections 16
// =============================================================================
import type { DerivedTOM, CompanyProfile, RiskProfile, ControlCategory } from '../tom-generator/types'
import { getControlById, getAllCategories, getCategoryMetadata } from '../tom-generator/controls/loader'
import type { TOMDocumentOrgHeader } from './types-defaults'
import {
CATEGORY_LABELS_DE,
STATUS_LABELS_DE,
STATUS_BADGE_CLASSES,
APPLICABILITY_LABELS_DE,
} from './types-defaults'
import { escHtml, formatDateDE } from './helpers'
export function buildSections1to6(
orgName: string,
orgHeader: TOMDocumentOrgHeader,
companyProfile: CompanyProfile | null,
riskProfile: RiskProfile | null,
applicableTOMs: DerivedTOM[],
tomsByCategory: Map<ControlCategory, DerivedTOM[]>,
today: string
): string {
let html = ''
html += buildCoverAndTOC(orgName, orgHeader, applicableTOMs, tomsByCategory, today)
html += buildSection1(orgName)
html += buildSection2(orgName, orgHeader, companyProfile, applicableTOMs, tomsByCategory)
html += buildSection3()
html += buildSection4(riskProfile)
html += buildSection5(tomsByCategory)
html += buildSection6(tomsByCategory)
return html
}
function buildCoverAndTOC(
orgName: string,
orgHeader: TOMDocumentOrgHeader,
applicableTOMs: DerivedTOM[],
tomsByCategory: Map<ControlCategory, DerivedTOM[]>,
today: string
): string {
const sections = [
'Ziel und Zweck',
'Geltungsbereich',
'Grundprinzipien Art. 32',
'Schutzbedarf und Risikoanalyse',
'Massnahmen-Uebersicht',
'Detaillierte Massnahmen',
'SDM Gewaehrleistungsziele',
'Verantwortlichkeiten',
'Pruef- und Revisionszyklus',
'Compliance-Status',
'Aenderungshistorie',
]
return `
<div class="cover">
<h1>TOM-Dokumentation</h1>
<div class="subtitle">Technische und Organisatorische Massnahmen gemaess Art. 32 DSGVO</div>
<div class="org-info">
<div><span class="label">Organisation:</span> ${escHtml(orgName)}</div>
${orgHeader.industry ? `<div><span class="label">Branche:</span> ${escHtml(orgHeader.industry)}</div>` : ''}
${orgHeader.dpoName ? `<div><span class="label">DSB:</span> ${escHtml(orgHeader.dpoName)}</div>` : ''}
${orgHeader.dpoContact ? `<div><span class="label">DSB-Kontakt:</span> ${escHtml(orgHeader.dpoContact)}</div>` : ''}
${orgHeader.responsiblePerson ? `<div><span class="label">Verantwortlicher:</span> ${escHtml(orgHeader.responsiblePerson)}</div>` : ''}
${orgHeader.itSecurityContact ? `<div><span class="label">IT-Sicherheit:</span> ${escHtml(orgHeader.itSecurityContact)}</div>` : ''}
${orgHeader.employeeCount ? `<div><span class="label">Mitarbeiter:</span> ${escHtml(orgHeader.employeeCount)}</div>` : ''}
${orgHeader.locations.length > 0 ? `<div><span class="label">Standorte:</span> ${escHtml(orgHeader.locations.join(', '))}</div>` : ''}
</div>
<div class="legal-ref">
Version ${escHtml(orgHeader.documentVersion)} | Stand: ${today}<br/>
Letzte Pruefung: ${formatDateDE(orgHeader.lastReviewDate)} | Naechste Pruefung: ${formatDateDE(orgHeader.nextReviewDate)}<br/>
Pruefintervall: ${escHtml(orgHeader.reviewInterval)}
</div>
</div>
<div class="toc">
<h2>Inhaltsverzeichnis</h2>
${sections.map((s, i) => `<div class="toc-entry"><span><span class="toc-num">${i + 1}.</span> ${escHtml(s)}</span></div>`).join('\n ')}
</div>
`
}
function buildSection1(orgName: string): string {
return `
<div class="section">
<div class="section-header">1. Ziel und Zweck</div>
<div class="section-body">
<p>Diese TOM-Dokumentation beschreibt die technischen und organisatorischen Massnahmen
zum Schutz personenbezogener Daten bei <strong>${escHtml(orgName)}</strong>. Sie dient
der Umsetzung folgender DSGVO-Anforderungen:</p>
<table>
<tr><th>Rechtsgrundlage</th><th>Inhalt</th></tr>
<tr><td><strong>Art. 32 Abs. 1 lit. a DSGVO</strong></td><td>Pseudonymisierung und Verschluesselung personenbezogener Daten</td></tr>
<tr><td><strong>Art. 32 Abs. 1 lit. b DSGVO</strong></td><td>Faehigkeit, die Vertraulichkeit, Integritaet, Verfuegbarkeit und Belastbarkeit der Systeme und Dienste im Zusammenhang mit der Verarbeitung auf Dauer sicherzustellen</td></tr>
<tr><td><strong>Art. 32 Abs. 1 lit. c DSGVO</strong></td><td>Faehigkeit, die Verfuegbarkeit der personenbezogenen Daten und den Zugang zu ihnen bei einem physischen oder technischen Zwischenfall rasch wiederherzustellen</td></tr>
<tr><td><strong>Art. 32 Abs. 1 lit. d DSGVO</strong></td><td>Verfahren zur regelmaessigen Ueberpruefung, Bewertung und Evaluierung der Wirksamkeit der technischen und organisatorischen Massnahmen</td></tr>
</table>
<p>Die TOM-Dokumentation ist fester Bestandteil des Datenschutz-Managementsystems und wird
regelmaessig ueberprueft und aktualisiert.</p>
</div>
</div>
`
}
function buildSection2(
orgName: string,
orgHeader: TOMDocumentOrgHeader,
companyProfile: CompanyProfile | null,
applicableTOMs: DerivedTOM[],
tomsByCategory: Map<ControlCategory, DerivedTOM[]>
): string {
const industryInfo = companyProfile?.industry || orgHeader.industry || ''
const hostingInfo = companyProfile
? `Unternehmen: ${escHtml(companyProfile.name || orgName)}, Groesse: ${escHtml(companyProfile.size || '-')}`
: ''
return `
<div class="section">
<div class="section-header">2. Geltungsbereich</div>
<div class="section-body">
<p>Diese TOM-Dokumentation gilt fuer alle IT-Systeme, Anwendungen und Verarbeitungsprozesse
von <strong>${escHtml(orgName)}</strong>${industryInfo ? ` (Branche: ${escHtml(industryInfo)})` : ''}.</p>
${hostingInfo ? `<p>${hostingInfo}</p>` : ''}
${orgHeader.locations.length > 0 ? `<p>Standorte: ${escHtml(orgHeader.locations.join(', '))}</p>` : ''}
<p>Die dokumentierten Massnahmen stammen aus zwei Quellen:</p>
<ul style="margin: 8px 0 8px 24px;">
<li><strong>Embedded Library (TOM-xxx):</strong> Integrierte Kontrollbibliothek mit spezifischen Massnahmen fuer Art. 32 DSGVO</li>
<li><strong>Canonical Control Library (CP-CLIB):</strong> Uebergreifende Kontrollbibliothek mit framework-uebergreifenden Massnahmen</li>
</ul>
<p>Insgesamt umfasst dieses Dokument <strong>${applicableTOMs.length}</strong> anwendbare Massnahmen
in <strong>${tomsByCategory.size}</strong> Kategorien.</p>
</div>
</div>
`
}
function buildSection3(): string {
return `
<div class="section">
<div class="section-header">3. Grundprinzipien Art. 32</div>
<div class="section-body">
<div class="principle"><strong>Vertraulichkeit:</strong> Schutz personenbezogener Daten vor unbefugter Kenntnisnahme durch Zutrittskontrolle, Zugangskontrolle, Zugriffskontrolle und Verschluesselung (Art. 32 Abs. 1 lit. b DSGVO).</div>
<div class="principle"><strong>Integritaet:</strong> Sicherstellung, dass personenbezogene Daten nicht unbefugt oder unbeabsichtigt veraendert werden koennen, durch Eingabekontrolle, Weitergabekontrolle und Protokollierung (Art. 32 Abs. 1 lit. b DSGVO).</div>
<div class="principle"><strong>Verfuegbarkeit und Belastbarkeit:</strong> Gewaehrleistung, dass Systeme und Dienste bei Lastspitzen und Stoerungen zuverlaessig funktionieren, durch Backup, Redundanz und Disaster Recovery (Art. 32 Abs. 1 lit. b DSGVO).</div>
<div class="principle"><strong>Rasche Wiederherstellbarkeit:</strong> Faehigkeit, nach einem physischen oder technischen Zwischenfall Daten und Systeme schnell wiederherzustellen, durch getestete Recovery-Prozesse (Art. 32 Abs. 1 lit. c DSGVO).</div>
<div class="principle"><strong>Regelmaessige Wirksamkeitspruefung:</strong> Verfahren zur regelmaessigen Ueberpruefung, Bewertung und Evaluierung der Wirksamkeit aller technischen und organisatorischen Massnahmen (Art. 32 Abs. 1 lit. d DSGVO).</div>
</div>
</div>
`
}
function buildSection4(riskProfile: RiskProfile | null): string {
let html = `
<div class="section">
<div class="section-header">4. Schutzbedarf und Risikoanalyse</div>
<div class="section-body">
`
if (riskProfile) {
html += ` <p>Die folgende Schutzbedarfsanalyse bildet die Grundlage fuer die Auswahl und Priorisierung
der technischen und organisatorischen Massnahmen:</p>
<table>
<tr><th>Kriterium</th><th>Bewertung</th></tr>
<tr><td>Vertraulichkeit</td><td>${riskProfile.ciaAssessment.confidentiality}/5</td></tr>
<tr><td>Integritaet</td><td>${riskProfile.ciaAssessment.integrity}/5</td></tr>
<tr><td>Verfuegbarkeit</td><td>${riskProfile.ciaAssessment.availability}/5</td></tr>
<tr><td>Schutzniveau</td><td><strong>${escHtml(riskProfile.protectionLevel)}</strong></td></tr>
<tr><td>DSFA-Pflicht</td><td>${riskProfile.dsfaRequired ? 'Ja' : 'Nein'}</td></tr>
${riskProfile.specialRisks.length > 0 ? `<tr><td>Spezialrisiken</td><td>${escHtml(riskProfile.specialRisks.join(', '))}</td></tr>` : ''}
${riskProfile.regulatoryRequirements.length > 0 ? `<tr><td>Regulatorische Anforderungen</td><td>${escHtml(riskProfile.regulatoryRequirements.join(', '))}</td></tr>` : ''}
</table>
`
} else {
html += ` <p><em>Die Schutzbedarfsanalyse wurde noch nicht durchgefuehrt. Fuehren Sie den
Risiko-Wizard im TOM-Generator durch, um den Schutzbedarf zu ermitteln.</em></p>
`
}
html += ` </div>
</div>
`
return html
}
function buildSection5(tomsByCategory: Map<ControlCategory, DerivedTOM[]>): string {
const allCategories = getAllCategories()
let html = `
<div class="section page-break">
<div class="section-header">5. Massnahmen-Uebersicht</div>
<div class="section-body">
<p>Die folgende Tabelle zeigt eine Uebersicht aller anwendbaren Massnahmen nach Kategorie:</p>
<table>
<tr>
<th>Kategorie</th>
<th>Gesamt</th>
<th>Umgesetzt</th>
<th>Teilweise</th>
<th>Offen</th>
</tr>
`
for (const cat of allCategories) {
const tomsInCat = tomsByCategory.get(cat)
if (!tomsInCat || tomsInCat.length === 0) continue
const implemented = tomsInCat.filter(t => t.implementationStatus === 'IMPLEMENTED').length
const partial = tomsInCat.filter(t => t.implementationStatus === 'PARTIAL').length
const notImpl = tomsInCat.filter(t => t.implementationStatus === 'NOT_IMPLEMENTED').length
const catLabel = CATEGORY_LABELS_DE[cat] || cat
html += ` <tr>
<td>${escHtml(catLabel)}</td>
<td>${tomsInCat.length}</td>
<td>${implemented}</td>
<td>${partial}</td>
<td>${notImpl}</td>
</tr>
`
}
html += ` </table>
</div>
</div>
`
return html
}
function buildSection6(tomsByCategory: Map<ControlCategory, DerivedTOM[]>): string {
const allCategories = getAllCategories()
let html = `
<div class="section">
<div class="section-header">6. Detaillierte Massnahmen</div>
<div class="section-body">
`
for (const cat of allCategories) {
const tomsInCat = tomsByCategory.get(cat)
if (!tomsInCat || tomsInCat.length === 0) continue
const catLabel = CATEGORY_LABELS_DE[cat] || cat
const catMeta = getCategoryMetadata(cat)
const gdprRef = catMeta?.gdprReference || ''
html += ` <h3 style="color: #5b21b6; margin: 20px 0 10px 0; font-size: 11pt;">${escHtml(catLabel)}${gdprRef ? ` <span style="font-weight: 400; font-size: 9pt; color: #64748b;">(${escHtml(gdprRef)})</span>` : ''}</h3>
`
const sortedTOMs = [...tomsInCat].sort((a, b) => {
const codeA = getControlById(a.controlId)?.code || a.controlId
const codeB = getControlById(b.controlId)?.code || b.controlId
return codeA.localeCompare(codeB)
})
for (const tom of sortedTOMs) {
const control = getControlById(tom.controlId)
const code = control?.code || tom.controlId
const nameDE = control?.name?.de || tom.name
const descDE = control?.description?.de || tom.description
const typeLabel = control?.type === 'TECHNICAL' ? 'Technisch' : control?.type === 'ORGANIZATIONAL' ? 'Organisatorisch' : '-'
const statusLabel = STATUS_LABELS_DE[tom.implementationStatus] || tom.implementationStatus
const statusBadge = STATUS_BADGE_CLASSES[tom.implementationStatus] || 'badge-draft'
const applicabilityLabel = APPLICABILITY_LABELS_DE[tom.applicability] || tom.applicability
const responsible = [tom.responsiblePerson, tom.responsibleDepartment].filter(s => s && s.trim()).join(' / ') || '-'
const implDate = tom.implementationDate ? formatDateDE(typeof tom.implementationDate === 'string' ? tom.implementationDate : tom.implementationDate.toISOString()) : '-'
const reviewDate = tom.reviewDate ? formatDateDE(typeof tom.reviewDate === 'string' ? tom.reviewDate : tom.reviewDate.toISOString()) : '-'
const evidenceInfo = tom.linkedEvidence.length > 0
? tom.linkedEvidence.join(', ')
: tom.evidenceGaps.length > 0
? `<em style="color: #d97706;">Fehlend: ${escHtml(tom.evidenceGaps.join(', '))}</em>`
: '-'
let mappingsHtml = '-'
if (control?.mappings && control.mappings.length > 0) {
mappingsHtml = control.mappings.map(m => `${escHtml(m.framework)}: ${escHtml(m.reference)}`).join('<br/>')
}
html += `
<div class="policy-detail">
<div class="policy-detail-header">
<span>${escHtml(code)}${escHtml(nameDE)}</span>
<span class="badge ${statusBadge}">${escHtml(statusLabel)}</span>
</div>
<div class="policy-detail-body">
<table>
<tr><th>Beschreibung</th><td>${escHtml(descDE)}</td></tr>
<tr><th>Massnahmentyp</th><td>${escHtml(typeLabel)}</td></tr>
<tr><th>Anwendbarkeit</th><td>${escHtml(applicabilityLabel)}${tom.applicabilityReason ? `${escHtml(tom.applicabilityReason)}` : ''}</td></tr>
<tr><th>Umsetzungsstatus</th><td><span class="badge ${statusBadge}">${escHtml(statusLabel)}</span></td></tr>
<tr><th>Verantwortlich</th><td>${escHtml(responsible)}</td></tr>
<tr><th>Umsetzungsdatum</th><td>${implDate}</td></tr>
<tr><th>Naechste Pruefung</th><td>${reviewDate}</td></tr>
<tr><th>Evidence</th><td>${evidenceInfo}</td></tr>
<tr><th>Framework-Mappings</th><td>${mappingsHtml}</td></tr>
</table>
</div>
</div>
`
}
}
html += ` </div>
</div>
`
return html
}

View File

@@ -0,0 +1,241 @@
// =============================================================================
// TOM Document — HTML Sections 711
// =============================================================================
import type { DerivedTOM, ControlCategory } from '../tom-generator/types'
import { SDM_CATEGORY_MAPPING } from '../tom-generator/types'
import type { TOMComplianceCheckResult, TOMComplianceIssueSeverity } from '../tom-compliance'
import type { TOMDocumentOrgHeader, TOMDocumentRevision } from './types-defaults'
import { SEVERITY_LABELS_DE, SEVERITY_COLORS } from './types-defaults'
import { escHtml, formatDateDE } from './helpers'
export function buildSections7to11(
orgName: string,
orgHeader: TOMDocumentOrgHeader,
tomsByCategory: Map<ControlCategory, DerivedTOM[]>,
roleMap: Map<string, string[]>,
complianceResult: TOMComplianceCheckResult | null,
revisions: TOMDocumentRevision[],
today: string
): string {
let html = ''
html += buildSection7(tomsByCategory)
html += buildSection8(roleMap)
html += buildSection9(orgHeader)
html += buildSection10(complianceResult)
html += buildSection11(revisions, orgHeader, today)
return html
}
function buildSection7(tomsByCategory: Map<ControlCategory, DerivedTOM[]>): string {
const allSDMGoals = [
'Verfuegbarkeit',
'Integritaet',
'Vertraulichkeit',
'Nichtverkettung',
'Intervenierbarkeit',
'Transparenz',
'Datenminimierung',
] as const
const sdmGoals: Array<{ goal: string; categories: ControlCategory[] }> = []
for (const goal of allSDMGoals) {
const cats: ControlCategory[] = []
for (const [cat, goals] of Object.entries(SDM_CATEGORY_MAPPING)) {
if (goals.includes(goal)) {
cats.push(cat as ControlCategory)
}
}
sdmGoals.push({ goal, categories: cats })
}
let html = `
<div class="section page-break">
<div class="section-header">7. SDM Gewaehrleistungsziele</div>
<div class="section-body">
<p>Die folgende Tabelle zeigt die Abdeckung der sieben Gewaehrleistungsziele des
Standard-Datenschutzmodells (SDM) durch die implementierten Massnahmen:</p>
<table>
<tr>
<th>Gewaehrleistungsziel</th>
<th>Abgedeckt</th>
<th>Gesamt</th>
<th>Abdeckung (%)</th>
</tr>
`
for (const { goal, categories } of sdmGoals) {
let totalInGoal = 0
let implementedInGoal = 0
for (const cat of categories) {
const tomsInCat = tomsByCategory.get(cat) || []
totalInGoal += tomsInCat.length
implementedInGoal += tomsInCat.filter(t => t.implementationStatus === 'IMPLEMENTED').length
}
const percentage = totalInGoal > 0 ? Math.round((implementedInGoal / totalInGoal) * 100) : 0
html += ` <tr>
<td>${escHtml(goal)}</td>
<td>${implementedInGoal}</td>
<td>${totalInGoal}</td>
<td>${percentage}%</td>
</tr>
`
}
html += ` </table>
</div>
</div>
`
return html
}
function buildSection8(roleMap: Map<string, string[]>): string {
let html = `
<div class="section">
<div class="section-header">8. Verantwortlichkeiten</div>
<div class="section-body">
<p>Die folgende Rollenmatrix zeigt, welche Personen oder Abteilungen fuer welche Massnahmen
die Umsetzungsverantwortung tragen:</p>
<table>
<tr><th>Rolle / Verantwortlich</th><th>Massnahmen</th><th>Anzahl</th></tr>
`
for (const [role, controls] of roleMap.entries()) {
html += ` <tr>
<td>${escHtml(role)}</td>
<td>${controls.map(c => escHtml(c)).join(', ')}</td>
<td>${controls.length}</td>
</tr>
`
}
html += ` </table>
</div>
</div>
`
return html
}
function buildSection9(orgHeader: TOMDocumentOrgHeader): string {
return `
<div class="section">
<div class="section-header">9. Pruef- und Revisionszyklus</div>
<div class="section-body">
<table>
<tr><th>Eigenschaft</th><th>Wert</th></tr>
<tr><td>Aktuelles Pruefintervall</td><td>${escHtml(orgHeader.reviewInterval)}</td></tr>
<tr><td>Letzte Pruefung</td><td>${formatDateDE(orgHeader.lastReviewDate)}</td></tr>
<tr><td>Naechste Pruefung</td><td>${formatDateDE(orgHeader.nextReviewDate)}</td></tr>
<tr><td>Aktuelle Version</td><td>${escHtml(orgHeader.documentVersion)}</td></tr>
</table>
<p style="margin-top: 8px;">Bei jeder Pruefung wird die TOM-Dokumentation auf folgende Punkte ueberprueft:</p>
<ul style="margin: 8px 0 8px 24px;">
<li>Vollstaendigkeit aller Massnahmen (neue Systeme oder Verarbeitungen erfasst?)</li>
<li>Aktualitaet des Umsetzungsstatus (Aenderungen seit letzter Pruefung?)</li>
<li>Wirksamkeit der technischen Massnahmen (Penetration-Tests, Audit-Ergebnisse)</li>
<li>Angemessenheit der organisatorischen Massnahmen (Schulungen, Richtlinien aktuell?)</li>
<li>Abdeckung aller SDM-Gewaehrleistungsziele</li>
<li>Zuordnung von Verantwortlichkeiten zu allen Massnahmen</li>
</ul>
</div>
</div>
`
}
function buildSection10(complianceResult: TOMComplianceCheckResult | null): string {
let html = `
<div class="section page-break">
<div class="section-header">10. Compliance-Status</div>
<div class="section-body">
`
if (complianceResult) {
const scoreClass = complianceResult.score >= 90 ? 'score-excellent'
: complianceResult.score >= 75 ? 'score-good'
: complianceResult.score >= 50 ? 'score-needs-work'
: 'score-poor'
const scoreLabel = complianceResult.score >= 90 ? 'Ausgezeichnet'
: complianceResult.score >= 75 ? 'Gut'
: complianceResult.score >= 50 ? 'Verbesserungswuerdig'
: 'Mangelhaft'
html += ` <p><span class="score-box ${scoreClass}">${complianceResult.score}/100</span> ${escHtml(scoreLabel)}</p>
<table style="margin-top: 12px;">
<tr><th>Kennzahl</th><th>Wert</th></tr>
<tr><td>Gepruefte Massnahmen</td><td>${complianceResult.stats.total}</td></tr>
<tr><td>Bestanden</td><td>${complianceResult.stats.passed}</td></tr>
<tr><td>Beanstandungen</td><td>${complianceResult.stats.failed}</td></tr>
</table>
`
if (complianceResult.issues.length > 0) {
html += ` <p style="margin-top: 12px;"><strong>Befunde nach Schweregrad:</strong></p>
<table>
<tr><th>Schweregrad</th><th>Anzahl</th><th>Befunde</th></tr>
`
const severityOrder: TOMComplianceIssueSeverity[] = ['CRITICAL', 'HIGH', 'MEDIUM', 'LOW']
for (const sev of severityOrder) {
const count = complianceResult.stats.bySeverity[sev]
if (count === 0) continue
const issuesForSev = complianceResult.issues.filter(i => i.severity === sev)
html += ` <tr>
<td><span class="badge badge-${sev.toLowerCase()}" style="color: ${SEVERITY_COLORS[sev]}">${SEVERITY_LABELS_DE[sev]}</span></td>
<td>${count}</td>
<td>${issuesForSev.map(i => escHtml(i.title)).join('; ')}</td>
</tr>
`
}
html += ` </table>
`
} else {
html += ` <p style="margin-top: 8px;"><em>Keine Beanstandungen. Alle Massnahmen sind konform.</em></p>
`
}
} else {
html += ` <p><em>Compliance-Check wurde noch nicht ausgefuehrt. Fuehren Sie den Check im
Export-Tab durch, um den Status in das Dokument aufzunehmen.</em></p>
`
}
html += ` </div>
</div>
`
return html
}
function buildSection11(
revisions: TOMDocumentRevision[],
orgHeader: TOMDocumentOrgHeader,
today: string
): string {
let html = `
<div class="section">
<div class="section-header">11. Aenderungshistorie</div>
<div class="section-body">
<table>
<tr><th>Version</th><th>Datum</th><th>Autor</th><th>Aenderungen</th></tr>
`
if (revisions.length > 0) {
for (const rev of revisions) {
html += ` <tr>
<td>${escHtml(rev.version)}</td>
<td>${formatDateDE(rev.date)}</td>
<td>${escHtml(rev.author)}</td>
<td>${escHtml(rev.changes)}</td>
</tr>
`
}
} else {
html += ` <tr>
<td>${escHtml(orgHeader.documentVersion)}</td>
<td>${today}</td>
<td>${escHtml(orgHeader.dpoName || orgHeader.responsiblePerson || '-')}</td>
<td>Erstversion der TOM-Dokumentation</td>
</tr>
`
}
html += ` </table>
</div>
</div>
`
return html
}

View File

@@ -0,0 +1,85 @@
// =============================================================================
// TOM Document — HTML/CSS Styles
// =============================================================================
export function buildDocumentStyles(orgNameEscaped: string): string {
return `<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<title>TOM-Dokumentation — ${orgNameEscaped}</title>
<style>
@page { size: A4; margin: 20mm 18mm 22mm 18mm; }
* { margin: 0; padding: 0; box-sizing: border-box; }
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
font-size: 10pt;
line-height: 1.5;
color: #1e293b;
}
.cover {
min-height: 90vh;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
text-align: center;
page-break-after: always;
}
.cover h1 { font-size: 28pt; color: #5b21b6; margin-bottom: 8px; font-weight: 700; }
.cover .subtitle { font-size: 14pt; color: #7c3aed; margin-bottom: 40px; }
.cover .org-info {
background: #f5f3ff;
border: 1px solid #ddd6fe;
border-radius: 8px;
padding: 24px 40px;
text-align: left;
width: 400px;
margin-bottom: 24px;
}
.cover .org-info div { margin-bottom: 6px; }
.cover .org-info .label { font-weight: 600; color: #5b21b6; display: inline-block; min-width: 160px; }
.cover .legal-ref { font-size: 9pt; color: #64748b; margin-top: 20px; }
.toc { page-break-after: always; padding-top: 40px; }
.toc h2 { font-size: 18pt; color: #5b21b6; margin-bottom: 20px; border-bottom: 2px solid #5b21b6; padding-bottom: 8px; }
.toc-entry { display: flex; justify-content: space-between; padding: 6px 0; border-bottom: 1px dotted #cbd5e1; font-size: 10pt; }
.toc-entry .toc-num { font-weight: 600; color: #5b21b6; min-width: 40px; }
.section { page-break-inside: avoid; margin-bottom: 24px; }
.section-header { font-size: 14pt; color: #5b21b6; font-weight: 700; margin: 30px 0 12px 0; border-bottom: 2px solid #ddd6fe; padding-bottom: 6px; }
.section-body { margin-bottom: 16px; }
table { width: 100%; border-collapse: collapse; margin: 10px 0 16px 0; font-size: 9pt; }
th, td { border: 1px solid #e2e8f0; padding: 6px 8px; text-align: left; vertical-align: top; }
th { background: #f5f3ff; color: #5b21b6; font-weight: 600; font-size: 8.5pt; text-transform: uppercase; letter-spacing: 0.3px; }
tr:nth-child(even) td { background: #faf5ff; }
.policy-detail { page-break-inside: avoid; border: 1px solid #e2e8f0; border-radius: 6px; margin-bottom: 16px; overflow: hidden; }
.policy-detail-header { background: #f5f3ff; padding: 8px 12px; font-weight: 700; color: #5b21b6; border-bottom: 1px solid #ddd6fe; display: flex; justify-content: space-between; }
.policy-detail-body { padding: 0; }
.policy-detail-body table { margin: 0; }
.policy-detail-body th { width: 200px; }
.badge { display: inline-block; padding: 1px 8px; border-radius: 9999px; font-size: 8pt; font-weight: 600; }
.badge-active { background: #dcfce7; color: #166534; }
.badge-draft { background: #f3f4f6; color: #374151; }
.badge-review { background: #fef9c3; color: #854d0e; }
.badge-critical { background: #fecaca; color: #991b1b; }
.badge-high { background: #fed7aa; color: #9a3412; }
.badge-medium { background: #fef3c7; color: #92400e; }
.badge-low { background: #f3f4f6; color: #4b5563; }
.principle { margin-bottom: 10px; padding-left: 20px; position: relative; }
.principle::before { content: ''; position: absolute; left: 0; top: 6px; width: 10px; height: 10px; background: #7c3aed; border-radius: 50%; }
.principle strong { color: #5b21b6; }
.score-box { display: inline-block; padding: 4px 16px; border-radius: 8px; font-size: 18pt; font-weight: 700; margin-right: 12px; }
.score-excellent { background: #dcfce7; color: #166534; }
.score-good { background: #dbeafe; color: #1e40af; }
.score-needs-work { background: #fef3c7; color: #92400e; }
.score-poor { background: #fecaca; color: #991b1b; }
.page-footer { position: fixed; bottom: 0; left: 0; right: 0; padding: 8px 18mm; font-size: 7.5pt; color: #94a3b8; display: flex; justify-content: space-between; border-top: 1px solid #e2e8f0; }
@media print {
body { -webkit-print-color-adjust: exact; print-color-adjust: exact; }
.no-print { display: none !important; }
.page-break { page-break-after: always; }
}
</style>
</head>
<body>
`
}

View File

@@ -0,0 +1,98 @@
// =============================================================================
// TOM Document — Types, Defaults & Label Constants
// =============================================================================
import type { ControlCategory } from '../tom-generator/types'
import type { TOMComplianceIssueSeverity } from '../tom-compliance'
export interface TOMDocumentOrgHeader {
organizationName: string
industry: string
dpoName: string
dpoContact: string
responsiblePerson: string
itSecurityContact: string
locations: string[]
employeeCount: string
documentVersion: string
lastReviewDate: string
nextReviewDate: string
reviewInterval: string
}
export interface TOMDocumentRevision {
version: string
date: string
author: string
changes: string
}
export function createDefaultTOMDocumentOrgHeader(): TOMDocumentOrgHeader {
const now = new Date()
const nextYear = new Date()
nextYear.setFullYear(nextYear.getFullYear() + 1)
return {
organizationName: '',
industry: '',
dpoName: '',
dpoContact: '',
responsiblePerson: '',
itSecurityContact: '',
locations: [],
employeeCount: '',
documentVersion: '1.0',
lastReviewDate: now.toISOString().split('T')[0],
nextReviewDate: nextYear.toISOString().split('T')[0],
reviewInterval: 'Jaehrlich',
}
}
export const SEVERITY_LABELS_DE: Record<TOMComplianceIssueSeverity, string> = {
CRITICAL: 'Kritisch',
HIGH: 'Hoch',
MEDIUM: 'Mittel',
LOW: 'Niedrig',
}
export const SEVERITY_COLORS: Record<TOMComplianceIssueSeverity, string> = {
CRITICAL: '#dc2626',
HIGH: '#ea580c',
MEDIUM: '#d97706',
LOW: '#6b7280',
}
export const CATEGORY_LABELS_DE: Record<ControlCategory, string> = {
ACCESS_CONTROL: 'Zutrittskontrolle',
ADMISSION_CONTROL: 'Zugangskontrolle',
ACCESS_AUTHORIZATION: 'Zugriffskontrolle',
TRANSFER_CONTROL: 'Weitergabekontrolle',
INPUT_CONTROL: 'Eingabekontrolle',
ORDER_CONTROL: 'Auftragskontrolle',
AVAILABILITY: 'Verfuegbarkeit',
SEPARATION: 'Trennbarkeit',
ENCRYPTION: 'Verschluesselung',
PSEUDONYMIZATION: 'Pseudonymisierung',
RESILIENCE: 'Belastbarkeit',
RECOVERY: 'Wiederherstellbarkeit',
REVIEW: 'Ueberpruefung & Bewertung',
}
export const STATUS_LABELS_DE: Record<string, string> = {
IMPLEMENTED: 'Umgesetzt',
PARTIAL: 'Teilweise umgesetzt',
NOT_IMPLEMENTED: 'Nicht umgesetzt',
}
export const STATUS_BADGE_CLASSES: Record<string, string> = {
IMPLEMENTED: 'badge-active',
PARTIAL: 'badge-review',
NOT_IMPLEMENTED: 'badge-critical',
}
export const APPLICABILITY_LABELS_DE: Record<string, string> = {
REQUIRED: 'Erforderlich',
RECOMMENDED: 'Empfohlen',
OPTIONAL: 'Optional',
NOT_APPLICABLE: 'Nicht anwendbar',
}

View File

@@ -1,813 +1,12 @@
/** /**
* Standard Processing Activities Catalog * Standard Processing Activities Catalog — Barrel
* *
* 28 predefined processing activities templates following Art. 30 DSGVO * 28 predefined processing activities templates following Art. 30 DSGVO
* Split into domain modules; re-exported here for backward compatibility.
*/ */
import { export * from './processing-activities/types'
ProcessingActivityFormData, export * from './processing-activities/hr-sales'
DataSubjectCategory, export * from './processing-activities/marketing-finance'
PersonalDataCategory, export * from './processing-activities/it-customer-web-general'
LegalBasisType, export * from './processing-activities/helpers'
ProtectionLevel,
LocalizedText,
} from '../types'
export interface ProcessingActivityTemplate {
id: string
category: ProcessingActivityCategory
name: LocalizedText
description: LocalizedText
purposes: LocalizedText[]
dataSubjectCategories: DataSubjectCategory[]
personalDataCategories: PersonalDataCategory[]
suggestedLegalBasis: LegalBasisType[]
suggestedRetentionYears: number
suggestedProtectionLevel: ProtectionLevel
dpiaLikely: boolean
commonSystems: string[]
commonVendorCategories: string[]
}
export type ProcessingActivityCategory =
| 'HR' // Human Resources
| 'SALES' // Vertrieb
| 'MARKETING' // Marketing
| 'FINANCE' // Finanzen
| 'IT' // IT & Sicherheit
| 'CUSTOMER_SERVICE' // Kundenservice
| 'WEBSITE' // Website & Apps
| 'GENERAL' // Allgemein
export const PROCESSING_ACTIVITY_CATEGORY_META: Record<ProcessingActivityCategory, LocalizedText> = {
HR: { de: 'Personal', en: 'Human Resources' },
SALES: { de: 'Vertrieb', en: 'Sales' },
MARKETING: { de: 'Marketing', en: 'Marketing' },
FINANCE: { de: 'Finanzen', en: 'Finance' },
IT: { de: 'IT & Sicherheit', en: 'IT & Security' },
CUSTOMER_SERVICE: { de: 'Kundenservice', en: 'Customer Service' },
WEBSITE: { de: 'Website & Apps', en: 'Website & Apps' },
GENERAL: { de: 'Allgemein', en: 'General' },
}
export const PROCESSING_ACTIVITY_TEMPLATES: ProcessingActivityTemplate[] = [
// ==========================================
// HR - Human Resources
// ==========================================
{
id: 'tpl-hr-recruitment',
category: 'HR',
name: {
de: 'Bewerbermanagement',
en: 'Recruitment Management',
},
description: {
de: 'Verarbeitung von Bewerberdaten im Rahmen des Recruiting-Prozesses',
en: 'Processing of applicant data as part of the recruitment process',
},
purposes: [
{ de: 'Durchführung des Bewerbungsverfahrens', en: 'Conducting the application process' },
{ de: 'Prüfung der Eignung', en: 'Assessing suitability' },
{ de: 'Aufbau eines Talentpools (bei Einwilligung)', en: 'Building a talent pool (with consent)' },
],
dataSubjectCategories: ['APPLICANTS'],
personalDataCategories: [
'NAME', 'CONTACT', 'ADDRESS', 'DOB', 'EDUCATION_DATA',
'EMPLOYMENT_DATA', 'PHOTO_VIDEO',
],
suggestedLegalBasis: ['CONTRACT', 'CONSENT'],
suggestedRetentionYears: 0.5, // 6 Monate nach Absage
suggestedProtectionLevel: 'MEDIUM',
dpiaLikely: false,
commonSystems: ['E-Recruiting', 'Personio', 'Workday'],
commonVendorCategories: ['HR_SOFTWARE', 'CLOUD_INFRASTRUCTURE'],
},
{
id: 'tpl-hr-personnel',
category: 'HR',
name: {
de: 'Personalverwaltung',
en: 'Personnel Administration',
},
description: {
de: 'Führung der Personalakte und Verwaltung des Beschäftigungsverhältnisses',
en: 'Maintaining personnel files and managing employment relationships',
},
purposes: [
{ de: 'Führung der Personalakte', en: 'Maintaining personnel files' },
{ de: 'Durchführung des Arbeitsverhältnisses', en: 'Executing the employment relationship' },
{ de: 'Erfüllung gesetzlicher Pflichten', en: 'Fulfilling legal obligations' },
],
dataSubjectCategories: ['EMPLOYEES'],
personalDataCategories: [
'NAME', 'CONTACT', 'ADDRESS', 'DOB', 'ID_NUMBER',
'SOCIAL_SECURITY', 'TAX_ID', 'BANK_ACCOUNT', 'EMPLOYMENT_DATA',
'SALARY_DATA', 'EDUCATION_DATA', 'PHOTO_VIDEO',
],
suggestedLegalBasis: ['CONTRACT', 'LEGAL_OBLIGATION'],
suggestedRetentionYears: 10, // Nach Beendigung
suggestedProtectionLevel: 'HIGH',
dpiaLikely: false,
commonSystems: ['SAP HCM', 'Personio', 'DATEV'],
commonVendorCategories: ['HR_SOFTWARE', 'ERP'],
},
{
id: 'tpl-hr-payroll',
category: 'HR',
name: {
de: 'Lohn- und Gehaltsabrechnung',
en: 'Payroll Processing',
},
description: {
de: 'Berechnung und Auszahlung von Gehältern, Abführung von Steuern und Sozialabgaben',
en: 'Calculation and payment of salaries, tax and social security contributions',
},
purposes: [
{ de: 'Gehaltsberechnung und -auszahlung', en: 'Salary calculation and payment' },
{ de: 'Abführung von Lohnsteuer und Sozialabgaben', en: 'Payment of payroll taxes and social contributions' },
{ de: 'Erstellung von Lohnabrechnungen', en: 'Creating payslips' },
],
dataSubjectCategories: ['EMPLOYEES'],
personalDataCategories: [
'NAME', 'ADDRESS', 'DOB', 'SOCIAL_SECURITY', 'TAX_ID',
'BANK_ACCOUNT', 'SALARY_DATA', 'EMPLOYMENT_DATA',
],
suggestedLegalBasis: ['CONTRACT', 'LEGAL_OBLIGATION'],
suggestedRetentionYears: 10, // Handels- und Steuerrecht
suggestedProtectionLevel: 'HIGH',
dpiaLikely: false,
commonSystems: ['DATEV', 'SAP', 'Lexware'],
commonVendorCategories: ['ACCOUNTING', 'HR_SOFTWARE'],
},
{
id: 'tpl-hr-time-tracking',
category: 'HR',
name: {
de: 'Arbeitszeiterfassung',
en: 'Time Tracking',
},
description: {
de: 'Erfassung der Arbeitszeiten zur Einhaltung des Arbeitszeitgesetzes',
en: 'Recording working hours for compliance with working time regulations',
},
purposes: [
{ de: 'Erfassung der Arbeitszeiten', en: 'Recording working hours' },
{ de: 'Einhaltung des Arbeitszeitgesetzes', en: 'Compliance with working time regulations' },
{ de: 'Grundlage für Gehaltsabrechnung', en: 'Basis for payroll' },
],
dataSubjectCategories: ['EMPLOYEES'],
personalDataCategories: ['NAME', 'EMPLOYMENT_DATA', 'USAGE_DATA'],
suggestedLegalBasis: ['LEGAL_OBLIGATION', 'CONTRACT'],
suggestedRetentionYears: 2,
suggestedProtectionLevel: 'LOW',
dpiaLikely: false,
commonSystems: ['ATOSS', 'Clockodo', 'Toggl'],
commonVendorCategories: ['HR_SOFTWARE'],
},
{
id: 'tpl-hr-health-management',
category: 'HR',
name: {
de: 'Betriebliches Gesundheitsmanagement',
en: 'Occupational Health Management',
},
description: {
de: 'Verwaltung von Arbeitsunfähigkeitsbescheinigungen und betriebsärztlichen Untersuchungen',
en: 'Management of sick notes and occupational health examinations',
},
purposes: [
{ de: 'Verwaltung von Krankmeldungen', en: 'Managing sick leave' },
{ de: 'Organisation betriebsärztlicher Untersuchungen', en: 'Organizing occupational health examinations' },
{ de: 'Betriebliches Eingliederungsmanagement', en: 'Occupational reintegration management' },
],
dataSubjectCategories: ['EMPLOYEES'],
personalDataCategories: ['NAME', 'EMPLOYMENT_DATA', 'HEALTH_DATA'],
suggestedLegalBasis: ['ART9_EMPLOYMENT', 'LEGAL_OBLIGATION'],
suggestedRetentionYears: 3,
suggestedProtectionLevel: 'HIGH',
dpiaLikely: true,
commonSystems: ['HR-Software', 'BEM-System'],
commonVendorCategories: ['HR_SOFTWARE', 'CONSULTING'],
},
// ==========================================
// SALES - Vertrieb
// ==========================================
{
id: 'tpl-sales-crm',
category: 'SALES',
name: {
de: 'Kundenbeziehungsmanagement (CRM)',
en: 'Customer Relationship Management (CRM)',
},
description: {
de: 'Verwaltung von Kundenbeziehungen, Kontakthistorie und Verkaufschancen',
en: 'Managing customer relationships, contact history, and sales opportunities',
},
purposes: [
{ de: 'Pflege von Kundenbeziehungen', en: 'Maintaining customer relationships' },
{ de: 'Dokumentation von Kundenkontakten', en: 'Documenting customer contacts' },
{ de: 'Vertriebssteuerung', en: 'Sales management' },
],
dataSubjectCategories: ['CUSTOMERS', 'PROSPECTIVE_CUSTOMERS', 'BUSINESS_PARTNERS'],
personalDataCategories: [
'NAME', 'CONTACT', 'ADDRESS', 'CONTRACT_DATA', 'COMMUNICATION_DATA',
],
suggestedLegalBasis: ['CONTRACT', 'LEGITIMATE_INTEREST'],
suggestedRetentionYears: 3, // Nach letztem Kontakt
suggestedProtectionLevel: 'MEDIUM',
dpiaLikely: false,
commonSystems: ['Salesforce', 'HubSpot', 'Pipedrive', 'Microsoft Dynamics'],
commonVendorCategories: ['CRM'],
},
{
id: 'tpl-sales-contract-management',
category: 'SALES',
name: {
de: 'Vertragsmanagement',
en: 'Contract Management',
},
description: {
de: 'Verwaltung von Kundenverträgen, Angeboten und Aufträgen',
en: 'Managing customer contracts, quotes, and orders',
},
purposes: [
{ de: 'Erstellung und Verwaltung von Verträgen', en: 'Creating and managing contracts' },
{ de: 'Angebotsverfolgung', en: 'Quote tracking' },
{ de: 'Auftragsabwicklung', en: 'Order processing' },
],
dataSubjectCategories: ['CUSTOMERS', 'BUSINESS_PARTNERS'],
personalDataCategories: [
'NAME', 'CONTACT', 'ADDRESS', 'CONTRACT_DATA', 'PAYMENT_DATA',
],
suggestedLegalBasis: ['CONTRACT', 'LEGAL_OBLIGATION'],
suggestedRetentionYears: 10, // Handelsrechtlich
suggestedProtectionLevel: 'MEDIUM',
dpiaLikely: false,
commonSystems: ['ERP', 'CRM', 'Vertragsverwaltung'],
commonVendorCategories: ['ERP', 'CRM'],
},
// ==========================================
// MARKETING
// ==========================================
{
id: 'tpl-marketing-newsletter',
category: 'MARKETING',
name: {
de: 'Newsletter-Versand',
en: 'Newsletter Distribution',
},
description: {
de: 'Versand von E-Mail-Newslettern und Marketing-Kommunikation',
en: 'Sending email newsletters and marketing communications',
},
purposes: [
{ de: 'Versand von Newsletter und Marketing-E-Mails', en: 'Sending newsletters and marketing emails' },
{ de: 'Messung von Öffnungs- und Klickraten', en: 'Measuring open and click rates' },
],
dataSubjectCategories: ['NEWSLETTER_SUBSCRIBERS', 'CUSTOMERS'],
personalDataCategories: ['NAME', 'CONTACT', 'USAGE_DATA'],
suggestedLegalBasis: ['CONSENT'],
suggestedRetentionYears: 0, // Bis Widerruf
suggestedProtectionLevel: 'LOW',
dpiaLikely: false,
commonSystems: ['Mailchimp', 'CleverReach', 'Sendinblue'],
commonVendorCategories: ['EMAIL', 'MARKETING'],
},
{
id: 'tpl-marketing-advertising',
category: 'MARKETING',
name: {
de: 'Online-Werbung',
en: 'Online Advertising',
},
description: {
de: 'Schaltung und Auswertung von Online-Werbeanzeigen',
en: 'Running and analyzing online advertisements',
},
purposes: [
{ de: 'Schaltung von Online-Werbung', en: 'Running online advertisements' },
{ de: 'Conversion-Tracking', en: 'Conversion tracking' },
{ de: 'Retargeting', en: 'Retargeting' },
],
dataSubjectCategories: ['WEBSITE_USERS'],
personalDataCategories: ['IP_ADDRESS', 'DEVICE_ID', 'USAGE_DATA'],
suggestedLegalBasis: ['CONSENT'],
suggestedRetentionYears: 1,
suggestedProtectionLevel: 'MEDIUM',
dpiaLikely: true,
commonSystems: ['Google Ads', 'Meta Ads', 'LinkedIn Ads'],
commonVendorCategories: ['MARKETING', 'ANALYTICS'],
},
{
id: 'tpl-marketing-events',
category: 'MARKETING',
name: {
de: 'Veranstaltungsmanagement',
en: 'Event Management',
},
description: {
de: 'Organisation und Durchführung von Veranstaltungen, Messen und Webinaren',
en: 'Organizing and conducting events, trade shows, and webinars',
},
purposes: [
{ de: 'Teilnehmerregistrierung', en: 'Participant registration' },
{ de: 'Veranstaltungsdurchführung', en: 'Event execution' },
{ de: 'Nachbereitung und Follow-up', en: 'Follow-up activities' },
],
dataSubjectCategories: ['CUSTOMERS', 'PROSPECTIVE_CUSTOMERS', 'BUSINESS_PARTNERS'],
personalDataCategories: ['NAME', 'CONTACT', 'ADDRESS', 'PHOTO_VIDEO'],
suggestedLegalBasis: ['CONTRACT', 'CONSENT'],
suggestedRetentionYears: 2,
suggestedProtectionLevel: 'LOW',
dpiaLikely: false,
commonSystems: ['Eventbrite', 'GoToWebinar', 'Zoom'],
commonVendorCategories: ['MARKETING', 'COMMUNICATION'],
},
// ==========================================
// FINANCE
// ==========================================
{
id: 'tpl-finance-accounting',
category: 'FINANCE',
name: {
de: 'Finanzbuchhaltung',
en: 'Financial Accounting',
},
description: {
de: 'Führung der Finanzbuchhaltung, Rechnungsstellung und Zahlungsabwicklung',
en: 'Financial accounting, invoicing, and payment processing',
},
purposes: [
{ de: 'Buchführung und Rechnungswesen', en: 'Bookkeeping and accounting' },
{ de: 'Rechnungsstellung', en: 'Invoicing' },
{ de: 'Zahlungsabwicklung', en: 'Payment processing' },
],
dataSubjectCategories: ['CUSTOMERS', 'SUPPLIERS', 'BUSINESS_PARTNERS'],
personalDataCategories: [
'NAME', 'ADDRESS', 'BANK_ACCOUNT', 'PAYMENT_DATA', 'CONTRACT_DATA', 'TAX_ID',
],
suggestedLegalBasis: ['CONTRACT', 'LEGAL_OBLIGATION'],
suggestedRetentionYears: 10, // HGB/AO
suggestedProtectionLevel: 'HIGH',
dpiaLikely: false,
commonSystems: ['DATEV', 'SAP', 'Lexware', 'Xero'],
commonVendorCategories: ['ACCOUNTING', 'ERP'],
},
{
id: 'tpl-finance-debt-collection',
category: 'FINANCE',
name: {
de: 'Forderungsmanagement',
en: 'Debt Collection',
},
description: {
de: 'Verwaltung offener Forderungen und Mahnwesen',
en: 'Managing outstanding receivables and dunning',
},
purposes: [
{ de: 'Überwachung offener Forderungen', en: 'Monitoring outstanding receivables' },
{ de: 'Mahnwesen', en: 'Dunning process' },
{ de: 'Inkasso bei Bedarf', en: 'Debt collection if necessary' },
],
dataSubjectCategories: ['CUSTOMERS'],
personalDataCategories: ['NAME', 'ADDRESS', 'CONTACT', 'PAYMENT_DATA', 'CONTRACT_DATA'],
suggestedLegalBasis: ['CONTRACT', 'LEGITIMATE_INTEREST'],
suggestedRetentionYears: 10,
suggestedProtectionLevel: 'MEDIUM',
dpiaLikely: false,
commonSystems: ['ERP', 'Inkasso-Software'],
commonVendorCategories: ['ACCOUNTING', 'LEGAL'],
},
// ==========================================
// IT & SICHERHEIT
// ==========================================
{
id: 'tpl-it-user-management',
category: 'IT',
name: {
de: 'IT-Benutzerverwaltung',
en: 'IT User Management',
},
description: {
de: 'Verwaltung von Benutzerkonten, Zugriffsrechten und Authentifizierung',
en: 'Managing user accounts, access rights, and authentication',
},
purposes: [
{ de: 'Verwaltung von Benutzerkonten', en: 'Managing user accounts' },
{ de: 'Zugriffssteuerung', en: 'Access control' },
{ de: 'Single Sign-On', en: 'Single Sign-On' },
],
dataSubjectCategories: ['EMPLOYEES'],
personalDataCategories: ['NAME', 'CONTACT', 'LOGIN_DATA', 'USAGE_DATA'],
suggestedLegalBasis: ['CONTRACT', 'LEGITIMATE_INTEREST'],
suggestedRetentionYears: 1, // Nach Kontoschließung
suggestedProtectionLevel: 'HIGH',
dpiaLikely: false,
commonSystems: ['Active Directory', 'Okta', 'Azure AD'],
commonVendorCategories: ['SECURITY', 'CLOUD_INFRASTRUCTURE'],
},
{
id: 'tpl-it-logging',
category: 'IT',
name: {
de: 'IT-Protokollierung',
en: 'IT Logging',
},
description: {
de: 'Protokollierung von IT-Aktivitäten zur Sicherheit und Fehleranalyse',
en: 'Logging IT activities for security and error analysis',
},
purposes: [
{ de: 'Sicherheitsüberwachung', en: 'Security monitoring' },
{ de: 'Fehleranalyse', en: 'Error analysis' },
{ de: 'Nachvollziehbarkeit', en: 'Traceability' },
],
dataSubjectCategories: ['EMPLOYEES', 'CUSTOMERS', 'WEBSITE_USERS'],
personalDataCategories: ['IP_ADDRESS', 'DEVICE_ID', 'USAGE_DATA', 'LOGIN_DATA'],
suggestedLegalBasis: ['LEGITIMATE_INTEREST'],
suggestedRetentionYears: 1,
suggestedProtectionLevel: 'MEDIUM',
dpiaLikely: false,
commonSystems: ['Splunk', 'ELK Stack', 'Datadog'],
commonVendorCategories: ['SECURITY', 'ANALYTICS'],
},
{
id: 'tpl-it-video-surveillance',
category: 'IT',
name: {
de: 'Videoüberwachung',
en: 'Video Surveillance',
},
description: {
de: 'Videoüberwachung von Geschäftsräumen zum Schutz vor Diebstahl und Vandalismus',
en: 'Video surveillance of business premises for theft and vandalism prevention',
},
purposes: [
{ de: 'Schutz vor Diebstahl und Vandalismus', en: 'Protection against theft and vandalism' },
{ de: 'Zugangskontrolle', en: 'Access control' },
{ de: 'Beweissicherung', en: 'Evidence preservation' },
],
dataSubjectCategories: ['EMPLOYEES', 'VISITORS', 'CUSTOMERS'],
personalDataCategories: ['PHOTO_VIDEO', 'BIOMETRIC_DATA'],
suggestedLegalBasis: ['LEGITIMATE_INTEREST'],
suggestedRetentionYears: 0.1, // 72 Stunden
suggestedProtectionLevel: 'HIGH',
dpiaLikely: true,
commonSystems: ['CCTV-System'],
commonVendorCategories: ['SECURITY'],
},
{
id: 'tpl-it-backup',
category: 'IT',
name: {
de: 'Datensicherung (Backup)',
en: 'Data Backup',
},
description: {
de: 'Regelmäßige Sicherung von Unternehmensdaten',
en: 'Regular backup of company data',
},
purposes: [
{ de: 'Datensicherung', en: 'Data backup' },
{ de: 'Disaster Recovery', en: 'Disaster Recovery' },
{ de: 'Geschäftskontinuität', en: 'Business continuity' },
],
dataSubjectCategories: ['EMPLOYEES', 'CUSTOMERS', 'SUPPLIERS'],
personalDataCategories: ['NAME', 'CONTACT', 'CONTRACT_DATA', 'COMMUNICATION_DATA'],
suggestedLegalBasis: ['LEGITIMATE_INTEREST', 'LEGAL_OBLIGATION'],
suggestedRetentionYears: 1, // Je nach Backup-Konzept
suggestedProtectionLevel: 'HIGH',
dpiaLikely: false,
commonSystems: ['Veeam', 'AWS Backup', 'Azure Backup'],
commonVendorCategories: ['BACKUP', 'CLOUD_INFRASTRUCTURE'],
},
// ==========================================
// CUSTOMER SERVICE
// ==========================================
{
id: 'tpl-cs-support',
category: 'CUSTOMER_SERVICE',
name: {
de: 'Kundenbetreuung und Support',
en: 'Customer Support',
},
description: {
de: 'Bearbeitung von Kundenanfragen, Beschwerden und Support-Tickets',
en: 'Handling customer inquiries, complaints, and support tickets',
},
purposes: [
{ de: 'Bearbeitung von Kundenanfragen', en: 'Handling customer inquiries' },
{ de: 'Beschwerdemanagement', en: 'Complaint management' },
{ de: 'Technischer Support', en: 'Technical support' },
],
dataSubjectCategories: ['CUSTOMERS'],
personalDataCategories: ['NAME', 'CONTACT', 'CONTRACT_DATA', 'COMMUNICATION_DATA'],
suggestedLegalBasis: ['CONTRACT', 'LEGITIMATE_INTEREST'],
suggestedRetentionYears: 3,
suggestedProtectionLevel: 'MEDIUM',
dpiaLikely: false,
commonSystems: ['Zendesk', 'Freshdesk', 'Intercom'],
commonVendorCategories: ['SUPPORT', 'CRM'],
},
{
id: 'tpl-cs-satisfaction',
category: 'CUSTOMER_SERVICE',
name: {
de: 'Kundenzufriedenheitsbefragungen',
en: 'Customer Satisfaction Surveys',
},
description: {
de: 'Durchführung von Umfragen zur Messung der Kundenzufriedenheit',
en: 'Conducting surveys to measure customer satisfaction',
},
purposes: [
{ de: 'Messung der Kundenzufriedenheit', en: 'Measuring customer satisfaction' },
{ de: 'Qualitätsverbesserung', en: 'Quality improvement' },
],
dataSubjectCategories: ['CUSTOMERS'],
personalDataCategories: ['NAME', 'CONTACT', 'USAGE_DATA'],
suggestedLegalBasis: ['CONSENT', 'LEGITIMATE_INTEREST'],
suggestedRetentionYears: 2,
suggestedProtectionLevel: 'LOW',
dpiaLikely: false,
commonSystems: ['SurveyMonkey', 'Typeform', 'NPS-Tools'],
commonVendorCategories: ['ANALYTICS', 'MARKETING'],
},
// ==========================================
// WEBSITE & APPS
// ==========================================
{
id: 'tpl-web-analytics',
category: 'WEBSITE',
name: {
de: 'Web-Analyse',
en: 'Web Analytics',
},
description: {
de: 'Analyse des Nutzerverhaltens auf der Website zur Optimierung',
en: 'Analyzing user behavior on the website for optimization',
},
purposes: [
{ de: 'Analyse des Nutzerverhaltens', en: 'Analyzing user behavior' },
{ de: 'Website-Optimierung', en: 'Website optimization' },
{ de: 'Conversion-Tracking', en: 'Conversion tracking' },
],
dataSubjectCategories: ['WEBSITE_USERS'],
personalDataCategories: ['IP_ADDRESS', 'DEVICE_ID', 'USAGE_DATA', 'LOCATION_DATA'],
suggestedLegalBasis: ['CONSENT'],
suggestedRetentionYears: 2,
suggestedProtectionLevel: 'MEDIUM',
dpiaLikely: false,
commonSystems: ['Google Analytics', 'Matomo', 'Plausible'],
commonVendorCategories: ['ANALYTICS'],
},
{
id: 'tpl-web-contact-form',
category: 'WEBSITE',
name: {
de: 'Kontaktformular',
en: 'Contact Form',
},
description: {
de: 'Verarbeitung von Anfragen über das Website-Kontaktformular',
en: 'Processing inquiries submitted via the website contact form',
},
purposes: [
{ de: 'Bearbeitung von Kontaktanfragen', en: 'Processing contact inquiries' },
{ de: 'Kommunikation mit Interessenten', en: 'Communication with prospects' },
],
dataSubjectCategories: ['PROSPECTIVE_CUSTOMERS', 'WEBSITE_USERS'],
personalDataCategories: ['NAME', 'CONTACT', 'COMMUNICATION_DATA'],
suggestedLegalBasis: ['CONTRACT', 'LEGITIMATE_INTEREST'],
suggestedRetentionYears: 1,
suggestedProtectionLevel: 'LOW',
dpiaLikely: false,
commonSystems: ['CRM', 'E-Mail-System'],
commonVendorCategories: ['CRM', 'EMAIL'],
},
{
id: 'tpl-web-user-accounts',
category: 'WEBSITE',
name: {
de: 'Benutzerkonten / Kundenportal',
en: 'User Accounts / Customer Portal',
},
description: {
de: 'Verwaltung von Benutzerkonten im Kundenportal oder Online-Shop',
en: 'Managing user accounts in customer portal or online shop',
},
purposes: [
{ de: 'Bereitstellung des Kundenportals', en: 'Providing customer portal' },
{ de: 'Benutzerverwaltung', en: 'User management' },
{ de: 'Personalisierung', en: 'Personalization' },
],
dataSubjectCategories: ['CUSTOMERS', 'APP_USERS'],
personalDataCategories: ['NAME', 'CONTACT', 'LOGIN_DATA', 'USAGE_DATA', 'CONTRACT_DATA'],
suggestedLegalBasis: ['CONTRACT'],
suggestedRetentionYears: 1, // Nach Kontoschließung
suggestedProtectionLevel: 'MEDIUM',
dpiaLikely: false,
commonSystems: ['E-Commerce', 'CRM', 'Auth0'],
commonVendorCategories: ['HOSTING', 'CRM', 'SECURITY'],
},
{
id: 'tpl-web-cookies',
category: 'WEBSITE',
name: {
de: 'Cookie-Verwaltung',
en: 'Cookie Management',
},
description: {
de: 'Verwaltung von Cookies und Einholung von Cookie-Einwilligungen',
en: 'Managing cookies and obtaining cookie consents',
},
purposes: [
{ de: 'Speicherung von Cookie-Präferenzen', en: 'Storing cookie preferences' },
{ de: 'Einwilligungsmanagement', en: 'Consent management' },
],
dataSubjectCategories: ['WEBSITE_USERS'],
personalDataCategories: ['IP_ADDRESS', 'DEVICE_ID', 'USAGE_DATA'],
suggestedLegalBasis: ['CONSENT', 'LEGITIMATE_INTEREST'],
suggestedRetentionYears: 1,
suggestedProtectionLevel: 'LOW',
dpiaLikely: false,
commonSystems: ['Cookiebot', 'Usercentrics', 'OneTrust'],
commonVendorCategories: ['ANALYTICS', 'SECURITY'],
},
// ==========================================
// GENERAL
// ==========================================
{
id: 'tpl-gen-communication',
category: 'GENERAL',
name: {
de: 'Geschäftliche Kommunikation',
en: 'Business Communication',
},
description: {
de: 'E-Mail-Kommunikation, Telefonie und Messaging im Geschäftsverkehr',
en: 'Email communication, telephony, and messaging in business operations',
},
purposes: [
{ de: 'Geschäftliche Kommunikation', en: 'Business communication' },
{ de: 'Dokumentation von Korrespondenz', en: 'Documentation of correspondence' },
],
dataSubjectCategories: ['CUSTOMERS', 'SUPPLIERS', 'BUSINESS_PARTNERS', 'EMPLOYEES'],
personalDataCategories: ['NAME', 'CONTACT', 'COMMUNICATION_DATA'],
suggestedLegalBasis: ['CONTRACT', 'LEGITIMATE_INTEREST'],
suggestedRetentionYears: 6, // Handelsrechtlich relevant
suggestedProtectionLevel: 'MEDIUM',
dpiaLikely: false,
commonSystems: ['Microsoft 365', 'Google Workspace', 'Slack'],
commonVendorCategories: ['EMAIL', 'COMMUNICATION', 'CLOUD_INFRASTRUCTURE'],
},
{
id: 'tpl-gen-visitor',
category: 'GENERAL',
name: {
de: 'Besucherverwaltung',
en: 'Visitor Management',
},
description: {
de: 'Erfassung und Verwaltung von Besuchern in Geschäftsräumen',
en: 'Recording and managing visitors in business premises',
},
purposes: [
{ de: 'Zutrittskontrolle', en: 'Access control' },
{ de: 'Sicherheit', en: 'Security' },
{ de: 'Nachvollziehbarkeit', en: 'Traceability' },
],
dataSubjectCategories: ['VISITORS'],
personalDataCategories: ['NAME', 'CONTACT', 'PHOTO_VIDEO'],
suggestedLegalBasis: ['LEGITIMATE_INTEREST'],
suggestedRetentionYears: 0.1, // 1 Monat
suggestedProtectionLevel: 'LOW',
dpiaLikely: false,
commonSystems: ['Besuchermanagement-System'],
commonVendorCategories: ['SECURITY'],
},
{
id: 'tpl-gen-supplier',
category: 'GENERAL',
name: {
de: 'Lieferantenverwaltung',
en: 'Supplier Management',
},
description: {
de: 'Verwaltung von Lieferantenbeziehungen und Beschaffung',
en: 'Managing supplier relationships and procurement',
},
purposes: [
{ de: 'Lieferantenverwaltung', en: 'Supplier management' },
{ de: 'Beschaffung', en: 'Procurement' },
{ de: 'Qualitätsmanagement', en: 'Quality management' },
],
dataSubjectCategories: ['SUPPLIERS', 'BUSINESS_PARTNERS'],
personalDataCategories: ['NAME', 'CONTACT', 'ADDRESS', 'CONTRACT_DATA', 'BANK_ACCOUNT'],
suggestedLegalBasis: ['CONTRACT', 'LEGITIMATE_INTEREST'],
suggestedRetentionYears: 10,
suggestedProtectionLevel: 'MEDIUM',
dpiaLikely: false,
commonSystems: ['ERP', 'Lieferantenportal'],
commonVendorCategories: ['ERP'],
},
{
id: 'tpl-gen-whistleblower',
category: 'GENERAL',
name: {
de: 'Hinweisgebersystem',
en: 'Whistleblower System',
},
description: {
de: 'Entgegennahme und Bearbeitung von Hinweisen gemäß Hinweisgeberschutzgesetz',
en: 'Receiving and processing reports according to whistleblower protection law',
},
purposes: [
{ de: 'Entgegennahme von Hinweisen', en: 'Receiving reports' },
{ de: 'Untersuchung von Verstößen', en: 'Investigating violations' },
{ de: 'Schutz von Hinweisgebern', en: 'Protecting whistleblowers' },
],
dataSubjectCategories: ['EMPLOYEES', 'BUSINESS_PARTNERS'],
personalDataCategories: ['NAME', 'CONTACT', 'COMMUNICATION_DATA'],
suggestedLegalBasis: ['LEGAL_OBLIGATION'],
suggestedRetentionYears: 3,
suggestedProtectionLevel: 'HIGH',
dpiaLikely: true,
commonSystems: ['Hinweisgeberportal'],
commonVendorCategories: ['SECURITY', 'LEGAL'],
},
]
/**
* Get templates by category
*/
export function getTemplatesByCategory(
category: ProcessingActivityCategory
): ProcessingActivityTemplate[] {
return PROCESSING_ACTIVITY_TEMPLATES.filter((t) => t.category === category)
}
/**
* Get template by ID
*/
export function getTemplateById(id: string): ProcessingActivityTemplate | undefined {
return PROCESSING_ACTIVITY_TEMPLATES.find((t) => t.id === id)
}
/**
* Get all categories with their templates
*/
export function getGroupedTemplates(): Map<ProcessingActivityCategory, ProcessingActivityTemplate[]> {
const grouped = new Map<ProcessingActivityCategory, ProcessingActivityTemplate[]>()
for (const template of PROCESSING_ACTIVITY_TEMPLATES) {
const existing = grouped.get(template.category) || []
grouped.set(template.category, [...existing, template])
}
return grouped
}
/**
* Create form data from template
*/
export function createFormDataFromTemplate(
template: ProcessingActivityTemplate,
organizationDefaults?: {
responsible?: ProcessingActivityFormData['responsible']
dpoContact?: ProcessingActivityFormData['dpoContact']
}
): Partial<ProcessingActivityFormData> {
return {
vvtId: '', // Will be generated
name: template.name,
purposes: template.purposes,
dataSubjectCategories: template.dataSubjectCategories,
personalDataCategories: template.personalDataCategories,
legalBasis: template.suggestedLegalBasis.map((type) => ({ type })),
protectionLevel: template.suggestedProtectionLevel,
dpiaRequired: template.dpiaLikely,
retentionPeriod: {
duration: template.suggestedRetentionYears,
durationUnit: 'YEARS',
description: { de: '', en: '' },
},
recipientCategories: [],
thirdCountryTransfers: [],
technicalMeasures: [],
dataSources: [],
systems: [],
dataFlows: [],
subProcessors: [],
owner: '',
responsible: organizationDefaults?.responsible,
dpoContact: organizationDefaults?.dpoContact,
}
}

View File

@@ -0,0 +1,87 @@
/**
* Processing Activities — Helper Functions
*/
import type { ProcessingActivityFormData } from '../../types'
import type { ProcessingActivityTemplate, ProcessingActivityCategory } from './types'
import { HR_TEMPLATES, SALES_TEMPLATES } from './hr-sales'
import { MARKETING_TEMPLATES, FINANCE_TEMPLATES } from './marketing-finance'
import { IT_TEMPLATES, CUSTOMER_SERVICE_TEMPLATES, WEBSITE_TEMPLATES, GENERAL_TEMPLATES } from './it-customer-web-general'
export const PROCESSING_ACTIVITY_TEMPLATES: ProcessingActivityTemplate[] = [
...HR_TEMPLATES,
...SALES_TEMPLATES,
...MARKETING_TEMPLATES,
...FINANCE_TEMPLATES,
...IT_TEMPLATES,
...CUSTOMER_SERVICE_TEMPLATES,
...WEBSITE_TEMPLATES,
...GENERAL_TEMPLATES,
]
/**
* Get templates by category
*/
export function getTemplatesByCategory(
category: ProcessingActivityCategory
): ProcessingActivityTemplate[] {
return PROCESSING_ACTIVITY_TEMPLATES.filter((t) => t.category === category)
}
/**
* Get template by ID
*/
export function getTemplateById(id: string): ProcessingActivityTemplate | undefined {
return PROCESSING_ACTIVITY_TEMPLATES.find((t) => t.id === id)
}
/**
* Get all categories with their templates
*/
export function getGroupedTemplates(): Map<ProcessingActivityCategory, ProcessingActivityTemplate[]> {
const grouped = new Map<ProcessingActivityCategory, ProcessingActivityTemplate[]>()
for (const template of PROCESSING_ACTIVITY_TEMPLATES) {
const existing = grouped.get(template.category) || []
grouped.set(template.category, [...existing, template])
}
return grouped
}
/**
* Create form data from template
*/
export function createFormDataFromTemplate(
template: ProcessingActivityTemplate,
organizationDefaults?: {
responsible?: ProcessingActivityFormData['responsible']
dpoContact?: ProcessingActivityFormData['dpoContact']
}
): Partial<ProcessingActivityFormData> {
return {
vvtId: '',
name: template.name,
purposes: template.purposes,
dataSubjectCategories: template.dataSubjectCategories,
personalDataCategories: template.personalDataCategories,
legalBasis: template.suggestedLegalBasis.map((type) => ({ type })),
protectionLevel: template.suggestedProtectionLevel,
dpiaRequired: template.dpiaLikely,
retentionPeriod: {
duration: template.suggestedRetentionYears,
durationUnit: 'YEARS',
description: { de: '', en: '' },
},
recipientCategories: [],
thirdCountryTransfers: [],
technicalMeasures: [],
dataSources: [],
systems: [],
dataFlows: [],
subProcessors: [],
owner: '',
responsible: organizationDefaults?.responsible,
dpoContact: organizationDefaults?.dpoContact,
}
}

View File

@@ -0,0 +1,200 @@
/**
* Processing Activities — HR & Sales Templates
*/
import { ProcessingActivityTemplate } from './types'
export const HR_TEMPLATES: ProcessingActivityTemplate[] = [
{
id: 'tpl-hr-recruitment',
category: 'HR',
name: {
de: 'Bewerbermanagement',
en: 'Recruitment Management',
},
description: {
de: 'Verarbeitung von Bewerberdaten im Rahmen des Recruiting-Prozesses',
en: 'Processing of applicant data as part of the recruitment process',
},
purposes: [
{ de: 'Durchführung des Bewerbungsverfahrens', en: 'Conducting the application process' },
{ de: 'Prüfung der Eignung', en: 'Assessing suitability' },
{ de: 'Aufbau eines Talentpools (bei Einwilligung)', en: 'Building a talent pool (with consent)' },
],
dataSubjectCategories: ['APPLICANTS'],
personalDataCategories: [
'NAME', 'CONTACT', 'ADDRESS', 'DOB', 'EDUCATION_DATA',
'EMPLOYMENT_DATA', 'PHOTO_VIDEO',
],
suggestedLegalBasis: ['CONTRACT', 'CONSENT'],
suggestedRetentionYears: 0.5,
suggestedProtectionLevel: 'MEDIUM',
dpiaLikely: false,
commonSystems: ['E-Recruiting', 'Personio', 'Workday'],
commonVendorCategories: ['HR_SOFTWARE', 'CLOUD_INFRASTRUCTURE'],
},
{
id: 'tpl-hr-personnel',
category: 'HR',
name: {
de: 'Personalverwaltung',
en: 'Personnel Administration',
},
description: {
de: 'Führung der Personalakte und Verwaltung des Beschäftigungsverhältnisses',
en: 'Maintaining personnel files and managing employment relationships',
},
purposes: [
{ de: 'Führung der Personalakte', en: 'Maintaining personnel files' },
{ de: 'Durchführung des Arbeitsverhältnisses', en: 'Executing the employment relationship' },
{ de: 'Erfüllung gesetzlicher Pflichten', en: 'Fulfilling legal obligations' },
],
dataSubjectCategories: ['EMPLOYEES'],
personalDataCategories: [
'NAME', 'CONTACT', 'ADDRESS', 'DOB', 'ID_NUMBER',
'SOCIAL_SECURITY', 'TAX_ID', 'BANK_ACCOUNT', 'EMPLOYMENT_DATA',
'SALARY_DATA', 'EDUCATION_DATA', 'PHOTO_VIDEO',
],
suggestedLegalBasis: ['CONTRACT', 'LEGAL_OBLIGATION'],
suggestedRetentionYears: 10,
suggestedProtectionLevel: 'HIGH',
dpiaLikely: false,
commonSystems: ['SAP HCM', 'Personio', 'DATEV'],
commonVendorCategories: ['HR_SOFTWARE', 'ERP'],
},
{
id: 'tpl-hr-payroll',
category: 'HR',
name: {
de: 'Lohn- und Gehaltsabrechnung',
en: 'Payroll Processing',
},
description: {
de: 'Berechnung und Auszahlung von Gehältern, Abführung von Steuern und Sozialabgaben',
en: 'Calculation and payment of salaries, tax and social security contributions',
},
purposes: [
{ de: 'Gehaltsberechnung und -auszahlung', en: 'Salary calculation and payment' },
{ de: 'Abführung von Lohnsteuer und Sozialabgaben', en: 'Payment of payroll taxes and social contributions' },
{ de: 'Erstellung von Lohnabrechnungen', en: 'Creating payslips' },
],
dataSubjectCategories: ['EMPLOYEES'],
personalDataCategories: [
'NAME', 'ADDRESS', 'DOB', 'SOCIAL_SECURITY', 'TAX_ID',
'BANK_ACCOUNT', 'SALARY_DATA', 'EMPLOYMENT_DATA',
],
suggestedLegalBasis: ['CONTRACT', 'LEGAL_OBLIGATION'],
suggestedRetentionYears: 10,
suggestedProtectionLevel: 'HIGH',
dpiaLikely: false,
commonSystems: ['DATEV', 'SAP', 'Lexware'],
commonVendorCategories: ['ACCOUNTING', 'HR_SOFTWARE'],
},
{
id: 'tpl-hr-time-tracking',
category: 'HR',
name: {
de: 'Arbeitszeiterfassung',
en: 'Time Tracking',
},
description: {
de: 'Erfassung der Arbeitszeiten zur Einhaltung des Arbeitszeitgesetzes',
en: 'Recording working hours for compliance with working time regulations',
},
purposes: [
{ de: 'Erfassung der Arbeitszeiten', en: 'Recording working hours' },
{ de: 'Einhaltung des Arbeitszeitgesetzes', en: 'Compliance with working time regulations' },
{ de: 'Grundlage für Gehaltsabrechnung', en: 'Basis for payroll' },
],
dataSubjectCategories: ['EMPLOYEES'],
personalDataCategories: ['NAME', 'EMPLOYMENT_DATA', 'USAGE_DATA'],
suggestedLegalBasis: ['LEGAL_OBLIGATION', 'CONTRACT'],
suggestedRetentionYears: 2,
suggestedProtectionLevel: 'LOW',
dpiaLikely: false,
commonSystems: ['ATOSS', 'Clockodo', 'Toggl'],
commonVendorCategories: ['HR_SOFTWARE'],
},
{
id: 'tpl-hr-health-management',
category: 'HR',
name: {
de: 'Betriebliches Gesundheitsmanagement',
en: 'Occupational Health Management',
},
description: {
de: 'Verwaltung von Arbeitsunfähigkeitsbescheinigungen und betriebsärztlichen Untersuchungen',
en: 'Management of sick notes and occupational health examinations',
},
purposes: [
{ de: 'Verwaltung von Krankmeldungen', en: 'Managing sick leave' },
{ de: 'Organisation betriebsärztlicher Untersuchungen', en: 'Organizing occupational health examinations' },
{ de: 'Betriebliches Eingliederungsmanagement', en: 'Occupational reintegration management' },
],
dataSubjectCategories: ['EMPLOYEES'],
personalDataCategories: ['NAME', 'EMPLOYMENT_DATA', 'HEALTH_DATA'],
suggestedLegalBasis: ['ART9_EMPLOYMENT', 'LEGAL_OBLIGATION'],
suggestedRetentionYears: 3,
suggestedProtectionLevel: 'HIGH',
dpiaLikely: true,
commonSystems: ['HR-Software', 'BEM-System'],
commonVendorCategories: ['HR_SOFTWARE', 'CONSULTING'],
},
]
export const SALES_TEMPLATES: ProcessingActivityTemplate[] = [
{
id: 'tpl-sales-crm',
category: 'SALES',
name: {
de: 'Kundenbeziehungsmanagement (CRM)',
en: 'Customer Relationship Management (CRM)',
},
description: {
de: 'Verwaltung von Kundenbeziehungen, Kontakthistorie und Verkaufschancen',
en: 'Managing customer relationships, contact history, and sales opportunities',
},
purposes: [
{ de: 'Pflege von Kundenbeziehungen', en: 'Maintaining customer relationships' },
{ de: 'Dokumentation von Kundenkontakten', en: 'Documenting customer contacts' },
{ de: 'Vertriebssteuerung', en: 'Sales management' },
],
dataSubjectCategories: ['CUSTOMERS', 'PROSPECTIVE_CUSTOMERS', 'BUSINESS_PARTNERS'],
personalDataCategories: [
'NAME', 'CONTACT', 'ADDRESS', 'CONTRACT_DATA', 'COMMUNICATION_DATA',
],
suggestedLegalBasis: ['CONTRACT', 'LEGITIMATE_INTEREST'],
suggestedRetentionYears: 3,
suggestedProtectionLevel: 'MEDIUM',
dpiaLikely: false,
commonSystems: ['Salesforce', 'HubSpot', 'Pipedrive', 'Microsoft Dynamics'],
commonVendorCategories: ['CRM'],
},
{
id: 'tpl-sales-contract-management',
category: 'SALES',
name: {
de: 'Vertragsmanagement',
en: 'Contract Management',
},
description: {
de: 'Verwaltung von Kundenverträgen, Angeboten und Aufträgen',
en: 'Managing customer contracts, quotes, and orders',
},
purposes: [
{ de: 'Erstellung und Verwaltung von Verträgen', en: 'Creating and managing contracts' },
{ de: 'Angebotsverfolgung', en: 'Quote tracking' },
{ de: 'Auftragsabwicklung', en: 'Order processing' },
],
dataSubjectCategories: ['CUSTOMERS', 'BUSINESS_PARTNERS'],
personalDataCategories: [
'NAME', 'CONTACT', 'ADDRESS', 'CONTRACT_DATA', 'PAYMENT_DATA',
],
suggestedLegalBasis: ['CONTRACT', 'LEGAL_OBLIGATION'],
suggestedRetentionYears: 10,
suggestedProtectionLevel: 'MEDIUM',
dpiaLikely: false,
commonSystems: ['ERP', 'CRM', 'Vertragsverwaltung'],
commonVendorCategories: ['ERP', 'CRM'],
},
]

View File

@@ -0,0 +1,363 @@
/**
* Processing Activities — IT, Customer Service, Website & General Templates
*/
import { ProcessingActivityTemplate } from './types'
export const IT_TEMPLATES: ProcessingActivityTemplate[] = [
{
id: 'tpl-it-user-management',
category: 'IT',
name: {
de: 'IT-Benutzerverwaltung',
en: 'IT User Management',
},
description: {
de: 'Verwaltung von Benutzerkonten, Zugriffsrechten und Authentifizierung',
en: 'Managing user accounts, access rights, and authentication',
},
purposes: [
{ de: 'Verwaltung von Benutzerkonten', en: 'Managing user accounts' },
{ de: 'Zugriffssteuerung', en: 'Access control' },
{ de: 'Single Sign-On', en: 'Single Sign-On' },
],
dataSubjectCategories: ['EMPLOYEES'],
personalDataCategories: ['NAME', 'CONTACT', 'LOGIN_DATA', 'USAGE_DATA'],
suggestedLegalBasis: ['CONTRACT', 'LEGITIMATE_INTEREST'],
suggestedRetentionYears: 1,
suggestedProtectionLevel: 'HIGH',
dpiaLikely: false,
commonSystems: ['Active Directory', 'Okta', 'Azure AD'],
commonVendorCategories: ['SECURITY', 'CLOUD_INFRASTRUCTURE'],
},
{
id: 'tpl-it-logging',
category: 'IT',
name: {
de: 'IT-Protokollierung',
en: 'IT Logging',
},
description: {
de: 'Protokollierung von IT-Aktivitäten zur Sicherheit und Fehleranalyse',
en: 'Logging IT activities for security and error analysis',
},
purposes: [
{ de: 'Sicherheitsüberwachung', en: 'Security monitoring' },
{ de: 'Fehleranalyse', en: 'Error analysis' },
{ de: 'Nachvollziehbarkeit', en: 'Traceability' },
],
dataSubjectCategories: ['EMPLOYEES', 'CUSTOMERS', 'WEBSITE_USERS'],
personalDataCategories: ['IP_ADDRESS', 'DEVICE_ID', 'USAGE_DATA', 'LOGIN_DATA'],
suggestedLegalBasis: ['LEGITIMATE_INTEREST'],
suggestedRetentionYears: 1,
suggestedProtectionLevel: 'MEDIUM',
dpiaLikely: false,
commonSystems: ['Splunk', 'ELK Stack', 'Datadog'],
commonVendorCategories: ['SECURITY', 'ANALYTICS'],
},
{
id: 'tpl-it-video-surveillance',
category: 'IT',
name: {
de: 'Videoüberwachung',
en: 'Video Surveillance',
},
description: {
de: 'Videoüberwachung von Geschäftsräumen zum Schutz vor Diebstahl und Vandalismus',
en: 'Video surveillance of business premises for theft and vandalism prevention',
},
purposes: [
{ de: 'Schutz vor Diebstahl und Vandalismus', en: 'Protection against theft and vandalism' },
{ de: 'Zugangskontrolle', en: 'Access control' },
{ de: 'Beweissicherung', en: 'Evidence preservation' },
],
dataSubjectCategories: ['EMPLOYEES', 'VISITORS', 'CUSTOMERS'],
personalDataCategories: ['PHOTO_VIDEO', 'BIOMETRIC_DATA'],
suggestedLegalBasis: ['LEGITIMATE_INTEREST'],
suggestedRetentionYears: 0.1,
suggestedProtectionLevel: 'HIGH',
dpiaLikely: true,
commonSystems: ['CCTV-System'],
commonVendorCategories: ['SECURITY'],
},
{
id: 'tpl-it-backup',
category: 'IT',
name: {
de: 'Datensicherung (Backup)',
en: 'Data Backup',
},
description: {
de: 'Regelmäßige Sicherung von Unternehmensdaten',
en: 'Regular backup of company data',
},
purposes: [
{ de: 'Datensicherung', en: 'Data backup' },
{ de: 'Disaster Recovery', en: 'Disaster Recovery' },
{ de: 'Geschäftskontinuität', en: 'Business continuity' },
],
dataSubjectCategories: ['EMPLOYEES', 'CUSTOMERS', 'SUPPLIERS'],
personalDataCategories: ['NAME', 'CONTACT', 'CONTRACT_DATA', 'COMMUNICATION_DATA'],
suggestedLegalBasis: ['LEGITIMATE_INTEREST', 'LEGAL_OBLIGATION'],
suggestedRetentionYears: 1,
suggestedProtectionLevel: 'HIGH',
dpiaLikely: false,
commonSystems: ['Veeam', 'AWS Backup', 'Azure Backup'],
commonVendorCategories: ['BACKUP', 'CLOUD_INFRASTRUCTURE'],
},
]
export const CUSTOMER_SERVICE_TEMPLATES: ProcessingActivityTemplate[] = [
{
id: 'tpl-cs-support',
category: 'CUSTOMER_SERVICE',
name: {
de: 'Kundenbetreuung und Support',
en: 'Customer Support',
},
description: {
de: 'Bearbeitung von Kundenanfragen, Beschwerden und Support-Tickets',
en: 'Handling customer inquiries, complaints, and support tickets',
},
purposes: [
{ de: 'Bearbeitung von Kundenanfragen', en: 'Handling customer inquiries' },
{ de: 'Beschwerdemanagement', en: 'Complaint management' },
{ de: 'Technischer Support', en: 'Technical support' },
],
dataSubjectCategories: ['CUSTOMERS'],
personalDataCategories: ['NAME', 'CONTACT', 'CONTRACT_DATA', 'COMMUNICATION_DATA'],
suggestedLegalBasis: ['CONTRACT', 'LEGITIMATE_INTEREST'],
suggestedRetentionYears: 3,
suggestedProtectionLevel: 'MEDIUM',
dpiaLikely: false,
commonSystems: ['Zendesk', 'Freshdesk', 'Intercom'],
commonVendorCategories: ['SUPPORT', 'CRM'],
},
{
id: 'tpl-cs-satisfaction',
category: 'CUSTOMER_SERVICE',
name: {
de: 'Kundenzufriedenheitsbefragungen',
en: 'Customer Satisfaction Surveys',
},
description: {
de: 'Durchführung von Umfragen zur Messung der Kundenzufriedenheit',
en: 'Conducting surveys to measure customer satisfaction',
},
purposes: [
{ de: 'Messung der Kundenzufriedenheit', en: 'Measuring customer satisfaction' },
{ de: 'Qualitätsverbesserung', en: 'Quality improvement' },
],
dataSubjectCategories: ['CUSTOMERS'],
personalDataCategories: ['NAME', 'CONTACT', 'USAGE_DATA'],
suggestedLegalBasis: ['CONSENT', 'LEGITIMATE_INTEREST'],
suggestedRetentionYears: 2,
suggestedProtectionLevel: 'LOW',
dpiaLikely: false,
commonSystems: ['SurveyMonkey', 'Typeform', 'NPS-Tools'],
commonVendorCategories: ['ANALYTICS', 'MARKETING'],
},
]
export const WEBSITE_TEMPLATES: ProcessingActivityTemplate[] = [
{
id: 'tpl-web-analytics',
category: 'WEBSITE',
name: {
de: 'Web-Analyse',
en: 'Web Analytics',
},
description: {
de: 'Analyse des Nutzerverhaltens auf der Website zur Optimierung',
en: 'Analyzing user behavior on the website for optimization',
},
purposes: [
{ de: 'Analyse des Nutzerverhaltens', en: 'Analyzing user behavior' },
{ de: 'Website-Optimierung', en: 'Website optimization' },
{ de: 'Conversion-Tracking', en: 'Conversion tracking' },
],
dataSubjectCategories: ['WEBSITE_USERS'],
personalDataCategories: ['IP_ADDRESS', 'DEVICE_ID', 'USAGE_DATA', 'LOCATION_DATA'],
suggestedLegalBasis: ['CONSENT'],
suggestedRetentionYears: 2,
suggestedProtectionLevel: 'MEDIUM',
dpiaLikely: false,
commonSystems: ['Google Analytics', 'Matomo', 'Plausible'],
commonVendorCategories: ['ANALYTICS'],
},
{
id: 'tpl-web-contact-form',
category: 'WEBSITE',
name: {
de: 'Kontaktformular',
en: 'Contact Form',
},
description: {
de: 'Verarbeitung von Anfragen über das Website-Kontaktformular',
en: 'Processing inquiries submitted via the website contact form',
},
purposes: [
{ de: 'Bearbeitung von Kontaktanfragen', en: 'Processing contact inquiries' },
{ de: 'Kommunikation mit Interessenten', en: 'Communication with prospects' },
],
dataSubjectCategories: ['PROSPECTIVE_CUSTOMERS', 'WEBSITE_USERS'],
personalDataCategories: ['NAME', 'CONTACT', 'COMMUNICATION_DATA'],
suggestedLegalBasis: ['CONTRACT', 'LEGITIMATE_INTEREST'],
suggestedRetentionYears: 1,
suggestedProtectionLevel: 'LOW',
dpiaLikely: false,
commonSystems: ['CRM', 'E-Mail-System'],
commonVendorCategories: ['CRM', 'EMAIL'],
},
{
id: 'tpl-web-user-accounts',
category: 'WEBSITE',
name: {
de: 'Benutzerkonten / Kundenportal',
en: 'User Accounts / Customer Portal',
},
description: {
de: 'Verwaltung von Benutzerkonten im Kundenportal oder Online-Shop',
en: 'Managing user accounts in customer portal or online shop',
},
purposes: [
{ de: 'Bereitstellung des Kundenportals', en: 'Providing customer portal' },
{ de: 'Benutzerverwaltung', en: 'User management' },
{ de: 'Personalisierung', en: 'Personalization' },
],
dataSubjectCategories: ['CUSTOMERS', 'APP_USERS'],
personalDataCategories: ['NAME', 'CONTACT', 'LOGIN_DATA', 'USAGE_DATA', 'CONTRACT_DATA'],
suggestedLegalBasis: ['CONTRACT'],
suggestedRetentionYears: 1,
suggestedProtectionLevel: 'MEDIUM',
dpiaLikely: false,
commonSystems: ['E-Commerce', 'CRM', 'Auth0'],
commonVendorCategories: ['HOSTING', 'CRM', 'SECURITY'],
},
{
id: 'tpl-web-cookies',
category: 'WEBSITE',
name: {
de: 'Cookie-Verwaltung',
en: 'Cookie Management',
},
description: {
de: 'Verwaltung von Cookies und Einholung von Cookie-Einwilligungen',
en: 'Managing cookies and obtaining cookie consents',
},
purposes: [
{ de: 'Speicherung von Cookie-Präferenzen', en: 'Storing cookie preferences' },
{ de: 'Einwilligungsmanagement', en: 'Consent management' },
],
dataSubjectCategories: ['WEBSITE_USERS'],
personalDataCategories: ['IP_ADDRESS', 'DEVICE_ID', 'USAGE_DATA'],
suggestedLegalBasis: ['CONSENT', 'LEGITIMATE_INTEREST'],
suggestedRetentionYears: 1,
suggestedProtectionLevel: 'LOW',
dpiaLikely: false,
commonSystems: ['Cookiebot', 'Usercentrics', 'OneTrust'],
commonVendorCategories: ['ANALYTICS', 'SECURITY'],
},
]
export const GENERAL_TEMPLATES: ProcessingActivityTemplate[] = [
{
id: 'tpl-gen-communication',
category: 'GENERAL',
name: {
de: 'Geschäftliche Kommunikation',
en: 'Business Communication',
},
description: {
de: 'E-Mail-Kommunikation, Telefonie und Messaging im Geschäftsverkehr',
en: 'Email communication, telephony, and messaging in business operations',
},
purposes: [
{ de: 'Geschäftliche Kommunikation', en: 'Business communication' },
{ de: 'Dokumentation von Korrespondenz', en: 'Documentation of correspondence' },
],
dataSubjectCategories: ['CUSTOMERS', 'SUPPLIERS', 'BUSINESS_PARTNERS', 'EMPLOYEES'],
personalDataCategories: ['NAME', 'CONTACT', 'COMMUNICATION_DATA'],
suggestedLegalBasis: ['CONTRACT', 'LEGITIMATE_INTEREST'],
suggestedRetentionYears: 6,
suggestedProtectionLevel: 'MEDIUM',
dpiaLikely: false,
commonSystems: ['Microsoft 365', 'Google Workspace', 'Slack'],
commonVendorCategories: ['EMAIL', 'COMMUNICATION', 'CLOUD_INFRASTRUCTURE'],
},
{
id: 'tpl-gen-visitor',
category: 'GENERAL',
name: {
de: 'Besucherverwaltung',
en: 'Visitor Management',
},
description: {
de: 'Erfassung und Verwaltung von Besuchern in Geschäftsräumen',
en: 'Recording and managing visitors in business premises',
},
purposes: [
{ de: 'Zutrittskontrolle', en: 'Access control' },
{ de: 'Sicherheit', en: 'Security' },
{ de: 'Nachvollziehbarkeit', en: 'Traceability' },
],
dataSubjectCategories: ['VISITORS'],
personalDataCategories: ['NAME', 'CONTACT', 'PHOTO_VIDEO'],
suggestedLegalBasis: ['LEGITIMATE_INTEREST'],
suggestedRetentionYears: 0.1,
suggestedProtectionLevel: 'LOW',
dpiaLikely: false,
commonSystems: ['Besuchermanagement-System'],
commonVendorCategories: ['SECURITY'],
},
{
id: 'tpl-gen-supplier',
category: 'GENERAL',
name: {
de: 'Lieferantenverwaltung',
en: 'Supplier Management',
},
description: {
de: 'Verwaltung von Lieferantenbeziehungen und Beschaffung',
en: 'Managing supplier relationships and procurement',
},
purposes: [
{ de: 'Lieferantenverwaltung', en: 'Supplier management' },
{ de: 'Beschaffung', en: 'Procurement' },
{ de: 'Qualitätsmanagement', en: 'Quality management' },
],
dataSubjectCategories: ['SUPPLIERS', 'BUSINESS_PARTNERS'],
personalDataCategories: ['NAME', 'CONTACT', 'ADDRESS', 'CONTRACT_DATA', 'BANK_ACCOUNT'],
suggestedLegalBasis: ['CONTRACT', 'LEGITIMATE_INTEREST'],
suggestedRetentionYears: 10,
suggestedProtectionLevel: 'MEDIUM',
dpiaLikely: false,
commonSystems: ['ERP', 'Lieferantenportal'],
commonVendorCategories: ['ERP'],
},
{
id: 'tpl-gen-whistleblower',
category: 'GENERAL',
name: {
de: 'Hinweisgebersystem',
en: 'Whistleblower System',
},
description: {
de: 'Entgegennahme und Bearbeitung von Hinweisen gemäß Hinweisgeberschutzgesetz',
en: 'Receiving and processing reports according to whistleblower protection law',
},
purposes: [
{ de: 'Entgegennahme von Hinweisen', en: 'Receiving reports' },
{ de: 'Untersuchung von Verstößen', en: 'Investigating violations' },
{ de: 'Schutz von Hinweisgebern', en: 'Protecting whistleblowers' },
],
dataSubjectCategories: ['EMPLOYEES', 'BUSINESS_PARTNERS'],
personalDataCategories: ['NAME', 'CONTACT', 'COMMUNICATION_DATA'],
suggestedLegalBasis: ['LEGAL_OBLIGATION'],
suggestedRetentionYears: 3,
suggestedProtectionLevel: 'HIGH',
dpiaLikely: true,
commonSystems: ['Hinweisgeberportal'],
commonVendorCategories: ['SECURITY', 'LEGAL'],
},
]

View File

@@ -0,0 +1,137 @@
/**
* Processing Activities — Marketing & Finance Templates
*/
import { ProcessingActivityTemplate } from './types'
export const MARKETING_TEMPLATES: ProcessingActivityTemplate[] = [
{
id: 'tpl-marketing-newsletter',
category: 'MARKETING',
name: {
de: 'Newsletter-Versand',
en: 'Newsletter Distribution',
},
description: {
de: 'Versand von E-Mail-Newslettern und Marketing-Kommunikation',
en: 'Sending email newsletters and marketing communications',
},
purposes: [
{ de: 'Versand von Newsletter und Marketing-E-Mails', en: 'Sending newsletters and marketing emails' },
{ de: 'Messung von Öffnungs- und Klickraten', en: 'Measuring open and click rates' },
],
dataSubjectCategories: ['NEWSLETTER_SUBSCRIBERS', 'CUSTOMERS'],
personalDataCategories: ['NAME', 'CONTACT', 'USAGE_DATA'],
suggestedLegalBasis: ['CONSENT'],
suggestedRetentionYears: 0,
suggestedProtectionLevel: 'LOW',
dpiaLikely: false,
commonSystems: ['Mailchimp', 'CleverReach', 'Sendinblue'],
commonVendorCategories: ['EMAIL', 'MARKETING'],
},
{
id: 'tpl-marketing-advertising',
category: 'MARKETING',
name: {
de: 'Online-Werbung',
en: 'Online Advertising',
},
description: {
de: 'Schaltung und Auswertung von Online-Werbeanzeigen',
en: 'Running and analyzing online advertisements',
},
purposes: [
{ de: 'Schaltung von Online-Werbung', en: 'Running online advertisements' },
{ de: 'Conversion-Tracking', en: 'Conversion tracking' },
{ de: 'Retargeting', en: 'Retargeting' },
],
dataSubjectCategories: ['WEBSITE_USERS'],
personalDataCategories: ['IP_ADDRESS', 'DEVICE_ID', 'USAGE_DATA'],
suggestedLegalBasis: ['CONSENT'],
suggestedRetentionYears: 1,
suggestedProtectionLevel: 'MEDIUM',
dpiaLikely: true,
commonSystems: ['Google Ads', 'Meta Ads', 'LinkedIn Ads'],
commonVendorCategories: ['MARKETING', 'ANALYTICS'],
},
{
id: 'tpl-marketing-events',
category: 'MARKETING',
name: {
de: 'Veranstaltungsmanagement',
en: 'Event Management',
},
description: {
de: 'Organisation und Durchführung von Veranstaltungen, Messen und Webinaren',
en: 'Organizing and conducting events, trade shows, and webinars',
},
purposes: [
{ de: 'Teilnehmerregistrierung', en: 'Participant registration' },
{ de: 'Veranstaltungsdurchführung', en: 'Event execution' },
{ de: 'Nachbereitung und Follow-up', en: 'Follow-up activities' },
],
dataSubjectCategories: ['CUSTOMERS', 'PROSPECTIVE_CUSTOMERS', 'BUSINESS_PARTNERS'],
personalDataCategories: ['NAME', 'CONTACT', 'ADDRESS', 'PHOTO_VIDEO'],
suggestedLegalBasis: ['CONTRACT', 'CONSENT'],
suggestedRetentionYears: 2,
suggestedProtectionLevel: 'LOW',
dpiaLikely: false,
commonSystems: ['Eventbrite', 'GoToWebinar', 'Zoom'],
commonVendorCategories: ['MARKETING', 'COMMUNICATION'],
},
]
export const FINANCE_TEMPLATES: ProcessingActivityTemplate[] = [
{
id: 'tpl-finance-accounting',
category: 'FINANCE',
name: {
de: 'Finanzbuchhaltung',
en: 'Financial Accounting',
},
description: {
de: 'Führung der Finanzbuchhaltung, Rechnungsstellung und Zahlungsabwicklung',
en: 'Financial accounting, invoicing, and payment processing',
},
purposes: [
{ de: 'Buchführung und Rechnungswesen', en: 'Bookkeeping and accounting' },
{ de: 'Rechnungsstellung', en: 'Invoicing' },
{ de: 'Zahlungsabwicklung', en: 'Payment processing' },
],
dataSubjectCategories: ['CUSTOMERS', 'SUPPLIERS', 'BUSINESS_PARTNERS'],
personalDataCategories: [
'NAME', 'ADDRESS', 'BANK_ACCOUNT', 'PAYMENT_DATA', 'CONTRACT_DATA', 'TAX_ID',
],
suggestedLegalBasis: ['CONTRACT', 'LEGAL_OBLIGATION'],
suggestedRetentionYears: 10,
suggestedProtectionLevel: 'HIGH',
dpiaLikely: false,
commonSystems: ['DATEV', 'SAP', 'Lexware', 'Xero'],
commonVendorCategories: ['ACCOUNTING', 'ERP'],
},
{
id: 'tpl-finance-debt-collection',
category: 'FINANCE',
name: {
de: 'Forderungsmanagement',
en: 'Debt Collection',
},
description: {
de: 'Verwaltung offener Forderungen und Mahnwesen',
en: 'Managing outstanding receivables and dunning',
},
purposes: [
{ de: 'Überwachung offener Forderungen', en: 'Monitoring outstanding receivables' },
{ de: 'Mahnwesen', en: 'Dunning process' },
{ de: 'Inkasso bei Bedarf', en: 'Debt collection if necessary' },
],
dataSubjectCategories: ['CUSTOMERS'],
personalDataCategories: ['NAME', 'ADDRESS', 'CONTACT', 'PAYMENT_DATA', 'CONTRACT_DATA'],
suggestedLegalBasis: ['CONTRACT', 'LEGITIMATE_INTEREST'],
suggestedRetentionYears: 10,
suggestedProtectionLevel: 'MEDIUM',
dpiaLikely: false,
commonSystems: ['ERP', 'Inkasso-Software'],
commonVendorCategories: ['ACCOUNTING', 'LEGAL'],
},
]

View File

@@ -0,0 +1,48 @@
/**
* Processing Activities Catalog — Shared Types & Metadata
*/
import {
DataSubjectCategory,
PersonalDataCategory,
LegalBasisType,
ProtectionLevel,
LocalizedText,
} from '../../types'
export interface ProcessingActivityTemplate {
id: string
category: ProcessingActivityCategory
name: LocalizedText
description: LocalizedText
purposes: LocalizedText[]
dataSubjectCategories: DataSubjectCategory[]
personalDataCategories: PersonalDataCategory[]
suggestedLegalBasis: LegalBasisType[]
suggestedRetentionYears: number
suggestedProtectionLevel: ProtectionLevel
dpiaLikely: boolean
commonSystems: string[]
commonVendorCategories: string[]
}
export type ProcessingActivityCategory =
| 'HR' // Human Resources
| 'SALES' // Vertrieb
| 'MARKETING' // Marketing
| 'FINANCE' // Finanzen
| 'IT' // IT & Sicherheit
| 'CUSTOMER_SERVICE' // Kundenservice
| 'WEBSITE' // Website & Apps
| 'GENERAL' // Allgemein
export const PROCESSING_ACTIVITY_CATEGORY_META: Record<ProcessingActivityCategory, LocalizedText> = {
HR: { de: 'Personal', en: 'Human Resources' },
SALES: { de: 'Vertrieb', en: 'Sales' },
MARKETING: { de: 'Marketing', en: 'Marketing' },
FINANCE: { de: 'Finanzen', en: 'Finance' },
IT: { de: 'IT & Sicherheit', en: 'IT & Security' },
CUSTOMER_SERVICE: { de: 'Kundenservice', en: 'Customer Service' },
WEBSITE: { de: 'Website & Apps', en: 'Website & Apps' },
GENERAL: { de: 'Allgemein', en: 'General' },
}

View File

@@ -0,0 +1,322 @@
/**
* Contract Review Checklist Data
*
* Pure data arrays for AVV, Incident, Transfer, and SLA/Liability checklists.
* Barrel-split from checklists.ts. Do NOT import directly; use checklists.ts.
*/
import { LocalizedText, FindingCategory } from '../types'
export interface ChecklistItem {
id: string
category: FindingCategory
requirement: LocalizedText
article: string
description: LocalizedText
checkPoints: LocalizedText[]
isRequired: boolean
severity: 'LOW' | 'MEDIUM' | 'HIGH' | 'CRITICAL'
}
// ==========================================
// ART. 28 DSGVO CHECKLIST
// ==========================================
export const AVV_CHECKLIST: ChecklistItem[] = [
{
id: 'art28_3_a',
category: 'INSTRUCTION',
requirement: { de: 'Weisungsgebundenheit', en: 'Instruction binding' },
article: 'Art. 28 Abs. 3 lit. a DSGVO',
description: {
de: 'Der Auftragsverarbeiter verarbeitet personenbezogene Daten nur auf dokumentierte Weisung des Verantwortlichen.',
en: 'The processor processes personal data only on documented instructions from the controller.',
},
checkPoints: [
{ de: 'Weisungsgebundenheit explizit vereinbart', en: 'Instruction binding explicitly agreed' },
{ de: 'Dokumentierte Weisungen vorgesehen', en: 'Documented instructions provided for' },
{ de: 'Hinweispflicht bei rechtswidrigen Weisungen', en: 'Obligation to notify of unlawful instructions' },
{ de: 'Keine eigenständige Verarbeitung erlaubt', en: 'No independent processing allowed' },
],
isRequired: true,
severity: 'CRITICAL',
},
{
id: 'art28_3_b',
category: 'CONFIDENTIALITY',
requirement: { de: 'Vertraulichkeitsverpflichtung', en: 'Confidentiality obligation' },
article: 'Art. 28 Abs. 3 lit. b DSGVO',
description: {
de: 'Der Auftragsverarbeiter gewährleistet, dass sich die zur Verarbeitung befugten Personen zur Vertraulichkeit verpflichtet haben.',
en: 'The processor ensures that persons authorised to process personal data have committed themselves to confidentiality.',
},
checkPoints: [
{ de: 'Vertraulichkeitsverpflichtung der Mitarbeiter', en: 'Confidentiality obligation of employees' },
{ de: 'Gesetzliche Verschwiegenheitspflicht oder', en: 'Statutory confidentiality obligation or' },
{ de: 'Vertragliche Verpflichtung', en: 'Contractual obligation' },
],
isRequired: true,
severity: 'HIGH',
},
{
id: 'art28_3_c',
category: 'TOM',
requirement: { de: 'Technische und organisatorische Maßnahmen', en: 'Technical and organisational measures' },
article: 'Art. 28 Abs. 3 lit. c DSGVO',
description: {
de: 'Der Auftragsverarbeiter trifft alle gemäß Art. 32 erforderlichen Maßnahmen.',
en: 'The processor takes all measures required pursuant to Art. 32.',
},
checkPoints: [
{ de: 'TOM-Anlage vorhanden', en: 'TOM annex present' },
{ de: 'TOM konkret und aktuell', en: 'TOM specific and current' },
{ de: 'Bezug zu Art. 32 DSGVO', en: 'Reference to Art. 32 GDPR' },
{ de: 'Aktualisierungspflicht vereinbart', en: 'Update obligation agreed' },
],
isRequired: true,
severity: 'CRITICAL',
},
{
id: 'art28_3_d',
category: 'SUBPROCESSOR',
requirement: { de: 'Unterauftragsverarbeitung', en: 'Sub-processing' },
article: 'Art. 28 Abs. 3 lit. d DSGVO',
description: {
de: 'Der Auftragsverarbeiter nimmt keinen weiteren Auftragsverarbeiter ohne vorherige Genehmigung in Anspruch.',
en: 'The processor does not engage another processor without prior authorisation.',
},
checkPoints: [
{ de: 'Genehmigungserfordernis (allgemein oder spezifisch)', en: 'Authorisation requirement (general or specific)' },
{ de: 'Bei allgemeiner Genehmigung: Informationspflicht', en: 'With general authorisation: notification obligation' },
{ de: 'Einspruchsrecht des Verantwortlichen', en: 'Right of objection for controller' },
{ de: 'Liste aktueller Unterauftragnehmer', en: 'List of current sub-processors' },
{ de: 'Weitergabe der Pflichten an Unterauftragnehmer', en: 'Transfer of obligations to sub-processors' },
],
isRequired: true,
severity: 'CRITICAL',
},
{
id: 'art28_3_e',
category: 'DATA_SUBJECT_RIGHTS',
requirement: { de: 'Unterstützung bei Betroffenenrechten', en: 'Assistance with data subject rights' },
article: 'Art. 28 Abs. 3 lit. e DSGVO',
description: {
de: 'Der Auftragsverarbeiter unterstützt den Verantwortlichen bei der Erfüllung der Betroffenenrechte.',
en: 'The processor assists the controller in fulfilling data subject rights obligations.',
},
checkPoints: [
{ de: 'Unterstützungspflicht vereinbart', en: 'Assistance obligation agreed' },
{ de: 'Verfahren zur Weiterleitung von Anfragen', en: 'Procedure for forwarding requests' },
{ de: 'Fristen für Unterstützung', en: 'Deadlines for assistance' },
{ de: 'Kostenregelung', en: 'Cost arrangement' },
],
isRequired: true,
severity: 'HIGH',
},
{
id: 'art28_3_f',
category: 'GENERAL',
requirement: { de: 'Unterstützung bei DSFA und Konsultation', en: 'Assistance with DPIA and consultation' },
article: 'Art. 28 Abs. 3 lit. f DSGVO',
description: {
de: 'Der Auftragsverarbeiter unterstützt den Verantwortlichen bei der Einhaltung der Pflichten gemäß Art. 32-36.',
en: 'The processor assists the controller in ensuring compliance with obligations pursuant to Art. 32-36.',
},
checkPoints: [
{ de: 'Unterstützung bei DSFA', en: 'Assistance with DPIA' },
{ de: 'Unterstützung bei vorheriger Konsultation', en: 'Assistance with prior consultation' },
{ de: 'Bereitstellung notwendiger Informationen', en: 'Provision of necessary information' },
],
isRequired: true,
severity: 'MEDIUM',
},
{
id: 'art28_3_g',
category: 'DELETION',
requirement: { de: 'Löschung/Rückgabe nach Vertragsende', en: 'Deletion/return after contract end' },
article: 'Art. 28 Abs. 3 lit. g DSGVO',
description: {
de: 'Nach Abschluss der Verarbeitung werden alle personenbezogenen Daten gelöscht oder zurückgegeben.',
en: 'After the end of processing, all personal data is deleted or returned.',
},
checkPoints: [
{ de: 'Löschung oder Rückgabe nach Wahl des Verantwortlichen', en: 'Deletion or return at controller choice' },
{ de: 'Frist für Löschung/Rückgabe (max. 30 Tage empfohlen)', en: 'Deadline for deletion/return (max. 30 days recommended)' },
{ de: 'Löschung auch bei Unterauftragnehmern', en: 'Deletion also at sub-processors' },
{ de: 'Löschbestätigung/Nachweis', en: 'Deletion confirmation/proof' },
{ de: 'Ausnahme nur bei gesetzlicher Aufbewahrungspflicht', en: 'Exception only for legal retention obligation' },
],
isRequired: true,
severity: 'CRITICAL',
},
{
id: 'art28_3_h',
category: 'AUDIT_RIGHTS',
requirement: { de: 'Audit- und Inspektionsrechte', en: 'Audit and inspection rights' },
article: 'Art. 28 Abs. 3 lit. h DSGVO',
description: {
de: 'Der Auftragsverarbeiter ermöglicht und unterstützt Überprüfungen durch den Verantwortlichen.',
en: 'The processor enables and contributes to audits and inspections by the controller.',
},
checkPoints: [
{ de: 'Auditrecht ausdrücklich vereinbart', en: 'Audit right explicitly agreed' },
{ de: 'Vor-Ort-Inspektionen möglich', en: 'On-site inspections possible' },
{ de: 'Angemessene Vorlaufzeit (max. 30 Tage)', en: 'Reasonable notice period (max. 30 days)' },
{ de: 'Keine unangemessenen Einschränkungen', en: 'No unreasonable restrictions' },
{ de: 'Bereitstellung aller relevanten Informationen', en: 'Provision of all relevant information' },
{ de: 'Akzeptanz unabhängiger Prüfer', en: 'Acceptance of independent auditors' },
],
isRequired: true,
severity: 'HIGH',
},
]
// ==========================================
// INCIDENT RESPONSE CHECKLIST
// ==========================================
export const INCIDENT_CHECKLIST: ChecklistItem[] = [
{
id: 'incident_notification',
category: 'INCIDENT',
requirement: { de: 'Meldung von Datenschutzverletzungen', en: 'Notification of data breaches' },
article: 'Art. 33 Abs. 2 DSGVO',
description: {
de: 'Der Auftragsverarbeiter meldet dem Verantwortlichen unverzüglich jede Datenschutzverletzung.',
en: 'The processor notifies the controller without undue delay of any personal data breach.',
},
checkPoints: [
{ de: 'Meldepflicht vereinbart', en: 'Notification obligation agreed' },
{ de: 'Frist: Unverzüglich (max. 24-48h empfohlen)', en: 'Deadline: Without undue delay (max. 24-48h recommended)' },
{ de: 'Mindestinhalt der Meldung definiert', en: 'Minimum content of notification defined' },
{ de: 'Kontaktstelle für Meldungen', en: 'Contact point for notifications' },
{ de: 'Unterstützung bei Dokumentation', en: 'Assistance with documentation' },
],
isRequired: true,
severity: 'CRITICAL',
},
{
id: 'incident_content',
category: 'INCIDENT',
requirement: { de: 'Inhalt der Incident-Meldung', en: 'Content of incident notification' },
article: 'Art. 33 Abs. 3 DSGVO',
description: {
de: 'Die Meldung muss bestimmte Mindestinformationen enthalten.',
en: 'The notification must contain certain minimum information.',
},
checkPoints: [
{ de: 'Art der Verletzung', en: 'Nature of the breach' },
{ de: 'Betroffene Datenkategorien', en: 'Affected data categories' },
{ de: 'Ungefähre Anzahl betroffener Personen', en: 'Approximate number of affected persons' },
{ de: 'Wahrscheinliche Folgen', en: 'Likely consequences' },
{ de: 'Ergriffene Maßnahmen', en: 'Measures taken' },
],
isRequired: true,
severity: 'HIGH',
},
]
// ==========================================
// THIRD COUNTRY TRANSFER CHECKLIST
// ==========================================
export const TRANSFER_CHECKLIST: ChecklistItem[] = [
{
id: 'transfer_basis',
category: 'TRANSFER',
requirement: { de: 'Rechtsgrundlage für Drittlandtransfer', en: 'Legal basis for third country transfer' },
article: 'Art. 44-49 DSGVO',
description: {
de: 'Drittlandtransfers nur auf Basis geeigneter Garantien.',
en: 'Third country transfers only on the basis of appropriate safeguards.',
},
checkPoints: [
{ de: 'Angemessenheitsbeschluss oder', en: 'Adequacy decision or' },
{ de: 'Standardvertragsklauseln (SCC) oder', en: 'Standard contractual clauses (SCC) or' },
{ de: 'Binding Corporate Rules (BCR) oder', en: 'Binding Corporate Rules (BCR) or' },
{ de: 'Sonstige Ausnahme Art. 49', en: 'Other derogation Art. 49' },
],
isRequired: true,
severity: 'CRITICAL',
},
{
id: 'transfer_scc',
category: 'TRANSFER',
requirement: { de: 'Standardvertragsklauseln', en: 'Standard Contractual Clauses' },
article: 'Art. 46 Abs. 2 lit. c DSGVO',
description: {
de: 'Bei SCC: Verwendung der aktuellen EU-Kommission-Klauseln.',
en: 'With SCC: Use of current EU Commission clauses.',
},
checkPoints: [
{ de: 'SCC 2021 verwendet', en: 'SCC 2021 used' },
{ de: 'Korrektes Modul gewählt', en: 'Correct module selected' },
{ de: 'Anhänge vollständig ausgefüllt', en: 'Annexes completely filled out' },
{ de: 'TIA durchgeführt (bei Risiko)', en: 'TIA conducted (if risk)' },
{ de: 'Zusätzliche Maßnahmen dokumentiert', en: 'Additional measures documented' },
],
isRequired: false,
severity: 'HIGH',
},
{
id: 'transfer_tia',
category: 'TRANSFER',
requirement: { de: 'Transfer Impact Assessment', en: 'Transfer Impact Assessment' },
article: 'Schrems II, EDSA 01/2020',
description: {
de: 'Bewertung der Risiken im Drittland.',
en: 'Assessment of risks in the third country.',
},
checkPoints: [
{ de: 'Rechtslage im Drittland analysiert', en: 'Legal situation in third country analyzed' },
{ de: 'Zugriff durch Behörden bewertet', en: 'Access by authorities assessed' },
{ de: 'Zusätzliche technische Maßnahmen', en: 'Additional technical measures' },
{ de: 'Dokumentation der Bewertung', en: 'Documentation of assessment' },
],
isRequired: true,
severity: 'HIGH',
},
]
// ==========================================
// SLA & LIABILITY CHECKLIST
// ==========================================
export const SLA_LIABILITY_CHECKLIST: ChecklistItem[] = [
{
id: 'sla_availability',
category: 'SLA',
requirement: { de: 'Verfügbarkeit', en: 'Availability' },
article: 'Vertragliche Vereinbarung',
description: {
de: 'Service Level Agreement für Verfügbarkeit des Dienstes.',
en: 'Service Level Agreement for service availability.',
},
checkPoints: [
{ de: 'Verfügbarkeit definiert (z.B. 99,9%)', en: 'Availability defined (e.g., 99.9%)' },
{ de: 'Messzeitraum festgelegt', en: 'Measurement period defined' },
{ de: 'Ausnahmen klar definiert', en: 'Exceptions clearly defined' },
{ de: 'Konsequenzen bei Nichteinhaltung', en: 'Consequences of non-compliance' },
],
isRequired: false,
severity: 'MEDIUM',
},
{
id: 'liability_cap',
category: 'LIABILITY',
requirement: { de: 'Haftungsbegrenzung', en: 'Liability cap' },
article: 'Vertragliche Vereinbarung',
description: {
de: 'Prüfung von Haftungsbegrenzungen und deren Auswirkungen.',
en: 'Review of liability caps and their implications.',
},
checkPoints: [
{ de: 'Haftungshöchstgrenze prüfen', en: 'Check liability cap' },
{ de: 'Ausschluss von Vorsatz/grober Fahrlässigkeit', en: 'Exclusion of intent/gross negligence' },
{ de: 'Freistellungsklauseln (Indemnity)', en: 'Indemnification clauses' },
{ de: 'Versicherungsnachweis', en: 'Insurance proof' },
],
isRequired: false,
severity: 'MEDIUM',
},
]

View File

@@ -1,21 +1,32 @@
/** /**
* Contract Review Checklists * Contract Review Checklists
* *
* DSGVO Art. 28 compliance checklists for contract reviews * DSGVO Art. 28 compliance checklists for contract reviews.
* Checklist data arrays live in checklists-data.ts.
*/ */
import { LocalizedText, FindingCategory } from '../types' import { LocalizedText, FindingCategory } from '../types'
export interface ChecklistItem { // Re-export data arrays and item type
id: string export type { ChecklistItem } from './checklists-data'
category: FindingCategory export {
requirement: LocalizedText AVV_CHECKLIST,
article: string INCIDENT_CHECKLIST,
description: LocalizedText TRANSFER_CHECKLIST,
checkPoints: LocalizedText[] SLA_LIABILITY_CHECKLIST,
isRequired: boolean } from './checklists-data'
severity: 'LOW' | 'MEDIUM' | 'HIGH' | 'CRITICAL'
} import type { ChecklistItem } from './checklists-data'
import {
AVV_CHECKLIST,
INCIDENT_CHECKLIST,
TRANSFER_CHECKLIST,
SLA_LIABILITY_CHECKLIST,
} from './checklists-data'
// ==========================================
// CHECKLIST GROUP TYPE
// ==========================================
export interface ChecklistGroup { export interface ChecklistGroup {
id: string id: string
@@ -24,369 +35,6 @@ export interface ChecklistGroup {
items: ChecklistItem[] items: ChecklistItem[]
} }
// ==========================================
// ART. 28 DSGVO CHECKLIST
// ==========================================
export const AVV_CHECKLIST: ChecklistItem[] = [
// Art. 28 Abs. 3 lit. a - Weisungsgebundenheit
{
id: 'art28_3_a',
category: 'INSTRUCTION',
requirement: {
de: 'Weisungsgebundenheit',
en: 'Instruction binding',
},
article: 'Art. 28 Abs. 3 lit. a DSGVO',
description: {
de: 'Der Auftragsverarbeiter verarbeitet personenbezogene Daten nur auf dokumentierte Weisung des Verantwortlichen.',
en: 'The processor processes personal data only on documented instructions from the controller.',
},
checkPoints: [
{ de: 'Weisungsgebundenheit explizit vereinbart', en: 'Instruction binding explicitly agreed' },
{ de: 'Dokumentierte Weisungen vorgesehen', en: 'Documented instructions provided for' },
{ de: 'Hinweispflicht bei rechtswidrigen Weisungen', en: 'Obligation to notify of unlawful instructions' },
{ de: 'Keine eigenständige Verarbeitung erlaubt', en: 'No independent processing allowed' },
],
isRequired: true,
severity: 'CRITICAL',
},
// Art. 28 Abs. 3 lit. b - Vertraulichkeit
{
id: 'art28_3_b',
category: 'CONFIDENTIALITY',
requirement: {
de: 'Vertraulichkeitsverpflichtung',
en: 'Confidentiality obligation',
},
article: 'Art. 28 Abs. 3 lit. b DSGVO',
description: {
de: 'Der Auftragsverarbeiter gewährleistet, dass sich die zur Verarbeitung befugten Personen zur Vertraulichkeit verpflichtet haben.',
en: 'The processor ensures that persons authorised to process personal data have committed themselves to confidentiality.',
},
checkPoints: [
{ de: 'Vertraulichkeitsverpflichtung der Mitarbeiter', en: 'Confidentiality obligation of employees' },
{ de: 'Gesetzliche Verschwiegenheitspflicht oder', en: 'Statutory confidentiality obligation or' },
{ de: 'Vertragliche Verpflichtung', en: 'Contractual obligation' },
],
isRequired: true,
severity: 'HIGH',
},
// Art. 28 Abs. 3 lit. c - Technische und organisatorische Maßnahmen
{
id: 'art28_3_c',
category: 'TOM',
requirement: {
de: 'Technische und organisatorische Maßnahmen',
en: 'Technical and organisational measures',
},
article: 'Art. 28 Abs. 3 lit. c DSGVO',
description: {
de: 'Der Auftragsverarbeiter trifft alle gemäß Art. 32 erforderlichen Maßnahmen.',
en: 'The processor takes all measures required pursuant to Art. 32.',
},
checkPoints: [
{ de: 'TOM-Anlage vorhanden', en: 'TOM annex present' },
{ de: 'TOM konkret und aktuell', en: 'TOM specific and current' },
{ de: 'Bezug zu Art. 32 DSGVO', en: 'Reference to Art. 32 GDPR' },
{ de: 'Aktualisierungspflicht vereinbart', en: 'Update obligation agreed' },
],
isRequired: true,
severity: 'CRITICAL',
},
// Art. 28 Abs. 3 lit. d - Unterauftragsverarbeitung
{
id: 'art28_3_d',
category: 'SUBPROCESSOR',
requirement: {
de: 'Unterauftragsverarbeitung',
en: 'Sub-processing',
},
article: 'Art. 28 Abs. 3 lit. d DSGVO',
description: {
de: 'Der Auftragsverarbeiter nimmt keinen weiteren Auftragsverarbeiter ohne vorherige Genehmigung in Anspruch.',
en: 'The processor does not engage another processor without prior authorisation.',
},
checkPoints: [
{ de: 'Genehmigungserfordernis (allgemein oder spezifisch)', en: 'Authorisation requirement (general or specific)' },
{ de: 'Bei allgemeiner Genehmigung: Informationspflicht', en: 'With general authorisation: notification obligation' },
{ de: 'Einspruchsrecht des Verantwortlichen', en: 'Right of objection for controller' },
{ de: 'Liste aktueller Unterauftragnehmer', en: 'List of current sub-processors' },
{ de: 'Weitergabe der Pflichten an Unterauftragnehmer', en: 'Transfer of obligations to sub-processors' },
],
isRequired: true,
severity: 'CRITICAL',
},
// Art. 28 Abs. 3 lit. e - Unterstützung bei Betroffenenrechten
{
id: 'art28_3_e',
category: 'DATA_SUBJECT_RIGHTS',
requirement: {
de: 'Unterstützung bei Betroffenenrechten',
en: 'Assistance with data subject rights',
},
article: 'Art. 28 Abs. 3 lit. e DSGVO',
description: {
de: 'Der Auftragsverarbeiter unterstützt den Verantwortlichen bei der Erfüllung der Betroffenenrechte.',
en: 'The processor assists the controller in fulfilling data subject rights obligations.',
},
checkPoints: [
{ de: 'Unterstützungspflicht vereinbart', en: 'Assistance obligation agreed' },
{ de: 'Verfahren zur Weiterleitung von Anfragen', en: 'Procedure for forwarding requests' },
{ de: 'Fristen für Unterstützung', en: 'Deadlines for assistance' },
{ de: 'Kostenregelung', en: 'Cost arrangement' },
],
isRequired: true,
severity: 'HIGH',
},
// Art. 28 Abs. 3 lit. f - Unterstützung bei DSFA
{
id: 'art28_3_f',
category: 'GENERAL',
requirement: {
de: 'Unterstützung bei DSFA und Konsultation',
en: 'Assistance with DPIA and consultation',
},
article: 'Art. 28 Abs. 3 lit. f DSGVO',
description: {
de: 'Der Auftragsverarbeiter unterstützt den Verantwortlichen bei der Einhaltung der Pflichten gemäß Art. 32-36.',
en: 'The processor assists the controller in ensuring compliance with obligations pursuant to Art. 32-36.',
},
checkPoints: [
{ de: 'Unterstützung bei DSFA', en: 'Assistance with DPIA' },
{ de: 'Unterstützung bei vorheriger Konsultation', en: 'Assistance with prior consultation' },
{ de: 'Bereitstellung notwendiger Informationen', en: 'Provision of necessary information' },
],
isRequired: true,
severity: 'MEDIUM',
},
// Art. 28 Abs. 3 lit. g - Löschung/Rückgabe
{
id: 'art28_3_g',
category: 'DELETION',
requirement: {
de: 'Löschung/Rückgabe nach Vertragsende',
en: 'Deletion/return after contract end',
},
article: 'Art. 28 Abs. 3 lit. g DSGVO',
description: {
de: 'Nach Abschluss der Verarbeitung werden alle personenbezogenen Daten gelöscht oder zurückgegeben.',
en: 'After the end of processing, all personal data is deleted or returned.',
},
checkPoints: [
{ de: 'Löschung oder Rückgabe nach Wahl des Verantwortlichen', en: 'Deletion or return at controller choice' },
{ de: 'Frist für Löschung/Rückgabe (max. 30 Tage empfohlen)', en: 'Deadline for deletion/return (max. 30 days recommended)' },
{ de: 'Löschung auch bei Unterauftragnehmern', en: 'Deletion also at sub-processors' },
{ de: 'Löschbestätigung/Nachweis', en: 'Deletion confirmation/proof' },
{ de: 'Ausnahme nur bei gesetzlicher Aufbewahrungspflicht', en: 'Exception only for legal retention obligation' },
],
isRequired: true,
severity: 'CRITICAL',
},
// Art. 28 Abs. 3 lit. h - Audit/Inspektion
{
id: 'art28_3_h',
category: 'AUDIT_RIGHTS',
requirement: {
de: 'Audit- und Inspektionsrechte',
en: 'Audit and inspection rights',
},
article: 'Art. 28 Abs. 3 lit. h DSGVO',
description: {
de: 'Der Auftragsverarbeiter ermöglicht und unterstützt Überprüfungen durch den Verantwortlichen.',
en: 'The processor enables and contributes to audits and inspections by the controller.',
},
checkPoints: [
{ de: 'Auditrecht ausdrücklich vereinbart', en: 'Audit right explicitly agreed' },
{ de: 'Vor-Ort-Inspektionen möglich', en: 'On-site inspections possible' },
{ de: 'Angemessene Vorlaufzeit (max. 30 Tage)', en: 'Reasonable notice period (max. 30 days)' },
{ de: 'Keine unangemessenen Einschränkungen', en: 'No unreasonable restrictions' },
{ de: 'Bereitstellung aller relevanten Informationen', en: 'Provision of all relevant information' },
{ de: 'Akzeptanz unabhängiger Prüfer', en: 'Acceptance of independent auditors' },
],
isRequired: true,
severity: 'HIGH',
},
]
// ==========================================
// INCIDENT RESPONSE CHECKLIST
// ==========================================
export const INCIDENT_CHECKLIST: ChecklistItem[] = [
{
id: 'incident_notification',
category: 'INCIDENT',
requirement: {
de: 'Meldung von Datenschutzverletzungen',
en: 'Notification of data breaches',
},
article: 'Art. 33 Abs. 2 DSGVO',
description: {
de: 'Der Auftragsverarbeiter meldet dem Verantwortlichen unverzüglich jede Datenschutzverletzung.',
en: 'The processor notifies the controller without undue delay of any personal data breach.',
},
checkPoints: [
{ de: 'Meldepflicht vereinbart', en: 'Notification obligation agreed' },
{ de: 'Frist: Unverzüglich (max. 24-48h empfohlen)', en: 'Deadline: Without undue delay (max. 24-48h recommended)' },
{ de: 'Mindestinhalt der Meldung definiert', en: 'Minimum content of notification defined' },
{ de: 'Kontaktstelle für Meldungen', en: 'Contact point for notifications' },
{ de: 'Unterstützung bei Dokumentation', en: 'Assistance with documentation' },
],
isRequired: true,
severity: 'CRITICAL',
},
{
id: 'incident_content',
category: 'INCIDENT',
requirement: {
de: 'Inhalt der Incident-Meldung',
en: 'Content of incident notification',
},
article: 'Art. 33 Abs. 3 DSGVO',
description: {
de: 'Die Meldung muss bestimmte Mindestinformationen enthalten.',
en: 'The notification must contain certain minimum information.',
},
checkPoints: [
{ de: 'Art der Verletzung', en: 'Nature of the breach' },
{ de: 'Betroffene Datenkategorien', en: 'Affected data categories' },
{ de: 'Ungefähre Anzahl betroffener Personen', en: 'Approximate number of affected persons' },
{ de: 'Wahrscheinliche Folgen', en: 'Likely consequences' },
{ de: 'Ergriffene Maßnahmen', en: 'Measures taken' },
],
isRequired: true,
severity: 'HIGH',
},
]
// ==========================================
// THIRD COUNTRY TRANSFER CHECKLIST
// ==========================================
export const TRANSFER_CHECKLIST: ChecklistItem[] = [
{
id: 'transfer_basis',
category: 'TRANSFER',
requirement: {
de: 'Rechtsgrundlage für Drittlandtransfer',
en: 'Legal basis for third country transfer',
},
article: 'Art. 44-49 DSGVO',
description: {
de: 'Drittlandtransfers nur auf Basis geeigneter Garantien.',
en: 'Third country transfers only on the basis of appropriate safeguards.',
},
checkPoints: [
{ de: 'Angemessenheitsbeschluss oder', en: 'Adequacy decision or' },
{ de: 'Standardvertragsklauseln (SCC) oder', en: 'Standard contractual clauses (SCC) or' },
{ de: 'Binding Corporate Rules (BCR) oder', en: 'Binding Corporate Rules (BCR) or' },
{ de: 'Sonstige Ausnahme Art. 49', en: 'Other derogation Art. 49' },
],
isRequired: true,
severity: 'CRITICAL',
},
{
id: 'transfer_scc',
category: 'TRANSFER',
requirement: {
de: 'Standardvertragsklauseln',
en: 'Standard Contractual Clauses',
},
article: 'Art. 46 Abs. 2 lit. c DSGVO',
description: {
de: 'Bei SCC: Verwendung der aktuellen EU-Kommission-Klauseln.',
en: 'With SCC: Use of current EU Commission clauses.',
},
checkPoints: [
{ de: 'SCC 2021 verwendet', en: 'SCC 2021 used' },
{ de: 'Korrektes Modul gewählt', en: 'Correct module selected' },
{ de: 'Anhänge vollständig ausgefüllt', en: 'Annexes completely filled out' },
{ de: 'TIA durchgeführt (bei Risiko)', en: 'TIA conducted (if risk)' },
{ de: 'Zusätzliche Maßnahmen dokumentiert', en: 'Additional measures documented' },
],
isRequired: false,
severity: 'HIGH',
},
{
id: 'transfer_tia',
category: 'TRANSFER',
requirement: {
de: 'Transfer Impact Assessment',
en: 'Transfer Impact Assessment',
},
article: 'Schrems II, EDSA 01/2020',
description: {
de: 'Bewertung der Risiken im Drittland.',
en: 'Assessment of risks in the third country.',
},
checkPoints: [
{ de: 'Rechtslage im Drittland analysiert', en: 'Legal situation in third country analyzed' },
{ de: 'Zugriff durch Behörden bewertet', en: 'Access by authorities assessed' },
{ de: 'Zusätzliche technische Maßnahmen', en: 'Additional technical measures' },
{ de: 'Dokumentation der Bewertung', en: 'Documentation of assessment' },
],
isRequired: true,
severity: 'HIGH',
},
]
// ==========================================
// SLA & LIABILITY CHECKLIST
// ==========================================
export const SLA_LIABILITY_CHECKLIST: ChecklistItem[] = [
{
id: 'sla_availability',
category: 'SLA',
requirement: {
de: 'Verfügbarkeit',
en: 'Availability',
},
article: 'Vertragliche Vereinbarung',
description: {
de: 'Service Level Agreement für Verfügbarkeit des Dienstes.',
en: 'Service Level Agreement for service availability.',
},
checkPoints: [
{ de: 'Verfügbarkeit definiert (z.B. 99,9%)', en: 'Availability defined (e.g., 99.9%)' },
{ de: 'Messzeitraum festgelegt', en: 'Measurement period defined' },
{ de: 'Ausnahmen klar definiert', en: 'Exceptions clearly defined' },
{ de: 'Konsequenzen bei Nichteinhaltung', en: 'Consequences of non-compliance' },
],
isRequired: false,
severity: 'MEDIUM',
},
{
id: 'liability_cap',
category: 'LIABILITY',
requirement: {
de: 'Haftungsbegrenzung',
en: 'Liability cap',
},
article: 'Vertragliche Vereinbarung',
description: {
de: 'Prüfung von Haftungsbegrenzungen und deren Auswirkungen.',
en: 'Review of liability caps and their implications.',
},
checkPoints: [
{ de: 'Haftungshöchstgrenze prüfen', en: 'Check liability cap' },
{ de: 'Ausschluss von Vorsatz/grober Fahrlässigkeit', en: 'Exclusion of intent/gross negligence' },
{ de: 'Freistellungsklauseln (Indemnity)', en: 'Indemnification clauses' },
{ de: 'Versicherungsnachweis', en: 'Insurance proof' },
],
isRequired: false,
severity: 'MEDIUM',
},
]
// ========================================== // ==========================================
// GROUPED CHECKLISTS // GROUPED CHECKLISTS
// ========================================== // ==========================================

View File

@@ -0,0 +1,331 @@
/**
* Finding Templates — pre-defined templates for contract reviews
*
* Barrel-split from findings.ts to stay under 500 LOC.
* Do NOT import this file directly; use findings.ts instead.
*/
import { FindingType, FindingCategory, FindingSeverity, LocalizedText } from '../types'
export interface FindingTemplate {
id: string
type: FindingType
category: FindingCategory
severity: FindingSeverity
title: LocalizedText
description: LocalizedText
recommendation: LocalizedText
affectedRequirement: string
triggerControls: string[]
}
export const FINDING_TEMPLATES: FindingTemplate[] = [
// AVV_CONTENT - Weisungsgebundenheit
{
id: 'tpl-avv-instruction-missing',
type: 'GAP',
category: 'AVV_CONTENT',
severity: 'CRITICAL',
title: { de: 'Weisungsgebundenheit fehlt', en: 'Instruction binding missing' },
description: {
de: 'Der Vertrag enthält keine Regelung zur Weisungsgebundenheit des Auftragsverarbeiters.',
en: 'The contract does not contain a provision on the processor\'s instruction binding.',
},
recommendation: {
de: 'Ergänzen Sie eine Klausel, die den Auftragsverarbeiter verpflichtet, personenbezogene Daten nur auf dokumentierte Weisung des Verantwortlichen zu verarbeiten.',
en: 'Add a clause obligating the processor to process personal data only on documented instructions from the controller.',
},
affectedRequirement: 'Art. 28 Abs. 3 lit. a DSGVO',
triggerControls: ['VND-CON-01'],
},
{
id: 'tpl-avv-instruction-weak',
type: 'RISK',
category: 'AVV_CONTENT',
severity: 'MEDIUM',
title: { de: 'Weisungsgebundenheit unvollständig', en: 'Instruction binding incomplete' },
description: {
de: 'Die Regelung zur Weisungsgebundenheit ist vorhanden, aber es fehlt die Hinweispflicht bei rechtswidrigen Weisungen.',
en: 'The instruction binding provision exists, but the obligation to notify of unlawful instructions is missing.',
},
recommendation: {
de: 'Ergänzen Sie eine Pflicht des Auftragsverarbeiters, den Verantwortlichen unverzüglich zu informieren, wenn eine Weisung nach seiner Auffassung gegen Datenschutzrecht verstößt.',
en: 'Add an obligation for the processor to immediately inform the controller if an instruction, in their opinion, violates data protection law.',
},
affectedRequirement: 'Art. 28 Abs. 3 lit. a DSGVO',
triggerControls: ['VND-CON-01'],
},
// AVV_CONTENT - TOM
{
id: 'tpl-avv-tom-missing',
type: 'GAP',
category: 'TOM',
severity: 'CRITICAL',
title: { de: 'TOM-Anlage fehlt', en: 'TOM annex missing' },
description: {
de: 'Der Vertrag enthält keine technischen und organisatorischen Maßnahmen (TOM) als Anlage.',
en: 'The contract does not contain technical and organizational measures (TOM) as an annex.',
},
recommendation: {
de: 'Fordern Sie eine detaillierte TOM-Anlage an, die die Maßnahmen gemäß Art. 32 DSGVO beschreibt.',
en: 'Request a detailed TOM annex describing the measures according to Art. 32 GDPR.',
},
affectedRequirement: 'Art. 28 Abs. 3 lit. c DSGVO',
triggerControls: ['VND-TOM-01'],
},
{
id: 'tpl-avv-tom-generic',
type: 'RISK',
category: 'TOM',
severity: 'MEDIUM',
title: { de: 'TOM zu unspezifisch', en: 'TOM too generic' },
description: {
de: 'Die TOM-Anlage enthält nur allgemeine Aussagen ohne konkrete Maßnahmen.',
en: 'The TOM annex contains only general statements without specific measures.',
},
recommendation: {
de: 'Fordern Sie eine konkretere Beschreibung der Maßnahmen mit Bezug zum spezifischen Verarbeitungskontext an.',
en: 'Request a more specific description of measures with reference to the specific processing context.',
},
affectedRequirement: 'Art. 28 Abs. 3 lit. c DSGVO',
triggerControls: ['VND-TOM-01'],
},
// SUBPROCESSOR
{
id: 'tpl-subprocessor-no-approval',
type: 'GAP',
category: 'SUBPROCESSOR',
severity: 'CRITICAL',
title: { de: 'Keine Genehmigungspflicht für Unterauftragnehmer', en: 'No approval requirement for sub-processors' },
description: {
de: 'Der Vertrag regelt nicht, ob und wie der Einsatz von Unterauftragnehmern zu genehmigen ist.',
en: 'The contract does not regulate whether and how the use of sub-processors must be approved.',
},
recommendation: {
de: 'Ergänzen Sie eine Klausel, die entweder eine spezifische oder allgemeine Genehmigung für Unterauftragnehmer vorsieht, einschließlich Informations- und Einspruchsrechten.',
en: 'Add a clause providing either specific or general authorization for sub-processors, including information and objection rights.',
},
affectedRequirement: 'Art. 28 Abs. 3 lit. d DSGVO',
triggerControls: ['VND-SUB-01'],
},
{
id: 'tpl-subprocessor-no-list',
type: 'RISK',
category: 'SUBPROCESSOR',
severity: 'HIGH',
title: { de: 'Keine Liste der Unterauftragnehmer', en: 'No list of sub-processors' },
description: {
de: 'Es liegt keine aktuelle Liste der eingesetzten Unterauftragnehmer vor.',
en: 'There is no current list of sub-processors used.',
},
recommendation: {
de: 'Fordern Sie eine vollständige Liste aller Unterauftragnehmer mit Name, Sitz und Verarbeitungszweck an.',
en: 'Request a complete list of all sub-processors with name, location, and processing purpose.',
},
affectedRequirement: 'Art. 28 Abs. 3 lit. d DSGVO',
triggerControls: ['VND-SUB-02'],
},
// INCIDENT
{
id: 'tpl-incident-no-notification',
type: 'GAP',
category: 'INCIDENT',
severity: 'CRITICAL',
title: { de: 'Keine Meldepflicht bei Datenpannen', en: 'No notification obligation for data breaches' },
description: {
de: 'Der Vertrag enthält keine Regelung zur Meldung von Datenschutzverletzungen.',
en: 'The contract does not contain a provision for reporting data breaches.',
},
recommendation: {
de: 'Ergänzen Sie eine Klausel, die den Auftragsverarbeiter verpflichtet, Datenschutzverletzungen unverzüglich (innerhalb von 24-48h) zu melden.',
en: 'Add a clause obligating the processor to report data breaches without undue delay (within 24-48h).',
},
affectedRequirement: 'Art. 33 Abs. 2 DSGVO',
triggerControls: ['VND-INC-01'],
},
{
id: 'tpl-incident-long-deadline',
type: 'RISK',
category: 'INCIDENT',
severity: 'HIGH',
title: { de: 'Zu lange Meldefrist', en: 'Notification deadline too long' },
description: {
de: 'Die vereinbarte Meldefrist für Datenschutzverletzungen ist zu lang (>72h), um die eigene Meldepflicht einhalten zu können.',
en: 'The agreed notification deadline for data breaches is too long (>72h) to meet own notification obligations.',
},
recommendation: {
de: 'Verkürzen Sie die Meldefrist auf maximal 24-48 Stunden, um ausreichend Zeit für die eigene Meldung an die Aufsichtsbehörde zu haben.',
en: 'Reduce the notification deadline to a maximum of 24-48 hours to have sufficient time for own notification to the supervisory authority.',
},
affectedRequirement: 'Art. 33 DSGVO',
triggerControls: ['VND-INC-01'],
},
// AUDIT_RIGHTS
{
id: 'tpl-audit-no-right',
type: 'GAP',
category: 'AUDIT_RIGHTS',
severity: 'HIGH',
title: { de: 'Kein Auditrecht vereinbart', en: 'No audit right agreed' },
description: {
de: 'Der Vertrag enthält kein Recht des Verantwortlichen auf Prüfungen und Inspektionen.',
en: 'The contract does not contain a right of the controller to audits and inspections.',
},
recommendation: {
de: 'Ergänzen Sie ein ausdrückliches Recht auf Vor-Ort-Inspektionen und die Einsicht in relevante Unterlagen.',
en: 'Add an explicit right to on-site inspections and access to relevant documents.',
},
affectedRequirement: 'Art. 28 Abs. 3 lit. h DSGVO',
triggerControls: ['VND-AUD-01'],
},
{
id: 'tpl-audit-restricted',
type: 'RISK',
category: 'AUDIT_RIGHTS',
severity: 'MEDIUM',
title: { de: 'Auditrecht eingeschränkt', en: 'Audit right restricted' },
description: {
de: 'Das Auditrecht ist durch unangemessene Einschränkungen (z.B. sehr lange Vorlaufzeit, Ausschluss von Vor-Ort-Inspektionen) begrenzt.',
en: 'The audit right is limited by unreasonable restrictions (e.g., very long notice period, exclusion of on-site inspections).',
},
recommendation: {
de: 'Verhandeln Sie angemessene Bedingungen für Audits (max. 30 Tage Vorlaufzeit, Möglichkeit zur Vor-Ort-Inspektion).',
en: 'Negotiate reasonable audit conditions (max. 30 days notice, possibility for on-site inspection).',
},
affectedRequirement: 'Art. 28 Abs. 3 lit. h DSGVO',
triggerControls: ['VND-AUD-01'],
},
// DELETION
{
id: 'tpl-deletion-no-clause',
type: 'GAP',
category: 'DELETION',
severity: 'CRITICAL',
title: { de: 'Keine Lösch-/Rückgaberegelung', en: 'No deletion/return clause' },
description: {
de: 'Der Vertrag regelt nicht, was mit den Daten nach Vertragsende geschieht.',
en: 'The contract does not regulate what happens to the data after contract termination.',
},
recommendation: {
de: 'Ergänzen Sie eine Klausel zur Löschung oder Rückgabe aller personenbezogenen Daten nach Vertragsende (max. 30 Tage).',
en: 'Add a clause for deletion or return of all personal data after contract end (max. 30 days).',
},
affectedRequirement: 'Art. 28 Abs. 3 lit. g DSGVO',
triggerControls: ['VND-DEL-01'],
},
{
id: 'tpl-deletion-no-confirmation',
type: 'RISK',
category: 'DELETION',
severity: 'MEDIUM',
title: { de: 'Keine Löschbestätigung vorgesehen', en: 'No deletion confirmation provided' },
description: {
de: 'Der Vertrag sieht keine Bestätigung der Löschung durch den Auftragsverarbeiter vor.',
en: 'The contract does not provide for confirmation of deletion by the processor.',
},
recommendation: {
de: 'Ergänzen Sie eine Pflicht zur schriftlichen Bestätigung der vollständigen Löschung.',
en: 'Add an obligation for written confirmation of complete deletion.',
},
affectedRequirement: 'Art. 28 Abs. 3 lit. g DSGVO',
triggerControls: ['VND-DEL-01'],
},
// TRANSFER
{
id: 'tpl-transfer-no-basis',
type: 'GAP',
category: 'TRANSFER',
severity: 'CRITICAL',
title: { de: 'Drittlandtransfer ohne Rechtsgrundlage', en: 'Third country transfer without legal basis' },
description: {
de: 'Der Vertrag erlaubt oder impliziert Transfers in Drittländer ohne geeignete Garantien.',
en: 'The contract allows or implies transfers to third countries without appropriate safeguards.',
},
recommendation: {
de: 'Vereinbaren Sie geeignete Garantien (SCC, BCR) oder beschränken Sie die Verarbeitung auf EU/EWR.',
en: 'Agree on appropriate safeguards (SCC, BCR) or restrict processing to EU/EEA.',
},
affectedRequirement: 'Art. 44-49 DSGVO',
triggerControls: ['VND-TRF-01'],
},
{
id: 'tpl-transfer-old-scc',
type: 'RISK',
category: 'TRANSFER',
severity: 'HIGH',
title: { de: 'Veraltete Standardvertragsklauseln', en: 'Outdated Standard Contractual Clauses' },
description: {
de: 'Der Vertrag verwendet die alten SCC (vor 2021), die nicht mehr gültig sind.',
en: 'The contract uses old SCC (pre-2021) that are no longer valid.',
},
recommendation: {
de: 'Aktualisieren Sie auf die SCC 2021 (Durchführungsbeschluss (EU) 2021/914).',
en: 'Update to SCC 2021 (Implementing Decision (EU) 2021/914).',
},
affectedRequirement: 'Art. 46 Abs. 2 lit. c DSGVO',
triggerControls: ['VND-TRF-02'],
},
// LIABILITY
{
id: 'tpl-liability-excessive-cap',
type: 'RISK',
category: 'LIABILITY',
severity: 'MEDIUM',
title: { de: 'Unangemessene Haftungsbegrenzung', en: 'Inappropriate liability cap' },
description: {
de: 'Die Haftungsbegrenzung ist sehr niedrig und könnte bei Datenschutzverletzungen problematisch sein.',
en: 'The liability cap is very low and could be problematic in case of data protection violations.',
},
recommendation: {
de: 'Prüfen Sie, ob die Haftungsbegrenzung angemessen ist. Erwägen Sie eine Ausnahme für Datenschutzverletzungen oder eine höhere Obergrenze.',
en: 'Check if the liability cap is appropriate. Consider an exception for data protection violations or a higher limit.',
},
affectedRequirement: 'Vertragliche Vereinbarung',
triggerControls: [],
},
// DATA_SUBJECT_RIGHTS
{
id: 'tpl-dsr-no-support',
type: 'GAP',
category: 'DATA_SUBJECT_RIGHTS',
severity: 'HIGH',
title: { de: 'Keine Unterstützung bei Betroffenenrechten', en: 'No support for data subject rights' },
description: {
de: 'Der Vertrag enthält keine Regelung zur Unterstützung bei der Erfüllung von Betroffenenrechten.',
en: 'The contract does not contain a provision for support in fulfilling data subject rights.',
},
recommendation: {
de: 'Ergänzen Sie eine Klausel zur Unterstützung bei Auskunft, Berichtigung, Löschung und anderen Betroffenenrechten.',
en: 'Add a clause for support with access, rectification, deletion, and other data subject rights.',
},
affectedRequirement: 'Art. 28 Abs. 3 lit. e DSGVO',
triggerControls: ['VND-DSR-01'],
},
// CONFIDENTIALITY
{
id: 'tpl-confidentiality-missing',
type: 'GAP',
category: 'CONFIDENTIALITY',
severity: 'HIGH',
title: { de: 'Keine Vertraulichkeitsverpflichtung', en: 'No confidentiality obligation' },
description: {
de: 'Der Vertrag enthält keine Verpflichtung zur Vertraulichkeit der Mitarbeiter.',
en: 'The contract does not contain an obligation for employee confidentiality.',
},
recommendation: {
de: 'Ergänzen Sie eine Klausel, die die Verpflichtung der Mitarbeiter zur Vertraulichkeit sicherstellt.',
en: 'Add a clause ensuring the obligation of employees to confidentiality.',
},
affectedRequirement: 'Art. 28 Abs. 3 lit. b DSGVO',
triggerControls: ['VND-CON-02'],
},
]

View File

@@ -1,7 +1,8 @@
/** /**
* Finding Types and Templates * Finding Types and Templates
* *
* Pre-defined finding templates for contract reviews * Pre-defined finding templates for contract reviews.
* Barrel re-export — FINDING_TEMPLATES lives in findings-templates.ts.
*/ */
import { import {
@@ -11,18 +12,6 @@ import {
LocalizedText, LocalizedText,
} from '../types' } from '../types'
export interface FindingTemplate {
id: string
type: FindingType
category: FindingCategory
severity: FindingSeverity
title: LocalizedText
description: LocalizedText
recommendation: LocalizedText
affectedRequirement: string
triggerControls: string[]
}
// ========================================== // ==========================================
// FINDING SEVERITY DEFINITIONS // FINDING SEVERITY DEFINITIONS
// ========================================== // ==========================================
@@ -126,371 +115,11 @@ export const FINDING_TYPE_DEFINITIONS: Record<FindingType, {
}, },
} }
// ========================================== import { FINDING_TEMPLATES } from './findings-templates'
// FINDING TEMPLATES import type { FindingTemplate } from './findings-templates'
// ==========================================
export const FINDING_TEMPLATES: FindingTemplate[] = [ export type { FindingTemplate }
// AVV_CONTENT - Weisungsgebundenheit export { FINDING_TEMPLATES }
{
id: 'tpl-avv-instruction-missing',
type: 'GAP',
category: 'AVV_CONTENT',
severity: 'CRITICAL',
title: {
de: 'Weisungsgebundenheit fehlt',
en: 'Instruction binding missing',
},
description: {
de: 'Der Vertrag enthält keine Regelung zur Weisungsgebundenheit des Auftragsverarbeiters.',
en: 'The contract does not contain a provision on the processor\'s instruction binding.',
},
recommendation: {
de: 'Ergänzen Sie eine Klausel, die den Auftragsverarbeiter verpflichtet, personenbezogene Daten nur auf dokumentierte Weisung des Verantwortlichen zu verarbeiten.',
en: 'Add a clause obligating the processor to process personal data only on documented instructions from the controller.',
},
affectedRequirement: 'Art. 28 Abs. 3 lit. a DSGVO',
triggerControls: ['VND-CON-01'],
},
{
id: 'tpl-avv-instruction-weak',
type: 'RISK',
category: 'AVV_CONTENT',
severity: 'MEDIUM',
title: {
de: 'Weisungsgebundenheit unvollständig',
en: 'Instruction binding incomplete',
},
description: {
de: 'Die Regelung zur Weisungsgebundenheit ist vorhanden, aber es fehlt die Hinweispflicht bei rechtswidrigen Weisungen.',
en: 'The instruction binding provision exists, but the obligation to notify of unlawful instructions is missing.',
},
recommendation: {
de: 'Ergänzen Sie eine Pflicht des Auftragsverarbeiters, den Verantwortlichen unverzüglich zu informieren, wenn eine Weisung nach seiner Auffassung gegen Datenschutzrecht verstößt.',
en: 'Add an obligation for the processor to immediately inform the controller if an instruction, in their opinion, violates data protection law.',
},
affectedRequirement: 'Art. 28 Abs. 3 lit. a DSGVO',
triggerControls: ['VND-CON-01'],
},
// AVV_CONTENT - TOM
{
id: 'tpl-avv-tom-missing',
type: 'GAP',
category: 'TOM',
severity: 'CRITICAL',
title: {
de: 'TOM-Anlage fehlt',
en: 'TOM annex missing',
},
description: {
de: 'Der Vertrag enthält keine technischen und organisatorischen Maßnahmen (TOM) als Anlage.',
en: 'The contract does not contain technical and organizational measures (TOM) as an annex.',
},
recommendation: {
de: 'Fordern Sie eine detaillierte TOM-Anlage an, die die Maßnahmen gemäß Art. 32 DSGVO beschreibt.',
en: 'Request a detailed TOM annex describing the measures according to Art. 32 GDPR.',
},
affectedRequirement: 'Art. 28 Abs. 3 lit. c DSGVO',
triggerControls: ['VND-TOM-01'],
},
{
id: 'tpl-avv-tom-generic',
type: 'RISK',
category: 'TOM',
severity: 'MEDIUM',
title: {
de: 'TOM zu unspezifisch',
en: 'TOM too generic',
},
description: {
de: 'Die TOM-Anlage enthält nur allgemeine Aussagen ohne konkrete Maßnahmen.',
en: 'The TOM annex contains only general statements without specific measures.',
},
recommendation: {
de: 'Fordern Sie eine konkretere Beschreibung der Maßnahmen mit Bezug zum spezifischen Verarbeitungskontext an.',
en: 'Request a more specific description of measures with reference to the specific processing context.',
},
affectedRequirement: 'Art. 28 Abs. 3 lit. c DSGVO',
triggerControls: ['VND-TOM-01'],
},
// SUBPROCESSOR
{
id: 'tpl-subprocessor-no-approval',
type: 'GAP',
category: 'SUBPROCESSOR',
severity: 'CRITICAL',
title: {
de: 'Keine Genehmigungspflicht für Unterauftragnehmer',
en: 'No approval requirement for sub-processors',
},
description: {
de: 'Der Vertrag regelt nicht, ob und wie der Einsatz von Unterauftragnehmern zu genehmigen ist.',
en: 'The contract does not regulate whether and how the use of sub-processors must be approved.',
},
recommendation: {
de: 'Ergänzen Sie eine Klausel, die entweder eine spezifische oder allgemeine Genehmigung für Unterauftragnehmer vorsieht, einschließlich Informations- und Einspruchsrechten.',
en: 'Add a clause providing either specific or general authorization for sub-processors, including information and objection rights.',
},
affectedRequirement: 'Art. 28 Abs. 3 lit. d DSGVO',
triggerControls: ['VND-SUB-01'],
},
{
id: 'tpl-subprocessor-no-list',
type: 'RISK',
category: 'SUBPROCESSOR',
severity: 'HIGH',
title: {
de: 'Keine Liste der Unterauftragnehmer',
en: 'No list of sub-processors',
},
description: {
de: 'Es liegt keine aktuelle Liste der eingesetzten Unterauftragnehmer vor.',
en: 'There is no current list of sub-processors used.',
},
recommendation: {
de: 'Fordern Sie eine vollständige Liste aller Unterauftragnehmer mit Name, Sitz und Verarbeitungszweck an.',
en: 'Request a complete list of all sub-processors with name, location, and processing purpose.',
},
affectedRequirement: 'Art. 28 Abs. 3 lit. d DSGVO',
triggerControls: ['VND-SUB-02'],
},
// INCIDENT
{
id: 'tpl-incident-no-notification',
type: 'GAP',
category: 'INCIDENT',
severity: 'CRITICAL',
title: {
de: 'Keine Meldepflicht bei Datenpannen',
en: 'No notification obligation for data breaches',
},
description: {
de: 'Der Vertrag enthält keine Regelung zur Meldung von Datenschutzverletzungen.',
en: 'The contract does not contain a provision for reporting data breaches.',
},
recommendation: {
de: 'Ergänzen Sie eine Klausel, die den Auftragsverarbeiter verpflichtet, Datenschutzverletzungen unverzüglich (innerhalb von 24-48h) zu melden.',
en: 'Add a clause obligating the processor to report data breaches without undue delay (within 24-48h).',
},
affectedRequirement: 'Art. 33 Abs. 2 DSGVO',
triggerControls: ['VND-INC-01'],
},
{
id: 'tpl-incident-long-deadline',
type: 'RISK',
category: 'INCIDENT',
severity: 'HIGH',
title: {
de: 'Zu lange Meldefrist',
en: 'Notification deadline too long',
},
description: {
de: 'Die vereinbarte Meldefrist für Datenschutzverletzungen ist zu lang (>72h), um die eigene Meldepflicht einhalten zu können.',
en: 'The agreed notification deadline for data breaches is too long (>72h) to meet own notification obligations.',
},
recommendation: {
de: 'Verkürzen Sie die Meldefrist auf maximal 24-48 Stunden, um ausreichend Zeit für die eigene Meldung an die Aufsichtsbehörde zu haben.',
en: 'Reduce the notification deadline to a maximum of 24-48 hours to have sufficient time for own notification to the supervisory authority.',
},
affectedRequirement: 'Art. 33 DSGVO',
triggerControls: ['VND-INC-01'],
},
// AUDIT_RIGHTS
{
id: 'tpl-audit-no-right',
type: 'GAP',
category: 'AUDIT_RIGHTS',
severity: 'HIGH',
title: {
de: 'Kein Auditrecht vereinbart',
en: 'No audit right agreed',
},
description: {
de: 'Der Vertrag enthält kein Recht des Verantwortlichen auf Prüfungen und Inspektionen.',
en: 'The contract does not contain a right of the controller to audits and inspections.',
},
recommendation: {
de: 'Ergänzen Sie ein ausdrückliches Recht auf Vor-Ort-Inspektionen und die Einsicht in relevante Unterlagen.',
en: 'Add an explicit right to on-site inspections and access to relevant documents.',
},
affectedRequirement: 'Art. 28 Abs. 3 lit. h DSGVO',
triggerControls: ['VND-AUD-01'],
},
{
id: 'tpl-audit-restricted',
type: 'RISK',
category: 'AUDIT_RIGHTS',
severity: 'MEDIUM',
title: {
de: 'Auditrecht eingeschränkt',
en: 'Audit right restricted',
},
description: {
de: 'Das Auditrecht ist durch unangemessene Einschränkungen (z.B. sehr lange Vorlaufzeit, Ausschluss von Vor-Ort-Inspektionen) begrenzt.',
en: 'The audit right is limited by unreasonable restrictions (e.g., very long notice period, exclusion of on-site inspections).',
},
recommendation: {
de: 'Verhandeln Sie angemessene Bedingungen für Audits (max. 30 Tage Vorlaufzeit, Möglichkeit zur Vor-Ort-Inspektion).',
en: 'Negotiate reasonable audit conditions (max. 30 days notice, possibility for on-site inspection).',
},
affectedRequirement: 'Art. 28 Abs. 3 lit. h DSGVO',
triggerControls: ['VND-AUD-01'],
},
// DELETION
{
id: 'tpl-deletion-no-clause',
type: 'GAP',
category: 'DELETION',
severity: 'CRITICAL',
title: {
de: 'Keine Lösch-/Rückgaberegelung',
en: 'No deletion/return clause',
},
description: {
de: 'Der Vertrag regelt nicht, was mit den Daten nach Vertragsende geschieht.',
en: 'The contract does not regulate what happens to the data after contract termination.',
},
recommendation: {
de: 'Ergänzen Sie eine Klausel zur Löschung oder Rückgabe aller personenbezogenen Daten nach Vertragsende (max. 30 Tage).',
en: 'Add a clause for deletion or return of all personal data after contract end (max. 30 days).',
},
affectedRequirement: 'Art. 28 Abs. 3 lit. g DSGVO',
triggerControls: ['VND-DEL-01'],
},
{
id: 'tpl-deletion-no-confirmation',
type: 'RISK',
category: 'DELETION',
severity: 'MEDIUM',
title: {
de: 'Keine Löschbestätigung vorgesehen',
en: 'No deletion confirmation provided',
},
description: {
de: 'Der Vertrag sieht keine Bestätigung der Löschung durch den Auftragsverarbeiter vor.',
en: 'The contract does not provide for confirmation of deletion by the processor.',
},
recommendation: {
de: 'Ergänzen Sie eine Pflicht zur schriftlichen Bestätigung der vollständigen Löschung.',
en: 'Add an obligation for written confirmation of complete deletion.',
},
affectedRequirement: 'Art. 28 Abs. 3 lit. g DSGVO',
triggerControls: ['VND-DEL-01'],
},
// TRANSFER
{
id: 'tpl-transfer-no-basis',
type: 'GAP',
category: 'TRANSFER',
severity: 'CRITICAL',
title: {
de: 'Drittlandtransfer ohne Rechtsgrundlage',
en: 'Third country transfer without legal basis',
},
description: {
de: 'Der Vertrag erlaubt oder impliziert Transfers in Drittländer ohne geeignete Garantien.',
en: 'The contract allows or implies transfers to third countries without appropriate safeguards.',
},
recommendation: {
de: 'Vereinbaren Sie geeignete Garantien (SCC, BCR) oder beschränken Sie die Verarbeitung auf EU/EWR.',
en: 'Agree on appropriate safeguards (SCC, BCR) or restrict processing to EU/EEA.',
},
affectedRequirement: 'Art. 44-49 DSGVO',
triggerControls: ['VND-TRF-01'],
},
{
id: 'tpl-transfer-old-scc',
type: 'RISK',
category: 'TRANSFER',
severity: 'HIGH',
title: {
de: 'Veraltete Standardvertragsklauseln',
en: 'Outdated Standard Contractual Clauses',
},
description: {
de: 'Der Vertrag verwendet die alten SCC (vor 2021), die nicht mehr gültig sind.',
en: 'The contract uses old SCC (pre-2021) that are no longer valid.',
},
recommendation: {
de: 'Aktualisieren Sie auf die SCC 2021 (Durchführungsbeschluss (EU) 2021/914).',
en: 'Update to SCC 2021 (Implementing Decision (EU) 2021/914).',
},
affectedRequirement: 'Art. 46 Abs. 2 lit. c DSGVO',
triggerControls: ['VND-TRF-02'],
},
// LIABILITY
{
id: 'tpl-liability-excessive-cap',
type: 'RISK',
category: 'LIABILITY',
severity: 'MEDIUM',
title: {
de: 'Unangemessene Haftungsbegrenzung',
en: 'Inappropriate liability cap',
},
description: {
de: 'Die Haftungsbegrenzung ist sehr niedrig und könnte bei Datenschutzverletzungen problematisch sein.',
en: 'The liability cap is very low and could be problematic in case of data protection violations.',
},
recommendation: {
de: 'Prüfen Sie, ob die Haftungsbegrenzung angemessen ist. Erwägen Sie eine Ausnahme für Datenschutzverletzungen oder eine höhere Obergrenze.',
en: 'Check if the liability cap is appropriate. Consider an exception for data protection violations or a higher limit.',
},
affectedRequirement: 'Vertragliche Vereinbarung',
triggerControls: [],
},
// DATA_SUBJECT_RIGHTS
{
id: 'tpl-dsr-no-support',
type: 'GAP',
category: 'DATA_SUBJECT_RIGHTS',
severity: 'HIGH',
title: {
de: 'Keine Unterstützung bei Betroffenenrechten',
en: 'No support for data subject rights',
},
description: {
de: 'Der Vertrag enthält keine Regelung zur Unterstützung bei der Erfüllung von Betroffenenrechten.',
en: 'The contract does not contain a provision for support in fulfilling data subject rights.',
},
recommendation: {
de: 'Ergänzen Sie eine Klausel zur Unterstützung bei Auskunft, Berichtigung, Löschung und anderen Betroffenenrechten.',
en: 'Add a clause for support with access, rectification, deletion, and other data subject rights.',
},
affectedRequirement: 'Art. 28 Abs. 3 lit. e DSGVO',
triggerControls: ['VND-DSR-01'],
},
// CONFIDENTIALITY
{
id: 'tpl-confidentiality-missing',
type: 'GAP',
category: 'CONFIDENTIALITY',
severity: 'HIGH',
title: {
de: 'Keine Vertraulichkeitsverpflichtung',
en: 'No confidentiality obligation',
},
description: {
de: 'Der Vertrag enthält keine Verpflichtung zur Vertraulichkeit der Mitarbeiter.',
en: 'The contract does not contain an obligation for employee confidentiality.',
},
recommendation: {
de: 'Ergänzen Sie eine Klausel, die die Verpflichtung der Mitarbeiter zur Vertraulichkeit sicherstellt.',
en: 'Add a clause ensuring the obligation of employees to confidentiality.',
},
affectedRequirement: 'Art. 28 Abs. 3 lit. b DSGVO',
triggerControls: ['VND-CON-02'],
},
]
// ========================================== // ==========================================
// HELPER FUNCTIONS // HELPER FUNCTIONS

View File

@@ -0,0 +1,191 @@
/**
* VVT Baseline-Katalog — HR & Finanzen
*/
import type { BaselineTemplate } from './types'
export const HR_VVT_TEMPLATES: BaselineTemplate[] = [
{
templateId: 'hr-mitarbeiterverwaltung',
businessFunction: 'hr',
name: 'Mitarbeiterverwaltung',
description: 'Verwaltung von Stammdaten, Vertraegen und Personalakten der Beschaeftigten',
purposes: ['Durchfuehrung des Beschaeftigungsverhaeltnisses', 'Personalverwaltung und -planung'],
legalBases: [
{ type: 'CONTRACT', description: 'Arbeitsvertrag', reference: 'Art. 6 Abs. 1 lit. b DSGVO' },
{ type: 'LEGAL_OBLIGATION', description: 'Arbeitsrechtliche Pflichten', reference: '§ 26 BDSG' },
],
dataSubjectCategories: ['EMPLOYEES'],
personalDataCategories: ['NAME', 'CONTACT', 'ADDRESS', 'DOB', 'SOCIAL_SECURITY', 'TAX_ID', 'BANK_ACCOUNT', 'EMPLOYMENT_DATA'],
recipientCategories: [
{ type: 'INTERNAL', name: 'Personalabteilung' },
{ type: 'AUTHORITY', name: 'Finanzamt' },
{ type: 'AUTHORITY', name: 'Sozialversicherungstraeger' },
],
retentionPeriod: { duration: 10, durationUnit: 'YEARS', description: '10 Jahre nach Ende des Beschaeftigungsverhaeltnisses', legalBasis: 'HGB § 257, AO § 147', deletionProcedure: 'Sichere Loeschung nach Ablauf' },
tomDescription: 'Zugriffskontrolle auf Personalakten, Verschluesselung, Protokollierung',
structuredToms: {
accessControl: ['RBAC', 'Need-to-know-Prinzip', 'Personalakten nur fuer HR'],
confidentiality: ['Verschluesselung personenbezogener Daten', 'Vertraulichkeitsvereinbarungen'],
integrity: ['Aenderungsprotokollierung', 'Vier-Augen-Prinzip bei Gehaltsaenderungen'],
availability: ['Regelmaessige Backups', 'Redundante Speicherung'],
separation: ['Trennung Personal-/Gehaltsdaten'],
},
typicalSystems: ['HR-Software', 'Gehaltsabrechnung', 'Dokumentenmanagement'],
protectionLevel: 'HIGH',
dpiaRequired: false,
tags: ['hr', 'mitarbeiter', 'personal'],
},
{
templateId: 'hr-gehaltsabrechnung',
businessFunction: 'hr',
name: 'Gehaltsabrechnung',
description: 'Berechnung und Auszahlung von Gehaeltern, Sozialabgaben und Steuern',
purposes: ['Lohn- und Gehaltsabrechnung', 'Erfuellung steuer- und sozialversicherungsrechtlicher Pflichten'],
legalBases: [
{ type: 'CONTRACT', description: 'Arbeitsvertrag', reference: 'Art. 6 Abs. 1 lit. b DSGVO' },
{ type: 'LEGAL_OBLIGATION', description: 'Steuer-/Sozialversicherungsrecht', reference: 'Art. 6 Abs. 1 lit. c DSGVO' },
],
dataSubjectCategories: ['EMPLOYEES'],
personalDataCategories: ['NAME', 'ADDRESS', 'SOCIAL_SECURITY', 'TAX_ID', 'BANK_ACCOUNT', 'SALARY_DATA'],
recipientCategories: [
{ type: 'PROCESSOR', name: 'Lohnbuero / Steuerberater' },
{ type: 'AUTHORITY', name: 'Finanzamt' },
{ type: 'AUTHORITY', name: 'Krankenkassen' },
],
retentionPeriod: { duration: 10, durationUnit: 'YEARS', description: '10 Jahre (steuerrechtlich)', legalBasis: 'AO § 147 Abs. 1 Nr. 1', deletionProcedure: 'Automatische Loeschung nach Fristablauf' },
tomDescription: 'Strenge Zugriffskontrolle, Verschluesselung, Trennung von Stamm- und Gehaltsdaten',
structuredToms: {
accessControl: ['Nur Lohnbuchhaltung/Steuerberater', 'MFA'],
confidentiality: ['Verschluesselung at-rest und in-transit', 'Vertraulichkeitsklausel'],
integrity: ['Revisionssichere Ablage', 'Pruefprotokoll'],
availability: ['Monatliche Backups', 'Jahresabschluss-Archiv'],
separation: ['Gehaltsdaten getrennt von allgemeinen Personaldaten'],
},
typicalSystems: ['DATEV', 'Lohnabrechnungssoftware'],
protectionLevel: 'HIGH',
dpiaRequired: false,
tags: ['hr', 'gehalt', 'lohn', 'steuer'],
},
{
templateId: 'hr-bewerbermanagement',
businessFunction: 'hr',
name: 'Bewerbermanagement',
description: 'Entgegennahme, Verwaltung und Bewertung von Bewerbungen',
purposes: ['Bearbeitung eingehender Bewerbungen', 'Bewerberauswahl'],
legalBases: [
{ type: 'CONTRACT', description: 'Vorvertragliche Massnahmen', reference: 'Art. 6 Abs. 1 lit. b DSGVO' },
{ type: 'LEGITIMATE_INTEREST', description: 'Bewerberauswahl', reference: '§ 26 Abs. 1 BDSG' },
],
dataSubjectCategories: ['APPLICANTS'],
personalDataCategories: ['NAME', 'CONTACT', 'ADDRESS', 'EDUCATION_DATA', 'EMPLOYMENT_DATA', 'PHOTO_VIDEO'],
recipientCategories: [
{ type: 'INTERNAL', name: 'Personalabteilung' },
{ type: 'INTERNAL', name: 'Fachabteilung' },
],
retentionPeriod: { duration: 6, durationUnit: 'MONTHS', description: '6 Monate nach Absage (AGG-Frist)', legalBasis: 'AGG § 15 Abs. 4', deletionProcedure: 'Automatische Loeschung 6 Monate nach Absage' },
tomDescription: 'Zugriffsbeschraenkung auf beteiligte Entscheidungstraeger, verschluesselte Uebertragung',
structuredToms: {
accessControl: ['Nur HR + Fachabteilung', 'Zeitlich begrenzter Zugriff'],
confidentiality: ['TLS fuer Bewerbungsportale', 'Verschluesselter E-Mail-Empfang'],
integrity: ['Unveraenderbare Bewerbungseingaenge'],
availability: ['Regelmaessige Backups'],
separation: ['Getrennte Bewerberdatenbank'],
},
typicalSystems: ['Bewerbermanagementsystem', 'E-Mail'],
protectionLevel: 'MEDIUM',
dpiaRequired: false,
tags: ['hr', 'bewerbung', 'recruiting'],
},
{
templateId: 'hr-zeiterfassung',
businessFunction: 'hr',
name: 'Zeiterfassung',
description: 'Erfassung von Arbeitszeiten, Urlaub und Fehlzeiten',
purposes: ['Arbeitszeiterfassung gemaess ArbZG', 'Urlaubsverwaltung'],
legalBases: [
{ type: 'LEGAL_OBLIGATION', description: 'Arbeitszeitgesetz', reference: 'Art. 6 Abs. 1 lit. c DSGVO, ArbZG § 16 Abs. 2' },
],
dataSubjectCategories: ['EMPLOYEES'],
personalDataCategories: ['NAME', 'EMPLOYMENT_DATA'],
recipientCategories: [
{ type: 'INTERNAL', name: 'Personalabteilung' },
{ type: 'INTERNAL', name: 'Vorgesetzte' },
],
retentionPeriod: { duration: 2, durationUnit: 'YEARS', description: '2 Jahre (ArbZG)', legalBasis: 'ArbZG § 16 Abs. 2', deletionProcedure: 'Automatische Loeschung' },
tomDescription: 'Zugriffskontrolle nach Abteilung, Protokollierung von Aenderungen',
structuredToms: {
accessControl: ['Vorgesetzte sehen nur eigene Abteilung', 'HR sieht alle'],
confidentiality: ['Krankmeldungen nur HR'],
integrity: ['Aenderungshistorie'],
availability: ['Taegliches Backup'],
separation: ['Trennung Zeitdaten / Gehaltsdaten'],
},
typicalSystems: ['Zeiterfassungssystem', 'HR-Software'],
protectionLevel: 'MEDIUM',
dpiaRequired: false,
tags: ['hr', 'zeiterfassung', 'arbeitszeit'],
},
]
export const FINANCE_VVT_TEMPLATES: BaselineTemplate[] = [
{
templateId: 'finance-buchhaltung',
businessFunction: 'finance',
name: 'Buchhaltung & Rechnungswesen',
description: 'Finanzbuchhaltung, Rechnungsstellung und Zahlungsverkehr',
purposes: ['Finanzbuchhaltung', 'Rechnungsstellung', 'Erfuellung handels-/steuerrechtlicher Aufbewahrungspflichten'],
legalBases: [
{ type: 'LEGAL_OBLIGATION', description: 'HGB, AO', reference: 'Art. 6 Abs. 1 lit. c DSGVO' },
{ type: 'CONTRACT', description: 'Vertragserfuellung', reference: 'Art. 6 Abs. 1 lit. b DSGVO' },
],
dataSubjectCategories: ['CUSTOMERS', 'SUPPLIERS', 'BUSINESS_PARTNERS'],
personalDataCategories: ['NAME', 'CONTACT', 'ADDRESS', 'BANK_ACCOUNT', 'PAYMENT_DATA', 'CONTRACT_DATA', 'TAX_ID'],
recipientCategories: [
{ type: 'PROCESSOR', name: 'Steuerberater / Wirtschaftspruefer' },
{ type: 'AUTHORITY', name: 'Finanzamt' },
],
retentionPeriod: { duration: 10, durationUnit: 'YEARS', description: '10 Jahre (HGB) / 6 Jahre (Geschaeftsbriefe)', legalBasis: 'HGB § 257, AO § 147', deletionProcedure: 'Loeschung nach Ablauf der jeweiligen Frist' },
tomDescription: 'Zugriffskontrolle nach Vier-Augen-Prinzip, revisionssichere Archivierung',
structuredToms: {
accessControl: ['Vier-Augen-Prinzip', 'RBAC nach Buchhaltungsrollen'],
confidentiality: ['Verschluesselung Finanzdaten'],
integrity: ['Revisionssichere Archivierung (GoBD)', 'Aenderungsprotokoll'],
availability: ['Redundante Speicherung', 'Jaehrliche Backups'],
separation: ['Trennung Debitoren/Kreditoren'],
},
typicalSystems: ['DATEV', 'ERP-System', 'Buchhaltungssoftware'],
protectionLevel: 'MEDIUM',
dpiaRequired: false,
tags: ['finance', 'buchhaltung', 'rechnungswesen'],
},
{
templateId: 'finance-zahlungsverkehr',
businessFunction: 'finance',
name: 'Zahlungsverkehr',
description: 'Abwicklung von Zahlungen, SEPA-Lastschriften und Ueberweisungen',
purposes: ['Zahlungsabwicklung', 'Mahnwesen'],
legalBases: [
{ type: 'CONTRACT', description: 'Vertragserfuellung', reference: 'Art. 6 Abs. 1 lit. b DSGVO' },
],
dataSubjectCategories: ['CUSTOMERS', 'SUPPLIERS'],
personalDataCategories: ['NAME', 'BANK_ACCOUNT', 'PAYMENT_DATA'],
recipientCategories: [
{ type: 'PROCESSOR', name: 'Zahlungsdienstleister' },
{ type: 'PROCESSOR', name: 'Kreditinstitut' },
],
retentionPeriod: { duration: 10, durationUnit: 'YEARS', description: '10 Jahre', legalBasis: 'HGB § 257', deletionProcedure: 'Automatische Loeschung' },
tomDescription: 'PCI-DSS-konforme Verarbeitung, Verschluesselung, Zugriffsbeschraenkung',
structuredToms: {
accessControl: ['Streng limitierter Zugriff', 'MFA'],
confidentiality: ['TLS 1.3', 'Tokenisierung von Zahlungsdaten'],
integrity: ['Transaktionsprotokoll'],
availability: ['Hochverfuegbarer Zahlungsservice'],
separation: ['Zahlungsdaten getrennt von CRM'],
},
typicalSystems: ['Banking-Software', 'Payment Gateway'],
protectionLevel: 'HIGH',
dpiaRequired: false,
tags: ['finance', 'zahlung', 'payment'],
},
]

View File

@@ -0,0 +1,30 @@
/**
* VVT Baseline-Katalog — Types
*/
import type { BusinessFunction } from '../vvt-types'
export interface BaselineTemplate {
templateId: string
businessFunction: BusinessFunction
name: string
description: string
purposes: string[]
legalBases: { type: string; description?: string; reference?: string }[]
dataSubjectCategories: string[]
personalDataCategories: string[]
recipientCategories: { type: string; name: string; description?: string }[]
retentionPeriod: { duration?: number; durationUnit?: string; description: string; legalBasis?: string; deletionProcedure?: string }
tomDescription: string
structuredToms: {
accessControl: string[]
confidentiality: string[]
integrity: string[]
availability: string[]
separation: string[]
}
typicalSystems: string[]
protectionLevel: 'LOW' | 'MEDIUM' | 'HIGH'
dpiaRequired: boolean
tags: string[]
}