refactor(admin-compliance): split 11 oversized files under 500 LOC hard cap (batch 2)

Barrel-split pattern: each original becomes a thin re-export barrel; logic
moved to sibling files so no consumer imports need updating.

Files split:
- loeschfristen-profiling.ts → profiling-data.ts + profiling-generator.ts
- vendor-compliance/catalog/vendor-templates.ts → vendor-country-profiles.ts
- vendor-compliance/catalog/legal-basis.ts → legal-basis-retention.ts
- dsfa/eu-legal-frameworks.ts → eu-legal-frameworks-national.ts
- compliance-scope-types/document-scope-matrix-core.ts → core-part2.ts
- compliance-scope-types/document-scope-matrix-extended.ts → extended-part2.ts
- app/sdk/document-generator/contextBridge.ts → contextBridge-helpers.ts
- app/api/sdk/drafting-engine/draft/route.ts → draft-helpers.ts + draft-helpers-v2.ts

All files ≤ 500 LOC. Zero behavior changes.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Sharang Parnerkar
2026-04-18 00:32:08 +02:00
parent 92a47bf6f9
commit feedeb052f
17 changed files with 2381 additions and 2640 deletions

View File

@@ -0,0 +1,249 @@
/**
* Compliance Scope Engine - Document Scope Matrix Core (Part 2)
*
* Continued from document-scope-matrix-core.ts for the 500 LOC hard cap.
* Contains: dsfa, daten_transfer, datenpannen, einwilligung, vertragsmanagement
*/
import type { ScopeDocumentType } from './documents'
import type { DocumentScopeRequirement } from './documents'
export const DOCUMENT_SCOPE_MATRIX_CORE_PART2: Partial<Record<ScopeDocumentType, DocumentScopeRequirement>> = {
dsfa: {
L1: {
required: false,
depth: 'Nicht erforderlich',
detailItems: ['Nur bei Hard Trigger erforderlich'],
estimatedEffort: 'N/A',
},
L2: {
required: false,
depth: 'Bei Bedarf',
detailItems: [
'DSFA-Schwellwertanalyse durchführen',
'Bei Erforderlichkeit: Basis-DSFA',
'Risiken identifiziert und bewertet',
'Maßnahmen zur Risikominimierung',
],
estimatedEffort: '4-8 Stunden pro DSFA',
},
L3: {
required: false,
depth: 'Standard',
detailItems: [
'Alle L2-Anforderungen',
'Detaillierte Risikobewertung',
'Konsultation der Betroffenen wo sinnvoll',
'Dokumentation der Entscheidungsprozesse',
'Regelmäßige Überprüfung',
],
estimatedEffort: '8-16 Stunden pro DSFA',
},
L4: {
required: true,
depth: 'Vollständig',
detailItems: [
'Alle L3-Anforderungen',
'Strukturierter DSFA-Prozess etabliert',
'Vorabkonsultation der Aufsichtsbehörde wo erforderlich',
'Vollständige Dokumentation aller Schritte',
'Integration in Projektmanagement',
],
estimatedEffort: '16-24 Stunden pro DSFA',
},
},
daten_transfer: {
L1: {
required: false,
depth: 'Basis',
detailItems: [
'Liste aller Drittlandtransfers',
'Grundlegende Rechtsgrundlage identifiziert',
'Standard-Vertragsklauseln wo nötig',
],
estimatedEffort: '1-2 Stunden',
},
L2: {
required: true,
depth: 'Standard',
detailItems: [
'Alle L1-Anforderungen',
'Detaillierte Dokumentation aller Transfers',
'Angemessenheitsbeschlüsse oder geeignete Garantien',
'Informationen an Betroffene bereitgestellt',
'Register geführt',
],
estimatedEffort: '3-6 Stunden',
},
L3: {
required: true,
depth: 'Detailliert',
detailItems: [
'Alle L2-Anforderungen',
'Transfer Impact Assessment (TIA) durchgeführt',
'Zusätzliche Schutzmaßnahmen dokumentiert',
'Regelmäßige Überprüfung der Rechtsgrundlagen',
'Risikobewertung für jedes Zielland',
],
estimatedEffort: '6-12 Stunden',
},
L4: {
required: true,
depth: 'Audit-Ready',
detailItems: [
'Alle L3-Anforderungen',
'Vollständige TIA-Dokumentation',
'Regelmäßige Reviews dokumentiert',
'Rechtliche Expertise nachgewiesen',
'Compliance-Nachweise für alle Transfers',
],
estimatedEffort: '12-20 Stunden',
},
},
datenpannen: {
L1: {
required: true,
depth: 'Basis',
detailItems: [
'Grundlegender Prozess für Datenpannen',
'Kontakt zur Aufsichtsbehörde bekannt',
'Verantwortlichkeiten grob definiert',
'Einfache Checkliste',
],
estimatedEffort: '1-2 Stunden',
},
L2: {
required: true,
depth: 'Standard',
detailItems: [
'Alle L1-Anforderungen',
'Detaillierter Incident-Response-Plan',
'Bewertungskriterien für Meldepflicht',
'Vorlagen für Meldungen (Behörde & Betroffene)',
'Dokumentationspflichten klar definiert',
],
estimatedEffort: '3-6 Stunden',
},
L3: {
required: true,
depth: 'Detailliert',
detailItems: [
'Alle L2-Anforderungen',
'Incident-Management-System etabliert',
'Regelmäßige Übungen durchgeführt',
'Eskalationsprozesse dokumentiert',
'Post-Incident-Review-Prozess',
'Lessons Learned dokumentiert',
],
estimatedEffort: '6-10 Stunden',
},
L4: {
required: true,
depth: 'Audit-Ready',
detailItems: [
'Alle L3-Anforderungen',
'Vollständiges Breach-Log geführt',
'Integration mit IT-Security-Incident-Response',
'Regelmäßige Audits des Prozesses',
'Compliance-Nachweise für alle Vorfälle',
],
estimatedEffort: '10-16 Stunden',
},
},
einwilligung: {
L1: {
required: false,
depth: 'Basis',
detailItems: [
'Einwilligungsformulare DSGVO-konform',
'Opt-in statt Opt-out',
'Widerrufsmöglichkeit bereitgestellt',
],
estimatedEffort: '1-2 Stunden',
},
L2: {
required: true,
depth: 'Standard',
detailItems: [
'Alle L1-Anforderungen',
'Granulare Einwilligungen',
'Nachweisbarkeit der Einwilligung',
'Dokumentation des Einwilligungsprozesses',
'Regelmäßige Überprüfung',
],
estimatedEffort: '3-6 Stunden',
},
L3: {
required: true,
depth: 'Detailliert',
detailItems: [
'Alle L2-Anforderungen',
'Consent-Management-System implementiert',
'Vollständiger Audit-Trail',
'A/B-Testing dokumentiert',
'Integration mit allen Datenverarbeitungen',
'Regelmäßige Revalidierung',
],
estimatedEffort: '6-12 Stunden',
},
L4: {
required: true,
depth: 'Audit-Ready',
detailItems: [
'Alle L3-Anforderungen',
'Enterprise Consent Management Platform',
'Vollständige Nachweiskette für alle Einwilligungen',
'Compliance-Dashboard',
'Regelmäßige externe Audits',
],
estimatedEffort: '12-20 Stunden',
},
},
vertragsmanagement: {
L1: {
required: false,
depth: 'Basis',
detailItems: [
'Einfaches Register wichtiger Verträge',
'Ablage datenschutzrelevanter Verträge',
],
estimatedEffort: '1-2 Stunden',
},
L2: {
required: true,
depth: 'Standard',
detailItems: [
'Alle L1-Anforderungen',
'Vollständiges Vertragsregister',
'Datenschutzklauseln in Standardverträgen',
'Überprüfungsprozess für neue Verträge',
'Ablaufdaten und Kündigungsfristen getrackt',
],
estimatedEffort: '3-6 Stunden Setup',
},
L3: {
required: true,
depth: 'Detailliert',
detailItems: [
'Alle L2-Anforderungen',
'Vertragsmanagement-System implementiert',
'Automatische Erinnerungen für Reviews',
'Risikobewertung für Vertragspartner',
'Compliance-Checks vor Vertragsabschluss',
],
estimatedEffort: '6-12 Stunden Setup',
},
L4: {
required: true,
depth: 'Audit-Ready',
detailItems: [
'Alle L3-Anforderungen',
'Enterprise Contract Management System',
'Vollständiger Audit-Trail',
'Integration mit Procurement',
'Regelmäßige Compliance-Audits',
],
estimatedEffort: '12-20 Stunden Setup',
},
},
}

View File

