feat(admin-v2): Major SDK/Compliance overhaul and new modules

SDK modules added/enhanced:
- compliance-hub, compliance-scope, consent-management, notfallplan
- audit-report, workflow, source-policy, dsms
- advisory-board documentation section
- TOM dashboard components, TOM generator SDM mapping
- DSFA: mitigation library, risk catalog, threshold analysis, source attribution
- VVT: baseline catalog, profiling engine, types
- Loeschfristen: baseline catalog, compliance engine, export, profiling, types
- Compliance scope: engine, profiling, golden tests, types

Existing SDK pages updated:
- dsfa/[id], tom, vvt, loeschfristen, advisory-board — expanded functionality
- SDKSidebar, StepHeader — new navigation items and layout
- SDK layout, context, types — expanded type system

Other admin-v2 changes:
- AI agents page, RAG pipeline DSFA integration
- GridOverlay component updates
- Companion feature (development + education)
- Compliance advisor SOUL definition

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
BreakPilot Dev
2026-02-10 00:01:04 +01:00
parent ee0c4b859c
commit 870302a82b
94 changed files with 29706 additions and 1039 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,722 @@
import type { ScopeProfilingAnswer, ComplianceDepthLevel, ScopeDocumentType } from './compliance-scope-types'
export interface GoldenTest {
id: string
name: string
description: string
answers: ScopeProfilingAnswer[]
expectedLevel: ComplianceDepthLevel | null // null for prefill tests
expectedMinDocuments?: ScopeDocumentType[]
expectedHardTriggerIds?: string[]
expectedDsfaRequired?: boolean
tags: string[]
}
export const GOLDEN_TESTS: GoldenTest[] = [
// GT-01: 2-Person Freelancer, nur B2B, DE-Hosting → L1
{
id: 'GT-01',
name: '2-Person Freelancer B2B',
description: 'Kleinstes Setup ohne besondere Risiken',
answers: [
{ questionId: 'org_employee_count', value: '2' },
{ questionId: 'org_business_model', value: 'b2b' },
{ questionId: 'tech_hosting_location', value: 'de' },
{ questionId: 'org_industry', value: 'consulting' },
{ questionId: 'data_health', value: false },
{ questionId: 'data_genetic', value: false },
{ questionId: 'data_biometric', value: false },
{ questionId: 'data_racial_ethnic', value: false },
{ questionId: 'data_political_opinion', value: false },
{ questionId: 'data_religious', value: false },
{ questionId: 'data_union_membership', value: false },
{ questionId: 'data_sexual_orientation', value: false },
{ questionId: 'data_criminal', value: false },
{ questionId: 'process_has_vvt', value: true },
{ questionId: 'process_has_tom', value: true },
{ questionId: 'process_has_dsfa', value: true },
{ questionId: 'process_has_incident_plan', value: true },
{ questionId: 'data_volume', value: '<1000' },
{ questionId: 'org_customer_count', value: '<100' },
],
expectedLevel: 'L1',
expectedMinDocuments: ['VVT', 'TOM', 'COOKIE_BANNER'],
expectedHardTriggerIds: [],
expectedDsfaRequired: false,
tags: ['baseline', 'freelancer', 'b2b'],
},
// GT-02: Solo IT-Berater → L1
{
id: 'GT-02',
name: 'Solo IT-Berater',
description: 'Einzelperson, minimale Datenverarbeitung',
answers: [
{ questionId: 'org_employee_count', value: '1' },
{ questionId: 'org_business_model', value: 'b2b' },
{ questionId: 'tech_hosting_location', value: 'de' },
{ questionId: 'org_industry', value: 'it_services' },
{ questionId: 'data_health', value: false },
{ questionId: 'data_genetic', value: false },
{ questionId: 'data_biometric', value: false },
{ questionId: 'data_volume', value: '<1000' },
{ questionId: 'org_customer_count', value: '<50' },
{ questionId: 'process_has_vvt', value: true },
{ questionId: 'process_has_tom', value: true },
],
expectedLevel: 'L1',
expectedHardTriggerIds: [],
tags: ['baseline', 'solo', 'minimal'],
},
// GT-03: 5-Person Agentur, Website, kein Tracking → L1
{
id: 'GT-03',
name: '5-Person Agentur ohne Tracking',
description: 'Kleine Agentur, einfache Website ohne Analytics',
answers: [
{ questionId: 'org_employee_count', value: '5' },
{ questionId: 'org_business_model', value: 'b2b' },
{ questionId: 'tech_hosting_location', value: 'eu' },
{ questionId: 'org_industry', value: 'marketing' },
{ questionId: 'tech_has_website', value: true },
{ questionId: 'tech_has_tracking', value: false },
{ questionId: 'data_volume', value: '1000-10000' },
{ questionId: 'org_customer_count', value: '100-1000' },
{ questionId: 'process_has_vvt', value: true },
{ questionId: 'process_has_tom', value: true },
],
expectedLevel: 'L1',
expectedMinDocuments: ['VVT', 'TOM', 'COOKIE_BANNER'],
tags: ['baseline', 'agency', 'simple'],
},
// GT-04: 30-Person SaaS B2B, EU-Cloud → L2 (scale trigger)
{
id: 'GT-04',
name: '30-Person SaaS B2B',
description: 'Scale-Trigger durch Mitarbeiterzahl',
answers: [
{ questionId: 'org_employee_count', value: '30' },
{ questionId: 'org_business_model', value: 'b2b' },
{ questionId: 'tech_hosting_location', value: 'eu' },
{ questionId: 'org_industry', value: 'software' },
{ questionId: 'tech_has_cloud', value: true },
{ questionId: 'data_volume', value: '10000-100000' },
{ questionId: 'org_customer_count', value: '1000-10000' },
{ questionId: 'process_has_vvt', value: true },
{ questionId: 'process_has_tom', value: true },
{ questionId: 'process_has_dsfa', value: false },
],
expectedLevel: 'L2',
expectedMinDocuments: ['VVT', 'TOM', 'AVV', 'COOKIE_BANNER'],
tags: ['scale', 'saas', 'growth'],
},
// GT-05: 50-Person Handel B2C, Webshop → L2 (B2C+Webshop)
{
id: 'GT-05',
name: '50-Person E-Commerce B2C',
description: 'B2C mit Webshop erhöht Anforderungen',
answers: [
{ questionId: 'org_employee_count', value: '50' },
{ questionId: 'org_business_model', value: 'b2c' },
{ questionId: 'tech_hosting_location', value: 'eu' },
{ questionId: 'org_industry', value: 'retail' },
{ questionId: 'tech_has_webshop', value: true },
{ questionId: 'data_volume', value: '100000-1000000' },
{ questionId: 'org_customer_count', value: '10000-100000' },
{ questionId: 'process_has_vvt', value: true },
{ questionId: 'process_has_tom', value: true },
],
expectedLevel: 'L2',
expectedHardTriggerIds: ['HT-H01'],
expectedMinDocuments: ['VVT', 'TOM', 'AVV', 'COOKIE_BANNER', 'EINWILLIGUNG'],
tags: ['b2c', 'webshop', 'retail'],
},
// GT-06: 80-Person Dienstleister, Cloud → L2 (scale)
{
id: 'GT-06',
name: '80-Person Dienstleister',
description: 'Größerer Betrieb mit Cloud-Services',
answers: [
{ questionId: 'org_employee_count', value: '80' },
{ questionId: 'org_business_model', value: 'b2b' },
{ questionId: 'tech_hosting_location', value: 'eu' },
{ questionId: 'org_industry', value: 'professional_services' },
{ questionId: 'tech_has_cloud', value: true },
{ questionId: 'data_volume', value: '100000-1000000' },
{ questionId: 'org_customer_count', value: '1000-10000' },
{ questionId: 'process_has_vvt', value: true },
{ questionId: 'process_has_tom', value: true },
],
expectedLevel: 'L2',
expectedMinDocuments: ['VVT', 'TOM', 'AVV'],
tags: ['scale', 'services'],
},
// GT-07: 20-Person Startup mit GA4 Tracking → L2 (tracking)
{
id: 'GT-07',
name: 'Startup mit Google Analytics',
description: 'Tracking-Tools erhöhen Compliance-Anforderungen',
answers: [
{ questionId: 'org_employee_count', value: '20' },
{ questionId: 'org_business_model', value: 'b2c' },
{ questionId: 'tech_hosting_location', value: 'eu' },
{ questionId: 'org_industry', value: 'technology' },
{ questionId: 'tech_has_website', value: true },
{ questionId: 'tech_has_tracking', value: true },
{ questionId: 'tech_tracking_tools', value: 'google_analytics' },
{ questionId: 'data_volume', value: '10000-100000' },
{ questionId: 'process_has_vvt', value: true },
],
expectedLevel: 'L2',
expectedMinDocuments: ['VVT', 'TOM', 'COOKIE_BANNER', 'EINWILLIGUNG'],
tags: ['tracking', 'analytics', 'startup'],
},
// GT-08: Kita-App (Minderjaehrige) → L3 (HT-B01)
{
id: 'GT-08',
name: 'Kita-App für Eltern',
description: 'Datenverarbeitung von Minderjährigen unter 16',
answers: [
{ questionId: 'org_employee_count', value: '15' },
{ questionId: 'org_business_model', value: 'b2c' },
{ questionId: 'tech_hosting_location', value: 'de' },
{ questionId: 'org_industry', value: 'education' },
{ questionId: 'data_subjects_minors', value: true },
{ questionId: 'data_subjects_minors_age', value: '<16' },
{ questionId: 'data_volume', value: '1000-10000' },
{ questionId: 'process_has_vvt', value: true },
{ questionId: 'process_has_tom', value: true },
],
expectedLevel: 'L3',
expectedHardTriggerIds: ['HT-B01'],
expectedDsfaRequired: true,
expectedMinDocuments: ['VVT', 'TOM', 'DSFA', 'EINWILLIGUNG', 'AVV'],
tags: ['hard-trigger', 'minors', 'education'],
},
// GT-09: Krankenhaus-Software → L3 (HT-A01)
{
id: 'GT-09',
name: 'Krankenhaus-Verwaltungssoftware',
description: 'Gesundheitsdaten Art. 9 DSGVO',
answers: [
{ questionId: 'org_employee_count', value: '200' },
{ questionId: 'org_business_model', value: 'b2b' },
{ questionId: 'tech_hosting_location', value: 'de' },
{ questionId: 'org_industry', value: 'healthcare' },
{ questionId: 'data_health', value: true },
{ questionId: 'data_volume', value: '>1000000' },
{ questionId: 'org_customer_count', value: '10-50' },
{ questionId: 'process_has_vvt', value: true },
{ questionId: 'process_has_tom', value: true },
],
expectedLevel: 'L3',
expectedHardTriggerIds: ['HT-A01'],
expectedDsfaRequired: true,
expectedMinDocuments: ['VVT', 'TOM', 'DSFA', 'AVV'],
tags: ['hard-trigger', 'health', 'art9'],
},
// GT-10: HR-Scoring-Plattform → L3 (HT-C01)
{
id: 'GT-10',
name: 'HR-Scoring für Bewerbungen',
description: 'Automatisierte Entscheidungen im HR-Bereich',
answers: [
{ questionId: 'org_employee_count', value: '40' },
{ questionId: 'org_business_model', value: 'b2b' },
{ questionId: 'tech_hosting_location', value: 'eu' },
{ questionId: 'org_industry', value: 'hr_tech' },
{ questionId: 'tech_has_adm', value: true },
{ questionId: 'tech_adm_type', value: 'profiling' },
{ questionId: 'tech_adm_impact', value: 'employment' },
{ questionId: 'data_volume', value: '100000-1000000' },
{ questionId: 'process_has_vvt', value: true },
],
expectedLevel: 'L3',
expectedHardTriggerIds: ['HT-C01'],
expectedDsfaRequired: true,
expectedMinDocuments: ['VVT', 'TOM', 'DSFA', 'AVV'],
tags: ['hard-trigger', 'adm', 'profiling'],
},
// GT-11: Fintech Kreditscoring → L3 (HT-H05 + C01)
{
id: 'GT-11',
name: 'Fintech Kreditscoring',
description: 'Finanzsektor mit automatisierten Entscheidungen',
answers: [
{ questionId: 'org_employee_count', value: '120' },
{ questionId: 'org_business_model', value: 'b2c' },
{ questionId: 'tech_hosting_location', value: 'eu' },
{ questionId: 'org_industry', value: 'finance' },
{ questionId: 'tech_has_adm', value: true },
{ questionId: 'tech_adm_type', value: 'scoring' },
{ questionId: 'tech_adm_impact', value: 'credit' },
{ questionId: 'data_volume', value: '>1000000' },
{ questionId: 'process_has_vvt', value: true },
{ questionId: 'process_has_tom', value: true },
],
expectedLevel: 'L3',
expectedHardTriggerIds: ['HT-H05', 'HT-C01'],
expectedDsfaRequired: true,
expectedMinDocuments: ['VVT', 'TOM', 'DSFA', 'AVV'],
tags: ['hard-trigger', 'finance', 'scoring'],
},
// GT-12: Bildungsplattform Minderjaehrige → L3 (HT-B01)
{
id: 'GT-12',
name: 'Online-Lernplattform für Schüler',
description: 'Bildungssektor mit minderjährigen Nutzern',
answers: [
{ questionId: 'org_employee_count', value: '35' },
{ questionId: 'org_business_model', value: 'b2c' },
{ questionId: 'tech_hosting_location', value: 'eu' },
{ questionId: 'org_industry', value: 'education' },
{ questionId: 'data_subjects_minors', value: true },
{ questionId: 'data_subjects_minors_age', value: '<16' },
{ questionId: 'tech_has_tracking', value: true },
{ questionId: 'data_volume', value: '100000-1000000' },
{ questionId: 'process_has_vvt', value: true },
],
expectedLevel: 'L3',
expectedHardTriggerIds: ['HT-B01'],
expectedDsfaRequired: true,
tags: ['hard-trigger', 'education', 'minors'],
},
// GT-13: Datenbroker → L3 (HT-H02)
{
id: 'GT-13',
name: 'Datenbroker / Adresshandel',
description: 'Geschäftsmodell basiert auf Datenhandel',
answers: [
{ questionId: 'org_employee_count', value: '25' },
{ questionId: 'org_business_model', value: 'b2b' },
{ questionId: 'tech_hosting_location', value: 'eu' },
{ questionId: 'org_industry', value: 'data_broker' },
{ questionId: 'data_is_core_business', value: true },
{ questionId: 'data_volume', value: '>1000000' },
{ questionId: 'org_customer_count', value: '100-1000' },
{ questionId: 'process_has_vvt', value: true },
],
expectedLevel: 'L3',
expectedHardTriggerIds: ['HT-H02'],
expectedDsfaRequired: true,
tags: ['hard-trigger', 'data-broker'],
},
// GT-14: Video + ADM → L3 (HT-D05)
{
id: 'GT-14',
name: 'Videoüberwachung mit Gesichtserkennung',
description: 'Biometrische Daten mit automatisierter Verarbeitung',
answers: [
{ questionId: 'org_employee_count', value: '60' },
{ questionId: 'org_business_model', value: 'b2b' },
{ questionId: 'tech_hosting_location', value: 'de' },
{ questionId: 'org_industry', value: 'security' },
{ questionId: 'data_biometric', value: true },
{ questionId: 'tech_has_video_surveillance', value: true },
{ questionId: 'tech_has_adm', value: true },
{ questionId: 'data_volume', value: '100000-1000000' },
{ questionId: 'process_has_vvt', value: true },
],
expectedLevel: 'L3',
expectedHardTriggerIds: ['HT-D05'],
expectedDsfaRequired: true,
tags: ['hard-trigger', 'biometric', 'video'],
},
// GT-15: 500-MA Konzern ohne Zert → L3 (HT-G04)
{
id: 'GT-15',
name: 'Großunternehmen ohne Zertifizierung',
description: 'Scale-Trigger durch Unternehmensgröße',
answers: [
{ questionId: 'org_employee_count', value: '500' },
{ questionId: 'org_business_model', value: 'b2b' },
{ questionId: 'tech_hosting_location', value: 'eu' },
{ questionId: 'org_industry', value: 'manufacturing' },
{ questionId: 'data_volume', value: '>1000000' },
{ questionId: 'org_customer_count', value: '>100000' },
{ questionId: 'cert_has_iso27001', value: false },
{ questionId: 'process_has_vvt', value: true },
{ questionId: 'process_has_tom', value: true },
],
expectedLevel: 'L3',
expectedHardTriggerIds: ['HT-G04'],
expectedDsfaRequired: true,
tags: ['hard-trigger', 'scale', 'enterprise'],
},
// GT-16: ISO 27001 Anbieter → L4 (HT-F01)
{
id: 'GT-16',
name: 'ISO 27001 zertifizierter Cloud-Provider',
description: 'Zertifizierung erfordert höchste Compliance',
answers: [
{ questionId: 'org_employee_count', value: '150' },
{ questionId: 'org_business_model', value: 'b2b' },
{ questionId: 'tech_hosting_location', value: 'eu' },
{ questionId: 'org_industry', value: 'cloud_services' },
{ questionId: 'cert_has_iso27001', value: true },
{ questionId: 'data_volume', value: '>1000000' },
{ questionId: 'process_has_vvt', value: true },
{ questionId: 'process_has_tom', value: true },
{ questionId: 'process_has_dsfa', value: true },
],
expectedLevel: 'L4',
expectedHardTriggerIds: ['HT-F01'],
expectedMinDocuments: ['VVT', 'TOM', 'DSFA', 'AVV', 'CERT_ISO27001'],
tags: ['hard-trigger', 'certification', 'iso'],
},
// GT-17: TISAX Automobilzulieferer → L4 (HT-F04)
{
id: 'GT-17',
name: 'TISAX-zertifizierter Automobilzulieferer',
description: 'Automotive-Branche mit TISAX-Anforderungen',
answers: [
{ questionId: 'org_employee_count', value: '300' },
{ questionId: 'org_business_model', value: 'b2b' },
{ questionId: 'tech_hosting_location', value: 'de' },
{ questionId: 'org_industry', value: 'automotive' },
{ questionId: 'cert_has_tisax', value: true },
{ questionId: 'data_volume', value: '>1000000' },
{ questionId: 'org_customer_count', value: '10-50' },
{ questionId: 'process_has_vvt', value: true },
{ questionId: 'process_has_tom', value: true },
],
expectedLevel: 'L4',
expectedHardTriggerIds: ['HT-F04'],
tags: ['hard-trigger', 'certification', 'tisax'],
},
// GT-18: ISO 27701 Cloud-Provider → L4 (HT-F02)
{
id: 'GT-18',
name: 'ISO 27701 Privacy-zertifiziert',
description: 'Privacy-spezifische Zertifizierung',
answers: [
{ questionId: 'org_employee_count', value: '200' },
{ questionId: 'org_business_model', value: 'b2b' },
{ questionId: 'tech_hosting_location', value: 'eu' },
{ questionId: 'org_industry', value: 'cloud_services' },
{ questionId: 'cert_has_iso27701', value: true },
{ questionId: 'data_volume', value: '>1000000' },
{ questionId: 'process_has_vvt', value: true },
{ questionId: 'process_has_tom', value: true },
{ questionId: 'process_has_dsfa', value: true },
],
expectedLevel: 'L4',
expectedHardTriggerIds: ['HT-F02'],
tags: ['hard-trigger', 'certification', 'privacy'],
},
// GT-19: Grosskonzern + Art.9 + >1M DS → L4 (HT-G05)
{
id: 'GT-19',
name: 'Konzern mit sensiblen Massendaten',
description: 'Kombination aus Scale und Art. 9 Daten',
answers: [
{ questionId: 'org_employee_count', value: '2000' },
{ questionId: 'org_business_model', value: 'b2c' },
{ questionId: 'tech_hosting_location', value: 'eu' },
{ questionId: 'org_industry', value: 'insurance' },
{ questionId: 'data_health', value: true },
{ questionId: 'data_volume', value: '>1000000' },
{ questionId: 'org_customer_count', value: '>100000' },
{ questionId: 'process_has_vvt', value: true },
{ questionId: 'process_has_tom', value: true },
],
expectedLevel: 'L4',
expectedHardTriggerIds: ['HT-G05'],
expectedDsfaRequired: true,
tags: ['hard-trigger', 'scale', 'art9'],
},
// GT-20: Nur B2C Webshop → L2 (HT-H01)
{
id: 'GT-20',
name: 'Reiner B2C Webshop',
description: 'B2C-Trigger ohne weitere Risiken',
answers: [
{ questionId: 'org_employee_count', value: '12' },
{ questionId: 'org_business_model', value: 'b2c' },
{ questionId: 'tech_hosting_location', value: 'eu' },
{ questionId: 'org_industry', value: 'retail' },
{ questionId: 'tech_has_webshop', value: true },
{ questionId: 'data_volume', value: '10000-100000' },
{ questionId: 'org_customer_count', value: '1000-10000' },
{ questionId: 'process_has_vvt', value: true },
],
expectedLevel: 'L2',
expectedHardTriggerIds: ['HT-H01'],
tags: ['b2c', 'webshop'],
},
// GT-21: Keine Daten, keine MA → L1
{
id: 'GT-21',
name: 'Minimale Datenverarbeitung',
description: 'Absolute Baseline ohne Risiken',
answers: [
{ questionId: 'org_employee_count', value: '1' },
{ questionId: 'org_business_model', value: 'b2b' },
{ questionId: 'tech_hosting_location', value: 'de' },
{ questionId: 'org_industry', value: 'consulting' },
{ questionId: 'data_volume', value: '<1000' },
{ questionId: 'org_customer_count', value: '<50' },
{ questionId: 'tech_has_website', value: false },
{ questionId: 'process_has_vvt', value: true },
],
expectedLevel: 'L1',
expectedHardTriggerIds: [],
tags: ['baseline', 'minimal'],
},
// GT-22: Alle Art.9 Kategorien → L3 (HT-A09)
{
id: 'GT-22',
name: 'Alle Art. 9 Kategorien',
description: 'Multiple sensible Datenkategorien',
answers: [
{ questionId: 'org_employee_count', value: '50' },
{ questionId: 'org_business_model', value: 'b2b' },
{ questionId: 'tech_hosting_location', value: 'eu' },
{ questionId: 'org_industry', value: 'research' },
{ questionId: 'data_health', value: true },
{ questionId: 'data_genetic', value: true },
{ questionId: 'data_biometric', value: true },
{ questionId: 'data_racial_ethnic', value: true },
{ questionId: 'data_political_opinion', value: true },
{ questionId: 'data_religious', value: true },
{ questionId: 'data_union_membership', value: true },
{ questionId: 'data_sexual_orientation', value: true },
{ questionId: 'data_criminal', value: true },
{ questionId: 'data_volume', value: '100000-1000000' },
{ questionId: 'process_has_vvt', value: true },
],
expectedLevel: 'L3',
expectedHardTriggerIds: ['HT-A09'],
expectedDsfaRequired: true,
tags: ['hard-trigger', 'art9', 'multiple-categories'],
},
// GT-23: Drittland + Art.9 → L3 (HT-E04)
{
id: 'GT-23',
name: 'Drittlandtransfer mit Art. 9 Daten',
description: 'Kombination aus Drittland und sensiblen Daten',
answers: [
{ questionId: 'org_employee_count', value: '45' },
{ questionId: 'org_business_model', value: 'b2b' },
{ questionId: 'tech_hosting_location', value: 'us' },
{ questionId: 'org_industry', value: 'healthcare' },
{ questionId: 'data_health', value: true },
{ questionId: 'tech_has_third_country_transfer', value: true },
{ questionId: 'data_volume', value: '100000-1000000' },
{ questionId: 'process_has_vvt', value: true },
],
expectedLevel: 'L3',
expectedHardTriggerIds: ['HT-E04'],
expectedDsfaRequired: true,
tags: ['hard-trigger', 'third-country', 'art9'],
},
// GT-24: Minderjaehrige + Art.9 → L4 (HT-B02)
{
id: 'GT-24',
name: 'Minderjährige mit Gesundheitsdaten',
description: 'Kombination aus vulnerabler Gruppe und Art. 9',
answers: [
{ questionId: 'org_employee_count', value: '30' },
{ questionId: 'org_business_model', value: 'b2c' },
{ questionId: 'tech_hosting_location', value: 'de' },
{ questionId: 'org_industry', value: 'healthcare' },
{ questionId: 'data_subjects_minors', value: true },
{ questionId: 'data_subjects_minors_age', value: '<16' },
{ questionId: 'data_health', value: true },
{ questionId: 'data_volume', value: '10000-100000' },
{ questionId: 'process_has_vvt', value: true },
],
expectedLevel: 'L4',
expectedHardTriggerIds: ['HT-B02'],
expectedDsfaRequired: true,
tags: ['hard-trigger', 'minors', 'health', 'combined-risk'],
},
// GT-25: KI autonome Entscheidungen → L3 (HT-C02)
{
id: 'GT-25',
name: 'KI mit autonomen Entscheidungen',
description: 'AI Act relevante autonome Systeme',
answers: [
{ questionId: 'org_employee_count', value: '70' },
{ questionId: 'org_business_model', value: 'b2b' },
{ questionId: 'tech_hosting_location', value: 'eu' },
{ questionId: 'org_industry', value: 'ai_services' },
{ questionId: 'tech_has_adm', value: true },
{ questionId: 'tech_adm_type', value: 'autonomous_decision' },
{ questionId: 'tech_has_ai', value: true },
{ questionId: 'data_volume', value: '100000-1000000' },
{ questionId: 'process_has_vvt', value: true },
],
expectedLevel: 'L3',
expectedHardTriggerIds: ['HT-C02'],
expectedDsfaRequired: true,
tags: ['hard-trigger', 'ai', 'adm'],
},
// GT-26: Multiple Zertifizierungen → L4 (HT-F01-05)
{
id: 'GT-26',
name: 'Multiple Zertifizierungen',
description: 'Mehrere Zertifizierungen kombiniert',
answers: [
{ questionId: 'org_employee_count', value: '250' },
{ questionId: 'org_business_model', value: 'b2b' },
{ questionId: 'tech_hosting_location', value: 'eu' },
{ questionId: 'org_industry', value: 'cloud_services' },
{ questionId: 'cert_has_iso27001', value: true },
{ questionId: 'cert_has_iso27701', value: true },
{ questionId: 'cert_has_soc2', value: true },
{ questionId: 'data_volume', value: '>1000000' },
{ questionId: 'process_has_vvt', value: true },
{ questionId: 'process_has_tom', value: true },
{ questionId: 'process_has_dsfa', value: true },
],
expectedLevel: 'L4',
expectedHardTriggerIds: ['HT-F01', 'HT-F02', 'HT-F03'],
tags: ['hard-trigger', 'certification', 'multiple'],
},
// GT-27: Oeffentlicher Sektor + Gesundheit → L3 (HT-H07 + A01)
{
id: 'GT-27',
name: 'Öffentlicher Sektor mit Gesundheitsdaten',
description: 'Behörde mit Art. 9 Datenverarbeitung',
answers: [
{ questionId: 'org_employee_count', value: '120' },
{ questionId: 'org_business_model', value: 'b2g' },
{ questionId: 'tech_hosting_location', value: 'de' },
{ questionId: 'org_industry', value: 'public_sector' },
{ questionId: 'org_is_public_sector', value: true },
{ questionId: 'data_health', value: true },
{ questionId: 'data_volume', value: '>1000000' },
{ questionId: 'process_has_vvt', value: true },
],
expectedLevel: 'L3',
expectedHardTriggerIds: ['HT-H07', 'HT-A01'],
expectedDsfaRequired: true,
tags: ['hard-trigger', 'public-sector', 'health'],
},
// GT-28: Bildung + KI + Minderjaehrige → L4 (HT-B03)
{
id: 'GT-28',
name: 'EdTech mit KI für Minderjährige',
description: 'Triple-Risiko: Bildung, KI, vulnerable Gruppe',
answers: [
{ questionId: 'org_employee_count', value: '55' },
{ questionId: 'org_business_model', value: 'b2c' },
{ questionId: 'tech_hosting_location', value: 'eu' },
{ questionId: 'org_industry', value: 'education' },
{ questionId: 'data_subjects_minors', value: true },
{ questionId: 'data_subjects_minors_age', value: '<16' },
{ questionId: 'tech_has_ai', value: true },
{ questionId: 'tech_has_adm', value: true },
{ questionId: 'data_volume', value: '100000-1000000' },
{ questionId: 'process_has_vvt', value: true },
],
expectedLevel: 'L4',
expectedHardTriggerIds: ['HT-B03'],
expectedDsfaRequired: true,
tags: ['hard-trigger', 'education', 'ai', 'minors', 'triple-risk'],
},
// GT-29: Freelancer mit 1 Art.9 → L3 (hard trigger override despite low score)
{
id: 'GT-29',
name: 'Freelancer mit Gesundheitsdaten',
description: 'Hard Trigger überschreibt niedrige Score-Bewertung',
answers: [
{ questionId: 'org_employee_count', value: '1' },
{ questionId: 'org_business_model', value: 'b2b' },
{ questionId: 'tech_hosting_location', value: 'de' },
{ questionId: 'org_industry', value: 'healthcare' },
{ questionId: 'data_health', value: true },
{ questionId: 'data_volume', value: '<1000' },
{ questionId: 'org_customer_count', value: '<50' },
{ questionId: 'process_has_vvt', value: true },
],
expectedLevel: 'L3',
expectedHardTriggerIds: ['HT-A01'],
expectedDsfaRequired: true,
tags: ['hard-trigger', 'override', 'art9', 'freelancer'],
},
// GT-30: Enterprise, alle Prozesse vorhanden → L3 (good process maturity)
{
id: 'GT-30',
name: 'Enterprise mit reifer Prozesslandschaft',
description: 'Große Organisation mit allen Compliance-Prozessen',
answers: [
{ questionId: 'org_employee_count', value: '450' },
{ questionId: 'org_business_model', value: 'b2b' },
{ questionId: 'tech_hosting_location', value: 'eu' },
{ questionId: 'org_industry', value: 'manufacturing' },
{ questionId: 'data_volume', value: '>1000000' },
{ questionId: 'org_customer_count', value: '10000-100000' },
{ questionId: 'process_has_vvt', value: true },
{ questionId: 'process_has_tom', value: true },
{ questionId: 'process_has_dsfa', value: true },
{ questionId: 'process_has_incident_plan', value: true },
{ questionId: 'process_has_dsb', value: true },
{ questionId: 'process_has_training', value: true },
],
expectedLevel: 'L3',
expectedHardTriggerIds: ['HT-G04'],
tags: ['enterprise', 'mature', 'all-processes'],
},
// GT-31: SMB, nur 1 Block beantwortet → L1 (graceful degradation)
{
id: 'GT-31',
name: 'Unvollständige Profilerstellung',
description: 'Test für graceful degradation bei unvollständigen Antworten',
answers: [
{ questionId: 'org_employee_count', value: '8' },
{ questionId: 'org_business_model', value: 'b2b' },
{ questionId: 'org_industry', value: 'consulting' },
// Nur Block 1 (Organization) beantwortet, Rest fehlt
],
expectedLevel: 'L1',
expectedHardTriggerIds: [],
tags: ['incomplete', 'degradation', 'edge-case'],
},
// GT-32: CompanyProfile Prefill Konsistenz → null (prefill test, no expected level)
{
id: 'GT-32',
name: 'CompanyProfile Prefill Test',
description: 'Prüft ob CompanyProfile-Daten korrekt in ScopeProfile übernommen werden',
answers: [
{ questionId: 'org_employee_count', value: '25' },
{ questionId: 'org_business_model', value: 'b2c' },
{ questionId: 'org_industry', value: 'retail' },
{ questionId: 'tech_hosting_location', value: 'eu' },
// Diese Werte sollten mit CompanyProfile-Prefill übereinstimmen
],
expectedLevel: null,
tags: ['prefill', 'integration', 'consistency'],
},
]