@@ -8,6 +8,7 @@
import type { ScopeDocumentType } from './documents'
import type { DocumentScopeRequirement } from './documents'
import { DOCUMENT_SCOPE_MATRIX_CORE_PART2 } from './document-scope-matrix-core-part2'
/**
* Scope-Matrix fuer Kern-DSGVO-Dokumente
@@ -311,241 +312,7 @@ export const DOCUMENT_SCOPE_MATRIX_CORE: Partial<Record<ScopeDocumentType, Docum
estimatedEffort: '10-16 Stunden',
},
},
dsfa: {
L1: {
required: false,
depth: 'Nicht erforderlich',
detailItems: ['Nur bei Hard Trigger erforderlich'],
estimatedEffort: 'N/A',
},
L2: {
required: false,
depth: 'Bei Bedarf',
detailItems: [
'DSFA-Schwellwertanalyse durchführen',
'Bei Erforderlichkeit: Basis-DSFA',
'Risiken identifiziert und bewertet',
'Maßnahmen zur Risikominimierung',
],
estimatedEffort: '4-8 Stunden pro DSFA',
},
L3: {
required: false,
depth: 'Standard',
detailItems: [
'Alle L2-Anforderungen',
'Detaillierte Risikobewertung',
'Konsultation der Betroffenen wo sinnvoll',
'Dokumentation der Entscheidungsprozesse',
'Regelmäßige Überprüfung',
],
estimatedEffort: '8-16 Stunden pro DSFA',
},
L4: {
required: true,
depth: 'Vollständig',
detailItems: [
'Alle L3-Anforderungen',
'Strukturierter DSFA-Prozess etabliert',
'Vorabkonsultation der Aufsichtsbehörde wo erforderlich',
'Vollständige Dokumentation aller Schritte',
'Integration in Projektmanagement',
],
estimatedEffort: '16-24 Stunden pro DSFA',
},
},
daten_transfer: {
L1: {
required: false,
depth: 'Basis',
detailItems: [
'Liste aller Drittlandtransfers',
'Grundlegende Rechtsgrundlage identifiziert',
'Standard-Vertragsklauseln wo nötig',
],
estimatedEffort: '1-2 Stunden',
},
L2: {
required: true,
depth: 'Standard',
detailItems: [
'Alle L1-Anforderungen',
'Detaillierte Dokumentation aller Transfers',
'Angemessenheitsbeschlüsse oder geeignete Garantien',
'Informationen an Betroffene bereitgestellt',
'Register geführt',
],
estimatedEffort: '3-6 Stunden',
},
L3: {
required: true,
depth: 'Detailliert',
detailItems: [
'Alle L2-Anforderungen',
'Transfer Impact Assessment (TIA) durchgeführt',
'Zusätzliche Schutzmaßnahmen dokumentiert',
'Regelmäßige Überprüfung der Rechtsgrundlagen',
'Risikobewertung für jedes Zielland',
],
estimatedEffort: '6-12 Stunden',
},
L4: {
required: true,
depth: 'Audit-Ready',
detailItems: [
'Alle L3-Anforderungen',
'Vollständige TIA-Dokumentation',
'Regelmäßige Reviews dokumentiert',
'Rechtliche Expertise nachgewiesen',
'Compliance-Nachweise für alle Transfers',
],
estimatedEffort: '12-20 Stunden',
},
},
datenpannen: {
L1: {
required: true,
depth: 'Basis',
detailItems: [
'Grundlegender Prozess für Datenpannen',
'Kontakt zur Aufsichtsbehörde bekannt',
'Verantwortlichkeiten grob definiert',
'Einfache Checkliste',
],
estimatedEffort: '1-2 Stunden',
},
L2: {
required: true,
depth: 'Standard',
detailItems: [
'Alle L1-Anforderungen',
'Detaillierter Incident-Response-Plan',
'Bewertungskriterien für Meldepflicht',
'Vorlagen für Meldungen (Behörde & Betroffene)',
'Dokumentationspflichten klar definiert',
],
estimatedEffort: '3-6 Stunden',
},
L3: {
required: true,
depth: 'Detailliert',
detailItems: [
'Alle L2-Anforderungen',
'Incident-Management-System etabliert',
'Regelmäßige Übungen durchgeführt',
'Eskalationsprozesse dokumentiert',
'Post-Incident-Review-Prozess',
'Lessons Learned dokumentiert',
],
estimatedEffort: '6-10 Stunden',
},
L4: {
required: true,
depth: 'Audit-Ready',
detailItems: [
'Alle L3-Anforderungen',
'Vollständiges Breach-Log geführt',
'Integration mit IT-Security-Incident-Response',
'Regelmäßige Audits des Prozesses',
'Compliance-Nachweise für alle Vorfälle',
],
estimatedEffort: '10-16 Stunden',
},
},
einwilligung: {
L1: {
required: false,
depth: 'Basis',
detailItems: [
'Einwilligungsformulare DSGVO-konform',
'Opt-in statt Opt-out',
'Widerrufsmöglichkeit bereitgestellt',
],
estimatedEffort: '1-2 Stunden',
},
L2: {
required: true,
depth: 'Standard',
detailItems: [
'Alle L1-Anforderungen',
'Granulare Einwilligungen',
'Nachweisbarkeit der Einwilligung',
'Dokumentation des Einwilligungsprozesses',
'Regelmäßige Überprüfung',
],
estimatedEffort: '3-6 Stunden',
},
L3: {
required: true,
depth: 'Detailliert',
detailItems: [
'Alle L2-Anforderungen',
'Consent-Management-System implementiert',
'Vollständiger Audit-Trail',
'A/B-Testing dokumentiert',
'Integration mit allen Datenverarbeitungen',
'Regelmäßige Revalidierung',
],
estimatedEffort: '6-12 Stunden',
},
L4: {
required: true,
depth: 'Audit-Ready',
detailItems: [
'Alle L3-Anforderungen',
'Enterprise Consent Management Platform',
'Vollständige Nachweiskette für alle Einwilligungen',
'Compliance-Dashboard',
'Regelmäßige externe Audits',
],
estimatedEffort: '12-20 Stunden',
},
},
vertragsmanagement: {
L1: {
required: false,
depth: 'Basis',
detailItems: [
'Einfaches Register wichtiger Verträge',
'Ablage datenschutzrelevanter Verträge',
],
estimatedEffort: '1-2 Stunden',
},
L2: {
required: true,
depth: 'Standard',
detailItems: [
'Alle L1-Anforderungen',
'Vollständiges Vertragsregister',
'Datenschutzklauseln in Standardverträgen',
'Überprüfungsprozess für neue Verträge',
'Ablaufdaten und Kündigungsfristen getrackt',
],
estimatedEffort: '3-6 Stunden Setup',
},
L3: {
required: true,
depth: 'Detailliert',
detailItems: [
'Alle L2-Anforderungen',
'Vertragsmanagement-System implementiert',
'Automatische Erinnerungen für Reviews',
'Risikobewertung für Vertragspartner',
'Compliance-Checks vor Vertragsabschluss',
],
estimatedEffort: '6-12 Stunden Setup',
},
L4: {
required: true,
depth: 'Audit-Ready',
detailItems: [
'Alle L3-Anforderungen',
'Enterprise Contract Management System',
'Vollständiger Audit-Trail',
'Integration mit Procurement',
'Regelmäßige Compliance-Audits',
],
estimatedEffort: '12-20 Stunden Setup',
},
},
};
...DOCUMENT_SCOPE_MATRIX_CORE_PART2,
}
export { DOCUMENT_SCOPE_MATRIX_CORE_PART2 } from './document-scope-matrix-core-part2'

View File

@@ -0,0 +1,286 @@
/**
* Compliance Scope Engine - Document Scope Matrix Extended (Part 2)
*
* Continued from document-scope-matrix-extended.ts for the 500 LOC hard cap.
* Contains: iace_ce_assessment, widerrufsbelehrung, preisangaben, fernabsatz_info,
* streitbeilegung, produktsicherheit, ai_act_doku
*/
import type { ScopeDocumentType } from './documents'
import type { DocumentScopeRequirement } from './documents'
export const DOCUMENT_SCOPE_MATRIX_EXTENDED_PART2: Partial<Record<ScopeDocumentType, DocumentScopeRequirement>> = {
iace_ce_assessment: {
L1: {
required: false,
depth: 'Minimal',
detailItems: [
'Regulatorischer Quick-Check fuer SW/FW/KI',
'Grundlegende Identifikation relevanter Vorschriften',
],
estimatedEffort: '2 Stunden',
},
L2: {
required: true,
depth: 'Standard',
detailItems: [
'CE-Risikobeurteilung fuer SW/FW-Komponenten',
'Hazard Log mit S×E×P Bewertung',
'CRA-Konformitaetspruefung',
'Grundlegende Massnahmendokumentation',
],
estimatedEffort: '8 Stunden',
},
L3: {
required: true,
depth: 'Detailliert',
detailItems: [
'Alle L2-Anforderungen',
'Vollstaendige CE-Akte inkl. KI-Dossier',
'AI Act High-Risk Konformitaetsbewertung',
'Maschinenverordnung Anhang III Nachweis',
'Verifikationsplan mit Akzeptanzkriterien',
'Evidence-Management fuer Testnachweise',
],
estimatedEffort: '16 Stunden',
},
L4: {
required: true,
depth: 'Audit-Ready',
detailItems: [
'Alle L3-Anforderungen',
'Zertifizierungsfertige CE-Dokumentation',
'Benannte-Stelle-tauglicher Nachweis',
'Revisionssichere Audit Trails',
'Post-Market Monitoring Plan',
'Continuous Compliance Framework',
],
estimatedEffort: '24 Stunden',
},
},
widerrufsbelehrung: {
L1: {
required: false,
depth: 'Nicht relevant',
detailItems: ['Nur bei B2C-Fernabsatz erforderlich'],
estimatedEffort: '0',
},
L2: {
required: true,
depth: 'Standard',
detailItems: [
'Muster-Widerrufsbelehrung nach EGBGB Anlage 1',
'Muster-Widerrufsformular nach EGBGB Anlage 2',
'Integration in Bestellprozess',
'14-Tage Widerrufsfrist korrekt dargestellt',
],
estimatedEffort: '2-4 Stunden',
},
L3: {
required: true,
depth: 'Erweitert',
detailItems: [
'Wie L2 + digitale Inhalte (§ 356 Abs. 5 BGB)',
'Ausnahmen dokumentiert (§ 312g Abs. 2 BGB)',
],
estimatedEffort: '4-6 Stunden',
},
L4: {
required: true,
depth: 'Vollstaendig',
detailItems: [
'Wie L3 + automatisierte Pruefung',
'Mehrsprachig bei EU-Verkauf',
],
estimatedEffort: '6-8 Stunden',
},
},
preisangaben: {
L1: {
required: false,
depth: 'Nicht relevant',
detailItems: ['Nur bei B2C-Preisauszeichnung erforderlich'],
estimatedEffort: '0',
},
L2: {
required: true,
depth: 'Standard',
detailItems: [
'Gesamtpreisangabe inkl. MwSt (§ 1 PAngV)',
'Grundpreisangabe bei Mengenware (§ 4 PAngV)',
'Versandkosten deutlich angegeben',
],
estimatedEffort: '2-3 Stunden',
},
L3: {
required: true,
depth: 'Erweitert',
detailItems: [
'Wie L2 + Preishistorie bei Rabattaktionen (Omnibus-RL)',
'Streichpreise korrekt dargestellt',
],
estimatedEffort: '3-5 Stunden',
},
L4: {
required: true,
depth: 'Vollstaendig',
detailItems: [
'Wie L3 + automatisierte Pruefung',
'Mehrwaehrungsunterstuetzung',
],
estimatedEffort: '5-8 Stunden',
},
},
fernabsatz_info: {
L1: {
required: false,
depth: 'Nicht relevant',
detailItems: ['Nur bei Fernabsatzvertraegen erforderlich'],
estimatedEffort: '0',
},
L2: {
required: true,
depth: 'Standard',
detailItems: [
'Pflichtinformationen nach § 312d BGB i.V.m. Art. 246a EGBGB',
'Wesentliche Eigenschaften der Ware/Dienstleistung',
'Identitaet und Anschrift des Unternehmers',
'Zahlungs-, Liefer- und Leistungsbedingungen',
],
estimatedEffort: '3-5 Stunden',
},
L3: {
required: true,
depth: 'Erweitert',
detailItems: [
'Wie L2 + Informationen zu digitalen Inhalten/Diensten',
'Funktionalitaet und Interoperabilitaet (§ 327 BGB)',
],
estimatedEffort: '5-8 Stunden',
},
L4: {
required: true,
depth: 'Vollstaendig',
detailItems: [
'Wie L3 + mehrsprachige Informationspflichten',
'Automatisierte Vollstaendigkeitspruefung',
],
estimatedEffort: '8-12 Stunden',
},
},
streitbeilegung: {
L1: {
required: false,
depth: 'Nicht relevant',
detailItems: ['Nur bei B2C-Handel erforderlich'],
estimatedEffort: '0',
},
L2: {
required: true,
depth: 'Standard',
detailItems: [
'Hinweis auf OS-Plattform der EU-Kommission (Art. 14 ODR-VO)',
'Erklaerung zur Teilnahmebereitschaft an Streitbeilegung (§ 36 VSBG)',
'Link zur OS-Plattform im Impressum/AGB',
],
estimatedEffort: '1-2 Stunden',
},
L3: {
required: true,
depth: 'Erweitert',
detailItems: [
'Wie L2 + Benennung zustaendiger Verbraucherschlichtungsstelle',
'Prozess fuer Streitbeilegungsanfragen dokumentiert',
],
estimatedEffort: '2-3 Stunden',
},
L4: {
required: true,
depth: 'Vollstaendig',
detailItems: [
'Wie L3 + Eskalationsprozess dokumentiert',
'Regelmaessige Auswertung von Beschwerden',
],
estimatedEffort: '3-4 Stunden',
},
},
produktsicherheit: {
L1: {
required: false,
depth: 'Minimal',
detailItems: ['Grundlegende Produktkennzeichnung pruefen'],
estimatedEffort: '1 Stunde',
},
L2: {
required: true,
depth: 'Standard',
detailItems: [
'Produktsicherheitsbewertung nach GPSR (EU 2023/988)',
'CE-Kennzeichnung und Konformitaetserklaerung',
'Wirtschaftsakteur-Angaben auf Produkt/Verpackung',
'Technische Dokumentation fuer Marktaufsicht',
],
estimatedEffort: '8-12 Stunden',
},
L3: {
required: true,
depth: 'Erweitert',
detailItems: [
'Wie L2 + Risikoanalyse fuer alle Produktvarianten',
'Rueckrufplan und Marktbeobachtungspflichten',
'Supply-Chain-Dokumentation',
],
estimatedEffort: '16-24 Stunden',
},
L4: {
required: true,
depth: 'Vollstaendig',
detailItems: [
'Wie L3 + vollstaendige GPSR-Konformitaetsakte',
'Post-Market-Surveillance System',
'Audit-Trail fuer alle Sicherheitsbewertungen',
],
estimatedEffort: '24-40 Stunden',
},
},
ai_act_doku: {
L1: {
required: false,
depth: 'Minimal',
detailItems: ['KI-Risikokategorisierung (Art. 6 AI Act)'],
estimatedEffort: '2 Stunden',
},
L2: {
required: true,
depth: 'Standard',
detailItems: [
'Technische Dokumentation nach Art. 11 AI Act',
'Transparenzpflichten (Art. 52 AI Act)',
'Risikomanagement-Grundlagen (Art. 9 AI Act)',
'Menschliche Aufsicht dokumentiert (Art. 14 AI Act)',
],
estimatedEffort: '8-12 Stunden',
},
L3: {
required: true,
depth: 'Erweitert',
detailItems: [
'Wie L2 + Datenqualitaetsmanagement (Art. 10 AI Act)',
'Genauigkeits- und Robustheitstests (Art. 15 AI Act)',
'Vollstaendige Konformitaetsbewertung fuer Hochrisiko-KI',
],
estimatedEffort: '16-24 Stunden',
},
L4: {
required: true,
depth: 'Audit-Ready',
detailItems: [
'Wie L3 + Zertifizierungsfertige AI Act Dokumentation',
'EU-Datenbank-Registrierung (Art. 60 AI Act)',
'Post-Market Monitoring fuer KI-Systeme',
'Continuous Compliance Framework fuer KI',
],
estimatedEffort: '24-40 Stunden',
},
},
}

View File

@@ -10,6 +10,7 @@
import type { ScopeDocumentType } from './documents'
import type { DocumentScopeRequirement } from './documents'
import { DOCUMENT_SCOPE_MATRIX_EXTENDED_PART2 } from './document-scope-matrix-extended-part2'
/**
* Scope-Matrix fuer erweiterte Dokumente
@@ -289,277 +290,7 @@ export const DOCUMENT_SCOPE_MATRIX_EXTENDED: Partial<Record<ScopeDocumentType, D
estimatedEffort: '24-40 Stunden',
},
},
iace_ce_assessment: {
L1: {
required: false,
depth: 'Minimal',
detailItems: [
'Regulatorischer Quick-Check fuer SW/FW/KI',
'Grundlegende Identifikation relevanter Vorschriften',
],
estimatedEffort: '2 Stunden',
},
L2: {
required: true,
depth: 'Standard',
detailItems: [
'CE-Risikobeurteilung fuer SW/FW-Komponenten',
'Hazard Log mit S×E×P Bewertung',
'CRA-Konformitaetspruefung',
'Grundlegende Massnahmendokumentation',
],
estimatedEffort: '8 Stunden',
},
L3: {
required: true,
depth: 'Detailliert',
detailItems: [
'Alle L2-Anforderungen',
'Vollstaendige CE-Akte inkl. KI-Dossier',
'AI Act High-Risk Konformitaetsbewertung',
'Maschinenverordnung Anhang III Nachweis',
'Verifikationsplan mit Akzeptanzkriterien',
'Evidence-Management fuer Testnachweise',
],
estimatedEffort: '16 Stunden',
},
L4: {
required: true,
depth: 'Audit-Ready',
detailItems: [
'Alle L3-Anforderungen',
'Zertifizierungsfertige CE-Dokumentation',
'Benannte-Stelle-tauglicher Nachweis',
'Revisionssichere Audit Trails',
'Post-Market Monitoring Plan',
'Continuous Compliance Framework',
],
estimatedEffort: '24 Stunden',
},
},
widerrufsbelehrung: {
L1: {
required: false,
depth: 'Nicht relevant',
detailItems: ['Nur bei B2C-Fernabsatz erforderlich'],
estimatedEffort: '0',
},
L2: {
required: true,
depth: 'Standard',
detailItems: [
'Muster-Widerrufsbelehrung nach EGBGB Anlage 1',
'Muster-Widerrufsformular nach EGBGB Anlage 2',
'Integration in Bestellprozess',
'14-Tage Widerrufsfrist korrekt dargestellt',
],
estimatedEffort: '2-4 Stunden',
},
L3: {
required: true,
depth: 'Erweitert',
detailItems: [
'Wie L2 + digitale Inhalte (§ 356 Abs. 5 BGB)',
'Ausnahmen dokumentiert (§ 312g Abs. 2 BGB)',
],
estimatedEffort: '4-6 Stunden',
},
L4: {
required: true,
depth: 'Vollstaendig',
detailItems: [
'Wie L3 + automatisierte Pruefung',
'Mehrsprachig bei EU-Verkauf',
],
estimatedEffort: '6-8 Stunden',
},
},
preisangaben: {
L1: {
required: false,
depth: 'Nicht relevant',
detailItems: ['Nur bei B2C-Preisauszeichnung erforderlich'],
estimatedEffort: '0',
},
L2: {
required: true,
depth: 'Standard',
detailItems: [
'Gesamtpreisangabe inkl. MwSt (§ 1 PAngV)',
'Grundpreisangabe bei Mengenware (§ 4 PAngV)',
'Versandkosten deutlich angegeben',
],
estimatedEffort: '2-3 Stunden',
},
L3: {
required: true,
depth: 'Erweitert',
detailItems: [
'Wie L2 + Preishistorie bei Rabattaktionen (Omnibus-RL)',
'Streichpreise korrekt dargestellt',
],
estimatedEffort: '3-5 Stunden',
},
L4: {
required: true,
depth: 'Vollstaendig',
detailItems: [
'Wie L3 + automatisierte Pruefung',
'Mehrwaehrungsunterstuetzung',
],
estimatedEffort: '5-8 Stunden',
},
},
fernabsatz_info: {
L1: {
required: false,
depth: 'Nicht relevant',
detailItems: ['Nur bei Fernabsatzvertraegen erforderlich'],
estimatedEffort: '0',
},
L2: {
required: true,
depth: 'Standard',
detailItems: [
'Pflichtinformationen nach § 312d BGB i.V.m. Art. 246a EGBGB',
'Wesentliche Eigenschaften der Ware/Dienstleistung',
'Identitaet und Anschrift des Unternehmers',
'Zahlungs-, Liefer- und Leistungsbedingungen',
],
estimatedEffort: '3-5 Stunden',
},
L3: {
required: true,
depth: 'Erweitert',
detailItems: [
'Wie L2 + Informationen zu digitalen Inhalten/Diensten',
'Funktionalitaet und Interoperabilitaet (§ 327 BGB)',
],
estimatedEffort: '5-8 Stunden',
},
L4: {
required: true,
depth: 'Vollstaendig',
detailItems: [
'Wie L3 + mehrsprachige Informationspflichten',
'Automatisierte Vollstaendigkeitspruefung',
],
estimatedEffort: '8-12 Stunden',
},
},
streitbeilegung: {
L1: {
required: false,
depth: 'Nicht relevant',
detailItems: ['Nur bei B2C-Handel erforderlich'],
estimatedEffort: '0',
},
L2: {
required: true,
depth: 'Standard',
detailItems: [
'Hinweis auf OS-Plattform der EU-Kommission (Art. 14 ODR-VO)',
'Erklaerung zur Teilnahmebereitschaft an Streitbeilegung (§ 36 VSBG)',
'Link zur OS-Plattform im Impressum/AGB',
],
estimatedEffort: '1-2 Stunden',
},
L3: {
required: true,
depth: 'Erweitert',
detailItems: [
'Wie L2 + Benennung zustaendiger Verbraucherschlichtungsstelle',
'Prozess fuer Streitbeilegungsanfragen dokumentiert',
],
estimatedEffort: '2-3 Stunden',
},
L4: {
required: true,
depth: 'Vollstaendig',
detailItems: [
'Wie L3 + Eskalationsprozess dokumentiert',
'Regelmaessige Auswertung von Beschwerden',
],
estimatedEffort: '3-4 Stunden',
},
},
produktsicherheit: {
L1: {
required: false,
depth: 'Minimal',
detailItems: ['Grundlegende Produktkennzeichnung pruefen'],
estimatedEffort: '1 Stunde',
},
L2: {
required: true,
depth: 'Standard',
detailItems: [
'Produktsicherheitsbewertung nach GPSR (EU 2023/988)',
'CE-Kennzeichnung und Konformitaetserklaerung',
'Wirtschaftsakteur-Angaben auf Produkt/Verpackung',
'Technische Dokumentation fuer Marktaufsicht',
],
estimatedEffort: '8-12 Stunden',
},
L3: {
required: true,
depth: 'Erweitert',
detailItems: [
'Wie L2 + Risikoanalyse fuer alle Produktvarianten',
'Rueckrufplan und Marktbeobachtungspflichten',
'Supply-Chain-Dokumentation',
],
estimatedEffort: '16-24 Stunden',
},
L4: {
required: true,
depth: 'Vollstaendig',
detailItems: [
'Wie L3 + vollstaendige GPSR-Konformitaetsakte',
'Post-Market-Surveillance System',
'Audit-Trail fuer alle Sicherheitsbewertungen',
],
estimatedEffort: '24-40 Stunden',
},
},
ai_act_doku: {
L1: {
required: false,
depth: 'Minimal',
detailItems: ['KI-Risikokategorisierung (Art. 6 AI Act)'],
estimatedEffort: '2 Stunden',
},
L2: {
required: true,
depth: 'Standard',
detailItems: [
'Technische Dokumentation nach Art. 11 AI Act',
'Transparenzpflichten (Art. 52 AI Act)',
'Risikomanagement-Grundlagen (Art. 9 AI Act)',
'Menschliche Aufsicht dokumentiert (Art. 14 AI Act)',
],
estimatedEffort: '8-12 Stunden',
},
L3: {
required: true,
depth: 'Erweitert',
detailItems: [
'Wie L2 + Datenqualitaetsmanagement (Art. 10 AI Act)',
'Genauigkeits- und Robustheitstests (Art. 15 AI Act)',
'Vollstaendige Konformitaetsbewertung fuer Hochrisiko-KI',
],
estimatedEffort: '16-24 Stunden',
},
L4: {
required: true,
depth: 'Audit-Ready',
detailItems: [
'Wie L3 + Zertifizierungsfertige AI Act Dokumentation',
'EU-Datenbank-Registrierung (Art. 60 AI Act)',
'Post-Market Monitoring fuer KI-Systeme',
'Continuous Compliance Framework fuer KI',
],
estimatedEffort: '24-40 Stunden',
},
},
};
...DOCUMENT_SCOPE_MATRIX_EXTENDED_PART2,
}
export { DOCUMENT_SCOPE_MATRIX_EXTENDED_PART2 } from './document-scope-matrix-extended-part2'

View File

@@ -0,0 +1,322 @@
/**
* EU/EWR Rechtsgrundlagen — Nationale Ergaenzungsgesetze + Helpers
*
* Split from eu-legal-frameworks.ts for the 500 LOC hard cap.
*/
import type { CountryCode, LegalDocumentType, LicenseType, LegalFramework, SupervisoryAuthority, DocumentTypeMatrix, RAGLayer, DocumentUniformity } from './eu-legal-frameworks'
export type { CountryCode, LegalDocumentType, LicenseType, DocumentUniformity }
// =============================================================================
// Nationale Ergaenzungsgesetze (Phase 2 — modular pro Land)
// =============================================================================
export const NATIONAL_FRAMEWORKS: LegalFramework[] = [
// --- Deutschland ---
{
id: 'DE-BDSG',
countryCode: 'DE',
name: 'BDSG',
fullName: 'Bundesdatenschutzgesetz (2018)',
abbreviation: 'BDSG',
type: 'national_law',
description:
'Nationales Begleitgesetz zur DSGVO. Ergaenzt u.a. Beschaeftigtendatenschutz (§26), ' +
'Videoueberwachung (§4), Forschung/Statistik, Bussgeldpraxis.',
sourceUrl: 'https://www.gesetze-im-internet.de/bdsg_2018/',
license: 'PUBLIC_DOMAIN',
licenseNote: 'Amtliches Werk, gemeinfrei (§5 UrhG)',
gdprOpeningClauses: ['Art. 6 Abs. 2', 'Art. 9 Abs. 4', 'Art. 23', 'Art. 85', 'Art. 88'],
specialProvisions: [
'§26 BDSG — Beschaeftigtendatenschutz',
'§4 BDSG — Videoueberwachung oeffentlich zugaenglicher Raeume',
'§22 BDSG — Verarbeitung besonderer Kategorien',
'§41-43 BDSG — Straf- und Bussgeldvorschriften',
],
supervisoryAuthorities: [
{ name: 'Bundesbeauftragter fuer den Datenschutz', abbreviation: 'BfDI', url: 'https://www.bfdi.bund.de', country: 'DE' },
],
ragPhase: 2,
},
{
id: 'DE-TTDSG',
countryCode: 'DE',
name: 'TTDSG',
fullName: 'Telekommunikation-Telemedien-Datenschutz-Gesetz',
abbreviation: 'TTDSG',
type: 'national_law',
description:
'Deutsche Umsetzung der ePrivacy-Richtlinie. Regelt insbesondere Cookie-Consent (§25 TTDSG), ' +
'Endgeraetezugriff und Telekommunikations-Datenschutz.',
sourceUrl: 'https://www.gesetze-im-internet.de/ttdsg/',
license: 'PUBLIC_DOMAIN',
licenseNote: 'Amtliches Werk, gemeinfrei (§5 UrhG)',
specialProvisions: [
'§25 TTDSG — Einwilligung fuer Cookies/Tracking',
'§26 TTDSG — Anerkannte Dienste zur Einwilligungsverwaltung',
],
ragPhase: 2,
},
{
id: 'DE-TMG',
countryCode: 'DE',
name: 'TMG / DDG',
fullName: 'Telemediengesetz / Digitale-Dienste-Gesetz',
abbreviation: 'TMG',
type: 'national_law',
description:
'Impressumspflicht (§5 TMG/DDG) und Anbieterkennzeichnung fuer Online-Dienste in Deutschland.',
sourceUrl: 'https://www.gesetze-im-internet.de/tmg/',
license: 'PUBLIC_DOMAIN',
licenseNote: 'Amtliches Werk, gemeinfrei (§5 UrhG)',
specialProvisions: [
'§5 TMG — Impressumspflicht (Anbieterkennzeichnung)',
'§7-10 TMG — Verantwortlichkeit von Diensteanbietern',
],
ragPhase: 3,
},
// --- Oesterreich ---
{
id: 'AT-DSG',
countryCode: 'AT',
name: 'DSG (AT)',
fullName: 'Datenschutzgesetz (Oesterreich, 2018)',
abbreviation: 'DSG',
type: 'national_law',
description:
'Oesterreichisches Begleitgesetz zur DSGVO. Enthält Besonderheiten fuer Behoerden, ' +
'Strafverfolgung und teilweise andere Auslegungspraxis als Deutschland.',
sourceUrl: 'https://www.ris.bka.gv.at/GeltendeFassung.wxe?Abfrage=Bundesnormen&Gesetzesnummer=10001597',
license: 'PUBLIC_DOMAIN',
licenseNote: 'Amtliches Werk, Rechtsinformationssystem des Bundes (RIS)',
supervisoryAuthorities: [
{ name: 'Oesterreichische Datenschutzbehoerde', abbreviation: 'DSB', url: 'https://www.dsb.gv.at', country: 'AT' },
],
ragPhase: 2,
},
// --- Schweiz (NICHT EU — eigenes Recht) ---
{
id: 'CH-DSG',
countryCode: 'CH',
name: 'revDSG (CH)',
fullName: 'Bundesgesetz ueber den Datenschutz (revidiertes DSG, seit 01.09.2023)',
abbreviation: 'revDSG',
type: 'national_law',
description:
'Die Schweiz ist nicht EU-Mitglied. Das revidierte DSG (2023) ist inhaltlich aehnlich der DSGVO, ' +
'aber nicht identisch. Unterschiede: andere Sanktionslogik (Busse bis 250.000 CHF gegen ' +
'natuerliche Personen), teils andere Begriffe, kein One-Stop-Shop.',
sourceUrl: 'https://www.fedlex.admin.ch/eli/cc/2022/491/de',
license: 'PUBLIC_DOMAIN',
licenseNote: 'Amtliches Bundesrecht, Fedlex (Schweiz)',
specialProvisions: [
'Art. 60-66 revDSG — Strafbestimmungen (gegen natuerliche Personen)',
'Art. 16-18 revDSG — Drittlandtransfer (eigene Laenderliste)',
'Art. 22 revDSG — Datenschutz-Folgenabschaetzung',
'Art. 12 revDSG — Verzeichnis der Bearbeitungstaetigkeiten',
],
supervisoryAuthorities: [
{ name: 'Eidgenoessischer Datenschutzbeauftragter', abbreviation: 'EDOEB', url: 'https://www.edoeb.admin.ch', country: 'CH' },
],
ragPhase: 2,
},
// --- Frankreich ---
{
id: 'FR-LIL',
countryCode: 'FR',
name: 'Loi Informatique et Libertés',
fullName: 'Loi n° 78-17 du 6 janvier 1978 relative à l\'informatique, aux fichiers et aux libertés',
abbreviation: 'LIL',
type: 'national_law',
description:
'Franzoesisches Begleitgesetz zur DSGVO (aktualisiert 2018). Spezialregelungen u.a. ' +
'zur Einwilligung Minderjaehriger (ab 15 Jahren), Forschungsdaten und Gesundheitsdaten.',
sourceUrl: 'https://www.legifrance.gouv.fr/loda/id/JORFTEXT000000886460',
license: 'PUBLIC_DOMAIN',
licenseNote: 'Amtliches Gesetz, Légifrance (gemeinfrei)',
supervisoryAuthorities: [
{ name: 'Commission Nationale de l\'Informatique et des Libertés', abbreviation: 'CNIL', url: 'https://www.cnil.fr', country: 'FR' },
],
ragPhase: 2,
},
// --- Spanien ---
{
id: 'ES-LOPDGDD',
countryCode: 'ES',
name: 'LOPDGDD',
fullName: 'Ley Orgánica 3/2018 de Protección de Datos Personales y garantía de los derechos digitales',
abbreviation: 'LOPDGDD',
type: 'national_law',
description:
'Spanisches Datenschutzgesetz. Ergaenzt DSGVO u.a. mit Regelungen zu ' +
'Kindereinwilligung, digitalem Testament und Rechten Verstorbener.',
sourceUrl: 'https://www.boe.es/diario_boe/txt.php?id=BOE-A-2018-16673',
license: 'PUBLIC_DOMAIN',
licenseNote: 'Amtliches Gesetz, Boletín Oficial del Estado (gemeinfrei)',
supervisoryAuthorities: [
{ name: 'Agencia Española de Protección de Datos', abbreviation: 'AEPD', url: 'https://www.aepd.es', country: 'ES' },
],
ragPhase: 2,
},
// --- Italien ---
{
id: 'IT-CODICE',
countryCode: 'IT',
name: 'Codice Privacy',
fullName: 'Decreto Legislativo 30 giugno 2003, n. 196 (Codice in materia di protezione dei dati personali)',
abbreviation: 'Codice Privacy',
type: 'national_law',
description:
'Italienischer Datenschutzkodex, angepasst an die DSGVO (D.Lgs. 101/2018). ' +
'Enthaelt Spezialregelungen fuer Gesundheitsdaten, Forschung und Journalismus.',
sourceUrl: 'https://www.normattiva.it/uri-res/N2Ls?urn:nir:stato:decreto.legislativo:2003-06-30;196!vig=',
license: 'PUBLIC_DOMAIN',
licenseNote: 'Amtliches Gesetz, Normattiva (gemeinfrei)',
supervisoryAuthorities: [
{ name: 'Garante per la protezione dei dati personali', abbreviation: 'Garante', url: 'https://www.garanteprivacy.it', country: 'IT' },
],
ragPhase: 2,
},
// --- Niederlande ---
{
id: 'NL-AVG',
countryCode: 'NL',
name: 'AVG / UAVG',
fullName: 'Uitvoeringswet Algemene verordening gegevensbescherming (UAVG)',
abbreviation: 'UAVG',
type: 'national_law',
description:
'Niederlaendisches Ausfuehrungsgesetz zur DSGVO.',
sourceUrl: 'https://wetten.overheid.nl/BWBR0040948/',
license: 'PUBLIC_DOMAIN',
licenseNote: 'Amtliches Gesetz, wetten.overheid.nl (gemeinfrei)',
supervisoryAuthorities: [
{ name: 'Autoriteit Persoonsgegevens', abbreviation: 'AP', url: 'https://www.autoriteitpersoonsgegevens.nl', country: 'NL' },
],
ragPhase: 2,
},
// --- Grossbritannien (post-Brexit) ---
{
id: 'GB-DPA',
countryCode: 'GB',
name: 'UK DPA 2018 / UK GDPR',
fullName: 'Data Protection Act 2018 + UK GDPR (retained EU law)',
abbreviation: 'DPA 2018',
type: 'national_law',
description:
'Nach Brexit: UK GDPR (inhaltlich weitgehend identisch mit EU-DSGVO) plus Data Protection Act 2018 ' +
'als nationales Begleitgesetz. ICO als Aufsichtsbehoerde.',
sourceUrl: 'https://www.legislation.gov.uk/ukpga/2018/12/contents',
license: 'OGL-3.0',
licenseNote: 'UK legislation, Open Government Licence v3.0',
supervisoryAuthorities: [
{ name: 'Information Commissioner\'s Office', abbreviation: 'ICO', url: 'https://ico.org.uk', country: 'GB' },
],
ragPhase: 2,
},
// --- Norwegen (EWR) ---
{
id: 'NO-PERSONOPPL',
countryCode: 'NO',
name: 'Personopplysningsloven',
fullName: 'Lov om behandling av personopplysninger (personopplysningsloven)',
abbreviation: 'POL',
type: 'national_law',
description:
'Norwegisches DSGVO-Ausfuehrungsgesetz (EWR-Mitglied, DSGVO gilt ueber EWR-Abkommen).',
sourceUrl: 'https://lovdata.no/dokument/NL/lov/2018-06-15-38',
license: 'PUBLIC_DOMAIN',
licenseNote: 'Amtliches Gesetz, Lovdata (gemeinfrei)',
supervisoryAuthorities: [
{ name: 'Datatilsynet', abbreviation: 'DT', url: 'https://www.datatilsynet.no', country: 'NO' },
],
ragPhase: 2,
},
]
// =============================================================================
// Helper Functions
// =============================================================================
export function getAllSupervisoryAuthorities(
allFrameworks: LegalFramework[]
): SupervisoryAuthority[] {
const authorities: SupervisoryAuthority[] = []
for (const fw of allFrameworks) {
if (fw.supervisoryAuthorities) {
for (const sa of fw.supervisoryAuthorities) {
if (!authorities.some(a => a.abbreviation === sa.abbreviation)) {
authorities.push(sa)
}
}
}
}
return authorities
}
export function getSupervisoryAuthority(
country: CountryCode,
allFrameworks: LegalFramework[]
): SupervisoryAuthority[] {
return getAllSupervisoryAuthorities(allFrameworks).filter(sa => sa.country === country)
}
export function getCountrySpecificDocTypes(
country: CountryCode,
matrix: DocumentTypeMatrix[]
): DocumentTypeMatrix[] {
return matrix.filter(
d => d.uniformity === 'country_specific' ||
(d.uniformity === 'needs_national_supplement' && country !== 'EU')
)
}
export function getEUUniformDocTypes(matrix: DocumentTypeMatrix[]): DocumentTypeMatrix[] {
return matrix.filter(d => d.uniformity === 'eu_uniform')
}
export function isGDPRCountry(country: CountryCode): boolean {
const gdprCountries: CountryCode[] = ['EU', 'DE', 'AT', 'FR', 'ES', 'IT', 'NL', 'NO', 'IS']
return gdprCountries.includes(country)
}
export function hasSeparateLegalFramework(country: CountryCode): boolean {
return country === 'CH' || country === 'GB'
}
export function getRAGSourcesForPhase(phase: 1 | 2 | 3, allFrameworks: LegalFramework[]): LegalFramework[] {
return allFrameworks.filter(f => f.ragPhase === phase)
}
export function getRequiredFrameworkSummary(
country: CountryCode,
allFrameworks: LegalFramework[]
): {
baseLaw: string
nationalLaw: string | null
supervisoryAuthority: string | null
separateFramework: boolean
} {
const isGDPR = isGDPRCountry(country)
const national = NATIONAL_FRAMEWORKS.filter(f => f.countryCode === country)
const authorities = getSupervisoryAuthority(country, allFrameworks)
return {
baseLaw: isGDPR ? 'DSGVO (EU 2016/679)' : (country === 'CH' ? 'revDSG (CH)' : 'UK GDPR'),
nationalLaw: national.length > 0 ? national.map(n => n.abbreviation).join(', ') : null,
supervisoryAuthority: authorities.length > 0 ? authorities.map(a => a.abbreviation).join(', ') : null,
separateFramework: hasSeparateLegalFramework(country),
}
}
// Re-export RAGLayer type for barrel consumers
export type { RAGLayer }