View File

@@ -0,0 +1,821 @@
import type {
ScopeQuestionBlock,
ScopeQuestionBlockId,
ScopeProfilingQuestion,
ScopeProfilingAnswer,
ComplianceScopeState,
} from './compliance-scope-types'
import type { CompanyProfile } from './types'
/**
* Block 1: Organisation & Reife
*/
const BLOCK_1_ORGANISATION: ScopeQuestionBlock = {
id: 'organisation',
title: 'Organisation & Reife',
description: 'Grundlegende Informationen zu Ihrer Organisation und Compliance-Zielen',
order: 1,
questions: [
{
id: 'org_employee_count',
type: 'number',
label: 'Wie viele Mitarbeiter hat Ihre Organisation?',
helpText: 'Geben Sie die Gesamtzahl aller Beschäftigten an (inkl. Teilzeit, Minijobs)',
required: true,
scoreWeights: { risk: 5, complexity: 8, assurance: 6 },
mapsToCompanyProfile: 'employeeCount',
},
{
id: 'org_customer_count',
type: 'single',
label: 'Wie viele Kunden/Nutzer betreuen Sie?',
helpText: 'Schätzen Sie die Anzahl aktiver Kunden oder Nutzer',
required: true,
options: [
{ value: '<100', label: 'Weniger als 100' },
{ value: '100-1000', label: '100 bis 1.000' },
{ value: '1000-10000', label: '1.000 bis 10.000' },
{ value: '10000-100000', label: '10.000 bis 100.000' },
{ value: '100000+', label: 'Mehr als 100.000' },
],
scoreWeights: { risk: 6, complexity: 7, assurance: 6 },
},
{
id: 'org_annual_revenue',
type: 'single',
label: 'Wie hoch ist Ihr jährlicher Umsatz?',
helpText: 'Wählen Sie die zutreffende Umsatzklasse',
required: true,
options: [
{ value: '<2Mio', label: 'Unter 2 Mio. EUR' },
{ value: '2-10Mio', label: '2 bis 10 Mio. EUR' },
{ value: '10-50Mio', label: '10 bis 50 Mio. EUR' },
{ value: '>50Mio', label: 'Über 50 Mio. EUR' },
],
scoreWeights: { risk: 4, complexity: 6, assurance: 7 },
mapsToCompanyProfile: 'annualRevenue',
},
{
id: 'org_cert_target',
type: 'multi',
label: 'Welche Zertifizierungen streben Sie an oder besitzen Sie bereits?',
helpText: 'Mehrfachauswahl möglich. Zertifizierungen erhöhen den Assurance-Bedarf',
required: false,
options: [
{ value: 'ISO27001', label: 'ISO 27001 (Informationssicherheit)' },
{ value: 'ISO27701', label: 'ISO 27701 (Datenschutz-Erweiterung)' },
{ value: 'TISAX', label: 'TISAX (Automotive)' },
{ value: 'SOC2', label: 'SOC 2 (US-Standard)' },
{ value: 'BSI-Grundschutz', label: 'BSI IT-Grundschutz' },
{ value: 'Keine', label: 'Keine Zertifizierung geplant' },
],
scoreWeights: { risk: 3, complexity: 5, assurance: 10 },
},
{
id: 'org_industry',
type: 'single',
label: 'In welcher Branche sind Sie tätig?',
helpText: 'Ihre Branche beeinflusst Risikobewertung und regulatorische Anforderungen',
required: true,
options: [
{ value: 'it_software', label: 'IT & Software' },
{ value: 'healthcare', label: 'Gesundheitswesen' },
{ value: 'education', label: 'Bildung & Forschung' },
{ value: 'finance', label: 'Finanzdienstleistungen' },
{ value: 'retail', label: 'Einzelhandel & E-Commerce' },
{ value: 'manufacturing', label: 'Produktion & Fertigung' },
{ value: 'consulting', label: 'Beratung & Dienstleistungen' },
{ value: 'public', label: 'Öffentliche Verwaltung' },
{ value: 'other', label: 'Sonstige' },
],
scoreWeights: { risk: 7, complexity: 5, assurance: 6 },
mapsToCompanyProfile: 'industry',
mapsToVVTQuestion: 'org_industry',
mapsToLFQuestion: 'org-branche',
},
{
id: 'org_business_model',
type: 'single',
label: 'Was ist Ihr primäres Geschäftsmodell?',
helpText: 'B2C-Modelle haben höhere Datenschutzanforderungen',
required: true,
options: [
{ value: 'b2b', label: 'B2B (Business-to-Business)' },
{ value: 'b2c', label: 'B2C (Business-to-Consumer)' },
{ value: 'both', label: 'B2B und B2C gemischt' },
{ value: 'b2g', label: 'B2G (Business-to-Government)' },
],
scoreWeights: { risk: 6, complexity: 5, assurance: 5 },
mapsToCompanyProfile: 'businessModel',
mapsToVVTQuestion: 'org_b2b_b2c',
mapsToLFQuestion: 'org-geschaeftsmodell',
},
{
id: 'org_has_dsb',
type: 'boolean',
label: 'Haben Sie einen Datenschutzbeauftragten bestellt?',
helpText: 'Ein DSB ist bei mehr als 20 Personen mit regelmäßiger Datenverarbeitung Pflicht',
required: true,
scoreWeights: { risk: 5, complexity: 3, assurance: 6 },
},
],
}
/**
* Block 2: Daten & Betroffene
*/
const BLOCK_2_DATA: ScopeQuestionBlock = {
id: 'data',
title: 'Daten & Betroffene',
description: 'Art und Umfang der verarbeiteten personenbezogenen Daten',
order: 2,
questions: [
{
id: 'data_minors',
type: 'boolean',
label: 'Verarbeiten Sie Daten von Minderjährigen?',
helpText: 'Besondere Schutzpflichten für unter 16-Jährige (bzw. 13-Jährige bei Online-Diensten)',
required: true,
scoreWeights: { risk: 10, complexity: 5, assurance: 7 },
mapsToVVTQuestion: 'data_minors',
},
{
id: 'data_art9',
type: 'multi',
label: 'Verarbeiten Sie besondere Kategorien personenbezogener Daten (Art. 9 DSGVO)?',
helpText: 'Diese Daten unterliegen erhöhten Schutzanforderungen',
required: true,
options: [
{ value: 'gesundheit', label: 'Gesundheitsdaten' },
{ value: 'biometrie', label: 'Biometrische Daten (z.B. Fingerabdruck, Gesichtserkennung)' },
{ value: 'genetik', label: 'Genetische Daten' },
{ value: 'politisch', label: 'Politische Meinungen' },
{ value: 'religion', label: 'Religiöse/weltanschauliche Überzeugungen' },
{ value: 'gewerkschaft', label: 'Gewerkschaftszugehörigkeit' },
{ value: 'sexualleben', label: 'Sexualleben/sexuelle Orientierung' },
{ value: 'strafrechtlich', label: 'Strafrechtliche Verurteilungen/Straftaten' },
{ value: 'ethnisch', label: 'Ethnische Herkunft' },
],
scoreWeights: { risk: 10, complexity: 8, assurance: 9 },
mapsToVVTQuestion: 'data_health',
},
{
id: 'data_hr',
type: 'boolean',
label: 'Verarbeiten Sie Personaldaten (HR)?',
helpText: 'Bewerberdaten, Gehälter, Leistungsbeurteilungen etc.',
required: true,
scoreWeights: { risk: 6, complexity: 4, assurance: 5 },
mapsToVVTQuestion: 'dept_hr',
mapsToLFQuestion: 'data-hr',
},
{
id: 'data_communication',
type: 'boolean',
label: 'Verarbeiten Sie Kommunikationsdaten (E-Mail, Chat, Telefonie)?',
helpText: 'Inhalte oder Metadaten von Kommunikationsvorgängen',
required: true,
scoreWeights: { risk: 7, complexity: 5, assurance: 6 },
},
{
id: 'data_financial',
type: 'boolean',
label: 'Verarbeiten Sie Finanzdaten (Konten, Zahlungen)?',
helpText: 'Bankdaten, Kreditkartendaten, Buchhaltungsdaten',
required: true,
scoreWeights: { risk: 8, complexity: 6, assurance: 7 },
mapsToVVTQuestion: 'dept_finance',
mapsToLFQuestion: 'data-buchhaltung',
},
{
id: 'data_volume',
type: 'single',
label: 'Wie viele Personendatensätze verarbeiten Sie insgesamt?',
helpText: 'Schätzen Sie die Gesamtzahl betroffener Personen',
required: true,
options: [
{ value: '<1000', label: 'Unter 1.000' },
{ value: '1000-10000', label: '1.000 bis 10.000' },
{ value: '10000-100000', label: '10.000 bis 100.000' },
{ value: '100000-1000000', label: '100.000 bis 1 Mio.' },
{ value: '>1000000', label: 'Über 1 Mio.' },
],
scoreWeights: { risk: 7, complexity: 6, assurance: 6 },
},
],
}
/**
* Block 3: Verarbeitung & Zweck
*/
const BLOCK_3_PROCESSING: ScopeQuestionBlock = {
id: 'processing',
title: 'Verarbeitung & Zweck',
description: 'Wie und wofür werden personenbezogene Daten verarbeitet?',
order: 3,
questions: [
{
id: 'proc_tracking',
type: 'boolean',
label: 'Setzen Sie Tracking oder Profiling ein?',
helpText: 'Web-Analytics, Werbe-Tracking, Nutzungsprofile etc.',
required: true,
scoreWeights: { risk: 7, complexity: 6, assurance: 6 },
},
{
id: 'proc_adm_scoring',
type: 'boolean',
label: 'Treffen Sie automatisierte Entscheidungen (Art. 22 DSGVO)?',
helpText: 'Scoring, Bonitätsprüfung, automatische Ablehnung ohne menschliche Beteiligung',
required: true,
scoreWeights: { risk: 9, complexity: 8, assurance: 8 },
},
{
id: 'proc_ai_usage',
type: 'multi',
label: 'Setzen Sie KI-Systeme ein?',
helpText: 'KI-Einsatz kann zusätzliche Anforderungen (EU AI Act) auslösen',
required: true,
options: [
{ value: 'keine', label: 'Keine KI im Einsatz' },
{ value: 'chatbot', label: 'Chatbots/Virtuelle Assistenten' },
{ value: 'scoring', label: 'Scoring/Risikobewertung' },
{ value: 'profiling', label: 'Profiling/Verhaltensvorhersage' },
{ value: 'generativ', label: 'Generative KI (Text, Bild, Code)' },
{ value: 'autonom', label: 'Autonome Systeme/Entscheidungen' },
],
scoreWeights: { risk: 8, complexity: 9, assurance: 7 },
},
{
id: 'proc_data_combination',
type: 'boolean',
label: 'Führen Sie Daten aus verschiedenen Quellen zusammen?',
helpText: 'Data Matching, Anreicherung aus externen Quellen',
required: true,
scoreWeights: { risk: 7, complexity: 7, assurance: 6 },
},
{
id: 'proc_employee_monitoring',
type: 'boolean',
label: 'Überwachen Sie Mitarbeiter (Zeiterfassung, Standort, IT-Nutzung)?',
helpText: 'Beschäftigtendatenschutz nach § 26 BDSG',
required: true,
scoreWeights: { risk: 8, complexity: 6, assurance: 7 },
},
{
id: 'proc_video_surveillance',
type: 'boolean',
label: 'Setzen Sie Videoüberwachung ein?',
helpText: 'Kameras in Büros, Produktionsstätten, Verkaufsräumen etc.',
required: true,
scoreWeights: { risk: 8, complexity: 5, assurance: 7 },
mapsToVVTQuestion: 'special_video_surveillance',
mapsToLFQuestion: 'data-video',
},
],
}
/**
* Block 4: Technik/Hosting/Transfers
*/
const BLOCK_4_TECH: ScopeQuestionBlock = {
id: 'tech',
title: 'Technik, Hosting & Transfers',
description: 'Technische Infrastruktur und Datenübermittlung',
order: 4,
questions: [
{
id: 'tech_hosting_location',
type: 'single',
label: 'Wo werden Ihre Daten primär gehostet?',
helpText: 'Standort bestimmt anwendbares Datenschutzrecht',
required: true,
options: [
{ value: 'de', label: 'Deutschland' },
{ value: 'eu', label: 'EU (ohne Deutschland)' },
{ value: 'ewr', label: 'EWR (z.B. Norwegen, Island)' },
{ value: 'us_adequacy', label: 'USA (mit Angemessenheitsbeschluss/DPF)' },
{ value: 'drittland', label: 'Drittland ohne Angemessenheitsbeschluss' },
],
scoreWeights: { risk: 7, complexity: 6, assurance: 7 },
},
{
id: 'tech_subprocessors',
type: 'boolean',
label: 'Nutzen Sie Auftragsverarbeiter (externe Dienstleister)?',
helpText: 'Cloud-Anbieter, Hosting, E-Mail-Service, CRM etc. erfordert AVV nach Art. 28 DSGVO',
required: true,
scoreWeights: { risk: 6, complexity: 7, assurance: 7 },
},
{
id: 'tech_third_country',
type: 'boolean',
label: 'Übermitteln Sie Daten in Drittländer?',
helpText: 'Transfer außerhalb EU/EWR erfordert Schutzmaßnahmen (SCC, BCR etc.)',
required: true,
scoreWeights: { risk: 9, complexity: 8, assurance: 8 },
mapsToVVTQuestion: 'transfer_cloud_us',
},
{
id: 'tech_encryption_rest',
type: 'boolean',
label: 'Sind Daten im Ruhezustand verschlüsselt (at rest)?',
helpText: 'Datenbank-, Dateisystem- oder Volume-Verschlüsselung',
required: true,
scoreWeights: { risk: -5, complexity: 3, assurance: 7 },
},
{
id: 'tech_encryption_transit',
type: 'boolean',
label: 'Sind Daten bei Übertragung verschlüsselt (in transit)?',
helpText: 'TLS/SSL für alle Verbindungen',
required: true,
scoreWeights: { risk: -5, complexity: 2, assurance: 7 },
},
{
id: 'tech_cloud_providers',
type: 'multi',
label: 'Welche Cloud-Anbieter nutzen Sie?',
helpText: 'Mehrfachauswahl möglich',
required: false,
options: [
{ value: 'aws', label: 'Amazon Web Services (AWS)' },
{ value: 'azure', label: 'Microsoft Azure' },
{ value: 'gcp', label: 'Google Cloud Platform (GCP)' },
{ value: 'hetzner', label: 'Hetzner' },
{ value: 'ionos', label: 'IONOS' },
{ value: 'ovh', label: 'OVH' },
{ value: 'andere', label: 'Andere Anbieter' },
{ value: 'keine', label: 'Keine Cloud-Nutzung (On-Premise)' },
],
scoreWeights: { risk: 5, complexity: 6, assurance: 6 },
},
],
}
/**
* Block 5: Rechte & Prozesse
*/
const BLOCK_5_PROCESSES: ScopeQuestionBlock = {
id: 'processes',
title: 'Rechte & Prozesse',
description: 'Etablierte Datenschutz- und Sicherheitsprozesse',
order: 5,
questions: [
{
id: 'proc_dsar_process',
type: 'boolean',
label: 'Haben Sie einen Prozess für Betroffenenrechte (DSAR)?',
helpText: 'Auskunft, Löschung, Berichtigung, Widerspruch etc. Art. 15-22 DSGVO',
required: true,
scoreWeights: { risk: 6, complexity: 5, assurance: 8 },
},
{
id: 'proc_deletion_concept',
type: 'boolean',
label: 'Haben Sie ein Löschkonzept?',
helpText: 'Definierte Löschfristen und automatisierte Löschroutinen',
required: true,
scoreWeights: { risk: 7, complexity: 6, assurance: 8 },
},
{
id: 'proc_incident_response',
type: 'boolean',
label: 'Haben Sie einen Notfallplan für Datenschutzvorfälle?',
helpText: 'Incident Response Plan, 72h-Meldepflicht an Aufsichtsbehörde (Art. 33 DSGVO)',
required: true,
scoreWeights: { risk: 8, complexity: 6, assurance: 9 },
},
{
id: 'proc_regular_audits',
type: 'boolean',
label: 'Führen Sie regelmäßige Datenschutz-Audits durch?',
helpText: 'Interne oder externe Prüfungen mindestens jährlich',
required: true,
scoreWeights: { risk: 5, complexity: 4, assurance: 9 },
},
{
id: 'proc_training',
type: 'boolean',
label: 'Schulen Sie Ihre Mitarbeiter im Datenschutz?',
helpText: 'Awareness-Trainings, Onboarding, jährliche Auffrischung',
required: true,
scoreWeights: { risk: 6, complexity: 3, assurance: 7 },
},
],
}
/**
* Block 6: Produktkontext
*/
const BLOCK_6_PRODUCT: ScopeQuestionBlock = {
id: 'product',
title: 'Produktkontext',
description: 'Spezifische Merkmale Ihrer Produkte und Services',
order: 6,
questions: [
{
id: 'prod_type',
type: 'multi',
label: 'Welche Art von Produkten/Services bieten Sie an?',
helpText: 'Mehrfachauswahl möglich',
required: true,
options: [
{ value: 'webapp', label: 'Web-Anwendung' },
{ value: 'mobile', label: 'Mobile App (iOS/Android)' },
{ value: 'saas', label: 'SaaS-Plattform' },
{ value: 'onpremise', label: 'On-Premise Software' },
{ value: 'api', label: 'API/Schnittstellen' },
{ value: 'iot', label: 'IoT/Hardware' },
{ value: 'beratung', label: 'Beratungsleistungen' },
{ value: 'handel', label: 'Handel/Vertrieb' },
],
scoreWeights: { risk: 5, complexity: 6, assurance: 5 },
},
{
id: 'prod_cookies_consent',
type: 'boolean',
label: 'Benötigen Sie Cookie-Consent (Tracking-Cookies)?',
helpText: 'Nicht-essenzielle Cookies erfordern opt-in Einwilligung',
required: true,
scoreWeights: { risk: 5, complexity: 4, assurance: 6 },
},
{
id: 'prod_webshop',
type: 'boolean',
label: 'Betreiben Sie einen Online-Shop?',
helpText: 'E-Commerce mit Zahlungsabwicklung, Bestellverwaltung',
required: true,
scoreWeights: { risk: 7, complexity: 6, assurance: 6 },
},
{
id: 'prod_api_external',
type: 'boolean',
label: 'Bieten Sie externe APIs an (Daten-Weitergabe an Dritte)?',
helpText: 'Programmierschnittstellen für Partner, Entwickler etc.',
required: true,
scoreWeights: { risk: 7, complexity: 7, assurance: 7 },
},
{
id: 'prod_data_broker',
type: 'boolean',
label: 'Handeln Sie mit Daten (Data Brokerage, Adresshandel)?',
helpText: 'Verkauf oder Vermittlung personenbezogener Daten',
required: true,
scoreWeights: { risk: 10, complexity: 8, assurance: 9 },
},
],
}
/**
* All question blocks in order
*/
export const SCOPE_QUESTION_BLOCKS: ScopeQuestionBlock[] = [
BLOCK_1_ORGANISATION,
BLOCK_2_DATA,
BLOCK_3_PROCESSING,
BLOCK_4_TECH,
BLOCK_5_PROCESSES,
BLOCK_6_PRODUCT,
]
/**
* Prefill scope answers from CompanyProfile
*/
export function prefillFromCompanyProfile(
profile: CompanyProfile
): ScopeProfilingAnswer[] {
const answers: ScopeProfilingAnswer[] = []
// employeeCount
if (profile.employeeCount != null) {
answers.push({
questionId: 'org_employee_count',
value: profile.employeeCount,
})
}
// annualRevenue
if (profile.annualRevenue) {
answers.push({
questionId: 'org_annual_revenue',
value: profile.annualRevenue,
})
}
// industry
if (profile.industry) {
answers.push({
questionId: 'org_industry',
value: profile.industry,
})
}
// businessModel
if (profile.businessModel) {
answers.push({
questionId: 'org_business_model',
value: profile.businessModel,
})
}
// dpoName -> org_has_dsb
if (profile.dpoName && profile.dpoName.trim() !== '') {
answers.push({
questionId: 'org_has_dsb',
value: true,
})
}
// usesAI -> proc_ai_usage
if (profile.usesAI === true) {
// We don't know which specific AI type, so just mark as "generativ" as a default
answers.push({
questionId: 'proc_ai_usage',
value: ['generativ'],
})
} else if (profile.usesAI === false) {
answers.push({
questionId: 'proc_ai_usage',
value: ['keine'],
})
}
// offerings -> prod_type mapping
if (profile.offerings && profile.offerings.length > 0) {
const prodTypes: string[] = []
const offeringsLower = profile.offerings.map((o) => o.toLowerCase())
if (offeringsLower.some((o) => o.includes('webapp') || o.includes('web'))) {
prodTypes.push('webapp')
}
if (
offeringsLower.some((o) => o.includes('mobile') || o.includes('app'))
) {
prodTypes.push('mobile')
}
if (offeringsLower.some((o) => o.includes('saas') || o.includes('cloud'))) {
prodTypes.push('saas')
}
if (
offeringsLower.some(
(o) => o.includes('onpremise') || o.includes('on-premise')
)
) {
prodTypes.push('onpremise')
}
if (offeringsLower.some((o) => o.includes('api'))) {
prodTypes.push('api')
}
if (offeringsLower.some((o) => o.includes('iot') || o.includes('hardware'))) {
prodTypes.push('iot')
}
if (
offeringsLower.some(
(o) => o.includes('beratung') || o.includes('consulting')
)
) {
prodTypes.push('beratung')
}
if (
offeringsLower.some(
(o) => o.includes('handel') || o.includes('shop') || o.includes('commerce')
)
) {
prodTypes.push('handel')
}
if (prodTypes.length > 0) {
answers.push({
questionId: 'prod_type',
value: prodTypes,
})
}
}
return answers
}
/**
* Prefill scope answers from VVT profiling answers
*/
export function prefillFromVVTAnswers(
vvtAnswers: Record<string, unknown>
): ScopeProfilingAnswer[] {
const answers: ScopeProfilingAnswer[] = []
// Build reverse mapping: VVT question -> Scope question
const reverseMap: Record<string, string> = {}
for (const block of SCOPE_QUESTION_BLOCKS) {
for (const q of block.questions) {
if (q.mapsToVVTQuestion) {
reverseMap[q.mapsToVVTQuestion] = q.id
}
}
}
// Map VVT answers to scope answers
for (const [vvtQuestionId, vvtValue] of Object.entries(vvtAnswers)) {
const scopeQuestionId = reverseMap[vvtQuestionId]
if (scopeQuestionId) {
answers.push({
questionId: scopeQuestionId,
value: vvtValue,
})
}
}
return answers
}
/**
* Prefill scope answers from Loeschfristen profiling answers
*/
export function prefillFromLoeschfristenAnswers(
lfAnswers: Array<{ questionId: string; value: unknown }>
): ScopeProfilingAnswer[] {
const answers: ScopeProfilingAnswer[] = []
// Build reverse mapping: LF question -> Scope question
const reverseMap: Record<string, string> = {}
for (const block of SCOPE_QUESTION_BLOCKS) {
for (const q of block.questions) {
if (q.mapsToLFQuestion) {
reverseMap[q.mapsToLFQuestion] = q.id
}
}
}
// Map LF answers to scope answers
for (const lfAnswer of lfAnswers) {
const scopeQuestionId = reverseMap[lfAnswer.questionId]
if (scopeQuestionId) {
answers.push({
questionId: scopeQuestionId,
value: lfAnswer.value,
})
}
}
return answers
}
/**
* Export scope answers in VVT format
*/
export function exportToVVTAnswers(
scopeAnswers: ScopeProfilingAnswer[]
): Record<string, unknown> {
const vvtAnswers: Record<string, unknown> = {}
for (const answer of scopeAnswers) {
// Find the question
let question: ScopeProfilingQuestion | undefined
for (const block of SCOPE_QUESTION_BLOCKS) {
question = block.questions.find((q) => q.id === answer.questionId)
if (question) break
}
if (question?.mapsToVVTQuestion) {
vvtAnswers[question.mapsToVVTQuestion] = answer.value
}
}
return vvtAnswers
}
/**
* Export scope answers in Loeschfristen format
*/
export function exportToLoeschfristenAnswers(
scopeAnswers: ScopeProfilingAnswer[]
): Array<{ questionId: string; value: unknown }> {
const lfAnswers: Array<{ questionId: string; value: unknown }> = []
for (const answer of scopeAnswers) {
// Find the question
let question: ScopeProfilingQuestion | undefined
for (const block of SCOPE_QUESTION_BLOCKS) {
question = block.questions.find((q) => q.id === answer.questionId)
if (question) break
}
if (question?.mapsToLFQuestion) {
lfAnswers.push({
questionId: question.mapsToLFQuestion,
value: answer.value,
})
}
}
return lfAnswers
}
/**
* Export scope answers for TOM generator
*/
export function exportToTOMProfile(
scopeAnswers: ScopeProfilingAnswer[]
): Record<string, unknown> {
const tomProfile: Record<string, unknown> = {}
// Get answer values
const getVal = (qId: string) => getAnswerValue(scopeAnswers, qId)
// Map relevant scope answers to TOM profile fields
tomProfile.industry = getVal('org_industry')
tomProfile.employeeCount = getVal('org_employee_count')
tomProfile.hasDataMinors = getVal('data_minors')
tomProfile.hasSpecialCategories = Array.isArray(getVal('data_art9'))
? (getVal('data_art9') as string[]).length > 0
: false
tomProfile.hasAutomatedDecisions = getVal('proc_adm_scoring')
tomProfile.usesAI = Array.isArray(getVal('proc_ai_usage'))
? !(getVal('proc_ai_usage') as string[]).includes('keine')
: false
tomProfile.hasThirdCountryTransfer = getVal('tech_third_country')
tomProfile.hasEncryptionRest = getVal('tech_encryption_rest')
tomProfile.hasEncryptionTransit = getVal('tech_encryption_transit')
tomProfile.hasIncidentResponse = getVal('proc_incident_response')
tomProfile.hasDeletionConcept = getVal('proc_deletion_concept')
tomProfile.hasRegularAudits = getVal('proc_regular_audits')
tomProfile.hasTraining = getVal('proc_training')
return tomProfile
}
/**
* Check if a block is complete (all required questions answered)
*/
export function isBlockComplete(
answers: ScopeProfilingAnswer[],
blockId: ScopeQuestionBlockId
): boolean {
const block = SCOPE_QUESTION_BLOCKS.find((b) => b.id === blockId)
if (!block) return false
const requiredQuestions = block.questions.filter((q) => q.required)
const answeredQuestionIds = new Set(answers.map((a) => a.questionId))
return requiredQuestions.every((q) => answeredQuestionIds.has(q.id))
}
/**
* Get progress for a specific block (0-100)
*/
export function getBlockProgress(
answers: ScopeProfilingAnswer[],
blockId: ScopeQuestionBlockId
): number {
const block = SCOPE_QUESTION_BLOCKS.find((b) => b.id === blockId)
if (!block) return 0
const requiredQuestions = block.questions.filter((q) => q.required)
if (requiredQuestions.length === 0) return 100
const answeredQuestionIds = new Set(answers.map((a) => a.questionId))
const answeredCount = requiredQuestions.filter((q) =>
answeredQuestionIds.has(q.id)
).length
return Math.round((answeredCount / requiredQuestions.length) * 100)
}
/**
* Get total progress across all blocks (0-100)
*/
export function getTotalProgress(answers: ScopeProfilingAnswer[]): number {
let totalRequired = 0
let totalAnswered = 0
const answeredQuestionIds = new Set(answers.map((a) => a.questionId))
for (const block of SCOPE_QUESTION_BLOCKS) {
const requiredQuestions = block.questions.filter((q) => q.required)
totalRequired += requiredQuestions.length
totalAnswered += requiredQuestions.filter((q) =>
answeredQuestionIds.has(q.id)
).length
}
if (totalRequired === 0) return 100
return Math.round((totalAnswered / totalRequired) * 100)
}
/**
* Get answer value for a specific question
*/
export function getAnswerValue(
answers: ScopeProfilingAnswer[],
questionId: string
): unknown {
const answer = answers.find((a) => a.questionId === questionId)
return answer?.value
}
/**
* Get all questions as a flat array
*/
export function getAllQuestions(): ScopeProfilingQuestion[] {
return SCOPE_QUESTION_BLOCKS.flatMap((block) => block.questions)
}