View File

@@ -150,294 +150,19 @@ export const EU_BASE_FRAMEWORKS: LegalFramework[] = [
},
]
// =============================================================================
// Nationale Ergaenzungsgesetze (Phase 2 — modular pro Land)
// =============================================================================
export const NATIONAL_FRAMEWORKS: LegalFramework[] = [
// --- Deutschland ---
{
id: 'DE-BDSG',
countryCode: 'DE',
name: 'BDSG',
fullName: 'Bundesdatenschutzgesetz (2018)',
abbreviation: 'BDSG',
type: 'national_law',
description:
'Nationales Begleitgesetz zur DSGVO. Ergaenzt u.a. Beschaeftigtendatenschutz (§26), ' +
'Videoueberwachung (§4), Forschung/Statistik, Bussgeldpraxis.',
sourceUrl: 'https://www.gesetze-im-internet.de/bdsg_2018/',
license: 'PUBLIC_DOMAIN',
licenseNote: 'Amtliches Werk, gemeinfrei (§5 UrhG)',
gdprOpeningClauses: ['Art. 6 Abs. 2', 'Art. 9 Abs. 4', 'Art. 23', 'Art. 85', 'Art. 88'],
specialProvisions: [
'§26 BDSG — Beschaeftigtendatenschutz',
'§4 BDSG — Videoueberwachung oeffentlich zugaenglicher Raeume',
'§22 BDSG — Verarbeitung besonderer Kategorien',
'§41-43 BDSG — Straf- und Bussgeldvorschriften',
],
supervisoryAuthorities: [
{ name: 'Bundesbeauftragter fuer den Datenschutz', abbreviation: 'BfDI', url: 'https://www.bfdi.bund.de', country: 'DE' },
],
ragPhase: 2,
},
{
id: 'DE-TTDSG',
countryCode: 'DE',
name: 'TTDSG',
fullName: 'Telekommunikation-Telemedien-Datenschutz-Gesetz',
abbreviation: 'TTDSG',
type: 'national_law',
description:
'Deutsche Umsetzung der ePrivacy-Richtlinie. Regelt insbesondere Cookie-Consent (§25 TTDSG), ' +
'Endgeraetezugriff und Telekommunikations-Datenschutz.',
sourceUrl: 'https://www.gesetze-im-internet.de/ttdsg/',
license: 'PUBLIC_DOMAIN',
licenseNote: 'Amtliches Werk, gemeinfrei (§5 UrhG)',
specialProvisions: [
'§25 TTDSG — Einwilligung fuer Cookies/Tracking',
'§26 TTDSG — Anerkannte Dienste zur Einwilligungsverwaltung',
],
ragPhase: 2,
},
{
id: 'DE-TMG',
countryCode: 'DE',
name: 'TMG / DDG',
fullName: 'Telemediengesetz / Digitale-Dienste-Gesetz',
abbreviation: 'TMG',
type: 'national_law',
description:
'Impressumspflicht (§5 TMG/DDG) und Anbieterkennzeichnung fuer Online-Dienste in Deutschland.',
sourceUrl: 'https://www.gesetze-im-internet.de/tmg/',
license: 'PUBLIC_DOMAIN',
licenseNote: 'Amtliches Werk, gemeinfrei (§5 UrhG)',
specialProvisions: [
'§5 TMG — Impressumspflicht (Anbieterkennzeichnung)',
'§7-10 TMG — Verantwortlichkeit von Diensteanbietern',
],
ragPhase: 3,
},
// --- Oesterreich ---
{
id: 'AT-DSG',
countryCode: 'AT',
name: 'DSG (AT)',
fullName: 'Datenschutzgesetz (Oesterreich, 2018)',
abbreviation: 'DSG',
type: 'national_law',
description:
'Oesterreichisches Begleitgesetz zur DSGVO. Enthält Besonderheiten fuer Behoerden, ' +
'Strafverfolgung und teilweise andere Auslegungspraxis als Deutschland.',
sourceUrl: 'https://www.ris.bka.gv.at/GeltendeFassung.wxe?Abfrage=Bundesnormen&Gesetzesnummer=10001597',
license: 'PUBLIC_DOMAIN',
licenseNote: 'Amtliches Werk, Rechtsinformationssystem des Bundes (RIS)',
supervisoryAuthorities: [
{ name: 'Oesterreichische Datenschutzbehoerde', abbreviation: 'DSB', url: 'https://www.dsb.gv.at', country: 'AT' },
],
ragPhase: 2,
},
// --- Schweiz (NICHT EU — eigenes Recht) ---
{
id: 'CH-DSG',
countryCode: 'CH',
name: 'revDSG (CH)',
fullName: 'Bundesgesetz ueber den Datenschutz (revidiertes DSG, seit 01.09.2023)',
abbreviation: 'revDSG',
type: 'national_law',
description:
'Die Schweiz ist nicht EU-Mitglied. Das revidierte DSG (2023) ist inhaltlich aehnlich der DSGVO, ' +
'aber nicht identisch. Unterschiede: andere Sanktionslogik (Busse bis 250.000 CHF gegen ' +
'natuerliche Personen), teils andere Begriffe, kein One-Stop-Shop.',
sourceUrl: 'https://www.fedlex.admin.ch/eli/cc/2022/491/de',
license: 'PUBLIC_DOMAIN',
licenseNote: 'Amtliches Bundesrecht, Fedlex (Schweiz)',
specialProvisions: [
'Art. 60-66 revDSG — Strafbestimmungen (gegen natuerliche Personen)',
'Art. 16-18 revDSG — Drittlandtransfer (eigene Laenderliste)',
'Art. 22 revDSG — Datenschutz-Folgenabschaetzung',
'Art. 12 revDSG — Verzeichnis der Bearbeitungstaetigkeiten',
],
supervisoryAuthorities: [
{ name: 'Eidgenoessischer Datenschutzbeauftragter', abbreviation: 'EDOEB', url: 'https://www.edoeb.admin.ch', country: 'CH' },
],
ragPhase: 2,
},
// --- Frankreich ---
{
id: 'FR-LIL',
countryCode: 'FR',
name: 'Loi Informatique et Libertés',
fullName: 'Loi n° 78-17 du 6 janvier 1978 relative à l\'informatique, aux fichiers et aux libertés',
abbreviation: 'LIL',
type: 'national_law',
description:
'Franzoesisches Begleitgesetz zur DSGVO (aktualisiert 2018). Spezialregelungen u.a. ' +
'zur Einwilligung Minderjaehriger (ab 15 Jahren), Forschungsdaten und Gesundheitsdaten.',
sourceUrl: 'https://www.legifrance.gouv.fr/loda/id/JORFTEXT000000886460',
license: 'PUBLIC_DOMAIN',
licenseNote: 'Amtliches Gesetz, Légifrance (gemeinfrei)',
supervisoryAuthorities: [
{ name: 'Commission Nationale de l\'Informatique et des Libertés', abbreviation: 'CNIL', url: 'https://www.cnil.fr', country: 'FR' },
],
ragPhase: 2,
},
// --- Spanien ---
{
id: 'ES-LOPDGDD',
countryCode: 'ES',
name: 'LOPDGDD',
fullName: 'Ley Orgánica 3/2018 de Protección de Datos Personales y garantía de los derechos digitales',
abbreviation: 'LOPDGDD',
type: 'national_law',
description:
'Spanisches Datenschutzgesetz. Ergaenzt DSGVO u.a. mit Regelungen zu ' +
'Kindereinwilligung, digitalem Testament und Rechten Verstorbener.',
sourceUrl: 'https://www.boe.es/diario_boe/txt.php?id=BOE-A-2018-16673',
license: 'PUBLIC_DOMAIN',
licenseNote: 'Amtliches Gesetz, Boletín Oficial del Estado (gemeinfrei)',
supervisoryAuthorities: [
{ name: 'Agencia Española de Protección de Datos', abbreviation: 'AEPD', url: 'https://www.aepd.es', country: 'ES' },
],
ragPhase: 2,
},
// --- Italien ---
{
id: 'IT-CODICE',
countryCode: 'IT',
name: 'Codice Privacy',
fullName: 'Decreto Legislativo 30 giugno 2003, n. 196 (Codice in materia di protezione dei dati personali)',
abbreviation: 'Codice Privacy',
type: 'national_law',
description:
'Italienischer Datenschutzkodex, angepasst an die DSGVO (D.Lgs. 101/2018). ' +
'Enthaelt Spezialregelungen fuer Gesundheitsdaten, Forschung und Journalismus.',
sourceUrl: 'https://www.normattiva.it/uri-res/N2Ls?urn:nir:stato:decreto.legislativo:2003-06-30;196!vig=',
license: 'PUBLIC_DOMAIN',
licenseNote: 'Amtliches Gesetz, Normattiva (gemeinfrei)',
supervisoryAuthorities: [
{ name: 'Garante per la protezione dei dati personali', abbreviation: 'Garante', url: 'https://www.garanteprivacy.it', country: 'IT' },
],
ragPhase: 2,
},
// --- Niederlande ---
{
id: 'NL-AVG',
countryCode: 'NL',
name: 'AVG / UAVG',
fullName: 'Uitvoeringswet Algemene verordening gegevensbescherming (UAVG)',
abbreviation: 'UAVG',
type: 'national_law',
description:
'Niederlaendisches Ausfuehrungsgesetz zur DSGVO.',
sourceUrl: 'https://wetten.overheid.nl/BWBR0040948/',
license: 'PUBLIC_DOMAIN',
licenseNote: 'Amtliches Gesetz, wetten.overheid.nl (gemeinfrei)',
supervisoryAuthorities: [
{ name: 'Autoriteit Persoonsgegevens', abbreviation: 'AP', url: 'https://www.autoriteitpersoonsgegevens.nl', country: 'NL' },
],
ragPhase: 2,
},
// --- Grossbritannien (post-Brexit) ---
{
id: 'GB-DPA',
countryCode: 'GB',
name: 'UK DPA 2018 / UK GDPR',
fullName: 'Data Protection Act 2018 + UK GDPR (retained EU law)',
abbreviation: 'DPA 2018',
type: 'national_law',
description:
'Nach Brexit: UK GDPR (inhaltlich weitgehend identisch mit EU-DSGVO) plus Data Protection Act 2018 ' +
'als nationales Begleitgesetz. ICO als Aufsichtsbehoerde.',
sourceUrl: 'https://www.legislation.gov.uk/ukpga/2018/12/contents',
license: 'OGL-3.0',
licenseNote: 'UK legislation, Open Government Licence v3.0',
supervisoryAuthorities: [
{ name: 'Information Commissioner\'s Office', abbreviation: 'ICO', url: 'https://ico.org.uk', country: 'GB' },
],
ragPhase: 2,
},
// --- Norwegen (EWR) ---
{
id: 'NO-PERSONOPPL',
countryCode: 'NO',
name: 'Personopplysningsloven',
fullName: 'Lov om behandling av personopplysninger (personopplysningsloven)',
abbreviation: 'POL',
type: 'national_law',
description:
'Norwegisches DSGVO-Ausfuehrungsgesetz (EWR-Mitglied, DSGVO gilt ueber EWR-Abkommen).',
sourceUrl: 'https://lovdata.no/dokument/NL/lov/2018-06-15-38',
license: 'PUBLIC_DOMAIN',
licenseNote: 'Amtliches Gesetz, Lovdata (gemeinfrei)',
supervisoryAuthorities: [
{ name: 'Datatilsynet', abbreviation: 'DT', url: 'https://www.datatilsynet.no', country: 'NO' },
],
ragPhase: 2,
},
]
// =============================================================================
// Dokumenttyp-Matrix: EU-einheitlich vs. laenderspezifisch
// =============================================================================
export const DOCUMENT_TYPE_MATRIX: DocumentTypeMatrix[] = [
{
documentType: 'privacy_policy',
label: 'Datenschutzerklaerung',
uniformity: 'needs_national_supplement',
description: 'DSGVO-Kern EU-weit gleich. Nationale Ergaenzungen fuer ePrivacy-Umsetzung, Behoerden-Praxis.',
},
{
documentType: 'ropa',
label: 'Verarbeitungsverzeichnis (VVT)',
uniformity: 'eu_uniform',
description: 'Art. 30 DSGVO — EU-weit identische Anforderungen.',
},
{
documentType: 'tom',
label: 'Technisch-Organisatorische Massnahmen',
uniformity: 'eu_uniform',
description: 'Art. 32 DSGVO — EU-weit identische Anforderungen.',
},
{
documentType: 'dpia',
label: 'Datenschutz-Folgenabschaetzung (DSFA)',
uniformity: 'eu_uniform',
description: 'Art. 35 DSGVO — EU-weit identisch. Muss-Listen variieren je Aufsichtsbehoerde.',
},
{
documentType: 'dpa',
label: 'Auftragsverarbeitungsvertrag (AVV)',
uniformity: 'eu_uniform',
description: 'Art. 28 DSGVO — EU-weit identische Anforderungen.',
},
{
documentType: 'deletion_concept',
label: 'Loeschkonzept',
uniformity: 'eu_uniform',
description: 'Art. 5(1)(e), Art. 17 DSGVO — EU-weit einheitlich.',
},
{
documentType: 'breach_process',
label: 'Data Breach / Incident Response',
uniformity: 'eu_uniform',
description: 'Art. 33-34 DSGVO — EU-weit identische 72-Stunden-Frist.',
},
{
documentType: 'dsar_process',
label: 'Betroffenenrechte-Prozess (DSAR)',
uniformity: 'eu_uniform',
description: 'Art. 12-22 DSGVO — EU-weit identische Rechte und Fristen.',
},
{ documentType: 'privacy_policy', label: 'Datenschutzerklaerung', uniformity: 'needs_national_supplement', description: 'DSGVO-Kern EU-weit gleich. Nationale Ergaenzungen fuer ePrivacy-Umsetzung, Behoerden-Praxis.' },
{ documentType: 'ropa', label: 'Verarbeitungsverzeichnis (VVT)', uniformity: 'eu_uniform', description: 'Art. 30 DSGVO — EU-weit identische Anforderungen.' },
{ documentType: 'tom', label: 'Technisch-Organisatorische Massnahmen', uniformity: 'eu_uniform', description: 'Art. 32 DSGVO — EU-weit identische Anforderungen.' },
{ documentType: 'dpia', label: 'Datenschutz-Folgenabschaetzung (DSFA)', uniformity: 'eu_uniform', description: 'Art. 35 DSGVO — EU-weit identisch. Muss-Listen variieren je Aufsichtsbehoerde.' },
{ documentType: 'dpa', label: 'Auftragsverarbeitungsvertrag (AVV)', uniformity: 'eu_uniform', description: 'Art. 28 DSGVO — EU-weit identische Anforderungen.' },
{ documentType: 'deletion_concept', label: 'Loeschkonzept', uniformity: 'eu_uniform', description: 'Art. 5(1)(e), Art. 17 DSGVO — EU-weit einheitlich.' },
{ documentType: 'breach_process', label: 'Data Breach / Incident Response', uniformity: 'eu_uniform', description: 'Art. 33-34 DSGVO — EU-weit identische 72-Stunden-Frist.' },
{ documentType: 'dsar_process', label: 'Betroffenenrechte-Prozess (DSAR)', uniformity: 'eu_uniform', description: 'Art. 12-22 DSGVO — EU-weit identische Rechte und Fristen.' },
{
documentType: 'imprint',
label: 'Impressum',
@@ -457,24 +182,9 @@ export const DOCUMENT_TYPE_MATRIX: DocumentTypeMatrix[] = [
'IS': 'Rafraeðislög',
},
},
{
documentType: 'terms_of_service',
label: 'AGB / Nutzungsbedingungen',
uniformity: 'country_specific',
description: 'Nationales Vertragsrecht (BGB, ABGB, OR). Verbraucherrecht teils EU-harmonisiert, aber national umgesetzt.',
},
{
documentType: 'withdrawal_notice',
label: 'Widerrufsbelehrung',
uniformity: 'country_specific',
description: 'EU-Verbraucherrechterichtlinie national umgesetzt. DE/AT: Muster-Widerrufsbelehrung. CH: eigene Logik.',
},
{
documentType: 'cookie_banner',
label: 'Cookie-Banner / Consent',
uniformity: 'needs_national_supplement',
description: 'ePrivacy + DSGVO EU-weit aehnlich, aber Aufsichtspraxis variiert (CNIL vs. DSK vs. DPC etc.).',
},
{ documentType: 'terms_of_service', label: 'AGB / Nutzungsbedingungen', uniformity: 'country_specific', description: 'Nationales Vertragsrecht (BGB, ABGB, OR). Verbraucherrecht teils EU-harmonisiert, aber national umgesetzt.' },
{ documentType: 'withdrawal_notice', label: 'Widerrufsbelehrung', uniformity: 'country_specific', description: 'EU-Verbraucherrechterichtlinie national umgesetzt. DE/AT: Muster-Widerrufsbelehrung. CH: eigene Logik.' },
{ documentType: 'cookie_banner', label: 'Cookie-Banner / Consent', uniformity: 'needs_national_supplement', description: 'ePrivacy + DSGVO EU-weit aehnlich, aber Aufsichtspraxis variiert (CNIL vs. DSK vs. DPC etc.).' },
]
// =============================================================================
@@ -533,9 +243,27 @@ export const RAG_LAYERS: RAGLayer[] = [
]
// =============================================================================
// Helper Functions
// Re-exports from national sibling (backward compat — no consumer import changes)
// =============================================================================
export {
NATIONAL_FRAMEWORKS,
getAllSupervisoryAuthorities,
getSupervisoryAuthority,
getCountrySpecificDocTypes,
getEUUniformDocTypes,
isGDPRCountry,
hasSeparateLegalFramework,
getRAGSourcesForPhase,
getRequiredFrameworkSummary,
} from './eu-legal-frameworks-national'
// =============================================================================
// Helper Functions (EU-level)
// =============================================================================
import { NATIONAL_FRAMEWORKS } from './eu-legal-frameworks-national'
/** Alle Rechtsgrundlagen zusammen (EU-Basis + National) */
export function getAllFrameworks(): LegalFramework[] {
return [...EU_BASE_FRAMEWORKS, ...NATIONAL_FRAMEWORKS]
@@ -552,71 +280,3 @@ export function getFrameworksForCountry(country: CountryCode): LegalFramework[]
export function getNationalFrameworks(country: CountryCode): LegalFramework[] {
return NATIONAL_FRAMEWORKS.filter(f => f.countryCode === country)
}
/** Alle Aufsichtsbehoerden */
export function getAllSupervisoryAuthorities(): SupervisoryAuthority[] {
const authorities: SupervisoryAuthority[] = []
for (const fw of getAllFrameworks()) {
if (fw.supervisoryAuthorities) {
for (const sa of fw.supervisoryAuthorities) {
if (!authorities.some(a => a.abbreviation === sa.abbreviation)) {
authorities.push(sa)
}
}
}
}
return authorities
}
/** Aufsichtsbehoerde(n) fuer ein Land */
export function getSupervisoryAuthority(country: CountryCode): SupervisoryAuthority[] {
return getAllSupervisoryAuthorities().filter(sa => sa.country === country)
}
/** Dokumenttypen, die fuer ein Land spezifische Logik brauchen */
export function getCountrySpecificDocTypes(country: CountryCode): DocumentTypeMatrix[] {
return DOCUMENT_TYPE_MATRIX.filter(
d => d.uniformity === 'country_specific' ||
(d.uniformity === 'needs_national_supplement' && country !== 'EU')
)
}
/** Dokumenttypen, die EU-weit einheitlich generiert werden koennen */
export function getEUUniformDocTypes(): DocumentTypeMatrix[] {
return DOCUMENT_TYPE_MATRIX.filter(d => d.uniformity === 'eu_uniform')
}
/** Pruefen ob ein Land EU/EWR-Mitglied ist (DSGVO direkt anwendbar) */
export function isGDPRCountry(country: CountryCode): boolean {
const gdprCountries: CountryCode[] = ['EU', 'DE', 'AT', 'FR', 'ES', 'IT', 'NL', 'NO', 'IS']
return gdprCountries.includes(country)
}
/** Pruefen ob ein Land einen separaten Rechtsrahmen hat (nicht DSGVO) */
export function hasSeparateLegalFramework(country: CountryCode): boolean {
return country === 'CH' || country === 'GB'
}
/** RAG-Quellen fuer eine bestimmte Phase */
export function getRAGSourcesForPhase(phase: 1 | 2 | 3): LegalFramework[] {
return getAllFrameworks().filter(f => f.ragPhase === phase)
}
/** Zusammenfassung: Was braucht ein Unternehmen in Land X? */
export function getRequiredFrameworkSummary(country: CountryCode): {
baseLaw: string
nationalLaw: string | null
supervisoryAuthority: string | null
separateFramework: boolean
} {
const isGDPR = isGDPRCountry(country)
const national = getNationalFrameworks(country)
const authorities = getSupervisoryAuthority(country)
return {
baseLaw: isGDPR ? 'DSGVO (EU 2016/679)' : (country === 'CH' ? 'revDSG (CH)' : 'UK GDPR'),
nationalLaw: national.length > 0 ? national.map(n => n.abbreviation).join(', ') : null,
supervisoryAuthority: authorities.length > 0 ? authorities.map(a => a.abbreviation).join(', ') : null,
separateFramework: hasSeparateLegalFramework(country),
}
}

View File

@@ -0,0 +1,290 @@
// =============================================================================
// Loeschfristen Module - Policy Generator
// Generates deletion policies from profiling answers
// =============================================================================
import type { LoeschfristPolicy, StorageLocation } from './loeschfristen-types'
import { BASELINE_TEMPLATES, type BaselineTemplate, templateToPolicy } from './loeschfristen-baseline-catalog'
import type { ProfilingAnswer, ProfilingResult } from './loeschfristen-profiling-data'
import { PROFILING_STEPS } from './loeschfristen-profiling-data'
// Re-export ProfilingResult so callers can type-annotate
export type { ProfilingResult }
// =============================================================================
// 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: import('./loeschfristen-profiling-data').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
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>()
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')
matchedTemplateIds.add('schulungsnachweise')
}
// 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')
matchedTemplateIds.add('kundenreklamationen')
matchedTemplateIds.add('lieferantenbewertungen')
}
// Marketing (data-marketing = true)
if (getBool('data-marketing')) {
matchedTemplateIds.add('newsletter-einwilligungen')
matchedTemplateIds.add('crm-kontakthistorie')
matchedTemplateIds.add('cookie-consent-logs')
matchedTemplateIds.add('social-media-daten')
}
// 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')
}
// Cloud (sys-cloud = true) → E-Mail-Archivierung
if (getBool('sys-cloud')) {
matchedTemplateIds.add('email-archivierung')
}
// Zutritt (sys-zutritt = true)
if (getBool('sys-zutritt')) {
matchedTemplateIds.add('zutrittsprotokolle')
}
// 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')) {
matchedTemplateIds.add('krankmeldungen')
matchedTemplateIds.add('betriebsarzt-doku')
}
// 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)
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)
for (const policy of generatedPolicies) {
policy.storageLocations.push({ ...backupLocation, id: crypto.randomUUID() })
}
}
// Legal Hold
const hasLegalHoldRequirement = getBool('special-legal-hold')
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

@@ -1,565 +1,23 @@
// =============================================================================
// Loeschfristen Module - Profiling Wizard
// 4-Step Profiling (16 Fragen) zur Generierung von Baseline-Loeschrichtlinien
// Loeschfristen Module - Profiling Wizard (barrel)
// =============================================================================
import type { LoeschfristPolicy, StorageLocation } from './loeschfristen-types'
import { BASELINE_TEMPLATES, type BaselineTemplate, templateToPolicy } from './loeschfristen-baseline-catalog'
import type { ProfilingAnswer, ProfilingStepId, ProfilingResult } from './loeschfristen-profiling-data'
// Types, steps, and step-level data
export type {
ProfilingStepId,
ProfilingQuestion,
ProfilingAnswer,
ProfilingStep,
ProfilingResult,
} from './loeschfristen-profiling-data'
export { PROFILING_STEPS } from './loeschfristen-profiling-data'
// Re-export types + data so existing imports work unchanged
export { type ProfilingStepId, type ProfilingQuestion, type ProfilingAnswer, type ProfilingStep, type ProfilingResult, PROFILING_STEPS } from './loeschfristen-profiling-data'
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, 16 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 (4 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,
},
{
id: 'sys-zutritt',
step: 'systems',
question: 'Nutzen Sie ein Zutrittskontrollsystem?',
helpText: 'Zutrittskontrollsysteme erzeugen Protokolle, die personenbezogene Daten enthalten und einer Loeschfrist unterliegen.',
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')
matchedTemplateIds.add('schulungsnachweise')
}
// -------------------------------------------------------------------------
// 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')
matchedTemplateIds.add('kundenreklamationen')
matchedTemplateIds.add('lieferantenbewertungen')
}
// -------------------------------------------------------------------------
// Marketing (data-marketing = true)
// -------------------------------------------------------------------------
if (getBool('data-marketing')) {
matchedTemplateIds.add('newsletter-einwilligungen')
matchedTemplateIds.add('crm-kontakthistorie')
matchedTemplateIds.add('cookie-consent-logs')
matchedTemplateIds.add('social-media-daten')
}
// -------------------------------------------------------------------------
// 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')
}
// -------------------------------------------------------------------------
// Cloud (sys-cloud = true) → E-Mail-Archivierung
// -------------------------------------------------------------------------
if (getBool('sys-cloud')) {
matchedTemplateIds.add('email-archivierung')
}
// -------------------------------------------------------------------------
// Zutritt (sys-zutritt = true)
// -------------------------------------------------------------------------
if (getBool('sys-zutritt')) {
matchedTemplateIds.add('zutrittsprotokolle')
}
// -------------------------------------------------------------------------
// 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')
matchedTemplateIds.add('betriebsarzt-doku')
}
// -------------------------------------------------------------------------
// 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',
]
// Generator, helpers, and scope integration
export {
getAnswerValue,
isStepComplete,
getProfilingProgress,
generatePoliciesFromProfile,
prefillFromScopeAnswers,
SCOPE_PREFILLED_LF_QUESTIONS,
} from './loeschfristen-profiling-generator'