File diff suppressed because it is too large Load Diff

View File

@@ -62,6 +62,9 @@ const initialState: SDKState = {
// Company Profile
companyProfile: null,
// Compliance Scope
complianceScope: null,
// Progress
currentPhase: 1,
currentStep: 'company-profile',
@@ -179,6 +182,16 @@ function sdkReducer(state: SDKState, action: ExtendedSDKAction): SDKState {
: null,
})
case 'SET_COMPLIANCE_SCOPE':
return updateState({ complianceScope: action.payload })
case 'UPDATE_COMPLIANCE_SCOPE':
return updateState({
complianceScope: state.complianceScope
? { ...state.complianceScope, ...action.payload }
: null,
})
case 'ADD_IMPORTED_DOCUMENT':
return updateState({
importedDocuments: [...state.importedDocuments, action.payload],
@@ -448,6 +461,10 @@ interface SDKContextValue {
setCompanyProfile: (profile: CompanyProfile) => void
updateCompanyProfile: (updates: Partial<CompanyProfile>) => void
// Compliance Scope
setComplianceScope: (scope: import('./compliance-scope-types').ComplianceScopeState) => void
updateComplianceScope: (updates: Partial<import('./compliance-scope-types').ComplianceScopeState>) => void
// Import (for existing customers)
addImportedDocument: (doc: ImportedDocument) => void
setGapAnalysis: (analysis: GapAnalysis) => void
@@ -740,6 +757,15 @@ export function SDKProvider({
dispatch({ type: 'UPDATE_COMPANY_PROFILE', payload: updates })
}, [])
// Compliance Scope
const setComplianceScope = useCallback((scope: import('./compliance-scope-types').ComplianceScopeState) => {
dispatch({ type: 'SET_COMPLIANCE_SCOPE', payload: scope })
}, [])
const updateComplianceScope = useCallback((updates: Partial<import('./compliance-scope-types').ComplianceScopeState>) => {
dispatch({ type: 'UPDATE_COMPLIANCE_SCOPE', payload: updates })
}, [])
// Import Document
const addImportedDocument = useCallback((doc: ImportedDocument) => {
dispatch({ type: 'ADD_IMPORTED_DOCUMENT', payload: doc })
@@ -1040,6 +1066,8 @@ export function SDKProvider({
setCustomerType,
setCompanyProfile,
updateCompanyProfile,
setComplianceScope,
updateComplianceScope,
addImportedDocument,
setGapAnalysis,
validateCheckpoint,

View File

@@ -6,3 +6,5 @@
export * from './types'
export * from './api'
export * from './risk-catalog'
export * from './mitigation-library'

View File

@@ -0,0 +1,694 @@
/**
* DSFA Massnahmenbibliothek - Vordefinierte Massnahmen
*
* ~50 Massnahmen gegliedert nach SDM-Gewaehrleistungszielen
* (Vertraulichkeit, Integritaet, Verfuegbarkeit, Datenminimierung,
* 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'
import type { SDMGoal } from './types'
// =============================================================================
// TYPES
// =============================================================================
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,615 @@
/**
* DSFA Risikokatalog - Vordefinierte Risikoszenarien
*
* ~40 Risiken gegliedert nach Vertraulichkeit, Integritaet, Verfuegbarkeit,
* Rechte & Freiheiten, Drittlandtransfer und Automatisierung.
*
* 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'
import type { SDMGoal } from './types'
// =============================================================================
// 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

@@ -5,6 +5,57 @@
* aligned with the backend Go models.
*/
// =============================================================================
// SDM GEWAEHRLEISTUNGSZIELE (Standard-Datenschutzmodell V2.0)
// =============================================================================
export type SDMGoal =
| 'datenminimierung'
| 'verfuegbarkeit'
| 'integritaet'
| 'vertraulichkeit'
| 'nichtverkettung'
| 'transparenz'
| 'intervenierbarkeit'
export const SDM_GOALS: Record<SDMGoal, { name: string; description: string; article: string }> = {
datenminimierung: {
name: 'Datenminimierung',
description: 'Verarbeitung personenbezogener Daten auf das dem Zweck angemessene, erhebliche und notwendige Mass beschraenken.',
article: 'Art. 5 Abs. 1 lit. c DSGVO',
},
verfuegbarkeit: {
name: 'Verfuegbarkeit',
description: 'Personenbezogene Daten muessen dem Verantwortlichen zur Verfuegung stehen und ordnungsgemaess im vorgesehenen Prozess verwendet werden koennen.',
article: 'Art. 32 Abs. 1 lit. b DSGVO',
},
integritaet: {
name: 'Integritaet',
description: 'Personenbezogene Daten bleiben waehrend der Verarbeitung unversehrt, vollstaendig und aktuell.',
article: 'Art. 5 Abs. 1 lit. d DSGVO',
},
vertraulichkeit: {
name: 'Vertraulichkeit',
description: 'Kein unbefugter Zugriff auf personenbezogene Daten. Nur befugte Personen koennen auf Daten zugreifen.',
article: 'Art. 32 Abs. 1 lit. b DSGVO',
},
nichtverkettung: {
name: 'Nichtverkettung',
description: 'Personenbezogene Daten duerfen nicht ohne Weiteres fuer einen anderen als den erhobenen Zweck zusammengefuehrt werden (Zweckbindung).',
article: 'Art. 5 Abs. 1 lit. b DSGVO',
},
transparenz: {
name: 'Transparenz',
description: 'Die Verarbeitung personenbezogener Daten muss fuer Betroffene und Aufsichtsbehoerden nachvollziehbar sein.',
article: 'Art. 5 Abs. 1 lit. a DSGVO',
},
intervenierbarkeit: {
name: 'Intervenierbarkeit',
description: 'Den Betroffenen werden wirksame Moeglichkeiten der Einflussnahme (Auskunft, Berichtigung, Loeschung, Widerspruch) auf die Verarbeitung gewaehrt.',
article: 'Art. 15-21 DSGVO',
},
}
// =============================================================================
// ENUMS & CONSTANTS
// =============================================================================

View File

@@ -55,6 +55,25 @@ export type {
GenerateResponse,
} from './sdk-client'
// Compliance Scope Engine
export type {
ComplianceDepthLevel,
ComplianceScores,
ComplianceScopeState,
ScopeDecision,
ScopeProfilingAnswer,
ScopeDocumentType,
} from './compliance-scope-types'
export {
DEPTH_LEVEL_LABELS,
DEPTH_LEVEL_DESCRIPTIONS,
DEPTH_LEVEL_COLORS,
DOCUMENT_TYPE_LABELS,
STORAGE_KEY as SCOPE_STORAGE_KEY,
createEmptyScopeState,
} from './compliance-scope-types'
export { complianceScopeEngine } from './compliance-scope-engine'
// Demo Data Seeding (stored via API like real customer data)
export {
generateDemoState,

View File

@@ -0,0 +1,578 @@
/**
* Loeschfristen Baseline-Katalog
*
* 18 vordefinierte Aufbewahrungsfristen-Templates fuer gaengige
* Datenobjekte in deutschen Unternehmen. Basierend auf AO, HGB,
* UStG, BGB, ArbZG, AGG, BDSG und BSIG.
*
* Werden genutzt, um neue Loeschfrist-Policies schnell aus
* bewaehrten Vorlagen zu erstellen.
*/
import type {
LoeschfristPolicy,
RetentionDriverType,
DeletionMethodType,
StorageLocation,
PolicyStatus,
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 (18 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'],
},
]
// =============================================================================
// 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,325 @@
// =============================================================================
// Loeschfristen Module - Compliance Check Engine
// Prueft Policies auf Vollstaendigkeit, Konsistenz und DSGVO-Konformitaet
// =============================================================================
import {
LoeschfristPolicy,
PolicyStatus,
isPolicyOverdue,
getActiveLegalHolds,
} from './loeschfristen-types'
// =============================================================================
// TYPES
// =============================================================================
export type ComplianceIssueType =
| 'MISSING_TRIGGER'
| 'MISSING_LEGAL_BASIS'
| 'OVERDUE_REVIEW'
| 'NO_RESPONSIBLE'
| 'LEGAL_HOLD_CONFLICT'
| 'STALE_DRAFT'
| 'UNCOVERED_VVT_CATEGORY'
export type ComplianceIssueSeverity = 'LOW' | 'MEDIUM' | 'HIGH' | 'CRITICAL'
export interface ComplianceIssue {
id: string
policyId: string
policyName: string
type: ComplianceIssueType
severity: ComplianceIssueSeverity
title: string
description: string
recommendation: string
}
export interface ComplianceCheckResult {
issues: ComplianceIssue[]
score: number // 0-100
stats: {
total: number
passed: number
failed: number
bySeverity: Record<ComplianceIssueSeverity, number>
}
}
// =============================================================================
// HELPERS
// =============================================================================
let issueCounter = 0
function createIssueId(): string {
issueCounter++
return `CI-${Date.now()}-${String(issueCounter).padStart(4, '0')}`
}
function createIssue(
policy: LoeschfristPolicy,
type: ComplianceIssueType,
severity: ComplianceIssueSeverity,
title: string,
description: string,
recommendation: string
): ComplianceIssue {
return {
id: createIssueId(),
policyId: policy.policyId,
policyName: policy.dataObjectName || policy.policyId,
type,
severity,
title,
description,
recommendation,
}
}
function daysBetween(dateStr: string, now: Date): number {
const date = new Date(dateStr)
const diffMs = now.getTime() - date.getTime()
return Math.floor(diffMs / (1000 * 60 * 60 * 24))
}
// =============================================================================
// INDIVIDUAL CHECKS
// =============================================================================
/**
* Check 1: MISSING_TRIGGER (HIGH)
* Policy has no deletionTrigger set, or trigger is PURPOSE_END but no startEvent defined.
*/
function checkMissingTrigger(policy: LoeschfristPolicy): ComplianceIssue | null {
if (!policy.deletionTrigger) {
return createIssue(
policy,
'MISSING_TRIGGER',
'HIGH',
'Kein Loeschtrigger definiert',
`Die Policy "${policy.dataObjectName}" hat keinen Loeschtrigger gesetzt. Ohne Trigger ist unklar, wann die Daten geloescht werden.`,
'Definieren Sie einen Loeschtrigger (Zweckende, Aufbewahrungspflicht oder Legal Hold) fuer diese Policy.'
)
}
if (policy.deletionTrigger === 'PURPOSE_END' && !policy.startEvent.trim()) {
return createIssue(
policy,
'MISSING_TRIGGER',
'HIGH',
'Zweckende ohne Startereignis',
`Die Policy "${policy.dataObjectName}" nutzt "Zweckende" als Trigger, hat aber kein Startereignis definiert. Ohne Startereignis laesst sich der Loeschzeitpunkt nicht berechnen.`,
'Definieren Sie ein konkretes Startereignis (z.B. "Vertragsende", "Abmeldung", "Projektabschluss").'
)
}
return null
}
/**
* Check 2: MISSING_LEGAL_BASIS (HIGH)
* Policy with RETENTION_DRIVER trigger but no retentionDriver set.
*/
function checkMissingLegalBasis(policy: LoeschfristPolicy): ComplianceIssue | null {
if (policy.deletionTrigger === 'RETENTION_DRIVER' && !policy.retentionDriver) {
return createIssue(
policy,
'MISSING_LEGAL_BASIS',
'HIGH',
'Aufbewahrungspflicht ohne Rechtsgrundlage',
`Die Policy "${policy.dataObjectName}" hat "Aufbewahrungspflicht" als Trigger, aber keinen konkreten Aufbewahrungstreiber (z.B. AO 147, HGB 257) zugeordnet.`,
'Waehlen Sie den passenden gesetzlichen Aufbewahrungstreiber aus oder wechseln Sie den Trigger-Typ.'
)
}
return null
}
/**
* Check 3: OVERDUE_REVIEW (MEDIUM)
* Policy where nextReviewDate is in the past.
*/
function checkOverdueReview(policy: LoeschfristPolicy): ComplianceIssue | null {
if (isPolicyOverdue(policy)) {
const overdueDays = daysBetween(policy.nextReviewDate, new Date())
return createIssue(
policy,
'OVERDUE_REVIEW',
'MEDIUM',
'Ueberfaellige Pruefung',
`Die Policy "${policy.dataObjectName}" haette am ${new Date(policy.nextReviewDate).toLocaleDateString('de-DE')} geprueft werden muessen. Die Pruefung ist ${overdueDays} Tag(e) ueberfaellig.`,
'Fuehren Sie umgehend eine Pruefung dieser Policy durch und aktualisieren Sie das naechste Pruefungsdatum.'
)
}
return null
}
/**
* Check 4: NO_RESPONSIBLE (MEDIUM)
* Policy with no responsiblePerson AND no responsibleRole.
*/
function checkNoResponsible(policy: LoeschfristPolicy): ComplianceIssue | null {
if (!policy.responsiblePerson.trim() && !policy.responsibleRole.trim()) {
return createIssue(
policy,
'NO_RESPONSIBLE',
'MEDIUM',
'Keine verantwortliche Person/Rolle',
`Die Policy "${policy.dataObjectName}" hat weder eine verantwortliche Person noch eine verantwortliche Rolle zugewiesen. Ohne Verantwortlichkeit kann die Loeschung nicht zuverlaessig durchgefuehrt werden.`,
'Weisen Sie eine verantwortliche Person oder zumindest eine verantwortliche Rolle (z.B. "Datenschutzbeauftragter", "IT-Leitung") zu.'
)
}
return null
}
/**
* Check 5: LEGAL_HOLD_CONFLICT (CRITICAL)
* Policy has active legal hold but deletionMethod is AUTO_DELETE.
*/
function checkLegalHoldConflict(policy: LoeschfristPolicy): ComplianceIssue | null {
const activeHolds = getActiveLegalHolds(policy)
if (activeHolds.length > 0 && policy.deletionMethod === 'AUTO_DELETE') {
const holdReasons = activeHolds.map((h) => h.reason).join(', ')
return createIssue(
policy,
'LEGAL_HOLD_CONFLICT',
'CRITICAL',
'Legal Hold mit automatischer Loeschung',
`Die Policy "${policy.dataObjectName}" hat ${activeHolds.length} aktive(n) Legal Hold(s) (${holdReasons}), aber die Loeschmethode ist auf "Automatische Loeschung" gesetzt. Dies kann zu unbeabsichtigter Vernichtung von Beweismitteln fuehren.`,
'Aendern Sie die Loeschmethode auf "Manuelle Pruefung & Loeschung" oder deaktivieren Sie die automatische Loeschung, solange der Legal Hold aktiv ist.'
)
}
return null
}
/**
* Check 6: STALE_DRAFT (LOW)
* Policy in DRAFT status older than 90 days.
*/
function checkStaleDraft(policy: LoeschfristPolicy): ComplianceIssue | null {
if (policy.status === 'DRAFT') {
const ageInDays = daysBetween(policy.createdAt, new Date())
if (ageInDays > 90) {
return createIssue(
policy,
'STALE_DRAFT',
'LOW',
'Veralteter Entwurf',
`Die Policy "${policy.dataObjectName}" ist seit ${ageInDays} Tagen im Entwurfsstatus. Entwuerfe, die laenger als 90 Tage nicht finalisiert werden, deuten auf unvollstaendige Dokumentation hin.`,
'Finalisieren Sie den Entwurf und setzen Sie den Status auf "Aktiv", oder archivieren Sie die Policy, falls sie nicht mehr benoetigt wird.'
)
}
}
return null
}
// =============================================================================
// MAIN COMPLIANCE CHECK
// =============================================================================
/**
* Fuehrt einen vollstaendigen Compliance-Check ueber alle Policies durch.
*
* @param policies - Alle Loeschfrist-Policies
* @param vvtDataCategories - Optionale Datenkategorien aus dem VVT (localStorage)
* @returns ComplianceCheckResult mit Issues, Score und Statistiken
*/
export function runComplianceCheck(
policies: LoeschfristPolicy[],
vvtDataCategories?: string[]
): ComplianceCheckResult {
// Reset counter for deterministic IDs within a single check run
issueCounter = 0
const issues: ComplianceIssue[] = []
// Run checks 1-6 for each policy
for (const policy of policies) {
const checks = [
checkMissingTrigger(policy),
checkMissingLegalBasis(policy),
checkOverdueReview(policy),
checkNoResponsible(policy),
checkLegalHoldConflict(policy),
checkStaleDraft(policy),
]
for (const issue of checks) {
if (issue !== null) {
issues.push(issue)
}
}
}
// Check 7: UNCOVERED_VVT_CATEGORY (MEDIUM)
if (vvtDataCategories && vvtDataCategories.length > 0) {
const coveredCategories = new Set<string>()
for (const policy of policies) {
for (const category of policy.dataCategories) {
coveredCategories.add(category.toLowerCase().trim())
}
}
for (const vvtCategory of vvtDataCategories) {
const normalized = vvtCategory.toLowerCase().trim()
if (!coveredCategories.has(normalized)) {
issues.push({
id: createIssueId(),
policyId: '-',
policyName: '-',
type: 'UNCOVERED_VVT_CATEGORY',
severity: 'MEDIUM',
title: `Datenkategorie ohne Loeschfrist: "${vvtCategory}"`,
description: `Die Datenkategorie "${vvtCategory}" ist im Verzeichnis der Verarbeitungstaetigkeiten (VVT) erfasst, hat aber keine zugehoerige Loeschfrist-Policy. Gemaess DSGVO Art. 5 Abs. 1 lit. e muss fuer jede Datenkategorie eine Speicherbegrenzung definiert sein.`,
recommendation: `Erstellen Sie eine neue Loeschfrist-Policy fuer die Datenkategorie "${vvtCategory}" oder ordnen Sie sie einer bestehenden Policy zu.`,
})
}
}
}
// Calculate score
const bySeverity: Record<ComplianceIssueSeverity, number> = {
LOW: 0,
MEDIUM: 0,
HIGH: 0,
CRITICAL: 0,
}
for (const issue of issues) {
bySeverity[issue.severity]++
}
const rawScore =
100 -
(bySeverity.CRITICAL * 15 +
bySeverity.HIGH * 10 +
bySeverity.MEDIUM * 5 +
bySeverity.LOW * 2)
const score = Math.max(0, rawScore)
// Calculate pass/fail per policy
const failedPolicyIds = new Set(
issues.filter((i) => i.policyId !== '-').map((i) => i.policyId)
)
const totalPolicies = policies.length
const failedCount = failedPolicyIds.size
const passedCount = totalPolicies - failedCount
return {
issues,
score,
stats: {
total: totalPolicies,
passed: passedCount,
failed: failedCount,
bySeverity,
},
}
}

View File

@@ -0,0 +1,353 @@
// =============================================================================
// Loeschfristen Module - Export & Report Generation
// JSON, CSV, Markdown-Compliance-Report und Browser-Download
// =============================================================================
import {
LoeschfristPolicy,
RETENTION_DRIVER_META,
DELETION_METHOD_LABELS,
STATUS_LABELS,
TRIGGER_LABELS,
formatRetentionDuration,
getEffectiveDeletionTrigger,
} from './loeschfristen-types'
import {
runComplianceCheck,
ComplianceCheckResult,
ComplianceIssueSeverity,
} from './loeschfristen-compliance'
// =============================================================================
// JSON EXPORT
// =============================================================================
interface PolicyExportEnvelope {
exportDate: string
version: string
totalPolicies: number
policies: LoeschfristPolicy[]
}
/**
* Exportiert alle Policies als pretty-printed JSON.
* Enthaelt Metadaten (Exportdatum, Version, Anzahl).
*/
export function exportPoliciesAsJSON(policies: LoeschfristPolicy[]): string {
const exportData: PolicyExportEnvelope = {
exportDate: new Date().toISOString(),
version: '1.0',
totalPolicies: policies.length,
policies: policies,
}
return JSON.stringify(exportData, null, 2)
}
// =============================================================================
// CSV EXPORT
// =============================================================================
/**
* Escapes a CSV field value according to RFC 4180.
* Fields containing commas, double quotes, or newlines are wrapped in quotes.
* Existing double quotes are doubled.
*/
function escapeCSVField(value: string): string {
if (
value.includes(',') ||
value.includes('"') ||
value.includes('\n') ||
value.includes('\r') ||
value.includes(';')
) {
return `"${value.replace(/"/g, '""')}"`
}
return value
}
/**
* Formats a date string to German locale format (DD.MM.YYYY).
* Returns empty string for null/undefined/empty values.
*/
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 ''
}
}
/**
* Exportiert alle Policies als CSV mit BOM fuer Excel-Kompatibilitaet.
* Trennzeichen ist Semikolon (;) fuer deutschsprachige Excel-Versionen.
*/
export function exportPoliciesAsCSV(policies: LoeschfristPolicy[]): string {
const BOM = '\uFEFF'
const SEPARATOR = ';'
const headers = [
'LF-Nr.',
'Datenobjekt',
'Beschreibung',
'Loeschtrigger',
'Aufbewahrungstreiber',
'Frist',
'Startereignis',
'Loeschmethode',
'Verantwortlich',
'Status',
'Legal Hold aktiv',
'Letzte Pruefung',
'Naechste Pruefung',
]
const rows: string[] = []
// Header row
rows.push(headers.map(escapeCSVField).join(SEPARATOR))
// Data rows
for (const policy of policies) {
const effectiveTrigger = getEffectiveDeletionTrigger(policy)
const triggerLabel = TRIGGER_LABELS[effectiveTrigger]
const driverLabel = policy.retentionDriver
? RETENTION_DRIVER_META[policy.retentionDriver].label
: ''
const durationLabel = formatRetentionDuration(
policy.retentionDuration,
policy.retentionUnit
)
const methodLabel = DELETION_METHOD_LABELS[policy.deletionMethod]
const statusLabel = STATUS_LABELS[policy.status]
// Combine responsiblePerson and responsibleRole
const responsible = [policy.responsiblePerson, policy.responsibleRole]
.filter((s) => s.trim())
.join(' / ')
const legalHoldActive = policy.hasActiveLegalHold ? 'Ja' : 'Nein'
const row = [
policy.policyId,
policy.dataObjectName,
policy.description,
triggerLabel,
driverLabel,
durationLabel,
policy.startEvent,
methodLabel,
responsible || '-',
statusLabel,
legalHoldActive,
formatDateDE(policy.lastReviewDate),
formatDateDE(policy.nextReviewDate),
]
rows.push(row.map(escapeCSVField).join(SEPARATOR))
}
return BOM + rows.join('\r\n')
}
// =============================================================================
// COMPLIANCE SUMMARY (MARKDOWN)
// =============================================================================
const SEVERITY_LABELS: Record<ComplianceIssueSeverity, string> = {
CRITICAL: 'Kritisch',
HIGH: 'Hoch',
MEDIUM: 'Mittel',
LOW: 'Niedrig',
}
const SEVERITY_EMOJI: Record<ComplianceIssueSeverity, string> = {
CRITICAL: '[!!!]',
HIGH: '[!!]',
MEDIUM: '[!]',
LOW: '[i]',
}
/**
* Returns a textual rating based on the compliance score.
*/
function getScoreRating(score: number): string {
if (score >= 90) return 'Ausgezeichnet'
if (score >= 75) return 'Gut'
if (score >= 50) return 'Verbesserungswuerdig'
if (score >= 25) return 'Mangelhaft'
return 'Kritisch'
}
/**
* Generiert einen Markdown-formatierten Compliance-Bericht.
* Enthaelt: Uebersicht, Score, Issue-Liste, Empfehlungen.
*/
export function generateComplianceSummary(
policies: LoeschfristPolicy[],
vvtDataCategories?: string[]
): string {
const result: ComplianceCheckResult = runComplianceCheck(policies, vvtDataCategories)
const now = new Date()
const lines: string[] = []
// Header
lines.push('# Compliance-Bericht: Loeschfristen')
lines.push('')
lines.push(
`**Erstellt am:** ${now.toLocaleDateString('de-DE', { day: '2-digit', month: '2-digit', year: 'numeric' })} um ${now.toLocaleTimeString('de-DE', { hour: '2-digit', minute: '2-digit' })} Uhr`
)
lines.push('')
// Overview
lines.push('## Uebersicht')
lines.push('')
lines.push(`| Kennzahl | Wert |`)
lines.push(`|----------|------|`)
lines.push(`| Gepruefte Policies | ${result.stats.total} |`)
lines.push(`| Bestanden | ${result.stats.passed} |`)
lines.push(`| Beanstandungen | ${result.stats.failed} |`)
lines.push(`| Compliance-Score | **${result.score}/100** (${getScoreRating(result.score)}) |`)
lines.push('')
// Severity breakdown
lines.push('## Befunde nach Schweregrad')
lines.push('')
lines.push('| Schweregrad | Anzahl |')
lines.push('|-------------|--------|')
const severityOrder: ComplianceIssueSeverity[] = ['CRITICAL', 'HIGH', 'MEDIUM', 'LOW']
for (const severity of severityOrder) {
const count = result.stats.bySeverity[severity]
lines.push(`| ${SEVERITY_LABELS[severity]} | ${count} |`)
}
lines.push('')
// Status distribution of policies
const statusCounts: Record<string, number> = {}
for (const policy of policies) {
const label = STATUS_LABELS[policy.status]
statusCounts[label] = (statusCounts[label] || 0) + 1
}
lines.push('## Policy-Status-Verteilung')
lines.push('')
lines.push('| Status | Anzahl |')
lines.push('|--------|--------|')
for (const [label, count] of Object.entries(statusCounts)) {
lines.push(`| ${label} | ${count} |`)
}
lines.push('')
// Issues list
if (result.issues.length === 0) {
lines.push('## Befunde')
lines.push('')
lines.push('Keine Beanstandungen gefunden. Alle Policies sind konform.')
lines.push('')
} else {
lines.push('## Befunde')
lines.push('')
// Group issues by severity
for (const severity of severityOrder) {
const issuesForSeverity = result.issues.filter((i) => i.severity === severity)
if (issuesForSeverity.length === 0) continue
lines.push(`### ${SEVERITY_LABELS[severity]} ${SEVERITY_EMOJI[severity]}`)
lines.push('')
for (const issue of issuesForSeverity) {
const policyRef =
issue.policyId !== '-' ? ` (${issue.policyId})` : ''
lines.push(`**${issue.title}**${policyRef}`)
lines.push('')
lines.push(`> ${issue.description}`)
lines.push('')
lines.push(`Empfehlung: ${issue.recommendation}`)
lines.push('')
lines.push('---')
lines.push('')
}
}
}
// Recommendations summary
lines.push('## Zusammenfassung der Empfehlungen')
lines.push('')
if (result.stats.bySeverity.CRITICAL > 0) {
lines.push(
`1. **Sofortmassnahmen erforderlich:** ${result.stats.bySeverity.CRITICAL} kritische(r) Befund(e) muessen umgehend behoben werden (Legal Hold-Konflikte).`
)
}
if (result.stats.bySeverity.HIGH > 0) {
lines.push(
`${result.stats.bySeverity.CRITICAL > 0 ? '2' : '1'}. **Hohe Prioritaet:** ${result.stats.bySeverity.HIGH} Befund(e) mit hoher Prioritaet (fehlende Trigger/Rechtsgrundlagen) sollten zeitnah bearbeitet werden.`
)
}
if (result.stats.bySeverity.MEDIUM > 0) {
lines.push(
`- **Mittlere Prioritaet:** ${result.stats.bySeverity.MEDIUM} Befund(e) betreffen ueberfaellige Pruefungen, fehlende Verantwortlichkeiten oder nicht abgedeckte Datenkategorien.`
)
}
if (result.stats.bySeverity.LOW > 0) {
lines.push(
`- **Niedrige Prioritaet:** ${result.stats.bySeverity.LOW} Befund(e) betreffen veraltete Entwuerfe, die finalisiert oder archiviert werden sollten.`
)
}
if (result.issues.length === 0) {
lines.push(
'Alle Policies sind konform. Stellen Sie sicher, dass die naechsten Pruefungstermine eingehalten werden.'
)
}
lines.push('')
// Footer
lines.push('---')
lines.push('')
lines.push(
'*Dieser Bericht wurde automatisch generiert und ersetzt keine rechtliche Beratung. Die Verantwortung fuer die DSGVO-Konformitaet liegt beim Verantwortlichen (Art. 4 Nr. 7 DSGVO).*'
)
return lines.join('\n')
}
// =============================================================================
// BROWSER DOWNLOAD UTILITY
// =============================================================================
/**
* Loest einen Datei-Download im Browser aus.
* Erstellt ein temporaeres Blob-URL und simuliert einen Link-Klick.
*
* @param content - Der Dateiinhalt als String
* @param filename - Der gewuenschte Dateiname (z.B. "loeschfristen-export.json")
* @param mimeType - Der MIME-Typ (z.B. "application/json", "text/csv;charset=utf-8")
*/
export function downloadFile(
content: string,
filename: string,
mimeType: string
): void {
const blob = new Blob([content], { type: mimeType })
const url = URL.createObjectURL(blob)
const link = document.createElement('a')
link.href = url
link.download = filename
document.body.appendChild(link)
link.click()
document.body.removeChild(link)
URL.revokeObjectURL(url)
}

View File

@@ -0,0 +1,538 @@
// =============================================================================
// Loeschfristen Module - Profiling Wizard
// 4-Step Profiling (15 Fragen) zur Generierung von Baseline-Loeschrichtlinien
// =============================================================================
import type { LoeschfristPolicy, StorageLocation } from './loeschfristen-types'
import { BASELINE_TEMPLATES, type BaselineTemplate, templateToPolicy } from './loeschfristen-baseline-catalog'
// =============================================================================
// TYPES
// =============================================================================
export type ProfilingStepId = 'organization' | 'data-categories' | 'systems' | 'special'
export interface ProfilingQuestion {
id: string
step: ProfilingStepId
question: string // German
helpText?: string
type: 'single' | 'multi' | 'boolean' | 'number'
options?: { value: string; label: string }[]
required: boolean
}
export interface ProfilingAnswer {
questionId: string
value: string | string[] | boolean | number
}
export interface ProfilingStep {
id: ProfilingStepId
title: string
description: string
questions: ProfilingQuestion[]
}
export interface ProfilingResult {
matchedTemplates: BaselineTemplate[]
generatedPolicies: LoeschfristPolicy[]
additionalStorageLocations: StorageLocation[]
hasLegalHoldRequirement: boolean
}
// =============================================================================
// PROFILING STEPS (4 Steps, 15 Questions)
// =============================================================================
export const PROFILING_STEPS: ProfilingStep[] = [
// =========================================================================
// Step 1: Organisation (4 Fragen)
// =========================================================================
{
id: 'organization',
title: 'Organisation',
description: 'Allgemeine Informationen zu Ihrem Unternehmen, um branchenspezifische Loeschfristen zu ermitteln.',
questions: [
{
id: 'org-branche',
step: 'organization',
question: 'In welcher Branche ist Ihr Unternehmen taetig?',
helpText: 'Die Branche bestimmt, welche branchenspezifischen Aufbewahrungspflichten relevant sind.',
type: 'single',
options: [
{ value: 'it-software', label: 'IT / Software' },
{ value: 'handel', label: 'Handel' },
{ value: 'dienstleistung', label: 'Dienstleistung' },
{ value: 'gesundheitswesen', label: 'Gesundheitswesen' },
{ value: 'bildung', label: 'Bildung' },
{ value: 'fertigung-industrie', label: 'Fertigung / Industrie' },
{ value: 'finanzwesen', label: 'Finanzwesen' },
{ value: 'oeffentlicher-sektor', label: 'Oeffentlicher Sektor' },
{ value: 'sonstige', label: 'Sonstige' },
],
required: true,
},
{
id: 'org-mitarbeiter',
step: 'organization',
question: 'Wie viele Mitarbeiter hat Ihr Unternehmen?',
helpText: 'Die Unternehmensgroesse beeinflusst den Umfang der erforderlichen Loeschkonzepte.',
type: 'single',
options: [
{ value: '<10', label: 'Weniger als 10' },
{ value: '10-49', label: '10 bis 49' },
{ value: '50-249', label: '50 bis 249' },
{ value: '250+', label: '250 und mehr' },
],
required: true,
},
{
id: 'org-geschaeftsmodell',
step: 'organization',
question: 'Welches Geschaeftsmodell verfolgen Sie?',
helpText: 'B2B und B2C haben unterschiedliche Anforderungen an die Datenhaltung.',
type: 'single',
options: [
{ value: 'b2b', label: 'B2B (Geschaeftskunden)' },
{ value: 'b2c', label: 'B2C (Endkunden)' },
{ value: 'beides', label: 'Beides (B2B und B2C)' },
],
required: true,
},
{
id: 'org-website',
step: 'organization',
question: 'Betreiben Sie eine Website oder Online-Praesenz?',
helpText: 'Websites erzeugen Webserver-Logs und erfordern Cookie-Consent-Verwaltung.',
type: 'boolean',
required: true,
},
],
},
// =========================================================================
// Step 2: Datenkategorien (5 Fragen)
// =========================================================================
{
id: 'data-categories',
title: 'Datenkategorien',
description: 'Welche Arten personenbezogener Daten verarbeiten Sie? Dies bestimmt die relevanten Aufbewahrungsfristen.',
questions: [
{
id: 'data-hr',
step: 'data-categories',
question: 'Verarbeiten Sie HR-/Personaldaten (Personalakten, Gehaltsabrechnungen, Zeiterfassung)?',
helpText: 'Personalakten unterliegen umfangreichen gesetzlichen Aufbewahrungspflichten (bis zu 10 Jahre).',
type: 'boolean',
required: true,
},
{
id: 'data-buchhaltung',
step: 'data-categories',
question: 'Fuehren Sie eine Buchhaltung mit Finanzdaten (Rechnungen, Belege, Steuererklarungen)?',
helpText: 'Buchhaltungsunterlagen muessen gemaess HGB und AO bis zu 10 Jahre aufbewahrt werden.',
type: 'boolean',
required: true,
},
{
id: 'data-vertraege',
step: 'data-categories',
question: 'Verwalten Sie Vertraege mit Kunden oder Lieferanten?',
helpText: 'Vertragsunterlagen und Geschaeftsbriefe haben spezifische Aufbewahrungspflichten.',
type: 'boolean',
required: true,
},
{
id: 'data-marketing',
step: 'data-categories',
question: 'Betreiben Sie Marketing-Aktivitaeten (Newsletter, CRM-Kampagnen)?',
helpText: 'Marketing-Einwilligungen und Kontakthistorien muessen dokumentiert und verwaltet werden.',
type: 'boolean',
required: true,
},
{
id: 'data-video',
step: 'data-categories',
question: 'Setzen Sie Videoueberwachung ein?',
helpText: 'Videoueberwachungsdaten haben besonders kurze Loeschfristen (in der Regel 72 Stunden).',
type: 'boolean',
required: true,
},
],
},
// =========================================================================
// Step 3: Systeme (3 Fragen)
// =========================================================================
{
id: 'systems',
title: 'Systeme & Infrastruktur',
description: 'Welche IT-Systeme und Infrastruktur nutzen Sie? Dies beeinflusst die Speicherorte in Ihrem Loeschkonzept.',
questions: [
{
id: 'sys-cloud',
step: 'systems',
question: 'Nutzen Sie Cloud-Dienste zur Datenspeicherung oder -verarbeitung?',
helpText: 'Cloud-Speicherorte muessen in den Loeschrichtlinien als separate Speicherorte dokumentiert werden.',
type: 'boolean',
required: true,
},
{
id: 'sys-backup',
step: 'systems',
question: 'Haben Sie Backup-Systeme im Einsatz?',
helpText: 'Backups erfordern eine eigene Loeschstrategie, da Daten dort nach der primaeren Loeschung weiter existieren koennen.',
type: 'boolean',
required: true,
},
{
id: 'sys-erp',
step: 'systems',
question: 'Setzen Sie ein ERP- oder CRM-System ein?',
helpText: 'ERP-/CRM-Systeme sind haeufig zentrale Speicherorte fuer Kunden- und Geschaeftsdaten.',
type: 'boolean',
required: true,
},
],
},
// =========================================================================
// Step 4: Spezielle Anforderungen (3 Fragen)
// =========================================================================
{
id: 'special',
title: 'Spezielle Anforderungen',
description: 'Gibt es besondere rechtliche oder organisatorische Anforderungen, die Ihr Loeschkonzept beeinflussen?',
questions: [
{
id: 'special-legal-hold',
step: 'special',
question: 'Gibt es Legal-Hold-Anforderungen (z.B. laufende Rechtsstreitigkeiten, behoerdliche Untersuchungen)?',
helpText: 'Bei einem Legal Hold muessen betroffene Daten trotz abgelaufener Loeschfristen aufbewahrt werden.',
type: 'boolean',
required: true,
},
{
id: 'special-archivierung',
step: 'special',
question: 'Benoetigen Sie eine Langzeitarchivierung von Dokumenten?',
helpText: 'Langzeitarchivierung kann ueber die gesetzlichen Mindestfristen hinausgehen und erfordert eine gesonderte Rechtfertigung.',
type: 'boolean',
required: true,
},
{
id: 'special-gesundheit',
step: 'special',
question: 'Verarbeiten Sie Gesundheitsdaten (z.B. Krankmeldungen, Arbeitsmedizin)?',
helpText: 'Gesundheitsdaten sind besonders schuetzenswerte Daten nach Art. 9 DSGVO und unterliegen strengeren Anforderungen.',
type: 'boolean',
required: true,
},
],
},
]
// =============================================================================
// HELPER FUNCTIONS
// =============================================================================
/**
* Retrieve the value of a specific answer by question ID.
*/
export function getAnswerValue(answers: ProfilingAnswer[], questionId: string): unknown {
const answer = answers.find(a => a.questionId === questionId)
return answer?.value ?? undefined
}
/**
* Check whether all required questions in a given step have been answered.
*/
export function isStepComplete(answers: ProfilingAnswer[], stepId: ProfilingStepId): boolean {
const step = PROFILING_STEPS.find(s => s.id === stepId)
if (!step) return false
return step.questions
.filter(q => q.required)
.every(q => {
const answer = answers.find(a => a.questionId === q.id)
if (!answer) return false
// Check that the value is not empty
const val = answer.value
if (val === undefined || val === null) return false
if (typeof val === 'string' && val.trim() === '') return false
if (Array.isArray(val) && val.length === 0) return false
return true
})
}
/**
* Calculate overall profiling progress as a percentage (0-100).
*/
export function getProfilingProgress(answers: ProfilingAnswer[]): number {
const totalRequired = PROFILING_STEPS.reduce(
(sum, step) => sum + step.questions.filter(q => q.required).length,
0
)
if (totalRequired === 0) return 100
const answeredRequired = PROFILING_STEPS.reduce((sum, step) => {
return (
sum +
step.questions.filter(q => q.required).filter(q => {
const answer = answers.find(a => a.questionId === q.id)
if (!answer) return false
const val = answer.value
if (val === undefined || val === null) return false
if (typeof val === 'string' && val.trim() === '') return false
if (Array.isArray(val) && val.length === 0) return false
return true
}).length
)
}, 0)
return Math.round((answeredRequired / totalRequired) * 100)
}
// =============================================================================
// CORE GENERATOR
// =============================================================================
/**
* Generate deletion policies based on the profiling answers.
*
* Logic:
* - Match baseline templates based on boolean and categorical answers
* - Deduplicate matched templates by templateId
* - Convert matched templates to full LoeschfristPolicy objects
* - Add additional storage locations (Cloud, Backup) if applicable
* - Detect legal hold requirements
*/
export function generatePoliciesFromProfile(answers: ProfilingAnswer[]): ProfilingResult {
const matchedTemplateIds = new Set<string>()
// -------------------------------------------------------------------------
// Helper to get a boolean answer
// -------------------------------------------------------------------------
const getBool = (questionId: string): boolean => {
const val = getAnswerValue(answers, questionId)
return val === true
}
const getString = (questionId: string): string => {
const val = getAnswerValue(answers, questionId)
return typeof val === 'string' ? val : ''
}
// -------------------------------------------------------------------------
// Always-included templates (universally recommended)
// -------------------------------------------------------------------------
matchedTemplateIds.add('protokolle-gesellschafter')
// -------------------------------------------------------------------------
// HR data (data-hr = true)
// -------------------------------------------------------------------------
if (getBool('data-hr')) {
matchedTemplateIds.add('personal-akten')
matchedTemplateIds.add('gehaltsabrechnungen')
matchedTemplateIds.add('zeiterfassung')
matchedTemplateIds.add('bewerbungsunterlagen')
matchedTemplateIds.add('krankmeldungen')
}
// -------------------------------------------------------------------------
// Buchhaltung (data-buchhaltung = true)
// -------------------------------------------------------------------------
if (getBool('data-buchhaltung')) {
matchedTemplateIds.add('buchhaltungsbelege')
matchedTemplateIds.add('rechnungen')
matchedTemplateIds.add('steuererklaerungen')
}
// -------------------------------------------------------------------------
// Vertraege (data-vertraege = true)
// -------------------------------------------------------------------------
if (getBool('data-vertraege')) {
matchedTemplateIds.add('vertraege')
matchedTemplateIds.add('geschaeftsbriefe')
matchedTemplateIds.add('kundenstammdaten')
}
// -------------------------------------------------------------------------
// Marketing (data-marketing = true)
// -------------------------------------------------------------------------
if (getBool('data-marketing')) {
matchedTemplateIds.add('newsletter-einwilligungen')
matchedTemplateIds.add('crm-kontakthistorie')
matchedTemplateIds.add('cookie-consent-logs')
}
// -------------------------------------------------------------------------
// Video (data-video = true)
// -------------------------------------------------------------------------
if (getBool('data-video')) {
matchedTemplateIds.add('videoueberwachung')
}
// -------------------------------------------------------------------------
// Website (org-website = true)
// -------------------------------------------------------------------------
if (getBool('org-website')) {
matchedTemplateIds.add('webserver-logs')
matchedTemplateIds.add('cookie-consent-logs')
}
// -------------------------------------------------------------------------
// ERP/CRM (sys-erp = true)
// -------------------------------------------------------------------------
if (getBool('sys-erp')) {
matchedTemplateIds.add('kundenstammdaten')
matchedTemplateIds.add('crm-kontakthistorie')
}
// -------------------------------------------------------------------------
// Backup (sys-backup = true)
// -------------------------------------------------------------------------
if (getBool('sys-backup')) {
matchedTemplateIds.add('backup-daten')
}
// -------------------------------------------------------------------------
// Gesundheitsdaten (special-gesundheit = true)
// -------------------------------------------------------------------------
if (getBool('special-gesundheit')) {
// Ensure krankmeldungen is included even without full HR data
matchedTemplateIds.add('krankmeldungen')
}
// -------------------------------------------------------------------------
// Resolve matched templates from catalog
// -------------------------------------------------------------------------
const matchedTemplates: BaselineTemplate[] = []
for (const templateId of matchedTemplateIds) {
const template = BASELINE_TEMPLATES.find(t => t.templateId === templateId)
if (template) {
matchedTemplates.push(template)
}
}
// -------------------------------------------------------------------------
// Convert to policies
// -------------------------------------------------------------------------
const generatedPolicies: LoeschfristPolicy[] = matchedTemplates.map(template =>
templateToPolicy(template)
)
// -------------------------------------------------------------------------
// Additional storage locations
// -------------------------------------------------------------------------
const additionalStorageLocations: StorageLocation[] = []
if (getBool('sys-cloud')) {
const cloudLocation: StorageLocation = {
id: crypto.randomUUID(),
name: 'Cloud-Speicher',
type: 'CLOUD',
isBackup: false,
provider: null,
deletionCapable: true,
}
additionalStorageLocations.push(cloudLocation)
// Add Cloud storage location to all generated policies
for (const policy of generatedPolicies) {
policy.storageLocations.push({ ...cloudLocation, id: crypto.randomUUID() })
}
}
if (getBool('sys-backup')) {
const backupLocation: StorageLocation = {
id: crypto.randomUUID(),
name: 'Backup-System',
type: 'BACKUP',
isBackup: true,
provider: null,
deletionCapable: true,
}
additionalStorageLocations.push(backupLocation)
// Add Backup storage location to all generated policies
for (const policy of generatedPolicies) {
policy.storageLocations.push({ ...backupLocation, id: crypto.randomUUID() })
}
}
// -------------------------------------------------------------------------
// Legal Hold
// -------------------------------------------------------------------------
const hasLegalHoldRequirement = getBool('special-legal-hold')
// If legal hold is active, mark all generated policies accordingly
if (hasLegalHoldRequirement) {
for (const policy of generatedPolicies) {
policy.hasActiveLegalHold = true
policy.deletionTrigger = 'LEGAL_HOLD'
}
}
// -------------------------------------------------------------------------
// Tag policies with profiling metadata
// -------------------------------------------------------------------------
const branche = getString('org-branche')
const mitarbeiter = getString('org-mitarbeiter')
for (const policy of generatedPolicies) {
policy.tags = [
...policy.tags,
'profiling-generated',
...(branche ? [`branche:${branche}`] : []),
...(mitarbeiter ? [`groesse:${mitarbeiter}`] : []),
]
}
return {
matchedTemplates,
generatedPolicies,
additionalStorageLocations,
hasLegalHoldRequirement,
}
}
// =============================================================================
// COMPLIANCE SCOPE INTEGRATION
// =============================================================================
/**
* Prefill Loeschfristen profiling answers from Compliance Scope Engine answers.
* The Scope Engine acts as the "Single Source of Truth" for organizational questions.
*/
export function prefillFromScopeAnswers(
scopeAnswers: import('./compliance-scope-types').ScopeProfilingAnswer[]
): ProfilingAnswer[] {
const { exportToLoeschfristenAnswers } = require('./compliance-scope-profiling')
const exported = exportToLoeschfristenAnswers(scopeAnswers) as Array<{ questionId: string; value: unknown }>
return exported.map(item => ({
questionId: item.questionId,
value: item.value as string | string[] | boolean | number,
}))
}
/**
* Get the list of Loeschfristen question IDs that are prefilled from Scope answers.
* These questions should show "Aus Scope-Analyse uebernommen" hint.
*/
export const SCOPE_PREFILLED_LF_QUESTIONS = [
'org-branche',
'org-mitarbeiter',
'org-geschaeftsmodell',
'org-website',
'data-hr',
'data-buchhaltung',
'data-vertraege',
'data-marketing',
'data-video',
'sys-cloud',
'sys-erp',
]

View File

@@ -0,0 +1,346 @@
// =============================================================================
// Loeschfristen Module - TypeScript Types
// 3-Level Loeschlogik: Zweckende -> Aufbewahrungstreiber -> Legal Hold
// =============================================================================
// =============================================================================
// ENUMS & LITERAL TYPES
// =============================================================================
export type DeletionTriggerLevel = 'PURPOSE_END' | 'RETENTION_DRIVER' | 'LEGAL_HOLD'
export type RetentionDriverType =
| 'AO_147' // 10 Jahre Steuerunterlagen
| 'HGB_257' // 10/6 Jahre Handelsbuecher/-briefe
| 'USTG_14B' // 10 Jahre Rechnungen
| 'BGB_195' // 3 Jahre Verjaehrung
| 'ARBZG_16' // 2 Jahre Zeiterfassung
| 'AGG_15' // 6 Monate Bewerbungen
| 'BDSG_35' // Unverzuegliche Loeschung
| 'BSIG' // 90 Tage Sicherheitslogs
| 'CUSTOM'
export type DeletionMethodType =
| 'AUTO_DELETE'
| 'MANUAL_REVIEW_DELETE'
| 'ANONYMIZATION'
| 'AGGREGATION'
| 'CRYPTO_ERASE'
| 'PHYSICAL_DESTROY'
export type PolicyStatus = 'DRAFT' | 'ACTIVE' | 'REVIEW_NEEDED' | 'ARCHIVED'
export type ReviewInterval = 'QUARTERLY' | 'SEMI_ANNUAL' | 'ANNUAL'
export type RetentionUnit = 'DAYS' | 'MONTHS' | 'YEARS'
export type StorageLocationType =
| 'DATABASE' | 'FILE_SYSTEM' | 'CLOUD' | 'EMAIL' | 'BACKUP' | 'PAPER' | 'OTHER'
export type LegalHoldStatus = 'ACTIVE' | 'RELEASED' | 'EXPIRED'
// =============================================================================
// INTERFACES
// =============================================================================
export interface LegalHold {
id: string
reason: string
legalBasis: string
responsiblePerson: string
startDate: string
expectedEndDate: string | null
actualEndDate: string | null
status: LegalHoldStatus
affectedDataCategories: string[]
}
export interface StorageLocation {
id: string
name: string
type: StorageLocationType
isBackup: boolean
provider: string | null
deletionCapable: boolean
}
export interface LoeschfristPolicy {
id: string
policyId: string // LF-2026-001
dataObjectName: string
description: string
affectedGroups: string[]
dataCategories: string[]
primaryPurpose: string
// 3-Level Loeschlogik
deletionTrigger: DeletionTriggerLevel
retentionDriver: RetentionDriverType | null
retentionDriverDetail: string
retentionDuration: number | null
retentionUnit: RetentionUnit | null
retentionDescription: string
startEvent: string
hasActiveLegalHold: boolean
legalHolds: LegalHold[]
// Speicherorte & Loeschung
storageLocations: StorageLocation[]
deletionMethod: DeletionMethodType
deletionMethodDetail: string
// Verantwortung & Workflow
responsibleRole: string
responsiblePerson: string
releaseProcess: string
linkedVVTActivityIds: string[]
// Status & Review
status: PolicyStatus
lastReviewDate: string
nextReviewDate: string
reviewInterval: ReviewInterval
tags: string[]
createdAt: string
updatedAt: string
}
// =============================================================================
// CONSTANTS
// =============================================================================
export interface RetentionDriverMeta {
label: string
statute: string
defaultDuration: number | null
defaultUnit: RetentionUnit | null
description: string
}
export const RETENTION_DRIVER_META: Record<RetentionDriverType, RetentionDriverMeta> = {
AO_147: {
label: 'Abgabenordnung (AO) 147',
statute: '147 AO',
defaultDuration: 10,
defaultUnit: 'YEARS',
description: 'Aufbewahrung steuerrelevanter Unterlagen (Buchungsbelege, Bilanzen, Jahresabschluesse)',
},
HGB_257: {
label: 'Handelsgesetzbuch (HGB) 257',
statute: '257 HGB',
defaultDuration: 10,
defaultUnit: 'YEARS',
description: 'Handelsbuecher und Buchungsbelege (10 J.), empfangene/gesendete Handelsbriefe (6 J.)',
},
USTG_14B: {
label: 'Umsatzsteuergesetz (UStG) 14b',
statute: '14b UStG',
defaultDuration: 10,
defaultUnit: 'YEARS',
description: 'Aufbewahrung von Rechnungen und rechnungsbegruendenden Unterlagen',
},
BGB_195: {
label: 'Buergerliches Gesetzbuch (BGB) 195',
statute: '195 BGB',
defaultDuration: 3,
defaultUnit: 'YEARS',
description: 'Regelmaessige Verjaehrungsfrist fuer vertragliche Ansprueche',
},
ARBZG_16: {
label: 'Arbeitszeitgesetz (ArbZG) 16',
statute: '16 Abs. 2 ArbZG',
defaultDuration: 2,
defaultUnit: 'YEARS',
description: 'Aufbewahrung von Arbeitszeitaufzeichnungen',
},
AGG_15: {
label: 'Allg. Gleichbehandlungsgesetz (AGG) 15',
statute: '15 Abs. 4 AGG',
defaultDuration: 6,
defaultUnit: 'MONTHS',
description: 'Frist fuer Geltendmachung von Entschaedigungsanspruechen nach Absage',
},
BDSG_35: {
label: 'BDSG 35 / DSGVO Art. 17',
statute: '35 BDSG / Art. 17 DSGVO',
defaultDuration: null,
defaultUnit: null,
description: 'Unverzuegliche Loeschung nach Zweckwegfall (kein fester Zeitraum)',
},
BSIG: {
label: 'BSI-Gesetz (BSIG)',
statute: 'BSIG / IT-SiG 2.0',
defaultDuration: 90,
defaultUnit: 'DAYS',
description: 'Aufbewahrung von Sicherheitslogs fuer Vorfallsanalyse',
},
CUSTOM: {
label: 'Individuelle Frist',
statute: 'Individuell',
defaultDuration: null,
defaultUnit: null,
description: 'Benutzerdefinierte Aufbewahrungsfrist',
},
}
export const DELETION_METHOD_LABELS: Record<DeletionMethodType, string> = {
AUTO_DELETE: 'Automatische Loeschung',
MANUAL_REVIEW_DELETE: 'Manuelle Pruefung & Loeschung',
ANONYMIZATION: 'Anonymisierung',
AGGREGATION: 'Aggregation (statistische Verdichtung)',
CRYPTO_ERASE: 'Kryptographische Loeschung',
PHYSICAL_DESTROY: 'Physische Vernichtung',
}
export const STATUS_LABELS: Record<PolicyStatus, string> = {
DRAFT: 'Entwurf',
ACTIVE: 'Aktiv',
REVIEW_NEEDED: 'Pruefung erforderlich',
ARCHIVED: 'Archiviert',
}
export const STATUS_COLORS: Record<PolicyStatus, string> = {
DRAFT: 'bg-gray-100 text-gray-700 border-gray-200',
ACTIVE: 'bg-green-100 text-green-700 border-green-200',
REVIEW_NEEDED: 'bg-yellow-100 text-yellow-700 border-yellow-200',
ARCHIVED: 'bg-blue-100 text-blue-700 border-blue-200',
}
export const TRIGGER_LABELS: Record<DeletionTriggerLevel, string> = {
PURPOSE_END: 'Zweckende',
RETENTION_DRIVER: 'Aufbewahrungspflicht',
LEGAL_HOLD: 'Legal Hold',
}
export const TRIGGER_COLORS: Record<DeletionTriggerLevel, string> = {
PURPOSE_END: 'bg-green-100 text-green-700',
RETENTION_DRIVER: 'bg-blue-100 text-blue-700',
LEGAL_HOLD: 'bg-red-100 text-red-700',
}
export const REVIEW_INTERVAL_LABELS: Record<ReviewInterval, string> = {
QUARTERLY: 'Vierteljaehrlich',
SEMI_ANNUAL: 'Halbjaehrlich',
ANNUAL: 'Jaehrlich',
}
export const STORAGE_LOCATION_LABELS: Record<StorageLocationType, string> = {
DATABASE: 'Datenbank',
FILE_SYSTEM: 'Dateisystem',
CLOUD: 'Cloud-Speicher',
EMAIL: 'E-Mail-System',
BACKUP: 'Backup-System',
PAPER: 'Papierarchiv',
OTHER: 'Sonstiges',
}
// =============================================================================
// HELPER FUNCTIONS
// =============================================================================
let policyCounter = 0
export function generatePolicyId(): string {
policyCounter++
const year = new Date().getFullYear()
const num = String(policyCounter).padStart(3, '0')
return `LF-${year}-${num}`
}
export function createEmptyPolicy(): LoeschfristPolicy {
const now = new Date().toISOString()
const nextYear = new Date()
nextYear.setFullYear(nextYear.getFullYear() + 1)
return {
id: crypto.randomUUID(),
policyId: generatePolicyId(),
dataObjectName: '',
description: '',
affectedGroups: [],
dataCategories: [],
primaryPurpose: '',
deletionTrigger: 'PURPOSE_END',
retentionDriver: null,
retentionDriverDetail: '',
retentionDuration: null,
retentionUnit: null,
retentionDescription: '',
startEvent: '',
hasActiveLegalHold: false,
legalHolds: [],
storageLocations: [],
deletionMethod: 'AUTO_DELETE',
deletionMethodDetail: '',
responsibleRole: '',
responsiblePerson: '',
releaseProcess: '',
linkedVVTActivityIds: [],
status: 'DRAFT',
lastReviewDate: now,
nextReviewDate: nextYear.toISOString(),
reviewInterval: 'ANNUAL',
tags: [],
createdAt: now,
updatedAt: now,
}
}
export function createEmptyLegalHold(): LegalHold {
return {
id: crypto.randomUUID(),
reason: '',
legalBasis: '',
responsiblePerson: '',
startDate: new Date().toISOString().split('T')[0],
expectedEndDate: null,
actualEndDate: null,
status: 'ACTIVE',
affectedDataCategories: [],
}
}
export function createEmptyStorageLocation(): StorageLocation {
return {
id: crypto.randomUUID(),
name: '',
type: 'DATABASE',
isBackup: false,
provider: null,
deletionCapable: true,
}
}
export function formatRetentionDuration(
duration: number | null,
unit: RetentionUnit | null
): string {
if (duration === null || unit === null) return 'Bis Zweckwegfall'
const unitLabels: Record<RetentionUnit, string> = {
DAYS: duration === 1 ? 'Tag' : 'Tage',
MONTHS: duration === 1 ? 'Monat' : 'Monate',
YEARS: duration === 1 ? 'Jahr' : 'Jahre',
}
return `${duration} ${unitLabels[unit]}`
}
export function isPolicyOverdue(policy: LoeschfristPolicy): boolean {
if (!policy.nextReviewDate) return false
return new Date(policy.nextReviewDate) <= new Date()
}
export function getActiveLegalHolds(policy: LoeschfristPolicy): LegalHold[] {
return policy.legalHolds.filter(h => h.status === 'ACTIVE')
}
export function getEffectiveDeletionTrigger(policy: LoeschfristPolicy): DeletionTriggerLevel {
if (policy.hasActiveLegalHold && getActiveLegalHolds(policy).length > 0) {
return 'LEGAL_HOLD'
}
if (policy.retentionDriver && policy.retentionDriver !== 'CUSTOM') {
return 'RETENTION_DRIVER'
}
return 'PURPOSE_END'
}
// =============================================================================
// LOCALSTORAGE KEY
// =============================================================================
export const LOESCHFRISTEN_STORAGE_KEY = 'bp_loeschfristen'

View File

@@ -63,6 +63,7 @@ type TOMGeneratorAction =
| { type: 'UPDATE_DERIVED_TOM'; payload: { id: string; data: Partial<DerivedTOM> } }
| { type: 'SET_GAP_ANALYSIS'; payload: GapAnalysisResult }
| { type: 'ADD_EXPORT'; payload: ExportRecord }
| { type: 'BULK_UPDATE_TOMS'; payload: { updates: Array<{ id: string; data: Partial<DerivedTOM> }> } }
| { type: 'LOAD_STATE'; payload: TOMGeneratorState }
// =============================================================================
@@ -236,6 +237,16 @@ function tomGeneratorReducer(
})
}
case 'BULK_UPDATE_TOMS': {
let updatedTOMs = [...state.derivedTOMs]
for (const update of action.payload.updates) {
updatedTOMs = updatedTOMs.map((tom) =>
tom.id === update.id ? { ...tom, ...update.data } : tom
)
}
return updateState({ derivedTOMs: updatedTOMs })
}
case 'LOAD_STATE': {
return action.payload
}
@@ -283,6 +294,7 @@ interface TOMGeneratorContextValue {
// TOM derivation
deriveTOMs: () => void
updateDerivedTOM: (id: string, data: Partial<DerivedTOM>) => void
bulkUpdateTOMs: (updates: Array<{ id: string; data: Partial<DerivedTOM> }>) => void
// Gap analysis
runGapAnalysis: () => void

View File

@@ -2072,6 +2072,287 @@ const CONTROL_LIBRARY_DATA: ControlLibrary = {
complexity: 'HIGH',
tags: ['dpia', 'dsfa', 'risk-assessment'],
},
// =========================================================================
// DELETION / VERNICHTUNG — Sichere Datenloeschung & Datentraegervernichtung
// =========================================================================
{
id: 'TOM-DL-01',
code: 'TOM-DL-01',
category: 'SEPARATION',
type: 'TECHNICAL',
name: {
de: 'Sichere Datenloeschung',
en: 'Secure Data Deletion',
},
description: {
de: 'Implementierung sicherer Loeschverfahren, die personenbezogene Daten unwiederbringlich entfernen (z.B. nach DIN 66399).',
en: 'Implementation of secure deletion procedures that irrecoverably remove personal data (e.g. per DIN 66399).',
},
mappings: [
{ framework: 'GDPR_ART17', reference: 'Art. 17' },
{ framework: 'GDPR_ART5', reference: 'Art. 5 Abs. 1 lit. e' },
{ framework: 'ISO27001_ANNEX_A', reference: 'A.8.10' },
{ framework: 'BSI_C5', reference: 'SY-09' },
],
applicabilityConditions: [
{
field: 'dataProfile.dataVolume',
operator: 'NOT_EQUALS',
value: 'NONE',
result: 'REQUIRED',
priority: 30,
},
],
defaultApplicability: 'REQUIRED',
evidenceRequirements: [
'Loeschkonzept / Loeschrichtlinie',
'Loeschprotokolle mit Zeitstempeln',
'DIN 66399 Konformitaetsnachweis',
],
reviewFrequency: 'ANNUAL',
priority: 'HIGH',
complexity: 'MEDIUM',
tags: ['deletion', 'loeschung', 'data-lifecycle', 'din-66399'],
},
{
id: 'TOM-DL-02',
code: 'TOM-DL-02',
category: 'SEPARATION',
type: 'TECHNICAL',
name: {
de: 'Datentraegervernichtung',
en: 'Media Destruction',
},
description: {
de: 'Physische Vernichtung von Datentraegern (Festplatten, SSDs, USB-Sticks, Papier) gemaess DIN 66399 Schutzklassen.',
en: 'Physical destruction of storage media (hard drives, SSDs, USB sticks, paper) per DIN 66399 protection classes.',
},
mappings: [
{ framework: 'GDPR_ART32', reference: 'Art. 32 Abs. 1' },
{ framework: 'ISO27001_ANNEX_A', reference: 'A.7.14' },
{ framework: 'BSI_C5', reference: 'AM-08' },
],
applicabilityConditions: [
{
field: 'dataProfile.dataVolume',
operator: 'NOT_EQUALS',
value: 'NONE',
result: 'RECOMMENDED',
priority: 20,
},
],
defaultApplicability: 'RECOMMENDED',
evidenceRequirements: [
'Vernichtungsprotokoll mit Seriennummern',
'Zertifikat des Vernichtungsdienstleisters',
'DIN 66399 Sicherheitsstufe-Nachweis',
],
reviewFrequency: 'ANNUAL',
priority: 'MEDIUM',
complexity: 'LOW',
tags: ['deletion', 'media-destruction', 'physical-security', 'din-66399'],
},
{
id: 'TOM-DL-03',
code: 'TOM-DL-03',
category: 'SEPARATION',
type: 'ORGANIZATIONAL',
name: {
de: 'Loeschprotokollierung',
en: 'Deletion Logging',
},
description: {
de: 'Systematische Protokollierung aller Loeschvorgaenge mit Zeitstempel, Verantwortlichem, Datenobjekt und Loeschmethode.',
en: 'Systematic logging of all deletion operations with timestamp, responsible person, data object, and deletion method.',
},
mappings: [
{ framework: 'GDPR_ART5', reference: 'Art. 5 Abs. 2 (Rechenschaftspflicht)' },
{ framework: 'ISO27001_ANNEX_A', reference: 'A.8.10' },
],
applicabilityConditions: [
{
field: 'dataProfile.dataVolume',
operator: 'NOT_EQUALS',
value: 'NONE',
result: 'REQUIRED',
priority: 25,
},
],
defaultApplicability: 'REQUIRED',
evidenceRequirements: [
'Loeschprotokoll-Template',
'Archivierte Loeschprotokolle (Stichprobe)',
'Automatisierungsnachweis (bei automatischen Loeschungen)',
],
reviewFrequency: 'SEMI_ANNUAL',
priority: 'HIGH',
complexity: 'LOW',
tags: ['deletion', 'logging', 'accountability', 'documentation'],
},
{
id: 'TOM-DL-04',
code: 'TOM-DL-04',
category: 'SEPARATION',
type: 'TECHNICAL',
name: {
de: 'Backup-Bereinigung',
en: 'Backup Sanitization',
},
description: {
de: 'Sicherstellung, dass personenbezogene Daten auch in Backup-Systemen nach Ablauf der Loeschfrist entfernt werden.',
en: 'Ensuring that personal data is also removed from backup systems after the retention period expires.',
},
mappings: [
{ framework: 'GDPR_ART17', reference: 'Art. 17 Abs. 2' },
{ framework: 'ISO27001_ANNEX_A', reference: 'A.8.13' },
],
applicabilityConditions: [
{
field: 'techProfile.hasBackups',
operator: 'EQUALS',
value: true,
result: 'REQUIRED',
priority: 25,
},
],
defaultApplicability: 'RECOMMENDED',
evidenceRequirements: [
'Backup-Loeschkonzept',
'Backup-Rotationsplan',
'Nachweis der Backup-Bereinigung',
],
reviewFrequency: 'SEMI_ANNUAL',
priority: 'MEDIUM',
complexity: 'HIGH',
tags: ['deletion', 'backup', 'data-lifecycle', 'retention'],
},
// =========================================================================
// SCHULUNG / VERTRAULICHKEIT — Training & Awareness
// =========================================================================
{
id: 'TOM-TR-01',
code: 'TOM-TR-01',
category: 'REVIEW',
type: 'ORGANIZATIONAL',
name: {
de: 'Datenschutzschulung',
en: 'Data Protection Training',
},
description: {
de: 'Regelmaessige Schulung aller Mitarbeiter zu Datenschutzgrundlagen, DSGVO-Anforderungen und betrieblichen Datenschutzrichtlinien.',
en: 'Regular training of all employees on data protection fundamentals, GDPR requirements, and organizational data protection policies.',
},
mappings: [
{ framework: 'GDPR_ART39', reference: 'Art. 39 Abs. 1 lit. b' },
{ framework: 'GDPR_ART47', reference: 'Art. 47 Abs. 2 lit. n' },
{ framework: 'ISO27001_ANNEX_A', reference: 'A.6.3' },
],
applicabilityConditions: [
{
field: 'orgProfile.employeeCount',
operator: 'GREATER_THAN',
value: 0,
result: 'REQUIRED',
priority: 30,
},
],
defaultApplicability: 'REQUIRED',
evidenceRequirements: [
'Schulungsplan (jaehrlich)',
'Teilnahmelisten / Schulungsnachweise',
'Schulungsmaterialien / Praesentation',
'Wissenstest-Ergebnisse (optional)',
],
reviewFrequency: 'ANNUAL',
priority: 'HIGH',
complexity: 'LOW',
tags: ['training', 'schulung', 'awareness', 'organizational'],
},
{
id: 'TOM-TR-02',
code: 'TOM-TR-02',
category: 'REVIEW',
type: 'ORGANIZATIONAL',
name: {
de: 'Verpflichtung auf Datengeheimnis',
en: 'Confidentiality Obligation',
},
description: {
de: 'Schriftliche Verpflichtung aller Mitarbeiter und externen Dienstleister auf die Vertraulichkeit personenbezogener Daten.',
en: 'Written obligation of all employees and external service providers to maintain confidentiality of personal data.',
},
mappings: [
{ framework: 'GDPR_ART28', reference: 'Art. 28 Abs. 3 lit. b' },
{ framework: 'GDPR_ART32', reference: 'Art. 32 Abs. 4' },
{ framework: 'ISO27001_ANNEX_A', reference: 'A.6.6' },
],
applicabilityConditions: [
{
field: 'orgProfile.employeeCount',
operator: 'GREATER_THAN',
value: 0,
result: 'REQUIRED',
priority: 30,
},
],
defaultApplicability: 'REQUIRED',
evidenceRequirements: [
'Muster-Verpflichtungserklaerung',
'Unterschriebene Verpflichtungserklaerungen',
'Register der verpflichteten Personen',
],
reviewFrequency: 'ANNUAL',
priority: 'HIGH',
complexity: 'LOW',
tags: ['training', 'confidentiality', 'vertraulichkeit', 'obligation'],
},
{
id: 'TOM-TR-03',
code: 'TOM-TR-03',
category: 'REVIEW',
type: 'ORGANIZATIONAL',
name: {
de: 'Security Awareness Programm',
en: 'Security Awareness Program',
},
description: {
de: 'Fortlaufendes Awareness-Programm zu IT-Sicherheit, Phishing-Erkennung, Social Engineering und sicherem Umgang mit Daten.',
en: 'Ongoing awareness program on IT security, phishing detection, social engineering, and safe data handling.',
},
mappings: [
{ framework: 'GDPR_ART32', reference: 'Art. 32 Abs. 1 lit. d' },
{ framework: 'ISO27001_ANNEX_A', reference: 'A.6.3' },
{ framework: 'BSI_C5', reference: 'ORP.3' },
],
applicabilityConditions: [
{
field: 'orgProfile.employeeCount',
operator: 'GREATER_THAN',
value: 10,
result: 'REQUIRED',
priority: 20,
},
{
field: 'orgProfile.employeeCount',
operator: 'GREATER_THAN',
value: 0,
result: 'RECOMMENDED',
priority: 15,
},
],
defaultApplicability: 'RECOMMENDED',
evidenceRequirements: [
'Awareness-Programm-Dokumentation',
'Phishing-Simulationsergebnisse',
'Teilnahmenachweise',
],
reviewFrequency: 'SEMI_ANNUAL',
priority: 'MEDIUM',
complexity: 'MEDIUM',
tags: ['training', 'security-awareness', 'phishing', 'social-engineering'],
},
],
}

View File

@@ -0,0 +1,192 @@
// =============================================================================
// SDM (Standard-Datenschutzmodell) Mapping
// Maps ControlCategories to SDM Gewaehrleistungsziele and Spec Modules
// =============================================================================
import { ControlCategory } from './types'
// =============================================================================
// TYPES
// =============================================================================
export type SDMGewaehrleistungsziel =
| 'Verfuegbarkeit'
| 'Integritaet'
| 'Vertraulichkeit'
| 'Nichtverkettung'
| 'Intervenierbarkeit'
| 'Transparenz'
| 'Datenminimierung'
export type TOMModuleCategory =
| 'IDENTITY_AUTH'
| 'LOGGING'
| 'DOCUMENTATION'
| 'SEPARATION'
| 'RETENTION'
| 'DELETION'
| 'TRAINING'
| 'REVIEW'
export const SDM_GOAL_LABELS: Record<SDMGewaehrleistungsziel, string> = {
Verfuegbarkeit: 'Verfuegbarkeit',
Integritaet: 'Integritaet',
Vertraulichkeit: 'Vertraulichkeit',
Nichtverkettung: 'Nichtverkettung',
Intervenierbarkeit: 'Intervenierbarkeit',
Transparenz: 'Transparenz',
Datenminimierung: 'Datenminimierung',
}
export const SDM_GOAL_DESCRIPTIONS: Record<SDMGewaehrleistungsziel, string> = {
Verfuegbarkeit: 'Personenbezogene Daten muessen zeitgerecht zur Verfuegung stehen und ordnungsgemaess verarbeitet werden koennen.',
Integritaet: 'Personenbezogene Daten muessen unversehrt, vollstaendig und aktuell bleiben.',
Vertraulichkeit: 'Nur Befugte duerfen personenbezogene Daten zur Kenntnis nehmen.',
Nichtverkettung: 'Daten duerfen nicht ohne Weiteres fuer andere Zwecke zusammengefuehrt werden.',
Intervenierbarkeit: 'Betroffene muessen ihre Rechte wahrnehmen koennen (Auskunft, Berichtigung, Loeschung).',
Transparenz: 'Verarbeitungsvorgaenge muessen nachvollziehbar dokumentiert sein.',
Datenminimierung: 'Nur die fuer den Zweck erforderlichen Daten duerfen verarbeitet werden.',
}
export const MODULE_LABELS: Record<TOMModuleCategory, string> = {
IDENTITY_AUTH: 'Identitaet & Authentifizierung',
LOGGING: 'Protokollierung',
DOCUMENTATION: 'Dokumentation',
SEPARATION: 'Trennung',
RETENTION: 'Aufbewahrung',
DELETION: 'Loeschung & Vernichtung',
TRAINING: 'Schulung & Vertraulichkeit',
REVIEW: 'Ueberpruefung & Bewertung',
}
// =============================================================================
// MAPPINGS
// =============================================================================
/**
* Maps ControlCategory to its primary SDM Gewaehrleistungsziele
*/
export const SDM_CATEGORY_MAPPING: Record<ControlCategory, SDMGewaehrleistungsziel[]> = {
ACCESS_CONTROL: ['Vertraulichkeit'],
ADMISSION_CONTROL: ['Vertraulichkeit', 'Integritaet'],
ACCESS_AUTHORIZATION: ['Vertraulichkeit', 'Nichtverkettung'],
TRANSFER_CONTROL: ['Vertraulichkeit', 'Integritaet'],
INPUT_CONTROL: ['Integritaet', 'Transparenz'],
ORDER_CONTROL: ['Transparenz', 'Intervenierbarkeit'],
AVAILABILITY: ['Verfuegbarkeit'],
SEPARATION: ['Nichtverkettung', 'Datenminimierung'],
ENCRYPTION: ['Vertraulichkeit', 'Integritaet'],
PSEUDONYMIZATION: ['Datenminimierung', 'Nichtverkettung'],
RESILIENCE: ['Verfuegbarkeit'],
RECOVERY: ['Verfuegbarkeit', 'Integritaet'],
REVIEW: ['Transparenz', 'Intervenierbarkeit'],
}
/**
* Maps ControlCategory to Spec Module Categories
*/
export const MODULE_CATEGORY_MAPPING: Record<ControlCategory, TOMModuleCategory[]> = {
ACCESS_CONTROL: ['IDENTITY_AUTH'],
ADMISSION_CONTROL: ['IDENTITY_AUTH'],
ACCESS_AUTHORIZATION: ['IDENTITY_AUTH', 'DOCUMENTATION'],
TRANSFER_CONTROL: ['DOCUMENTATION'],
INPUT_CONTROL: ['LOGGING'],
ORDER_CONTROL: ['DOCUMENTATION'],
AVAILABILITY: ['REVIEW'],
SEPARATION: ['SEPARATION'],
ENCRYPTION: ['IDENTITY_AUTH'],
PSEUDONYMIZATION: ['SEPARATION', 'DELETION'],
RESILIENCE: ['REVIEW'],
RECOVERY: ['REVIEW'],
REVIEW: ['REVIEW', 'TRAINING'],
}
// =============================================================================
// HELPER FUNCTIONS
// =============================================================================
import type { DerivedTOM, ControlLibraryEntry } from './types'
import { getControlById } from './controls/loader'
/**
* Get SDM goals for a given control (by looking up its category)
*/
export function getSDMGoalsForControl(controlId: string): SDMGewaehrleistungsziel[] {
const control = getControlById(controlId)
if (!control) return []
return SDM_CATEGORY_MAPPING[control.category] || []
}
/**
* Get derived TOMs that map to a specific SDM goal
*/
export function getTOMsBySDMGoal(
toms: DerivedTOM[],
goal: SDMGewaehrleistungsziel
): DerivedTOM[] {
return toms.filter(tom => {
const goals = getSDMGoalsForControl(tom.controlId)
return goals.includes(goal)
})
}
/**
* Get derived TOMs belonging to a specific module
*/
export function getTOMsByModule(
toms: DerivedTOM[],
module: TOMModuleCategory
): DerivedTOM[] {
return toms.filter(tom => {
const control = getControlById(tom.controlId)
if (!control) return false
const modules = MODULE_CATEGORY_MAPPING[control.category] || []
return modules.includes(module)
})
}
/**
* Get SDM goal coverage statistics
*/
export function getSDMCoverageStats(toms: DerivedTOM[]): Record<SDMGewaehrleistungsziel, {
total: number
implemented: number
partial: number
missing: number
}> {
const goals = Object.keys(SDM_GOAL_LABELS) as SDMGewaehrleistungsziel[]
const stats = {} as Record<SDMGewaehrleistungsziel, { total: number; implemented: number; partial: number; missing: number }>
for (const goal of goals) {
const goalTOMs = getTOMsBySDMGoal(toms, goal)
stats[goal] = {
total: goalTOMs.length,
implemented: goalTOMs.filter(t => t.implementationStatus === 'IMPLEMENTED').length,
partial: goalTOMs.filter(t => t.implementationStatus === 'PARTIAL').length,
missing: goalTOMs.filter(t => t.implementationStatus === 'NOT_IMPLEMENTED').length,
}
}
return stats
}
/**
* Get module coverage statistics
*/
export function getModuleCoverageStats(toms: DerivedTOM[]): Record<TOMModuleCategory, {
total: number
implemented: number
}> {
const modules = Object.keys(MODULE_LABELS) as TOMModuleCategory[]
const stats = {} as Record<TOMModuleCategory, { total: number; implemented: number }>
for (const mod of modules) {
const modTOMs = getTOMsByModule(toms, mod)
stats[mod] = {
total: modTOMs.length,
implemented: modTOMs.filter(t => t.implementationStatus === 'IMPLEMENTED').length,
}
}
return stats
}

View File

@@ -899,3 +899,65 @@ export function createInitialTOMGeneratorState(
* Alias for createInitialTOMGeneratorState (for API compatibility)
*/
export const createEmptyTOMGeneratorState = createInitialTOMGeneratorState
// =============================================================================
// SDM TYPES (Standard-Datenschutzmodell)
// =============================================================================
export type SDMGewaehrleistungsziel =
| 'Verfuegbarkeit'
| 'Integritaet'
| 'Vertraulichkeit'
| 'Nichtverkettung'
| 'Intervenierbarkeit'
| 'Transparenz'
| 'Datenminimierung'
export type TOMModuleCategory =
| 'IDENTITY_AUTH'
| 'LOGGING'
| 'DOCUMENTATION'
| 'SEPARATION'
| 'RETENTION'
| 'DELETION'
| 'TRAINING'
| 'REVIEW'
/**
* Maps ControlCategory to SDM Gewaehrleistungsziele.
* Used by the TOM Dashboard to display SDM coverage.
*/
export const SDM_CATEGORY_MAPPING: Record<ControlCategory, SDMGewaehrleistungsziel[]> = {
ACCESS_CONTROL: ['Vertraulichkeit'],
ADMISSION_CONTROL: ['Vertraulichkeit', 'Integritaet'],
ACCESS_AUTHORIZATION: ['Vertraulichkeit', 'Nichtverkettung'],
TRANSFER_CONTROL: ['Vertraulichkeit', 'Integritaet'],
INPUT_CONTROL: ['Integritaet', 'Transparenz'],
ORDER_CONTROL: ['Transparenz', 'Intervenierbarkeit'],
AVAILABILITY: ['Verfuegbarkeit'],
SEPARATION: ['Nichtverkettung', 'Datenminimierung'],
ENCRYPTION: ['Vertraulichkeit', 'Integritaet'],
PSEUDONYMIZATION: ['Datenminimierung', 'Nichtverkettung'],
RESILIENCE: ['Verfuegbarkeit'],
RECOVERY: ['Verfuegbarkeit', 'Integritaet'],
REVIEW: ['Transparenz', 'Intervenierbarkeit'],
}
/**
* Maps ControlCategory to Spec Module Categories.
*/
export const MODULE_CATEGORY_MAPPING: Record<ControlCategory, TOMModuleCategory[]> = {
ACCESS_CONTROL: ['IDENTITY_AUTH'],
ADMISSION_CONTROL: ['IDENTITY_AUTH'],
ACCESS_AUTHORIZATION: ['IDENTITY_AUTH', 'DOCUMENTATION'],
TRANSFER_CONTROL: ['DOCUMENTATION'],
INPUT_CONTROL: ['LOGGING'],
ORDER_CONTROL: ['DOCUMENTATION'],
AVAILABILITY: ['REVIEW'],
SEPARATION: ['SEPARATION'],
ENCRYPTION: ['IDENTITY_AUTH'],
PSEUDONYMIZATION: ['SEPARATION', 'DELETION'],
RESILIENCE: ['REVIEW'],
RECOVERY: ['REVIEW'],
REVIEW: ['REVIEW', 'TRAINING'],
}

View File

@@ -314,10 +314,23 @@ export const SDK_STEPS: SDKStep[] = [
isOptional: false,
},
{
id: 'use-case-assessment',
id: 'compliance-scope',
phase: 1,
package: 'vorbereitung',
order: 2,
name: 'Compliance Scope',
nameShort: 'Scope',
description: 'Umfang und Tiefe Ihrer Compliance-Dokumentation bestimmen',
url: '/sdk/compliance-scope',
checkpointId: 'CP-SCOPE',
prerequisiteSteps: ['company-profile'],
isOptional: false,
},
{
id: 'use-case-assessment',
phase: 1,
package: 'vorbereitung',
order: 3,
name: 'Anwendungsfall-Erfassung',
nameShort: 'Anwendung',
description: 'AI-Anwendungsfälle strukturiert dokumentieren',
@@ -330,7 +343,7 @@ export const SDK_STEPS: SDKStep[] = [
id: 'import',
phase: 1,
package: 'vorbereitung',
order: 3,
order: 4,
name: 'Dokument-Import',
nameShort: 'Import',
description: 'Bestehende Dokumente hochladen (Bestandskunden)',
@@ -343,7 +356,7 @@ export const SDK_STEPS: SDKStep[] = [
id: 'screening',
phase: 1,
package: 'vorbereitung',
order: 4,
order: 5,
name: 'System Screening',
nameShort: 'Screening',
description: 'SBOM + Security Check',
@@ -356,7 +369,7 @@ export const SDK_STEPS: SDKStep[] = [
id: 'modules',
phase: 1,
package: 'vorbereitung',
order: 5,
order: 6,
name: 'Compliance Modules',
nameShort: 'Module',
description: 'Abgleich welche Regulierungen gelten',
@@ -365,6 +378,19 @@ export const SDK_STEPS: SDKStep[] = [
prerequisiteSteps: ['screening'],
isOptional: false,
},
{
id: 'source-policy',
phase: 1,
package: 'vorbereitung',
order: 7,
name: 'Source Policy',
nameShort: 'Quellen',
description: 'Datenquellen-Governance & Whitelist',
url: '/sdk/source-policy',
checkpointId: 'CP-SPOL',
prerequisiteSteps: ['modules'],
isOptional: false,
},
// =============================================================================
// PAKET 2: ANALYSE (Assessment)
@@ -379,7 +405,7 @@ export const SDK_STEPS: SDKStep[] = [
description: 'Prüfaspekte aus Regulierungen ableiten',
url: '/sdk/requirements',
checkpointId: 'CP-REQ',
prerequisiteSteps: ['modules'],
prerequisiteSteps: ['source-policy'],
isOptional: false,
},
{
@@ -447,6 +473,19 @@ export const SDK_STEPS: SDKStep[] = [
prerequisiteSteps: ['ai-act'],
isOptional: false,
},
{
id: 'audit-report',
phase: 1,
package: 'analyse',
order: 7,
name: 'Audit Report',
nameShort: 'Report',
description: 'Audit-Sitzungen & PDF-Report',
url: '/sdk/audit-report',
checkpointId: 'CP-AREP',
prerequisiteSteps: ['audit-checklist'],
isOptional: false,
},
// =============================================================================
// PAKET 3: DOKUMENTATION (Compliance Docs)
@@ -461,7 +500,7 @@ export const SDK_STEPS: SDKStep[] = [
description: 'NIS2, DSGVO, AI Act Pflichten',
url: '/sdk/obligations',
checkpointId: 'CP-OBL',
prerequisiteSteps: ['audit-checklist'],
prerequisiteSteps: ['audit-report'],
isOptional: false,
},
{
@@ -572,6 +611,19 @@ export const SDK_STEPS: SDKStep[] = [
prerequisiteSteps: ['cookie-banner'],
isOptional: true,
},
{
id: 'workflow',
phase: 2,
package: 'rechtliche-texte',
order: 5,
name: 'Document Workflow',
nameShort: 'Workflow',
description: 'Versionierung & Freigabe-Workflow',
url: '/sdk/workflow',
checkpointId: 'CP-WRKF',
prerequisiteSteps: ['document-generator'],
isOptional: false,
},
// =============================================================================
// PAKET 5: BETRIEB (Operations)
@@ -586,7 +638,7 @@ export const SDK_STEPS: SDKStep[] = [
description: 'Betroffenenrechte-Portal',
url: '/sdk/dsr',
checkpointId: 'CP-DSR',
prerequisiteSteps: ['cookie-banner'],
prerequisiteSteps: ['workflow'],
isOptional: false,
},
{
@@ -615,6 +667,32 @@ export const SDK_STEPS: SDKStep[] = [
prerequisiteSteps: ['escalations'],
isOptional: false,
},
{
id: 'consent-management',
phase: 2,
package: 'betrieb',
order: 4,
name: 'Consent Verwaltung',
nameShort: 'Consent Mgmt',
description: 'Dokument-Lifecycle & DSGVO-Prozesse',
url: '/sdk/consent-management',
checkpointId: 'CP-CMGMT',
prerequisiteSteps: ['vendor-compliance'],
isOptional: false,
},
{
id: 'notfallplan',
phase: 2,
package: 'betrieb',
order: 5,
name: 'Notfallplan & Breach Response',
nameShort: 'Notfallplan',
description: 'Datenpannen-Management nach Art. 33/34 DSGVO',
url: '/sdk/notfallplan',
checkpointId: 'CP-NOTF',
prerequisiteSteps: ['consent-management'],
isOptional: false,
},
]
// =============================================================================
@@ -1208,6 +1286,9 @@ export interface SDKState {
// Company Profile (collected before use cases)
companyProfile: CompanyProfile | null
// Compliance Scope (determines depth level L1-L4)
complianceScope: import('./compliance-scope-types').ComplianceScopeState | null
// Progress
currentPhase: SDKPhase
currentStep: string
@@ -1265,6 +1346,8 @@ export type SDKAction =
| { type: 'SET_CUSTOMER_TYPE'; payload: CustomerType }
| { type: 'SET_COMPANY_PROFILE'; payload: CompanyProfile }
| { type: 'UPDATE_COMPANY_PROFILE'; payload: Partial<CompanyProfile> }
| { type: 'SET_COMPLIANCE_SCOPE'; payload: import('./compliance-scope-types').ComplianceScopeState }
| { type: 'UPDATE_COMPLIANCE_SCOPE'; payload: Partial<import('./compliance-scope-types').ComplianceScopeState> }
| { type: 'ADD_IMPORTED_DOCUMENT'; payload: ImportedDocument }
| { type: 'UPDATE_IMPORTED_DOCUMENT'; payload: { id: string; data: Partial<ImportedDocument> } }
| { type: 'DELETE_IMPORTED_DOCUMENT'; payload: string }
@@ -1783,3 +1866,243 @@ export const JURISDICTION_LABELS: Record<Jurisdiction, string> = {
US: 'United States',
INTL: 'International',
}
// =============================================================================
// DSFA RAG TYPES (Source Attribution & Corpus Management)
// =============================================================================
/**
* License codes for DSFA source documents
*/
export type DSFALicenseCode =
| 'DL-DE-BY-2.0' // Datenlizenz Deutschland Namensnennung
| 'DL-DE-ZERO-2.0' // Datenlizenz Deutschland Zero
| 'CC-BY-4.0' // Creative Commons Attribution 4.0
| 'EDPB-LICENSE' // EDPB Document License
| 'PUBLIC_DOMAIN' // Public Domain
| 'PROPRIETARY' // Internal/Proprietary
/**
* Document types in the DSFA corpus
*/
export type DSFADocumentType = 'guideline' | 'checklist' | 'regulation' | 'template'
/**
* Category for DSFA chunks (for filtering)
*/
export type DSFACategory =
| 'threshold_analysis'
| 'risk_assessment'
| 'mitigation'
| 'consultation'
| 'documentation'
| 'process'
| 'criteria'
/**
* DSFA source registry entry
*/
export interface DSFASource {
id: string
sourceCode: string
name: string
fullName?: string
organization?: string
sourceUrl?: string
eurLexCelex?: string
licenseCode: DSFALicenseCode
licenseName: string
licenseUrl?: string
attributionRequired: boolean
attributionText: string
documentType?: DSFADocumentType
language: string
}
/**
* DSFA document entry
*/
export interface DSFADocument {
id: string
sourceId: string
title: string
description?: string
fileName?: string
fileType?: string
fileSizeBytes?: number
minioBucket: string
minioPath?: string
originalUrl?: string
ocrProcessed: boolean
textExtracted: boolean
chunksGenerated: number
lastIndexedAt?: string
metadata: Record<string, unknown>
createdAt: string
updatedAt: string
}
/**
* DSFA chunk with full attribution
*/
export interface DSFAChunk {
chunkId: string
content: string
sectionTitle?: string
pageNumber?: number
category?: DSFACategory
documentId: string
documentTitle?: string
sourceId: string
sourceCode: string
sourceName: string
attributionText: string
licenseCode: DSFALicenseCode
licenseName: string
licenseUrl?: string
attributionRequired: boolean
sourceUrl?: string
documentType?: DSFADocumentType
}
/**
* DSFA search result with score and attribution
*/
export interface DSFASearchResult {
chunkId: string
content: string
score: number
sourceCode: string
sourceName: string
attributionText: string
licenseCode: DSFALicenseCode
licenseName: string
licenseUrl?: string
attributionRequired: boolean
sourceUrl?: string
documentType?: DSFADocumentType
category?: DSFACategory
sectionTitle?: string
pageNumber?: number
}
/**
* DSFA search response with aggregated attribution
*/
export interface DSFASearchResponse {
query: string
results: DSFASearchResult[]
totalResults: number
licensesUsed: string[]
attributionNotice: string
}
/**
* Source statistics for dashboard
*/
export interface DSFASourceStats {
sourceId: string
sourceCode: string
name: string
organization?: string
licenseCode: DSFALicenseCode
documentType?: DSFADocumentType
documentCount: number
chunkCount: number
lastIndexedAt?: string
}
/**
* Corpus statistics for dashboard
*/
export interface DSFACorpusStats {
sources: DSFASourceStats[]
totalSources: number
totalDocuments: number
totalChunks: number
qdrantCollection: string
qdrantPointsCount: number
qdrantStatus: string
}
/**
* License information
*/
export interface DSFALicenseInfo {
code: DSFALicenseCode
name: string
url?: string
attributionRequired: boolean
modificationAllowed: boolean
commercialUse: boolean
}
/**
* Ingestion request for DSFA documents
*/
export interface DSFAIngestRequest {
documentUrl?: string
documentText?: string
title?: string
}
/**
* Ingestion response
*/
export interface DSFAIngestResponse {
sourceCode: string
documentId?: string
chunksCreated: number
message: string
}
/**
* Props for SourceAttribution component
*/
export interface SourceAttributionProps {
sources: Array<{
sourceCode: string
sourceName: string
attributionText: string
licenseCode: DSFALicenseCode
sourceUrl?: string
score?: number
}>
compact?: boolean
showScores?: boolean
}
/**
* License code display labels
*/
export const DSFA_LICENSE_LABELS: Record<DSFALicenseCode, string> = {
'DL-DE-BY-2.0': 'Datenlizenz DE Namensnennung 2.0',
'DL-DE-ZERO-2.0': 'Datenlizenz DE Zero 2.0',
'CC-BY-4.0': 'CC BY 4.0 International',
'EDPB-LICENSE': 'EDPB Document License',
'PUBLIC_DOMAIN': 'Public Domain',
'PROPRIETARY': 'Proprietary',
}
/**
* Document type display labels
*/
export const DSFA_DOCUMENT_TYPE_LABELS: Record<DSFADocumentType, string> = {
guideline: 'Leitlinie',
checklist: 'Prüfliste',
regulation: 'Verordnung',
template: 'Vorlage',
}
/**
* Category display labels
*/
export const DSFA_CATEGORY_LABELS: Record<DSFACategory, string> = {
threshold_analysis: 'Schwellwertanalyse',
risk_assessment: 'Risikobewertung',
mitigation: 'Risikominderung',
consultation: 'Behördenkonsultation',
documentation: 'Dokumentation',
process: 'Prozessschritte',
criteria: 'Kriterien',
}

View File

@@ -0,0 +1,630 @@
/**
* VVT Baseline-Katalog
*
* Vordefinierte Verarbeitungstaetigkeiten als Templates.
* Werden vom Profiling-Fragebogen (Generator) genutzt, um
* auf Basis der Antworten VVT-Eintraege vorzubefuellen.
*/
import type { VVTActivity, 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[]
}
// =============================================================================
// BASELINE TEMPLATES
// =============================================================================
export const VVT_BASELINE_CATALOG: BaselineTemplate[] = [
// ==================== HR ====================
{
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'],
},
// ==================== FINANCE ====================
{
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'],
},
// ==================== SALES / CRM ====================
{
templateId: 'sales-kundenverwaltung',
businessFunction: 'sales_crm',
name: 'Kundenverwaltung (CRM)',
description: 'Verwaltung von Kundenbeziehungen, Kontakten und Vertriebsaktivitaeten',
purposes: ['Kundenbetreuung', 'Vertragserfuellung', 'Vertriebssteuerung'],
legalBases: [
{ type: 'CONTRACT', description: 'Kundenvertrag', reference: 'Art. 6 Abs. 1 lit. b DSGVO' },
{ type: 'LEGITIMATE_INTEREST', description: 'Kundenbindung', reference: 'Art. 6 Abs. 1 lit. f DSGVO' },
],
dataSubjectCategories: ['CUSTOMERS', 'PROSPECTIVE_CUSTOMERS', 'BUSINESS_PARTNERS'],
personalDataCategories: ['NAME', 'CONTACT', 'ADDRESS', 'CONTRACT_DATA', 'COMMUNICATION_DATA'],
recipientCategories: [
{ type: 'INTERNAL', name: 'Vertrieb' },
{ type: 'INTERNAL', name: 'Kundenservice' },
],
retentionPeriod: { duration: 3, durationUnit: 'YEARS', description: '3 Jahre nach letzter Interaktion (Verjaeherung)', legalBasis: 'BGB § 195', deletionProcedure: 'Loeschung nach Inaktivitaetsfrist' },
tomDescription: 'Zugriffskontrolle nach Kundengruppen, Verschluesselung, regemaessige Datenpflege',
structuredToms: {
accessControl: ['RBAC nach Vertriebsgebiet', 'Kundendaten-Owner'],
confidentiality: ['Verschluesselung in CRM', 'VPN fuer Fernzugriff'],
integrity: ['Aenderungshistorie im CRM'],
availability: ['Cloud-CRM mit SLA 99.9%'],
separation: ['Mandantentrennung'],
},
typicalSystems: ['CRM-System', 'E-Mail', 'Telefon'],
protectionLevel: 'MEDIUM',
dpiaRequired: false,
tags: ['sales', 'crm', 'kunden', 'vertrieb'],
},
{
templateId: 'sales-vertriebssteuerung',
businessFunction: 'sales_crm',
name: 'Vertriebssteuerung',
description: 'Analyse von Vertriebskennzahlen und Pipeline-Management',
purposes: ['Vertriebsoptimierung', 'Umsatzplanung'],
legalBases: [
{ type: 'LEGITIMATE_INTEREST', description: 'Unternehmenssteuerung', reference: 'Art. 6 Abs. 1 lit. f DSGVO' },
],
dataSubjectCategories: ['CUSTOMERS', 'PROSPECTIVE_CUSTOMERS'],
personalDataCategories: ['NAME', 'CONTRACT_DATA', 'COMMUNICATION_DATA'],
recipientCategories: [
{ type: 'INTERNAL', name: 'Vertriebsleitung' },
{ type: 'INTERNAL', name: 'Geschaeftsfuehrung' },
],
retentionPeriod: { duration: 3, durationUnit: 'YEARS', description: '3 Jahre', legalBasis: 'Berechtigtes Interesse', deletionProcedure: 'Anonymisierung nach Ablauf' },
tomDescription: 'Aggregierte Auswertungen wo moeglich, Zugriffsbeschraenkung auf Fuehrungsebene',
structuredToms: {
accessControl: ['Nur Management'],
confidentiality: ['Aggregierte Reports bevorzugt'],
integrity: ['Nachvollziehbare Berechnungen'],
availability: ['Dashboard-Verfuegbarkeit'],
separation: ['Reporting getrennt von Operativdaten'],
},
typicalSystems: ['CRM-System', 'BI-Tool'],
protectionLevel: 'LOW',
dpiaRequired: false,
tags: ['sales', 'vertrieb', 'reporting'],
},
// ==================== MARKETING ====================
{
templateId: 'marketing-newsletter',
businessFunction: 'marketing',
name: 'Newsletter-Marketing',
description: 'Versand von Marketing-E-Mails und Newslettern an Abonnenten',
purposes: ['Direktmarketing', 'Kundenbindung', 'Informationsversand'],
legalBases: [
{ type: 'CONSENT', description: 'Einwilligung zum Newsletter-Empfang', reference: 'Art. 6 Abs. 1 lit. a DSGVO, § 7 Abs. 2 UWG' },
],
dataSubjectCategories: ['NEWSLETTER_SUBSCRIBERS', 'CUSTOMERS'],
personalDataCategories: ['NAME', 'CONTACT', 'USAGE_DATA'],
recipientCategories: [
{ type: 'PROCESSOR', name: 'E-Mail-Dienstleister' },
{ type: 'INTERNAL', name: 'Marketing-Abteilung' },
],
retentionPeriod: { description: 'Bis zum Widerruf der Einwilligung', deletionProcedure: 'Sofortige Loeschung bei Abmeldung' },
tomDescription: 'Double-Opt-In, Abmeldelink in jeder E-Mail, Einwilligungsprotokollierung',
structuredToms: {
accessControl: ['Nur Marketing-Team'],
confidentiality: ['TLS-Versand', 'Keine Weitergabe an Dritte'],
integrity: ['Einwilligungsnachweis (Timestamp, IP, Version)'],
availability: ['Redundanter E-Mail-Service'],
separation: ['Newsletter-Liste getrennt von CRM'],
},
typicalSystems: ['Newsletter-Tool', 'E-Mail-Marketing-Plattform'],
protectionLevel: 'LOW',
dpiaRequired: false,
tags: ['marketing', 'newsletter', 'email'],
},
{
templateId: 'marketing-website-analytics',
businessFunction: 'marketing',
name: 'Website-Analytics',
description: 'Analyse des Nutzerverhaltens auf der Website mittels Tracking-Tools',
purposes: ['Website-Optimierung', 'Reichweitenmessung'],
legalBases: [
{ type: 'CONSENT', description: 'Cookie-Einwilligung', reference: 'Art. 6 Abs. 1 lit. a DSGVO, § 25 TDDDG' },
],
dataSubjectCategories: ['WEBSITE_USERS'],
personalDataCategories: ['IP_ADDRESS', 'DEVICE_ID', 'USAGE_DATA', 'LOCATION_DATA'],
recipientCategories: [
{ type: 'PROCESSOR', name: 'Analytics-Anbieter' },
{ type: 'INTERNAL', name: 'Marketing' },
],
retentionPeriod: { duration: 14, durationUnit: 'MONTHS', description: '14 Monate', deletionProcedure: 'Automatische Loeschung/Anonymisierung' },
tomDescription: 'IP-Anonymisierung, Cookie-Consent-Management, Opt-Out-Moeglichkeit',
structuredToms: {
accessControl: ['Nur Webanalyse-Team'],
confidentiality: ['IP-Anonymisierung', 'Pseudonymisierung'],
integrity: ['Datenqualitaetspruefung'],
availability: ['CDN-basiertes Tracking'],
separation: ['Analytics getrennt von personenbezogenen Profilen'],
},
typicalSystems: ['Matomo', 'Plausible', 'Google Analytics'],
protectionLevel: 'MEDIUM',
dpiaRequired: false,
tags: ['marketing', 'analytics', 'website', 'tracking'],
},
{
templateId: 'marketing-social-media',
businessFunction: 'marketing',
name: 'Social-Media-Marketing',
description: 'Betrieb von Social-Media-Kanaelen und Interaktion mit Nutzern',
purposes: ['Oeffentlichkeitsarbeit', 'Kundeninteraktion'],
legalBases: [
{ type: 'LEGITIMATE_INTEREST', description: 'Marketing', reference: 'Art. 6 Abs. 1 lit. f DSGVO' },
],
dataSubjectCategories: ['WEBSITE_USERS', 'CUSTOMERS'],
personalDataCategories: ['NAME', 'CONTACT', 'USAGE_DATA', 'COMMUNICATION_DATA'],
recipientCategories: [
{ type: 'CONTROLLER', name: 'Social-Media-Plattform (gemeinsame Verantwortlichkeit)' },
],
retentionPeriod: { description: 'Abhaengig von Plattform-Einstellungen', deletionProcedure: 'Regelmaessige Pruefung und Bereinigung' },
tomDescription: 'Datenschutzeinstellungen der Plattform, gemeinsame Verantwortlichkeit gemaess Art. 26',
structuredToms: {
accessControl: ['Nur Social-Media-Manager', 'Passwort-Manager'],
confidentiality: ['Plattform-Datenschutzeinstellungen'],
integrity: ['Redaktionsplan'],
availability: ['Multi-Kanal-Management'],
separation: ['Geschaeftlich/Privat getrennt'],
},
typicalSystems: ['Social-Media-Plattformen', 'Social-Media-Management-Tool'],
protectionLevel: 'LOW',
dpiaRequired: false,
tags: ['marketing', 'social-media'],
},
// ==================== SUPPORT ====================
{
templateId: 'support-ticketsystem',
businessFunction: 'support',
name: 'Kundenservice / Ticketsystem',
description: 'Bearbeitung von Kundenanfragen und Support-Tickets',
purposes: ['Kundenservice', 'Reklamationsbearbeitung', 'Vertragserfuellung'],
legalBases: [
{ type: 'CONTRACT', description: 'Kundenvertrag', reference: 'Art. 6 Abs. 1 lit. b DSGVO' },
],
dataSubjectCategories: ['CUSTOMERS', 'APP_USERS'],
personalDataCategories: ['NAME', 'CONTACT', 'CONTRACT_DATA', 'COMMUNICATION_DATA'],
recipientCategories: [
{ type: 'INTERNAL', name: 'Support-Team' },
{ type: 'PROCESSOR', name: 'Helpdesk-Software-Anbieter' },
],
retentionPeriod: { duration: 3, durationUnit: 'YEARS', description: '3 Jahre nach Ticketschliessung', legalBasis: 'BGB § 195', deletionProcedure: 'Automatische Loeschung geschlossener Tickets' },
tomDescription: 'Zugriffskontrolle nach Ticket-Owner, Verschluesselung, Audit-Trail',
structuredToms: {
accessControl: ['Ticket-basierte Zugriffskontrolle', 'Agent-Rollen'],
confidentiality: ['TLS', 'Verschluesselung'],
integrity: ['Ticket-Historie unveraenderbar'],
availability: ['Hochverfuegbarer Helpdesk'],
separation: ['Mandantentrennung'],
},
typicalSystems: ['Helpdesk-Software', 'E-Mail', 'Chat'],
protectionLevel: 'MEDIUM',
dpiaRequired: false,
tags: ['support', 'kundenservice', 'tickets'],
},
// ==================== IT OPERATIONS ====================
{
templateId: 'it-systemadministration',
businessFunction: 'it_operations',
name: 'Systemadministration',
description: 'Verwaltung von IT-Systemen, Benutzerkonten und Zugriffsrechten',
purposes: ['IT-Betrieb', 'Benutzerverwaltung', 'Sicherheitsueberwachung'],
legalBases: [
{ type: 'LEGITIMATE_INTEREST', description: 'IT-Sicherheit', reference: 'Art. 6 Abs. 1 lit. f DSGVO' },
{ type: 'CONTRACT', description: 'Bereitstellung IT-Dienste', reference: 'Art. 6 Abs. 1 lit. b DSGVO' },
],
dataSubjectCategories: ['EMPLOYEES', 'APP_USERS'],
personalDataCategories: ['NAME', 'CONTACT', 'LOGIN_DATA', 'IP_ADDRESS', 'DEVICE_ID'],
recipientCategories: [
{ type: 'INTERNAL', name: 'IT-Abteilung' },
{ type: 'PROCESSOR', name: 'IT-Dienstleister' },
],
retentionPeriod: { duration: 1, durationUnit: 'YEARS', description: '1 Jahr nach Kontodeaktivierung', deletionProcedure: 'Automatische Loeschung deaktivierter Konten' },
tomDescription: 'PAM, MFA, Protokollierung, regelmaessige Rechtereviews',
structuredToms: {
accessControl: ['PAM (Privileged Access Management)', 'MFA', 'Regelmaessige Rechtereviews'],
confidentiality: ['Verschluesselung', 'Passwort-Policies'],
integrity: ['Change Management', 'Konfigurationsmanagement'],
availability: ['Redundanz', 'Monitoring', 'Alerting'],
separation: ['Prod/Dev/Staging getrennt', 'Admin-Netze isoliert'],
},
typicalSystems: ['Active Directory / IAM', 'Monitoring', 'ITSM'],
protectionLevel: 'MEDIUM',
dpiaRequired: false,
tags: ['it', 'admin', 'benutzerverwaltung'],
},
{
templateId: 'it-backup',
businessFunction: 'it_operations',
name: 'Backup & Recovery',
description: 'Sicherung und Wiederherstellung von Daten und Systemen',
purposes: ['Datensicherung', 'Disaster Recovery', 'Geschaeftskontinuitaet'],
legalBases: [
{ type: 'LEGITIMATE_INTEREST', description: 'Datensicherheit', reference: 'Art. 6 Abs. 1 lit. f DSGVO, Art. 32 DSGVO' },
],
dataSubjectCategories: ['EMPLOYEES', 'CUSTOMERS'],
personalDataCategories: ['NAME', 'CONTACT', 'CONTRACT_DATA'],
recipientCategories: [
{ type: 'PROCESSOR', name: 'Backup-Dienstleister' },
{ type: 'INTERNAL', name: 'IT-Abteilung' },
],
retentionPeriod: { duration: 90, durationUnit: 'DAYS', description: '90 Tage Aufbewahrung der Backups', deletionProcedure: 'Automatische Rotation und Loeschung' },
tomDescription: 'Verschluesselung, Zugriffskontrolle, regelmaessige Wiederherstellungstests',
structuredToms: {
accessControl: ['Nur Backup-Admins', 'Separater Encryption Key'],
confidentiality: ['AES-256-Verschluesselung', 'Verschluesselter Transport'],
integrity: ['Checksummen-Pruefung', 'Regelmaessige Restore-Tests'],
availability: ['3-2-1-Backup-Regel', 'Georedundanz'],
separation: ['Backup-Netzwerk isoliert'],
},
typicalSystems: ['Backup-Software', 'Cloud-Storage'],
protectionLevel: 'MEDIUM',
dpiaRequired: false,
tags: ['it', 'backup', 'recovery'],
},
{
templateId: 'it-logging',
businessFunction: 'it_operations',
name: 'Protokollierung & Logging',
description: 'Erfassung von System- und Sicherheitslogs zur Fehlerbehebung und Angriffserkennung',
purposes: ['IT-Sicherheit', 'Fehlerbehebung', 'Angriffserkennung'],
legalBases: [
{ type: 'LEGITIMATE_INTEREST', description: 'IT-Sicherheit und Betrieb', reference: 'Art. 6 Abs. 1 lit. f DSGVO' },
],
dataSubjectCategories: ['EMPLOYEES', 'APP_USERS', 'WEBSITE_USERS'],
personalDataCategories: ['IP_ADDRESS', 'LOGIN_DATA', 'USAGE_DATA', 'DEVICE_ID'],
recipientCategories: [
{ type: 'INTERNAL', name: 'IT-Sicherheit' },
{ type: 'PROCESSOR', name: 'SIEM-Anbieter' },
],
retentionPeriod: { duration: 90, durationUnit: 'DAYS', description: '90 Tage (Standard) / 1 Jahr (Security-Logs)', deletionProcedure: 'Automatische Rotation' },
tomDescription: 'SIEM, Integritaetsschutz der Logs, Zugriffskontrolle, Pseudonymisierung',
structuredToms: {
accessControl: ['Nur Security-Team', 'Read-Only fuer Auditoren'],
confidentiality: ['Pseudonymisierung wo moeglich'],
integrity: ['WORM-Storage fuer Security-Logs', 'Hashketten'],
availability: ['Redundante Log-Speicherung'],
separation: ['Zentrale Log-Infrastruktur getrennt'],
},
typicalSystems: ['SIEM', 'ELK Stack', 'Syslog'],
protectionLevel: 'MEDIUM',
dpiaRequired: false,
tags: ['it', 'logging', 'sicherheit'],
},
{
templateId: 'it-iam',
businessFunction: 'it_operations',
name: 'Identity & Access Management',
description: 'Verwaltung von Identitaeten, Authentifizierung und Autorisierung',
purposes: ['Zugriffskontrolle', 'Identitaetsverwaltung', 'Compliance'],
legalBases: [
{ type: 'LEGITIMATE_INTEREST', description: 'IT-Sicherheit', reference: 'Art. 6 Abs. 1 lit. f DSGVO' },
{ type: 'CONTRACT', description: 'Bereitstellung IT-Dienste', reference: 'Art. 6 Abs. 1 lit. b DSGVO' },
],
dataSubjectCategories: ['EMPLOYEES', 'APP_USERS'],
personalDataCategories: ['NAME', 'CONTACT', 'LOGIN_DATA'],
recipientCategories: [
{ type: 'INTERNAL', name: 'IT-Abteilung' },
{ type: 'PROCESSOR', name: 'IAM-Anbieter' },
],
retentionPeriod: { duration: 6, durationUnit: 'MONTHS', description: '6 Monate nach Kontodeaktivierung', deletionProcedure: 'Automatische Deprovisionierung' },
tomDescription: 'MFA, SSO, regelmaessige Access Reviews, Least-Privilege-Prinzip',
structuredToms: {
accessControl: ['MFA', 'SSO', 'Least Privilege', 'Regelmaessige Reviews'],
confidentiality: ['Passwort-Hashing (bcrypt)', 'Token-basierte Auth'],
integrity: ['Audit-Trail aller Aenderungen'],
availability: ['Hochverfuegbarer IdP'],
separation: ['Identitaeten pro Mandant'],
},
typicalSystems: ['IAM-System', 'SSO Provider', 'MFA'],
protectionLevel: 'HIGH',
dpiaRequired: false,
tags: ['it', 'iam', 'zugriffskontrolle'],
},
// ==================== OTHER ====================
{
templateId: 'other-videokonferenz',
businessFunction: 'other',
name: 'Videokonferenzen',
description: 'Durchfuehrung von Video-Meetings und Online-Besprechungen',
purposes: ['Interne Kommunikation', 'Kundeninteraktion', 'Remote-Arbeit'],
legalBases: [
{ type: 'LEGITIMATE_INTEREST', description: 'Geschaeftliche Kommunikation', reference: 'Art. 6 Abs. 1 lit. f DSGVO' },
{ type: 'CONTRACT', description: 'Arbeitsvertrag (bei Mitarbeitern)', reference: 'Art. 6 Abs. 1 lit. b DSGVO' },
],
dataSubjectCategories: ['EMPLOYEES', 'CUSTOMERS', 'BUSINESS_PARTNERS'],
personalDataCategories: ['NAME', 'CONTACT', 'PHOTO_VIDEO', 'IP_ADDRESS', 'COMMUNICATION_DATA'],
recipientCategories: [
{ type: 'PROCESSOR', name: 'Videokonferenz-Anbieter' },
],
retentionPeriod: { description: 'Keine dauerhafte Speicherung von Meetings (sofern nicht aufgezeichnet)', deletionProcedure: 'Aufzeichnungen nach Verwendungszweck loeschen' },
tomDescription: 'Ende-zu-Ende-Verschluesselung, Warteraum, Passwortschutz, Aufnahme nur mit Einwilligung',
structuredToms: {
accessControl: ['Meeting-Passwort', 'Warteraum', 'Host-Kontrolle'],
confidentiality: ['TLS / E2E-Verschluesselung'],
integrity: ['Teilnehmerliste'],
availability: ['Redundante Infrastruktur'],
separation: ['Separate Meeting-Raeume'],
},
typicalSystems: ['Jitsi', 'Zoom', 'Teams', 'Google Meet'],
protectionLevel: 'LOW',
dpiaRequired: false,
tags: ['kommunikation', 'video', 'meeting'],
},
{
templateId: 'other-besuchermanagement',
businessFunction: 'other',
name: 'Besuchermanagement',
description: 'Erfassung und Verwaltung von Besuchern am Firmenstandort',
purposes: ['Zutrittskontrolle', 'Sicherheit', 'Nachverfolgung'],
legalBases: [
{ type: 'LEGITIMATE_INTEREST', description: 'Gebaeudesicherheit', reference: 'Art. 6 Abs. 1 lit. f DSGVO' },
],
dataSubjectCategories: ['VISITORS'],
personalDataCategories: ['NAME', 'CONTACT', 'PHOTO_VIDEO'],
recipientCategories: [
{ type: 'INTERNAL', name: 'Empfang / Sicherheit' },
],
retentionPeriod: { duration: 30, durationUnit: 'DAYS', description: '30 Tage nach Besuch', deletionProcedure: 'Automatische Loeschung' },
tomDescription: 'Besucherausweise, Begleitpflicht, zeitlich begrenzter Zugang',
structuredToms: {
accessControl: ['Besucherausweise', 'Begleitpflicht'],
confidentiality: ['Besucherliste nicht oeffentlich einsehbar'],
integrity: ['Besuchsprotokoll'],
availability: ['Papier-Backup fuer Besucherliste'],
separation: ['Besucherbereich getrennt'],
},
typicalSystems: ['Besuchermanagementsystem', 'Zutrittskontrollsystem'],
protectionLevel: 'LOW',
dpiaRequired: false,
tags: ['besucher', 'zutritt', 'empfang'],
},
]
// =============================================================================
// HELPER: Convert template to VVTActivity
// =============================================================================
export function templateToActivity(template: BaselineTemplate, vvtId: string): Omit<import('./vvt-types').VVTActivity, 'id'> & { id: string } {
const now = new Date().toISOString()
return {
id: crypto.randomUUID(),
vvtId,
name: template.name,
description: template.description,
purposes: template.purposes,
legalBases: template.legalBases,
dataSubjectCategories: template.dataSubjectCategories,
personalDataCategories: template.personalDataCategories,
recipientCategories: template.recipientCategories,
thirdCountryTransfers: [],
retentionPeriod: template.retentionPeriod,
tomDescription: template.tomDescription,
businessFunction: template.businessFunction,
systems: template.typicalSystems.map((s, i) => ({ systemId: `sys-${i}`, name: s })),
deploymentModel: 'cloud',
dataSources: [{ type: 'DATA_SUBJECT', description: 'Direkt von der betroffenen Person' }],
dataFlows: [],
protectionLevel: template.protectionLevel,
dpiaRequired: template.dpiaRequired,
structuredToms: template.structuredToms,
status: 'DRAFT',
responsible: '',
owner: '',
createdAt: now,
updatedAt: now,
}
}
// =============================================================================
// HELPER: Get templates by business function
// =============================================================================
export function getTemplatesByFunction(fn: BusinessFunction): BaselineTemplate[] {
return VVT_BASELINE_CATALOG.filter(t => t.businessFunction === fn)
}
export function getTemplateById(templateId: string): BaselineTemplate | undefined {
return VVT_BASELINE_CATALOG.find(t => t.templateId === templateId)
}

View File

@@ -0,0 +1,492 @@
/**
* VVT Profiling — Generator-Fragebogen
*
* ~25 Fragen in 6 Schritten, die auf Basis der Antworten
* Baseline-Verarbeitungstaetigkeiten generieren.
*/
import { VVT_BASELINE_CATALOG, templateToActivity } from './vvt-baseline-catalog'
import { generateVVTId } from './vvt-types'
import type { VVTActivity, BusinessFunction } from './vvt-types'
// =============================================================================
// TYPES
// =============================================================================
export interface ProfilingQuestion {
id: string
step: number
question: string
type: 'single_choice' | 'multi_choice' | 'number' | 'text' | 'boolean'
options?: { value: string; label: string }[]
helpText?: string
triggersTemplates: string[] // Template-IDs that get activated when answered positively
}
export interface ProfilingStep {
step: number
title: string
description: string
}
export interface ProfilingAnswers {
[questionId: string]: string | string[] | number | boolean
}
export interface ProfilingResult {
answers: ProfilingAnswers
generatedActivities: VVTActivity[]
coverageScore: number
art30Abs5Exempt: boolean
}
// =============================================================================
// STEPS
// =============================================================================
export const PROFILING_STEPS: ProfilingStep[] = [
{ step: 1, title: 'Organisation', description: 'Grunddaten zu Ihrem Unternehmen' },
{ step: 2, title: 'Geschaeftsbereiche', description: 'Welche Bereiche sind aktiv?' },
{ step: 3, title: 'Systeme & Tools', description: 'Welche IT-Systeme nutzen Sie?' },
{ step: 4, title: 'Datenkategorien', description: 'Welche besonderen Daten verarbeiten Sie?' },
{ step: 5, title: 'Drittlandtransfers', description: 'Transfers ausserhalb der EU/EWR' },
{ step: 6, title: 'Besondere Verarbeitungen', description: 'KI, Scoring, Ueberwachung' },
]
// =============================================================================
// QUESTIONS
// =============================================================================
export const PROFILING_QUESTIONS: ProfilingQuestion[] = [
// === STEP 1: Organisation ===
{
id: 'org_industry',
step: 1,
question: 'In welcher Branche ist Ihr Unternehmen taetig?',
type: 'single_choice',
options: [
{ value: 'it_software', label: 'IT & Software' },
{ value: 'healthcare', label: 'Gesundheitswesen' },
{ value: 'education', label: 'Bildung & Erziehung' },
{ value: 'finance', label: 'Finanzdienstleistungen' },
{ value: 'retail', label: 'Handel & E-Commerce' },
{ value: 'manufacturing', label: 'Produktion & Industrie' },
{ value: 'consulting', label: 'Beratung & Dienstleistung' },
{ value: 'public', label: 'Oeffentlicher Sektor' },
{ value: 'other', label: 'Sonstige' },
],
triggersTemplates: [],
},
{
id: 'org_employees',
step: 1,
question: 'Wie viele Mitarbeiter hat Ihr Unternehmen?',
type: 'number',
helpText: 'Relevant fuer Art. 30 Abs. 5 DSGVO (Ausnahme < 250 Mitarbeiter)',
triggersTemplates: [],
},
{
id: 'org_locations',
step: 1,
question: 'An wie vielen Standorten ist Ihr Unternehmen taetig?',
type: 'single_choice',
options: [
{ value: '1', label: '1 Standort' },
{ value: '2-5', label: '2-5 Standorte' },
{ value: '6-20', label: '6-20 Standorte' },
{ value: '20+', label: 'Mehr als 20 Standorte' },
],
triggersTemplates: [],
},
{
id: 'org_b2b_b2c',
step: 1,
question: 'Welches Geschaeftsmodell betreiben Sie?',
type: 'single_choice',
options: [
{ value: 'b2b', label: 'B2B (Geschaeftskunden)' },
{ value: 'b2c', label: 'B2C (Endkunden)' },
{ value: 'both', label: 'Beides (B2B + B2C)' },
{ value: 'b2g', label: 'B2G (Oeffentlicher Sektor)' },
],
triggersTemplates: [],
},
// === STEP 2: Geschaeftsbereiche ===
{
id: 'dept_hr',
step: 2,
question: 'Haben Sie eine Personalabteilung / HR?',
type: 'boolean',
triggersTemplates: ['hr-mitarbeiterverwaltung', 'hr-gehaltsabrechnung', 'hr-zeiterfassung'],
},
{
id: 'dept_recruiting',
step: 2,
question: 'Betreiben Sie aktives Recruiting / Bewerbermanagement?',
type: 'boolean',
triggersTemplates: ['hr-bewerbermanagement'],
},
{
id: 'dept_finance',
step: 2,
question: 'Haben Sie eine Finanz-/Buchhaltungsabteilung?',
type: 'boolean',
triggersTemplates: ['finance-buchhaltung', 'finance-zahlungsverkehr'],
},
{
id: 'dept_sales',
step: 2,
question: 'Haben Sie einen Vertrieb / Kundenverwaltung?',
type: 'boolean',
triggersTemplates: ['sales-kundenverwaltung', 'sales-vertriebssteuerung'],
},
{
id: 'dept_marketing',
step: 2,
question: 'Betreiben Sie Marketing-Aktivitaeten?',
type: 'boolean',
triggersTemplates: ['marketing-social-media'],
},
{
id: 'dept_support',
step: 2,
question: 'Haben Sie einen Kundenservice / Support?',
type: 'boolean',
triggersTemplates: ['support-ticketsystem'],
},
// === STEP 3: Systeme & Tools ===
{
id: 'sys_crm',
step: 3,
question: 'Nutzen Sie ein CRM-System (z.B. Salesforce, HubSpot, Pipedrive)?',
type: 'boolean',
triggersTemplates: ['sales-kundenverwaltung'],
},
{
id: 'sys_website_analytics',
step: 3,
question: 'Nutzen Sie Website-Analytics (z.B. Matomo, Google Analytics)?',
type: 'boolean',
triggersTemplates: ['marketing-website-analytics'],
},
{
id: 'sys_newsletter',
step: 3,
question: 'Versenden Sie Newsletter (z.B. Mailchimp, CleverReach)?',
type: 'boolean',
triggersTemplates: ['marketing-newsletter'],
},
{
id: 'sys_video',
step: 3,
question: 'Nutzen Sie Videokonferenz-Tools (z.B. Zoom, Teams, Jitsi)?',
type: 'boolean',
triggersTemplates: ['other-videokonferenz'],
},
{
id: 'sys_erp',
step: 3,
question: 'Nutzen Sie ein ERP-System?',
type: 'boolean',
helpText: 'z.B. SAP, ERPNext, Microsoft Dynamics',
triggersTemplates: ['finance-buchhaltung'],
},
{
id: 'sys_visitor',
step: 3,
question: 'Haben Sie ein Besuchermanagement-System?',
type: 'boolean',
triggersTemplates: ['other-besuchermanagement'],
},
// === STEP 4: Datenkategorien ===
{
id: 'data_health',
step: 4,
question: 'Verarbeiten Sie Gesundheitsdaten (Art. 9 DSGVO)?',
type: 'boolean',
helpText: 'z.B. Krankmeldungen, Arbeitsmedizin, Gesundheitsversorgung',
triggersTemplates: [],
},
{
id: 'data_minors',
step: 4,
question: 'Verarbeiten Sie Daten von Minderjaehrigen?',
type: 'boolean',
helpText: 'z.B. Schueler, Kinder unter 16 Jahren',
triggersTemplates: [],
},
{
id: 'data_biometric',
step: 4,
question: 'Verarbeiten Sie biometrische Daten zur Identifizierung?',
type: 'boolean',
helpText: 'z.B. Fingerabdruck, Gesichtserkennung, Stimmerkennung',
triggersTemplates: [],
},
{
id: 'data_criminal',
step: 4,
question: 'Verarbeiten Sie Daten ueber strafrechtliche Verurteilungen (Art. 10 DSGVO)?',
type: 'boolean',
helpText: 'z.B. Fuehrungszeugnisse',
triggersTemplates: [],
},
// === STEP 5: Drittlandtransfers ===
{
id: 'transfer_cloud_us',
step: 5,
question: 'Nutzen Sie Cloud-Dienste mit Sitz in den USA?',
type: 'boolean',
helpText: 'z.B. AWS, Azure, Google Cloud, Microsoft 365',
triggersTemplates: [],
},
{
id: 'transfer_support_non_eu',
step: 5,
question: 'Haben Sie Support-Mitarbeiter oder Dienstleister ausserhalb der EU?',
type: 'boolean',
triggersTemplates: [],
},
{
id: 'transfer_subprocessor',
step: 5,
question: 'Nutzen Sie Auftragsverarbeiter mit Unteraufragnehmern in Drittlaendern?',
type: 'boolean',
triggersTemplates: [],
},
// === STEP 6: Besondere Verarbeitungen ===
{
id: 'special_ai',
step: 6,
question: 'Setzen Sie KI oder automatisierte Entscheidungsfindung ein?',
type: 'boolean',
helpText: 'z.B. Chatbots, Scoring, Profiling, automatische Bewertungen',
triggersTemplates: [],
},
{
id: 'special_video_surveillance',
step: 6,
question: 'Betreiben Sie Videoueberwachung?',
type: 'boolean',
triggersTemplates: [],
},
{
id: 'special_tracking',
step: 6,
question: 'Betreiben Sie umfangreiches Nutzer-Tracking oder Profiling?',
type: 'boolean',
helpText: 'z.B. Verhaltensprofiling, Cross-Device-Tracking',
triggersTemplates: [],
},
]
// =============================================================================
// GENERATOR LOGIC
// =============================================================================
export function generateActivities(answers: ProfilingAnswers): ProfilingResult {
// Collect all triggered template IDs
const triggeredIds = new Set<string>()
for (const question of PROFILING_QUESTIONS) {
const answer = answers[question.id]
if (!answer) continue
// Boolean questions: if true, trigger templates
if (question.type === 'boolean' && answer === true) {
question.triggersTemplates.forEach(id => triggeredIds.add(id))
}
}
// Always add IT baseline templates (every company needs these)
triggeredIds.add('it-systemadministration')
triggeredIds.add('it-backup')
triggeredIds.add('it-logging')
triggeredIds.add('it-iam')
// Generate activities from triggered templates
const existingIds: string[] = []
const activities: VVTActivity[] = []
for (const templateId of triggeredIds) {
const template = VVT_BASELINE_CATALOG.find(t => t.templateId === templateId)
if (!template) continue
const vvtId = generateVVTId(existingIds)
existingIds.push(vvtId)
const activity = templateToActivity(template, vvtId)
// Enrich with profiling answers
enrichActivityFromAnswers(activity, answers)
activities.push(activity)
}
// Calculate coverage score
const totalFields = activities.length * 12 // 12 key fields per activity
let filledFields = 0
for (const a of activities) {
if (a.name) filledFields++
if (a.description) filledFields++
if (a.purposes.length > 0) filledFields++
if (a.legalBases.length > 0) filledFields++
if (a.dataSubjectCategories.length > 0) filledFields++
if (a.personalDataCategories.length > 0) filledFields++
if (a.recipientCategories.length > 0) filledFields++
if (a.retentionPeriod.description) filledFields++
if (a.tomDescription) filledFields++
if (a.businessFunction !== 'other') filledFields++
if (a.structuredToms.accessControl.length > 0) filledFields++
if (a.responsible || a.owner) filledFields++
}
const coverageScore = totalFields > 0 ? Math.round((filledFields / totalFields) * 100) : 0
// Art. 30 Abs. 5 check
const employeeCount = typeof answers.org_employees === 'number' ? answers.org_employees : 0
const hasSpecialCategories = answers.data_health === true || answers.data_biometric === true || answers.data_criminal === true
const art30Abs5Exempt = employeeCount < 250 && !hasSpecialCategories
return {
answers,
generatedActivities: activities,
coverageScore,
art30Abs5Exempt,
}
}
// =============================================================================
// ENRICHMENT
// =============================================================================
function enrichActivityFromAnswers(activity: VVTActivity, answers: ProfilingAnswers): void {
// Add third-country transfers if US cloud is used
if (answers.transfer_cloud_us === true) {
activity.thirdCountryTransfers.push({
country: 'US',
recipient: 'Cloud-Dienstleister (USA)',
transferMechanism: 'SCC_PROCESSOR',
additionalMeasures: ['Verschluesselung at-rest', 'Transfer Impact Assessment'],
})
}
// Add special data categories if applicable
if (answers.data_health === true) {
if (!activity.personalDataCategories.includes('HEALTH_DATA')) {
// Only add to HR activities
if (activity.businessFunction === 'hr') {
activity.personalDataCategories.push('HEALTH_DATA')
// Ensure Art. 9 legal basis
if (!activity.legalBases.some(lb => lb.type.startsWith('ART9_'))) {
activity.legalBases.push({
type: 'ART9_EMPLOYMENT',
description: 'Arbeitsrechtliche Verarbeitung',
reference: 'Art. 9 Abs. 2 lit. b DSGVO',
})
}
}
}
}
if (answers.data_minors === true) {
if (!activity.dataSubjectCategories.includes('MINORS')) {
// Add to relevant activities (education, app users)
if (activity.businessFunction === 'support' || activity.businessFunction === 'product_engineering') {
activity.dataSubjectCategories.push('MINORS')
}
}
}
// Set DPIA required for special processing
if (answers.special_ai === true || answers.special_video_surveillance === true || answers.special_tracking === true) {
if (answers.special_ai === true && activity.businessFunction === 'product_engineering') {
activity.dpiaRequired = true
}
}
}
// =============================================================================
// HELPERS
// =============================================================================
export function getQuestionsForStep(step: number): ProfilingQuestion[] {
return PROFILING_QUESTIONS.filter(q => q.step === step)
}
export function getStepProgress(answers: ProfilingAnswers, step: number): number {
const questions = getQuestionsForStep(step)
if (questions.length === 0) return 100
const answered = questions.filter(q => {
const a = answers[q.id]
return a !== undefined && a !== null && a !== ''
}).length
return Math.round((answered / questions.length) * 100)
}
export function getTotalProgress(answers: ProfilingAnswers): number {
const total = PROFILING_QUESTIONS.length
if (total === 0) return 100
const answered = PROFILING_QUESTIONS.filter(q => {
const a = answers[q.id]
return a !== undefined && a !== null && a !== ''
}).length
return Math.round((answered / total) * 100)
}
// =============================================================================
// COMPLIANCE SCOPE INTEGRATION
// =============================================================================
/**
* Prefill VVT profiling answers from Compliance Scope Engine answers.
* The Scope Engine acts as the "Single Source of Truth" for organizational questions.
* Redundant questions are auto-filled with a "prefilled" marker.
*/
export function prefillFromScopeAnswers(
scopeAnswers: import('./compliance-scope-types').ScopeProfilingAnswer[]
): ProfilingAnswers {
const { exportToVVTAnswers } = require('./compliance-scope-profiling')
const exported = exportToVVTAnswers(scopeAnswers) as Record<string, unknown>
const prefilled: ProfilingAnswers = {}
for (const [key, value] of Object.entries(exported)) {
if (value !== undefined && value !== null) {
prefilled[key] = value as string | string[] | number | boolean
}
}
return prefilled
}
/**
* Get the list of VVT question IDs that are prefilled from Scope answers.
* These questions should show "Aus Scope-Analyse uebernommen" hint.
*/
export const SCOPE_PREFILLED_VVT_QUESTIONS = [
'org_industry',
'org_employees',
'org_b2b_b2c',
'dept_hr',
'dept_finance',
'dept_marketing',
'data_health',
'data_minors',
'data_biometric',
'data_criminal',
'special_ai',
'special_video_surveillance',
'special_tracking',
'transfer_cloud_us',
'transfer_subprocessor',
'transfer_support_non_eu',
]

View File

@@ -0,0 +1,247 @@
/**
* VVT (Verarbeitungsverzeichnis) Types — Art. 30 DSGVO
*
* Re-exports common types from vendor-compliance/types.ts and adds
* VVT-specific interfaces for the 4-tab VVT module.
*/
// Re-exports from vendor-compliance/types.ts
export type {
DataSubjectCategory,
PersonalDataCategory,
LegalBasisType,
TransferMechanismType,
RecipientCategoryType,
ProcessingActivityStatus,
ProtectionLevel,
ThirdCountryTransfer,
RetentionPeriod,
LegalBasis,
RecipientCategory,
DataSource,
SystemReference,
DataFlow,
DataSourceType,
LocalizedText,
} from './vendor-compliance/types'
export {
DATA_SUBJECT_CATEGORY_META,
PERSONAL_DATA_CATEGORY_META,
LEGAL_BASIS_META,
TRANSFER_MECHANISM_META,
isSpecialCategory,
hasAdequacyDecision,
generateVVTId,
} from './vendor-compliance/types'
// =============================================================================
// VVT-SPECIFIC TYPES
// =============================================================================
export interface VVTOrganizationHeader {
organizationName: string
industry: string
locations: string[]
employeeCount: number
dpoName: string
dpoContact: string
vvtVersion: string
lastReviewDate: string
nextReviewDate: string
reviewInterval: 'quarterly' | 'semi_annual' | 'annual'
}
export type BusinessFunction =
| 'hr'
| 'finance'
| 'sales_crm'
| 'marketing'
| 'support'
| 'it_operations'
| 'product_engineering'
| 'legal'
| 'management'
| 'other'
export interface StructuredTOMs {
accessControl: string[]
confidentiality: string[]
integrity: string[]
availability: string[]
separation: string[]
}
export interface VVTActivity {
// Pflichtfelder Art. 30 Abs. 1 (Controller)
id: string
vvtId: string
name: string
description: string
purposes: string[]
legalBases: { type: string; description?: string; reference?: string }[]
dataSubjectCategories: string[]
personalDataCategories: string[]
recipientCategories: { type: string; name: string; description?: string; isThirdCountry?: boolean; country?: string }[]
thirdCountryTransfers: { country: string; recipient: string; transferMechanism: string; additionalMeasures?: string[] }[]
retentionPeriod: { duration?: number; durationUnit?: string; description: string; legalBasis?: string; deletionProcedure?: string }
tomDescription: string
// Generator-Optimierung (Layer B)
businessFunction: BusinessFunction
systems: { systemId: string; name: string; description?: string; type?: string }[]
deploymentModel: 'cloud' | 'on_prem' | 'hybrid'
dataSources: { type: string; description?: string }[]
dataFlows: { sourceSystem?: string; targetSystem?: string; description: string; dataCategories: string[] }[]
protectionLevel: 'LOW' | 'MEDIUM' | 'HIGH'
dpiaRequired: boolean
structuredToms: StructuredTOMs
// Workflow
status: 'DRAFT' | 'REVIEW' | 'APPROVED' | 'ARCHIVED'
responsible: string
owner: string
createdAt: string
updatedAt: string
}
// Processor-Record (Art. 30 Abs. 2)
export interface VVTProcessorActivity {
id: string
vvtId: string
controllerReference: string
processingCategories: string[]
subProcessorChain: SubProcessor[]
thirdCountryTransfers: { country: string; recipient: string; transferMechanism: string }[]
tomDescription: string
status: 'DRAFT' | 'REVIEW' | 'APPROVED' | 'ARCHIVED'
}
export interface SubProcessor {
name: string
purpose: string
country: string
isThirdCountry: boolean
}
// =============================================================================
// CONSTANTS
// =============================================================================
export const BUSINESS_FUNCTION_LABELS: Record<BusinessFunction, string> = {
hr: 'Personal (HR)',
finance: 'Finanzen & Buchhaltung',
sales_crm: 'Vertrieb & CRM',
marketing: 'Marketing',
support: 'Kundenservice',
it_operations: 'IT-Betrieb',
product_engineering: 'Produktentwicklung',
legal: 'Recht & Compliance',
management: 'Geschaeftsfuehrung',
other: 'Sonstiges',
}
export const STATUS_LABELS: Record<string, string> = {
DRAFT: 'Entwurf',
REVIEW: 'In Pruefung',
APPROVED: 'Genehmigt',
ARCHIVED: 'Archiviert',
}
export const STATUS_COLORS: Record<string, string> = {
DRAFT: 'bg-gray-100 text-gray-700',
REVIEW: 'bg-yellow-100 text-yellow-700',
APPROVED: 'bg-green-100 text-green-700',
ARCHIVED: 'bg-red-100 text-red-700',
}
export const PROTECTION_LEVEL_LABELS: Record<string, string> = {
LOW: 'Niedrig',
MEDIUM: 'Mittel',
HIGH: 'Hoch',
}
export const DEPLOYMENT_LABELS: Record<string, string> = {
cloud: 'Cloud',
on_prem: 'On-Premise',
hybrid: 'Hybrid',
}
export const REVIEW_INTERVAL_LABELS: Record<string, string> = {
quarterly: 'Vierteljaehrlich',
semi_annual: 'Halbjaehrlich',
annual: 'Jaehrlich',
}
// Art. 9 special categories for highlighting
export const ART9_CATEGORIES: string[] = [
'HEALTH_DATA',
'GENETIC_DATA',
'BIOMETRIC_DATA',
'RACIAL_ETHNIC',
'POLITICAL_OPINIONS',
'RELIGIOUS_BELIEFS',
'TRADE_UNION',
'SEX_LIFE',
'CRIMINAL_DATA',
]
// =============================================================================
// HELPER: Create empty activity
// =============================================================================
export function createEmptyActivity(vvtId: string): VVTActivity {
const now = new Date().toISOString()
return {
id: crypto.randomUUID(),
vvtId,
name: '',
description: '',
purposes: [],
legalBases: [],
dataSubjectCategories: [],
personalDataCategories: [],
recipientCategories: [],
thirdCountryTransfers: [],
retentionPeriod: { description: '', legalBasis: '', deletionProcedure: '' },
tomDescription: '',
businessFunction: 'other',
systems: [],
deploymentModel: 'cloud',
dataSources: [],
dataFlows: [],
protectionLevel: 'MEDIUM',
dpiaRequired: false,
structuredToms: {
accessControl: [],
confidentiality: [],
integrity: [],
availability: [],
separation: [],
},
status: 'DRAFT',
responsible: '',
owner: '',
createdAt: now,
updatedAt: now,
}
}
// =============================================================================
// HELPER: Default organization header
// =============================================================================
export function createDefaultOrgHeader(): VVTOrganizationHeader {
return {
organizationName: '',
industry: '',
locations: [],
employeeCount: 0,
dpoName: '',
dpoContact: '',
vvtVersion: '1.0',
lastReviewDate: new Date().toISOString().split('T')[0],
nextReviewDate: '',
reviewInterval: 'annual',
}
}