View File

@@ -0,0 +1,215 @@
/**
* Retention Period Catalog
*
* Standard GDPR/German-law retention periods and helper functions.
* Split from legal-basis.ts for the 500 LOC hard cap.
*/
import type { LocalizedText } from '../types'
export interface RetentionPeriodInfo {
id: string
name: LocalizedText
legalBasis: string
duration: {
value: number
unit: 'DAYS' | 'MONTHS' | 'YEARS'
}
description: LocalizedText
applicableTo: string[]
}
// ==========================================
// RETENTION PERIODS
// ==========================================
export const STANDARD_RETENTION_PERIODS: RetentionPeriodInfo[] = [
// Handelsrechtliche Aufbewahrung
{
id: 'hgb-257',
name: { de: 'Handelsbücher und Buchungsbelege', en: 'Commercial Books and Vouchers' },
legalBasis: '§ 257 HGB',
duration: { value: 10, unit: 'YEARS' },
description: {
de: 'Handelsbücher, Inventare, Eröffnungsbilanzen, Jahresabschlüsse, Lageberichte, Konzernabschlüsse, Buchungsbelege',
en: 'Commercial books, inventories, opening balance sheets, annual financial statements, management reports, consolidated financial statements, accounting vouchers',
},
applicableTo: ['Buchhaltung', 'Jahresabschlüsse', 'Rechnungen', 'Verträge'],
},
{
id: 'hgb-257-6',
name: { de: 'Handels- und Geschäftsbriefe', en: 'Commercial and Business Correspondence' },
legalBasis: '§ 257 Abs. 1 Nr. 2, 3 HGB',
duration: { value: 6, unit: 'YEARS' },
description: {
de: 'Empfangene Handels- und Geschäftsbriefe, Wiedergaben der abgesandten Handels- und Geschäftsbriefe',
en: 'Received commercial and business correspondence, copies of sent correspondence',
},
applicableTo: ['Geschäftskorrespondenz', 'Angebote', 'Auftragsbestätigungen'],
},
// Steuerrechtliche Aufbewahrung
{
id: 'ao-147',
name: { de: 'Steuerrechtliche Unterlagen', en: 'Tax Documents' },
legalBasis: '§ 147 AO',
duration: { value: 10, unit: 'YEARS' },
description: {
de: 'Bücher und Aufzeichnungen, Inventare, Jahresabschlüsse, Buchungsbelege, steuerrelevante Unterlagen',
en: 'Books and records, inventories, annual financial statements, accounting vouchers, tax-relevant documents',
},
applicableTo: ['Steuererklärungen', 'Buchhaltung', 'Belege'],
},
// Arbeitsrechtliche Aufbewahrung
{
id: 'arbeitsrecht-personal',
name: { de: 'Personalunterlagen', en: 'Personnel Records' },
legalBasis: 'Verschiedene (AGG, ArbZG, etc.)',
duration: { value: 3, unit: 'YEARS' },
description: {
de: 'Personalakte nach Beendigung des Arbeitsverhältnisses (Regelverjährung)',
en: 'Personnel file after termination of employment (standard limitation period)',
},
applicableTo: ['Personalakten', 'Arbeitsverträge', 'Zeugnisse'],
},
{
id: 'arbzg',
name: { de: 'Arbeitszeitaufzeichnungen', en: 'Working Time Records' },
legalBasis: '§ 16 Abs. 2 ArbZG',
duration: { value: 2, unit: 'YEARS' },
description: {
de: 'Aufzeichnungen über Arbeitszeiten, die über 8 Stunden hinausgehen',
en: 'Records of working hours exceeding 8 hours',
},
applicableTo: ['Zeiterfassung', 'Überstunden'],
},
{
id: 'lohnsteuer',
name: { de: 'Lohnunterlagen', en: 'Payroll Documents' },
legalBasis: '§ 41 EStG, § 28f SGB IV',
duration: { value: 6, unit: 'YEARS' },
description: {
de: 'Lohnkonten und Unterlagen für den Lohnsteuerabzug',
en: 'Payroll accounts and documents for wage tax deduction',
},
applicableTo: ['Lohnabrechnungen', 'Lohnsteuerbescheinigungen'],
},
{
id: 'sozialversicherung',
name: { de: 'Sozialversicherungsunterlagen', en: 'Social Security Documents' },
legalBasis: '§ 28f SGB IV',
duration: { value: 5, unit: 'YEARS' },
description: {
de: 'Unterlagen zum Gesamtsozialversicherungsbeitrag',
en: 'Documents for total social security contributions',
},
applicableTo: ['Sozialversicherungsmeldungen', 'Beitragsnachweise'],
},
// Bewerberdaten
{
id: 'bewerbung',
name: { de: 'Bewerbungsunterlagen', en: 'Application Documents' },
legalBasis: '§ 15 Abs. 4 AGG',
duration: { value: 6, unit: 'MONTHS' },
description: {
de: 'Bewerbungsunterlagen nach Absage (AGG-Frist)',
en: 'Application documents after rejection (AGG deadline)',
},
applicableTo: ['Bewerbungen', 'Lebensläufe', 'Zeugnisse von Bewerbern'],
},
// Datenschutzrechtliche Fristen
{
id: 'einwilligung',
name: { de: 'Einwilligungen', en: 'Consents' },
legalBasis: 'Art. 7 Abs. 1 DSGVO',
duration: { value: 3, unit: 'YEARS' },
description: {
de: 'Dokumentation der Einwilligung (Regelverjährung)',
en: 'Documentation of consent (standard limitation period)',
},
applicableTo: ['Einwilligungsnachweise', 'Opt-in-Dokumentation'],
},
{
id: 'videoüberwachung',
name: { de: 'Videoüberwachung', en: 'Video Surveillance' },
legalBasis: 'Verhältnismäßigkeit',
duration: { value: 72, unit: 'DAYS' },
description: {
de: 'Videoaufnahmen (max. 72 Stunden, sofern kein Vorfall)',
en: 'Video recordings (max. 72 hours, unless incident occurred)',
},
applicableTo: ['CCTV-Aufnahmen', 'Überwachungsvideos'],
},
// Löschung nach Vertrag
{
id: 'avv-loeschung',
name: { de: 'AVV-Daten nach Vertragsende', en: 'DPA Data after Contract End' },
legalBasis: 'Art. 28 Abs. 3 lit. g DSGVO',
duration: { value: 30, unit: 'DAYS' },
description: {
de: 'Löschung oder Rückgabe aller personenbezogenen Daten nach Vertragsende',
en: 'Deletion or return of all personal data after contract end',
},
applicableTo: ['Auftragsverarbeitung', 'Dienstleister-Daten'],
},
]
// ==========================================
// HELPER FUNCTIONS
// ==========================================
/**
* Get retention period by ID
*/
export function getRetentionPeriod(id: string): RetentionPeriodInfo | undefined {
return STANDARD_RETENTION_PERIODS.find((rp) => rp.id === id)
}
/**
* Get retention periods applicable to a category
*/
export function getRetentionPeriodsForCategory(category: string): RetentionPeriodInfo[] {
return STANDARD_RETENTION_PERIODS.filter((rp) =>
rp.applicableTo.some((a) => a.toLowerCase().includes(category.toLowerCase()))
)
}
/**
* Get longest applicable retention period
*/
export function getLongestRetentionPeriod(categories: string[]): RetentionPeriodInfo | undefined {
const applicable = categories.flatMap((cat) => getRetentionPeriodsForCategory(cat))
if (applicable.length === 0) return undefined
return applicable.reduce((longest, current) => {
const longestMonths = toMonths(longest.duration)
const currentMonths = toMonths(current.duration)
return currentMonths > longestMonths ? current : longest
})
}
function toMonths(duration: { value: number; unit: 'DAYS' | 'MONTHS' | 'YEARS' }): number {
switch (duration.unit) {
case 'DAYS':
return duration.value / 30
case 'MONTHS':
return duration.value
case 'YEARS':
return duration.value * 12
}
}
/**
* Format retention period for display
*/
export function formatRetentionPeriod(
duration: { value: number; unit: 'DAYS' | 'MONTHS' | 'YEARS' },
locale: 'de' | 'en' = 'de'
): string {
const units = {
de: { DAYS: 'Tage', MONTHS: 'Monate', YEARS: 'Jahre' },
en: { DAYS: 'days', MONTHS: 'months', YEARS: 'years' },
}
return `${duration.value} ${units[locale][duration.unit]}`
}

View File

@@ -20,18 +20,6 @@ export interface LegalBasisInfo {
notes?: LocalizedText
}
export interface RetentionPeriodInfo {
id: string
name: LocalizedText
legalBasis: string
duration: {
value: number
unit: 'DAYS' | 'MONTHS' | 'YEARS'
}
description: LocalizedText
applicableTo: string[]
}
// ==========================================
// LEGAL BASIS INFORMATION (Art. 6 DSGVO)
// ==========================================
@@ -319,140 +307,6 @@ export const LEGAL_BASIS_INFO: LegalBasisInfo[] = [
},
]
// ==========================================
// RETENTION PERIODS
// ==========================================
export const STANDARD_RETENTION_PERIODS: RetentionPeriodInfo[] = [
// Handelsrechtliche Aufbewahrung
{
id: 'hgb-257',
name: { de: 'Handelsbücher und Buchungsbelege', en: 'Commercial Books and Vouchers' },
legalBasis: '§ 257 HGB',
duration: { value: 10, unit: 'YEARS' },
description: {
de: 'Handelsbücher, Inventare, Eröffnungsbilanzen, Jahresabschlüsse, Lageberichte, Konzernabschlüsse, Buchungsbelege',
en: 'Commercial books, inventories, opening balance sheets, annual financial statements, management reports, consolidated financial statements, accounting vouchers',
},
applicableTo: ['Buchhaltung', 'Jahresabschlüsse', 'Rechnungen', 'Verträge'],
},
{
id: 'hgb-257-6',
name: { de: 'Handels- und Geschäftsbriefe', en: 'Commercial and Business Correspondence' },
legalBasis: '§ 257 Abs. 1 Nr. 2, 3 HGB',
duration: { value: 6, unit: 'YEARS' },
description: {
de: 'Empfangene Handels- und Geschäftsbriefe, Wiedergaben der abgesandten Handels- und Geschäftsbriefe',
en: 'Received commercial and business correspondence, copies of sent correspondence',
},
applicableTo: ['Geschäftskorrespondenz', 'Angebote', 'Auftragsbestätigungen'],
},
// Steuerrechtliche Aufbewahrung
{
id: 'ao-147',
name: { de: 'Steuerrechtliche Unterlagen', en: 'Tax Documents' },
legalBasis: '§ 147 AO',
duration: { value: 10, unit: 'YEARS' },
description: {
de: 'Bücher und Aufzeichnungen, Inventare, Jahresabschlüsse, Buchungsbelege, steuerrelevante Unterlagen',
en: 'Books and records, inventories, annual financial statements, accounting vouchers, tax-relevant documents',
},
applicableTo: ['Steuererklärungen', 'Buchhaltung', 'Belege'],
},
// Arbeitsrechtliche Aufbewahrung
{
id: 'arbeitsrecht-personal',
name: { de: 'Personalunterlagen', en: 'Personnel Records' },
legalBasis: 'Verschiedene (AGG, ArbZG, etc.)',
duration: { value: 3, unit: 'YEARS' },
description: {
de: 'Personalakte nach Beendigung des Arbeitsverhältnisses (Regelverjährung)',
en: 'Personnel file after termination of employment (standard limitation period)',
},
applicableTo: ['Personalakten', 'Arbeitsverträge', 'Zeugnisse'],
},
{
id: 'arbzg',
name: { de: 'Arbeitszeitaufzeichnungen', en: 'Working Time Records' },
legalBasis: '§ 16 Abs. 2 ArbZG',
duration: { value: 2, unit: 'YEARS' },
description: {
de: 'Aufzeichnungen über Arbeitszeiten, die über 8 Stunden hinausgehen',
en: 'Records of working hours exceeding 8 hours',
},
applicableTo: ['Zeiterfassung', 'Überstunden'],
},
{
id: 'lohnsteuer',
name: { de: 'Lohnunterlagen', en: 'Payroll Documents' },
legalBasis: '§ 41 EStG, § 28f SGB IV',
duration: { value: 6, unit: 'YEARS' },
description: {
de: 'Lohnkonten und Unterlagen für den Lohnsteuerabzug',
en: 'Payroll accounts and documents for wage tax deduction',
},
applicableTo: ['Lohnabrechnungen', 'Lohnsteuerbescheinigungen'],
},
{
id: 'sozialversicherung',
name: { de: 'Sozialversicherungsunterlagen', en: 'Social Security Documents' },
legalBasis: '§ 28f SGB IV',
duration: { value: 5, unit: 'YEARS' },
description: {
de: 'Unterlagen zum Gesamtsozialversicherungsbeitrag',
en: 'Documents for total social security contributions',
},
applicableTo: ['Sozialversicherungsmeldungen', 'Beitragsnachweise'],
},
// Bewerberdaten
{
id: 'bewerbung',
name: { de: 'Bewerbungsunterlagen', en: 'Application Documents' },
legalBasis: '§ 15 Abs. 4 AGG',
duration: { value: 6, unit: 'MONTHS' },
description: {
de: 'Bewerbungsunterlagen nach Absage (AGG-Frist)',
en: 'Application documents after rejection (AGG deadline)',
},
applicableTo: ['Bewerbungen', 'Lebensläufe', 'Zeugnisse von Bewerbern'],
},
// Datenschutzrechtliche Fristen
{
id: 'einwilligung',
name: { de: 'Einwilligungen', en: 'Consents' },
legalBasis: 'Art. 7 Abs. 1 DSGVO',
duration: { value: 3, unit: 'YEARS' },
description: {
de: 'Dokumentation der Einwilligung (Regelverjährung)',
en: 'Documentation of consent (standard limitation period)',
},
applicableTo: ['Einwilligungsnachweise', 'Opt-in-Dokumentation'],
},
{
id: 'videoüberwachung',
name: { de: 'Videoüberwachung', en: 'Video Surveillance' },
legalBasis: 'Verhältnismäßigkeit',
duration: { value: 72, unit: 'DAYS' },
description: {
de: 'Videoaufnahmen (max. 72 Stunden, sofern kein Vorfall)',
en: 'Video recordings (max. 72 hours, unless incident occurred)',
},
applicableTo: ['CCTV-Aufnahmen', 'Überwachungsvideos'],
},
// Löschung nach Vertrag
{
id: 'avv-loeschung',
name: { de: 'AVV-Daten nach Vertragsende', en: 'DPA Data after Contract End' },
legalBasis: 'Art. 28 Abs. 3 lit. g DSGVO',
duration: { value: 30, unit: 'DAYS' },
description: {
de: 'Löschung oder Rückgabe aller personenbezogenen Daten nach Vertragsende',
en: 'Deletion or return of all personal data after contract end',
},
applicableTo: ['Auftragsverarbeitung', 'Dienstleister-Daten'],
},
]
// ==========================================
// HELPER FUNCTIONS
// ==========================================
@@ -492,7 +346,6 @@ export function getAppropriateLegalBases(
)
if (hasSpecialCategory) {
// Return Art. 9 bases plus compatible Art. 6 bases
return [
...getSpecialCategoryLegalBases(),
...getStandardLegalBases().filter((lb) =>
@@ -504,59 +357,12 @@ export function getAppropriateLegalBases(
return getStandardLegalBases()
}
/**
* Get retention period by ID
*/
export function getRetentionPeriod(id: string): RetentionPeriodInfo | undefined {
return STANDARD_RETENTION_PERIODS.find((rp) => rp.id === id)
}
/**
* Get retention periods applicable to a category
*/
export function getRetentionPeriodsForCategory(category: string): RetentionPeriodInfo[] {
return STANDARD_RETENTION_PERIODS.filter((rp) =>
rp.applicableTo.some((a) => a.toLowerCase().includes(category.toLowerCase()))
)
}
/**
* Get longest applicable retention period
*/
export function getLongestRetentionPeriod(categories: string[]): RetentionPeriodInfo | undefined {
const applicable = categories.flatMap((cat) => getRetentionPeriodsForCategory(cat))
if (applicable.length === 0) return undefined
return applicable.reduce((longest, current) => {
const longestMonths = toMonths(longest.duration)
const currentMonths = toMonths(current.duration)
return currentMonths > longestMonths ? current : longest
})
}
function toMonths(duration: { value: number; unit: 'DAYS' | 'MONTHS' | 'YEARS' }): number {
switch (duration.unit) {
case 'DAYS':
return duration.value / 30
case 'MONTHS':
return duration.value
case 'YEARS':
return duration.value * 12
}
}
/**
* Format retention period for display
*/
export function formatRetentionPeriod(
duration: { value: number; unit: 'DAYS' | 'MONTHS' | 'YEARS' },
locale: 'de' | 'en' = 'de'
): string {
const units = {
de: { DAYS: 'Tage', MONTHS: 'Monate', YEARS: 'Jahre' },
en: { DAYS: 'days', MONTHS: 'months', YEARS: 'years' },
}
return `${duration.value} ${units[locale][duration.unit]}`
}
// Re-export retention periods and functions for backward compatibility
export type { RetentionPeriodInfo } from './legal-basis-retention'
export {
STANDARD_RETENTION_PERIODS,
getRetentionPeriod,
getRetentionPeriodsForCategory,
getLongestRetentionPeriod,
formatRetentionPeriod,
} from './legal-basis-retention'

View File

@@ -0,0 +1,127 @@
/**
* Vendor Country Risk Profiles
*
* GDPR transfer risk profiles per country and helper functions.
* Split from vendor-templates.ts for the 500 LOC hard cap.
*/
import type { TransferMechanismType } from '../types'
import type { CountryRiskProfile } from './vendor-templates'
export type { CountryRiskProfile }
// ==========================================
// COUNTRY RISK PROFILES
// ==========================================
export const COUNTRY_RISK_PROFILES: CountryRiskProfile[] = [
// EU Countries (Low Risk)
{ code: 'DE', name: { de: 'Deutschland', en: 'Germany' }, isEU: true, isEEA: true, hasAdequacyDecision: true, riskLevel: 'LOW' },
{ code: 'AT', name: { de: 'Österreich', en: 'Austria' }, isEU: true, isEEA: true, hasAdequacyDecision: true, riskLevel: 'LOW' },
{ code: 'FR', name: { de: 'Frankreich', en: 'France' }, isEU: true, isEEA: true, hasAdequacyDecision: true, riskLevel: 'LOW' },
{ code: 'NL', name: { de: 'Niederlande', en: 'Netherlands' }, isEU: true, isEEA: true, hasAdequacyDecision: true, riskLevel: 'LOW' },
{ code: 'BE', name: { de: 'Belgien', en: 'Belgium' }, isEU: true, isEEA: true, hasAdequacyDecision: true, riskLevel: 'LOW' },
{ code: 'IT', name: { de: 'Italien', en: 'Italy' }, isEU: true, isEEA: true, hasAdequacyDecision: true, riskLevel: 'LOW' },
{ code: 'ES', name: { de: 'Spanien', en: 'Spain' }, isEU: true, isEEA: true, hasAdequacyDecision: true, riskLevel: 'LOW' },
{ code: 'PT', name: { de: 'Portugal', en: 'Portugal' }, isEU: true, isEEA: true, hasAdequacyDecision: true, riskLevel: 'LOW' },
{ code: 'PL', name: { de: 'Polen', en: 'Poland' }, isEU: true, isEEA: true, hasAdequacyDecision: true, riskLevel: 'LOW' },
{ code: 'CZ', name: { de: 'Tschechien', en: 'Czech Republic' }, isEU: true, isEEA: true, hasAdequacyDecision: true, riskLevel: 'LOW' },
{ code: 'SE', name: { de: 'Schweden', en: 'Sweden' }, isEU: true, isEEA: true, hasAdequacyDecision: true, riskLevel: 'LOW' },
{ code: 'DK', name: { de: 'Dänemark', en: 'Denmark' }, isEU: true, isEEA: true, hasAdequacyDecision: true, riskLevel: 'LOW' },
{ code: 'FI', name: { de: 'Finnland', en: 'Finland' }, isEU: true, isEEA: true, hasAdequacyDecision: true, riskLevel: 'LOW' },
{ code: 'IE', name: { de: 'Irland', en: 'Ireland' }, isEU: true, isEEA: true, hasAdequacyDecision: true, riskLevel: 'LOW' },
{ code: 'LU', name: { de: 'Luxemburg', en: 'Luxembourg' }, isEU: true, isEEA: true, hasAdequacyDecision: true, riskLevel: 'LOW' },
// EEA Countries
{ code: 'NO', name: { de: 'Norwegen', en: 'Norway' }, isEU: false, isEEA: true, hasAdequacyDecision: true, riskLevel: 'LOW' },
{ code: 'IS', name: { de: 'Island', en: 'Iceland' }, isEU: false, isEEA: true, hasAdequacyDecision: true, riskLevel: 'LOW' },
{ code: 'LI', name: { de: 'Liechtenstein', en: 'Liechtenstein' }, isEU: false, isEEA: true, hasAdequacyDecision: true, riskLevel: 'LOW' },
// Adequacy Decision Countries
{ code: 'CH', name: { de: 'Schweiz', en: 'Switzerland' }, isEU: false, isEEA: false, hasAdequacyDecision: true, riskLevel: 'LOW' },
{ code: 'GB', name: { de: 'Vereinigtes Königreich', en: 'United Kingdom' }, isEU: false, isEEA: false, hasAdequacyDecision: true, adequacyDecisionDate: '2021-06-28', riskLevel: 'LOW' },
{ code: 'JP', name: { de: 'Japan', en: 'Japan' }, isEU: false, isEEA: false, hasAdequacyDecision: true, adequacyDecisionDate: '2019-01-23', riskLevel: 'LOW' },
{ code: 'KR', name: { de: 'Südkorea', en: 'South Korea' }, isEU: false, isEEA: false, hasAdequacyDecision: true, adequacyDecisionDate: '2022-12-17', riskLevel: 'LOW' },
{ code: 'IL', name: { de: 'Israel', en: 'Israel' }, isEU: false, isEEA: false, hasAdequacyDecision: true, riskLevel: 'LOW' },
{ code: 'NZ', name: { de: 'Neuseeland', en: 'New Zealand' }, isEU: false, isEEA: false, hasAdequacyDecision: true, riskLevel: 'LOW' },
{ code: 'CA', name: { de: 'Kanada', en: 'Canada' }, isEU: false, isEEA: false, hasAdequacyDecision: true, riskLevel: 'LOW', notes: { de: 'Nur PIPEDA-Bereich', en: 'PIPEDA scope only' } },
{ code: 'AR', name: { de: 'Argentinien', en: 'Argentina' }, isEU: false, isEEA: false, hasAdequacyDecision: true, riskLevel: 'LOW' },
{ code: 'UY', name: { de: 'Uruguay', en: 'Uruguay' }, isEU: false, isEEA: false, hasAdequacyDecision: true, riskLevel: 'LOW' },
// US (Special - DPF)
{ code: 'US', name: { de: 'USA', en: 'United States' }, isEU: false, isEEA: false, hasAdequacyDecision: true, adequacyDecisionDate: '2023-07-10', riskLevel: 'MEDIUM', notes: { de: 'EU-US Data Privacy Framework erforderlich', en: 'EU-US Data Privacy Framework required' } },
// Third Countries without Adequacy (High Risk)
{ code: 'CN', name: { de: 'China', en: 'China' }, isEU: false, isEEA: false, hasAdequacyDecision: false, riskLevel: 'VERY_HIGH', notes: { de: 'Staatlicher Datenzugriff möglich', en: 'Government data access possible' } },
{ code: 'RU', name: { de: 'Russland', en: 'Russia' }, isEU: false, isEEA: false, hasAdequacyDecision: false, riskLevel: 'VERY_HIGH', notes: { de: 'Sanktionen beachten', en: 'Consider sanctions' } },
{ code: 'IN', name: { de: 'Indien', en: 'India' }, isEU: false, isEEA: false, hasAdequacyDecision: false, riskLevel: 'HIGH' },
{ code: 'BR', name: { de: 'Brasilien', en: 'Brazil' }, isEU: false, isEEA: false, hasAdequacyDecision: false, riskLevel: 'MEDIUM', notes: { de: 'LGPD vorhanden', en: 'LGPD in place' } },
{ code: 'AU', name: { de: 'Australien', en: 'Australia' }, isEU: false, isEEA: false, hasAdequacyDecision: false, riskLevel: 'MEDIUM' },
{ code: 'SG', name: { de: 'Singapur', en: 'Singapore' }, isEU: false, isEEA: false, hasAdequacyDecision: false, riskLevel: 'MEDIUM', notes: { de: 'PDPA vorhanden', en: 'PDPA in place' } },
{ code: 'HK', name: { de: 'Hongkong', en: 'Hong Kong' }, isEU: false, isEEA: false, hasAdequacyDecision: false, riskLevel: 'HIGH' },
{ code: 'AE', name: { de: 'VAE', en: 'UAE' }, isEU: false, isEEA: false, hasAdequacyDecision: false, riskLevel: 'HIGH' },
{ code: 'ZA', name: { de: 'Südafrika', en: 'South Africa' }, isEU: false, isEEA: false, hasAdequacyDecision: false, riskLevel: 'MEDIUM', notes: { de: 'POPIA vorhanden', en: 'POPIA in place' } },
]
// ==========================================
// HELPER FUNCTIONS
// ==========================================
/**
* Get country risk profile
*/
export function getCountryRiskProfile(countryCode: string): CountryRiskProfile | undefined {
return COUNTRY_RISK_PROFILES.find((c) => c.code === countryCode.toUpperCase())
}
/**
* Check if country requires transfer mechanism
*/
export function requiresTransferMechanism(countryCode: string): boolean {
const profile = getCountryRiskProfile(countryCode)
if (!profile) return true // Unknown country = requires mechanism
return !profile.isEU && !profile.isEEA && !profile.hasAdequacyDecision
}
/**
* Get suggested transfer mechanisms for country
*/
export function getSuggestedTransferMechanisms(countryCode: string): TransferMechanismType[] {
const profile = getCountryRiskProfile(countryCode)
if (!profile) {
return ['SCC_PROCESSOR']
}
if (profile.isEU || profile.isEEA) {
return [] // No mechanism needed
}
if (profile.hasAdequacyDecision) {
return ['ADEQUACY_DECISION']
}
// Third country without adequacy
return ['SCC_PROCESSOR', 'BCR']
}
/**
* Get all EU/EEA countries
*/
export function getEUEEACountries(): CountryRiskProfile[] {
return COUNTRY_RISK_PROFILES.filter((c) => c.isEU || c.isEEA)
}
/**
* Get all countries with adequacy decision
*/
export function getAdequateCountries(): CountryRiskProfile[] {
return COUNTRY_RISK_PROFILES.filter((c) => c.hasAdequacyDecision)
}
/**
* Get all high-risk countries
*/
export function getHighRiskCountries(): CountryRiskProfile[] {
return COUNTRY_RISK_PROFILES.filter((c) => c.riskLevel === 'HIGH' || c.riskLevel === 'VERY_HIGH')
}

View File

@@ -402,60 +402,7 @@ export const VENDOR_TEMPLATES: VendorTemplate[] = [
]
// ==========================================
// COUNTRY RISK PROFILES
// ==========================================
export const COUNTRY_RISK_PROFILES: CountryRiskProfile[] = [
// EU Countries (Low Risk)
{ code: 'DE', name: { de: 'Deutschland', en: 'Germany' }, isEU: true, isEEA: true, hasAdequacyDecision: true, riskLevel: 'LOW' },
{ code: 'AT', name: { de: 'Österreich', en: 'Austria' }, isEU: true, isEEA: true, hasAdequacyDecision: true, riskLevel: 'LOW' },
{ code: 'FR', name: { de: 'Frankreich', en: 'France' }, isEU: true, isEEA: true, hasAdequacyDecision: true, riskLevel: 'LOW' },
{ code: 'NL', name: { de: 'Niederlande', en: 'Netherlands' }, isEU: true, isEEA: true, hasAdequacyDecision: true, riskLevel: 'LOW' },
{ code: 'BE', name: { de: 'Belgien', en: 'Belgium' }, isEU: true, isEEA: true, hasAdequacyDecision: true, riskLevel: 'LOW' },
{ code: 'IT', name: { de: 'Italien', en: 'Italy' }, isEU: true, isEEA: true, hasAdequacyDecision: true, riskLevel: 'LOW' },
{ code: 'ES', name: { de: 'Spanien', en: 'Spain' }, isEU: true, isEEA: true, hasAdequacyDecision: true, riskLevel: 'LOW' },
{ code: 'PT', name: { de: 'Portugal', en: 'Portugal' }, isEU: true, isEEA: true, hasAdequacyDecision: true, riskLevel: 'LOW' },
{ code: 'PL', name: { de: 'Polen', en: 'Poland' }, isEU: true, isEEA: true, hasAdequacyDecision: true, riskLevel: 'LOW' },
{ code: 'CZ', name: { de: 'Tschechien', en: 'Czech Republic' }, isEU: true, isEEA: true, hasAdequacyDecision: true, riskLevel: 'LOW' },
{ code: 'SE', name: { de: 'Schweden', en: 'Sweden' }, isEU: true, isEEA: true, hasAdequacyDecision: true, riskLevel: 'LOW' },
{ code: 'DK', name: { de: 'Dänemark', en: 'Denmark' }, isEU: true, isEEA: true, hasAdequacyDecision: true, riskLevel: 'LOW' },
{ code: 'FI', name: { de: 'Finnland', en: 'Finland' }, isEU: true, isEEA: true, hasAdequacyDecision: true, riskLevel: 'LOW' },
{ code: 'IE', name: { de: 'Irland', en: 'Ireland' }, isEU: true, isEEA: true, hasAdequacyDecision: true, riskLevel: 'LOW' },
{ code: 'LU', name: { de: 'Luxemburg', en: 'Luxembourg' }, isEU: true, isEEA: true, hasAdequacyDecision: true, riskLevel: 'LOW' },
// EEA Countries
{ code: 'NO', name: { de: 'Norwegen', en: 'Norway' }, isEU: false, isEEA: true, hasAdequacyDecision: true, riskLevel: 'LOW' },
{ code: 'IS', name: { de: 'Island', en: 'Iceland' }, isEU: false, isEEA: true, hasAdequacyDecision: true, riskLevel: 'LOW' },
{ code: 'LI', name: { de: 'Liechtenstein', en: 'Liechtenstein' }, isEU: false, isEEA: true, hasAdequacyDecision: true, riskLevel: 'LOW' },
// Adequacy Decision Countries
{ code: 'CH', name: { de: 'Schweiz', en: 'Switzerland' }, isEU: false, isEEA: false, hasAdequacyDecision: true, riskLevel: 'LOW' },
{ code: 'GB', name: { de: 'Vereinigtes Königreich', en: 'United Kingdom' }, isEU: false, isEEA: false, hasAdequacyDecision: true, adequacyDecisionDate: '2021-06-28', riskLevel: 'LOW' },
{ code: 'JP', name: { de: 'Japan', en: 'Japan' }, isEU: false, isEEA: false, hasAdequacyDecision: true, adequacyDecisionDate: '2019-01-23', riskLevel: 'LOW' },
{ code: 'KR', name: { de: 'Südkorea', en: 'South Korea' }, isEU: false, isEEA: false, hasAdequacyDecision: true, adequacyDecisionDate: '2022-12-17', riskLevel: 'LOW' },
{ code: 'IL', name: { de: 'Israel', en: 'Israel' }, isEU: false, isEEA: false, hasAdequacyDecision: true, riskLevel: 'LOW' },
{ code: 'NZ', name: { de: 'Neuseeland', en: 'New Zealand' }, isEU: false, isEEA: false, hasAdequacyDecision: true, riskLevel: 'LOW' },
{ code: 'CA', name: { de: 'Kanada', en: 'Canada' }, isEU: false, isEEA: false, hasAdequacyDecision: true, riskLevel: 'LOW', notes: { de: 'Nur PIPEDA-Bereich', en: 'PIPEDA scope only' } },
{ code: 'AR', name: { de: 'Argentinien', en: 'Argentina' }, isEU: false, isEEA: false, hasAdequacyDecision: true, riskLevel: 'LOW' },
{ code: 'UY', name: { de: 'Uruguay', en: 'Uruguay' }, isEU: false, isEEA: false, hasAdequacyDecision: true, riskLevel: 'LOW' },
// US (Special - DPF)
{ code: 'US', name: { de: 'USA', en: 'United States' }, isEU: false, isEEA: false, hasAdequacyDecision: true, adequacyDecisionDate: '2023-07-10', riskLevel: 'MEDIUM', notes: { de: 'EU-US Data Privacy Framework erforderlich', en: 'EU-US Data Privacy Framework required' } },
// Third Countries without Adequacy (High Risk)
{ code: 'CN', name: { de: 'China', en: 'China' }, isEU: false, isEEA: false, hasAdequacyDecision: false, riskLevel: 'VERY_HIGH', notes: { de: 'Staatlicher Datenzugriff möglich', en: 'Government data access possible' } },
{ code: 'RU', name: { de: 'Russland', en: 'Russia' }, isEU: false, isEEA: false, hasAdequacyDecision: false, riskLevel: 'VERY_HIGH', notes: { de: 'Sanktionen beachten', en: 'Consider sanctions' } },
{ code: 'IN', name: { de: 'Indien', en: 'India' }, isEU: false, isEEA: false, hasAdequacyDecision: false, riskLevel: 'HIGH' },
{ code: 'BR', name: { de: 'Brasilien', en: 'Brazil' }, isEU: false, isEEA: false, hasAdequacyDecision: false, riskLevel: 'MEDIUM', notes: { de: 'LGPD vorhanden', en: 'LGPD in place' } },
{ code: 'AU', name: { de: 'Australien', en: 'Australia' }, isEU: false, isEEA: false, hasAdequacyDecision: false, riskLevel: 'MEDIUM' },
{ code: 'SG', name: { de: 'Singapur', en: 'Singapore' }, isEU: false, isEEA: false, hasAdequacyDecision: false, riskLevel: 'MEDIUM', notes: { de: 'PDPA vorhanden', en: 'PDPA in place' } },
{ code: 'HK', name: { de: 'Hongkong', en: 'Hong Kong' }, isEU: false, isEEA: false, hasAdequacyDecision: false, riskLevel: 'HIGH' },
{ code: 'AE', name: { de: 'VAE', en: 'UAE' }, isEU: false, isEEA: false, hasAdequacyDecision: false, riskLevel: 'HIGH' },
{ code: 'ZA', name: { de: 'Südafrika', en: 'South Africa' }, isEU: false, isEEA: false, hasAdequacyDecision: false, riskLevel: 'MEDIUM', notes: { de: 'POPIA vorhanden', en: 'POPIA in place' } },
]
// ==========================================
// HELPER FUNCTIONS
// HELPER FUNCTIONS (template-specific)
// ==========================================
/**
@@ -472,44 +419,6 @@ export function getVendorTemplatesByCategory(category: ServiceCategory): VendorT
return VENDOR_TEMPLATES.filter((t) => t.serviceCategory === category)
}
/**
* Get country risk profile
*/
export function getCountryRiskProfile(countryCode: string): CountryRiskProfile | undefined {
return COUNTRY_RISK_PROFILES.find((c) => c.code === countryCode.toUpperCase())
}
/**
* Check if country requires transfer mechanism
*/
export function requiresTransferMechanism(countryCode: string): boolean {
const profile = getCountryRiskProfile(countryCode)
if (!profile) return true // Unknown country = requires mechanism
return !profile.isEU && !profile.isEEA && !profile.hasAdequacyDecision
}
/**
* Get suggested transfer mechanisms for country
*/
export function getSuggestedTransferMechanisms(countryCode: string): TransferMechanismType[] {
const profile = getCountryRiskProfile(countryCode)
if (!profile) {
return ['SCC_PROCESSOR']
}
if (profile.isEU || profile.isEEA) {
return [] // No mechanism needed
}
if (profile.hasAdequacyDecision) {
return ['ADEQUACY_DECISION']
}
// Third country without adequacy
return ['SCC_PROCESSOR', 'BCR']
}
/**
* Calculate inherent risk score for vendor template
*/
@@ -542,23 +451,13 @@ export function createVendorFormDataFromTemplate(
}
}
/**
* Get all EU/EEA countries
*/
export function getEUEEACountries(): CountryRiskProfile[] {
return COUNTRY_RISK_PROFILES.filter((c) => c.isEU || c.isEEA)
}
/**
* Get all countries with adequacy decision
*/
export function getAdequateCountries(): CountryRiskProfile[] {
return COUNTRY_RISK_PROFILES.filter((c) => c.hasAdequacyDecision)
}
/**
* Get all high-risk countries
*/
export function getHighRiskCountries(): CountryRiskProfile[] {
return COUNTRY_RISK_PROFILES.filter((c) => c.riskLevel === 'HIGH' || c.riskLevel === 'VERY_HIGH')
}
// Re-export country profiles and functions for backward compatibility
export {
COUNTRY_RISK_PROFILES,
getCountryRiskProfile,
requiresTransferMechanism,
getSuggestedTransferMechanisms,
getEUEEACountries,
getAdequateCountries,
getHighRiskCountries,
} from './vendor-country-profiles'