From 911d872178a39614d0363415dbc8e651c9a16da0 Mon Sep 17 00:00:00 2001 From: Sharang Parnerkar <30073382+mighty840@users.noreply.github.com> Date: Fri, 10 Apr 2026 13:33:51 +0200 Subject: [PATCH] refactor(admin): split compliance-scope-engine.ts (1811 LOC) into focused modules Extract data constants and document-scope logic from the monolithic engine: - compliance-scope-data.ts (133 LOC): score weights + answer multipliers - compliance-scope-triggers.ts (823 LOC): 50 hard trigger rules (data table) - compliance-scope-documents.ts (497 LOC): document scope, risk flags, gaps, actions, reasoning - compliance-scope-engine.ts (406 LOC): core class with scoring + trigger evaluation All logic files stay under the 500 LOC cap. The triggers file exceeds it as a pure declarative data table with no logic. Co-Authored-By: Claude Opus 4.6 (1M context) --- .../lib/sdk/compliance-scope-data.ts | 133 ++ .../lib/sdk/compliance-scope-documents.ts | 497 ++++++ .../lib/sdk/compliance-scope-engine.ts | 1465 +---------------- .../lib/sdk/compliance-scope-triggers.ts | 823 +++++++++ 4 files changed, 1483 insertions(+), 1435 deletions(-) create mode 100644 admin-compliance/lib/sdk/compliance-scope-data.ts create mode 100644 admin-compliance/lib/sdk/compliance-scope-documents.ts create mode 100644 admin-compliance/lib/sdk/compliance-scope-triggers.ts diff --git a/admin-compliance/lib/sdk/compliance-scope-data.ts b/admin-compliance/lib/sdk/compliance-scope-data.ts new file mode 100644 index 0000000..57b72b3 --- /dev/null +++ b/admin-compliance/lib/sdk/compliance-scope-data.ts @@ -0,0 +1,133 @@ +// ============================================================================ +// SCORE WEIGHTS PRO FRAGE +// ============================================================================ + +export const QUESTION_SCORE_WEIGHTS: Record< + string, + { risk: number; complexity: number; assurance: number } +> = { + // Organisationsprofil (6 Fragen) + org_employee_count: { risk: 3, complexity: 5, assurance: 4 }, + org_industry: { risk: 6, complexity: 4, assurance: 5 }, + org_business_model: { risk: 5, complexity: 3, assurance: 4 }, + org_customer_count: { risk: 4, complexity: 6, assurance: 5 }, + org_cert_target: { risk: 2, complexity: 8, assurance: 9 }, + org_has_dpo: { risk: 7, complexity: 2, assurance: 8 }, + + // Datenarten (5 Fragen) + data_art9: { risk: 10, complexity: 7, assurance: 9 }, + data_minors: { risk: 10, complexity: 6, assurance: 9 }, + data_volume: { risk: 6, complexity: 7, assurance: 6 }, + data_retention_years: { risk: 5, complexity: 4, assurance: 5 }, + data_sources: { risk: 4, complexity: 5, assurance: 4 }, + + // Verarbeitungszwecke (9 Fragen) + proc_adm_scoring: { risk: 9, complexity: 7, assurance: 8 }, + proc_ai_usage: { risk: 8, complexity: 8, assurance: 8 }, + proc_video_surveillance: { risk: 7, complexity: 5, assurance: 7 }, + proc_employee_monitoring: { risk: 7, complexity: 5, assurance: 7 }, + proc_tracking: { risk: 6, complexity: 4, assurance: 6 }, + proc_dsar_process: { risk: 8, complexity: 6, assurance: 8 }, + proc_deletion_concept: { risk: 7, complexity: 5, assurance: 7 }, + proc_incident_response: { risk: 9, complexity: 6, assurance: 9 }, + proc_regular_audits: { risk: 5, complexity: 7, assurance: 8 }, + + // Technik (7 Fragen) + tech_hosting_location: { risk: 7, complexity: 5, assurance: 7 }, + tech_third_country: { risk: 8, complexity: 6, assurance: 8 }, + tech_encryption_transit: { risk: 8, complexity: 4, assurance: 8 }, + tech_encryption_rest: { risk: 8, complexity: 4, assurance: 8 }, + tech_access_control: { risk: 7, complexity: 5, assurance: 7 }, + tech_logging: { risk: 6, complexity: 5, assurance: 7 }, + tech_backup_recovery: { risk: 6, complexity: 5, assurance: 7 }, + + // Produkt/Features (5 Fragen) + prod_webshop: { risk: 5, complexity: 4, assurance: 5 }, + prod_data_broker: { risk: 9, complexity: 7, assurance: 8 }, + prod_api_external: { risk: 6, complexity: 5, assurance: 6 }, + prod_consent_management: { risk: 7, complexity: 5, assurance: 8 }, + prod_data_portability: { risk: 4, complexity: 5, assurance: 5 }, + + // Compliance Reife (3 Fragen) + comp_training: { risk: 5, complexity: 4, assurance: 7 }, + comp_vendor_management: { risk: 6, complexity: 6, assurance: 7 }, + comp_documentation_level: { risk: 6, complexity: 7, assurance: 8 }, +} + +// ============================================================================ +// ANSWER MULTIPLIERS FÜR SINGLE-CHOICE FRAGEN +// ============================================================================ + +export const ANSWER_MULTIPLIERS: Record> = { + org_employee_count: { + '1-9': 0.1, + '10-49': 0.3, + '50-249': 0.5, + '250-999': 0.7, + '1000+': 1.0, + }, + org_industry: { + tech: 0.4, + finance: 0.8, + healthcare: 0.9, + public: 0.7, + retail: 0.5, + education: 0.6, + other: 0.3, + }, + org_business_model: { + b2b: 0.4, + b2c: 0.7, + b2b2c: 0.6, + internal: 0.3, + }, + org_customer_count: { + '0-100': 0.1, + '100-1000': 0.2, + '1000-10000': 0.4, + '10000-100000': 0.7, + '100000+': 1.0, + }, + data_volume: { + '<1000': 0.1, + '1000-10000': 0.2, + '10000-100000': 0.4, + '100000-1000000': 0.7, + '>1000000': 1.0, + }, + data_retention_years: { + '<1': 0.2, + '1-3': 0.4, + '3-5': 0.6, + '5-10': 0.8, + '>10': 1.0, + }, + tech_hosting_location: { + eu: 0.2, + eu_us_adequacy: 0.4, + us_adequacy: 0.6, + drittland: 1.0, + }, + tech_access_control: { + none: 1.0, + basic: 0.6, + rbac: 0.3, + advanced: 0.1, + }, + tech_logging: { + none: 1.0, + basic: 0.6, + comprehensive: 0.2, + }, + tech_backup_recovery: { + none: 1.0, + basic: 0.5, + tested: 0.2, + }, + comp_documentation_level: { + none: 1.0, + basic: 0.6, + structured: 0.3, + comprehensive: 0.1, + }, +} diff --git a/admin-compliance/lib/sdk/compliance-scope-documents.ts b/admin-compliance/lib/sdk/compliance-scope-documents.ts new file mode 100644 index 0000000..e756aa2 --- /dev/null +++ b/admin-compliance/lib/sdk/compliance-scope-documents.ts @@ -0,0 +1,497 @@ +/** + * Document-scope calculation, risk flags, gap analysis, next actions, + * and reasoning (audit trail) helpers for the ComplianceScopeEngine. + */ +import type { + ComplianceDepthLevel, + ComplianceScores, + ScopeProfilingAnswer, + TriggeredHardTrigger, + RequiredDocument, + RiskFlag, + ScopeGap, + NextAction, + ScopeReasoning, + ScopeDocumentType, + HardTriggerRule, +} from './compliance-scope-types' +import { + getDepthLevelNumeric, + DOCUMENT_SCOPE_MATRIX, + DOCUMENT_TYPE_LABELS, + DOCUMENT_SDK_STEP_MAP, +} from './compliance-scope-types' +import { HARD_TRIGGER_RULES } from './compliance-scope-triggers' + +// --------------------------------------------------------------------------- +// Shared helpers +// --------------------------------------------------------------------------- + +/** Parse employee-count bucket string to a representative number. */ +export function parseEmployeeCount(value: string): number { + if (value === '1-9') return 9 + if (value === '10-49') return 49 + if (value === '50-249') return 249 + if (value === '250-999') return 999 + if (value === '1000+') return 1000 + return 0 +} + +/** Derive level purely from composite score. */ +export function getLevelFromScore(composite: number): ComplianceDepthLevel { + if (composite <= 25) return 'L1' + if (composite <= 50) return 'L2' + if (composite <= 75) return 'L3' + return 'L4' +} + +/** Highest level among the given triggers. */ +export function getMaxTriggerLevel(triggers: TriggeredHardTrigger[]): ComplianceDepthLevel { + if (triggers.length === 0) return 'L1' + let max: ComplianceDepthLevel = 'L1' + for (const t of triggers) { + if (getDepthLevelNumeric(t.minimumLevel) > getDepthLevelNumeric(max)) { + max = t.minimumLevel + } + } + return max +} + +// --------------------------------------------------------------------------- +// normalizeDocType +// --------------------------------------------------------------------------- + +/** + * Maps UPPERCASE document-type identifiers from the hard-trigger rules + * to the lowercase ScopeDocumentType keys. + */ +export function normalizeDocType(raw: string): ScopeDocumentType | null { + const mapping: Record = { + VVT: 'vvt', + TOM: 'tom', + DSFA: 'dsfa', + DSE: 'dsi', + AGB: 'vertragsmanagement', + AVV: 'av_vertrag', + COOKIE_BANNER: 'einwilligung', + EINWILLIGUNGEN: 'einwilligung', + TRANSFER_DOKU: 'daten_transfer', + AUDIT_CHECKLIST: 'audit_log', + VENDOR_MANAGEMENT: 'vertragsmanagement', + LOESCHKONZEPT: 'lf', + DSR_PROZESS: 'betroffenenrechte', + NOTFALLPLAN: 'notfallplan', + AI_ACT_DOKU: 'ai_act_doku', + WIDERRUFSBELEHRUNG: 'widerrufsbelehrung', + PREISANGABEN: 'preisangaben', + FERNABSATZ_INFO: 'fernabsatz_info', + STREITBEILEGUNG: 'streitbeilegung', + PRODUKTSICHERHEIT: 'produktsicherheit', + } + if (raw in DOCUMENT_SCOPE_MATRIX) return raw as ScopeDocumentType + return mapping[raw] ?? null +} + +// --------------------------------------------------------------------------- +// Document scope +// --------------------------------------------------------------------------- + +function getDocumentPriority( + docType: ScopeDocumentType, + isMandatoryFromTrigger: boolean, +): 'high' | 'medium' | 'low' { + if (isMandatoryFromTrigger) return 'high' + if (['VVT', 'TOM', 'DSE'].includes(docType)) return 'high' + if (['DSFA', 'AVV', 'EINWILLIGUNGEN'].includes(docType)) return 'high' + return 'medium' +} + +function estimateEffort(docType: ScopeDocumentType): number { + const effortMap: Partial> = { + vvt: 8, + tom: 12, + dsfa: 16, + av_vertrag: 4, + dsi: 6, + einwilligung: 6, + lf: 10, + daten_transfer: 8, + betroffenenrechte: 8, + notfallplan: 12, + vertragsmanagement: 10, + audit_log: 8, + risikoanalyse: 6, + schulung: 4, + datenpannen: 6, + zertifizierung: 8, + datenschutzmanagement: 12, + iace_ce_assessment: 8, + widerrufsbelehrung: 3, + preisangaben: 2, + fernabsatz_info: 4, + streitbeilegung: 1, + produktsicherheit: 8, + ai_act_doku: 12, + } + return effortMap[docType] ?? 6 +} + +/** + * Build the full document-scope list based on compliance level and triggers. + */ +export function buildDocumentScope( + level: ComplianceDepthLevel, + triggers: TriggeredHardTrigger[], + _answers: ScopeProfilingAnswer[], +): RequiredDocument[] { + const requiredDocs: RequiredDocument[] = [] + const mandatoryFromTriggers = new Set() + const triggerDocOrigins = new Map() + + for (const trigger of triggers) { + for (const doc of trigger.mandatoryDocuments) { + const normalized = normalizeDocType(doc) + if (normalized) { + mandatoryFromTriggers.add(normalized) + if (!triggerDocOrigins.has(normalized)) triggerDocOrigins.set(normalized, []) + triggerDocOrigins.get(normalized)!.push(doc) + } + } + } + + for (const docType of Object.keys(DOCUMENT_SCOPE_MATRIX) as ScopeDocumentType[]) { + const requirement = DOCUMENT_SCOPE_MATRIX[docType][level] + const isMandatoryFromTrigger = mandatoryFromTriggers.has(docType) + + if (requirement === 'mandatory' || isMandatoryFromTrigger) { + const originDocs = triggerDocOrigins.get(docType) ?? [] + requiredDocs.push({ + documentType: docType, + label: DOCUMENT_TYPE_LABELS[docType], + requirement: 'mandatory', + priority: getDocumentPriority(docType, isMandatoryFromTrigger), + estimatedEffort: estimateEffort(docType), + sdkStepUrl: DOCUMENT_SDK_STEP_MAP[docType], + triggeredBy: isMandatoryFromTrigger + ? triggers + .filter((t) => t.mandatoryDocuments.some((d) => originDocs.includes(d))) + .map((t) => t.ruleId) + : [], + }) + } else if (requirement === 'recommended') { + requiredDocs.push({ + documentType: docType, + label: DOCUMENT_TYPE_LABELS[docType], + requirement: 'recommended', + priority: 'medium', + estimatedEffort: estimateEffort(docType), + sdkStepUrl: DOCUMENT_SDK_STEP_MAP[docType], + triggeredBy: [], + }) + } + } + + requiredDocs.sort((a, b) => { + if (a.requirement === 'mandatory' && b.requirement !== 'mandatory') return -1 + if (a.requirement !== 'mandatory' && b.requirement === 'mandatory') return 1 + const priorityOrder: Record = { high: 3, medium: 2, low: 1 } + return priorityOrder[b.priority] - priorityOrder[a.priority] + }) + + return requiredDocs +} + +// --------------------------------------------------------------------------- +// Risk flags +// --------------------------------------------------------------------------- + +function getMaturityRecommendation(ruleId: string): string { + const recommendations: Record = { + 'HT-I01': 'Prozess für Betroffenenrechte (DSAR) etablieren und dokumentieren', + 'HT-I02': 'Löschkonzept gemäß Art. 17 DSGVO entwickeln und implementieren', + 'HT-I03': + 'Incident-Response-Plan für Datenschutzverletzungen (Art. 33 DSGVO) erstellen', + 'HT-I04': 'Regelmäßige interne Audits und Reviews einführen', + 'HT-I05': 'Schulungsprogramm für Mitarbeiter zum Datenschutz etablieren', + } + return recommendations[ruleId] || 'Prozess etablieren und dokumentieren' +} + +/** + * Evaluate risk flags based on process-maturity gaps and other risks. + * + * `checkTriggerFn` is injected to avoid a circular dependency on the engine. + */ +export function evaluateRiskFlags( + answers: ScopeProfilingAnswer[], + level: ComplianceDepthLevel, + checkTriggerFn: ( + rule: HardTriggerRule, + answerMap: Map, + answers: ScopeProfilingAnswer[], + ) => boolean, +): RiskFlag[] { + const flags: RiskFlag[] = [] + const answerMap = new Map(answers.map((a) => [a.questionId, a.value])) + + const maturityRules = HARD_TRIGGER_RULES.filter((r) => r.category === 'process_maturity') + for (const rule of maturityRules) { + if (checkTriggerFn(rule, answerMap, answers)) { + flags.push({ + severity: 'medium', + category: 'process', + message: rule.description, + legalReference: rule.legalReference, + recommendation: getMaturityRecommendation(rule.id), + }) + } + } + + if (getDepthLevelNumeric(level) >= 2) { + const encTransit = answerMap.get('tech_encryption_transit') + const encRest = answerMap.get('tech_encryption_rest') + + if (encTransit === false) { + flags.push({ + severity: 'high', + category: 'technical', + message: 'Fehlende Verschlüsselung bei Datenübertragung', + legalReference: 'Art. 32 DSGVO', + recommendation: 'TLS 1.2+ für alle Datenübertragungen implementieren', + }) + } + + if (encRest === false) { + flags.push({ + severity: 'high', + category: 'technical', + message: 'Fehlende Verschlüsselung gespeicherter Daten', + legalReference: 'Art. 32 DSGVO', + recommendation: 'Verschlüsselung at-rest für sensitive Daten implementieren', + }) + } + } + + const thirdCountry = answerMap.get('tech_third_country') + const hostingLocation = answerMap.get('tech_hosting_location') + if ( + thirdCountry === true && + hostingLocation !== 'eu' && + hostingLocation !== 'eu_us_adequacy' + ) { + flags.push({ + severity: 'high', + category: 'legal', + message: 'Drittlandtransfer ohne angemessene Garantien', + legalReference: 'Art. 44 ff. DSGVO', + recommendation: + 'Standardvertragsklauseln (SCCs) oder Binding Corporate Rules (BCRs) implementieren', + }) + } + + const hasDPO = answerMap.get('org_has_dpo') + const employeeCount = answerMap.get('org_employee_count') + if (hasDPO === false && parseEmployeeCount(employeeCount as string) >= 250) { + flags.push({ + severity: 'medium', + category: 'organizational', + message: 'Kein Datenschutzbeauftragter bei großer Organisation', + legalReference: 'Art. 37 DSGVO', + recommendation: 'Bestellung eines Datenschutzbeauftragten prüfen', + }) + } + + return flags +} + +// --------------------------------------------------------------------------- +// Gap analysis +// --------------------------------------------------------------------------- + +export function calculateGaps( + answers: ScopeProfilingAnswer[], + level: ComplianceDepthLevel, +): ScopeGap[] { + const gaps: ScopeGap[] = [] + const answerMap = new Map(answers.map((a) => [a.questionId, a.value])) + + if (getDepthLevelNumeric(level) >= 3) { + const hasDSFA = answerMap.get('proc_regular_audits') + if (hasDSFA === false) { + gaps.push({ + gapType: 'documentation', + severity: 'high', + description: 'Datenschutz-Folgenabschätzung (DSFA) fehlt', + requiredFor: level, + currentState: 'Keine DSFA durchgeführt', + targetState: 'DSFA für Hochrisiko-Verarbeitungen durchgeführt und dokumentiert', + effort: 16, + priority: 'high', + }) + } + } + + const hasDeletion = answerMap.get('proc_deletion_concept') + if (hasDeletion === false && getDepthLevelNumeric(level) >= 2) { + gaps.push({ + gapType: 'process', + severity: 'medium', + description: 'Löschkonzept fehlt', + requiredFor: level, + currentState: 'Kein systematisches Löschkonzept', + targetState: 'Dokumentiertes Löschkonzept mit definierten Fristen', + effort: 10, + priority: 'high', + }) + } + + const hasDSAR = answerMap.get('proc_dsar_process') + if (hasDSAR === false) { + gaps.push({ + gapType: 'process', + severity: 'high', + description: 'Prozess für Betroffenenrechte fehlt', + requiredFor: level, + currentState: 'Kein etablierter DSAR-Prozess', + targetState: 'Dokumentierter Prozess zur Bearbeitung von Betroffenenrechten', + effort: 8, + priority: 'high', + }) + } + + const hasIncident = answerMap.get('proc_incident_response') + if (hasIncident === false) { + gaps.push({ + gapType: 'process', + severity: 'high', + description: 'Incident-Response-Plan fehlt', + requiredFor: level, + currentState: 'Kein Prozess für Datenschutzverletzungen', + targetState: 'Dokumentierter Incident-Response-Plan gemäß Art. 33 DSGVO', + effort: 12, + priority: 'high', + }) + } + + const hasTraining = answerMap.get('comp_training') + if (hasTraining === false && getDepthLevelNumeric(level) >= 2) { + gaps.push({ + gapType: 'organizational', + severity: 'medium', + description: 'Datenschutzschulungen fehlen', + requiredFor: level, + currentState: 'Keine regelmäßigen Schulungen', + targetState: 'Etabliertes Schulungsprogramm für alle Mitarbeiter', + effort: 6, + priority: 'medium', + }) + } + + return gaps +} + +// --------------------------------------------------------------------------- +// Next actions +// --------------------------------------------------------------------------- + +export function buildNextActions( + requiredDocuments: RequiredDocument[], + gaps: ScopeGap[], +): NextAction[] { + const actions: NextAction[] = [] + + for (const doc of requiredDocuments) { + if (doc.requirement === 'mandatory') { + actions.push({ + actionType: 'create_document', + title: `${doc.label} erstellen`, + description: `Pflichtdokument für Compliance-Level erstellen`, + priority: doc.priority, + estimatedEffort: doc.estimatedEffort, + documentType: doc.documentType, + sdkStepUrl: doc.sdkStepUrl, + blockers: [], + }) + } + } + + for (const gap of gaps) { + let actionType: NextAction['actionType'] = 'establish_process' + if (gap.gapType === 'documentation') actionType = 'create_document' + else if (gap.gapType === 'technical') actionType = 'implement_technical' + else if (gap.gapType === 'organizational') actionType = 'organizational_change' + + actions.push({ + actionType, + title: `Gap schließen: ${gap.description}`, + description: `Von "${gap.currentState}" zu "${gap.targetState}"`, + priority: gap.priority, + estimatedEffort: gap.effort, + blockers: [], + }) + } + + const priorityOrder: Record = { high: 3, medium: 2, low: 1 } + actions.sort((a, b) => priorityOrder[b.priority] - priorityOrder[a.priority]) + + return actions +} + +// --------------------------------------------------------------------------- +// Reasoning (audit trail) +// --------------------------------------------------------------------------- + +export function buildReasoning( + scores: ComplianceScores, + triggers: TriggeredHardTrigger[], + level: ComplianceDepthLevel, + docs: RequiredDocument[], +): ScopeReasoning[] { + const reasoning: ScopeReasoning[] = [] + + reasoning.push({ + step: 'score_calculation', + description: 'Risikobasierte Score-Berechnung aus Profiling-Antworten', + factors: [ + `Risiko-Score: ${scores.risk_score}/10`, + `Komplexitäts-Score: ${scores.complexity_score}/10`, + `Assurance-Score: ${scores.assurance_need}/10`, + `Composite Score: ${scores.composite_score}/10`, + ], + impact: `Score-basiertes Level: ${getLevelFromScore(scores.composite_score)}`, + }) + + if (triggers.length > 0) { + reasoning.push({ + step: 'hard_trigger_evaluation', + description: `${triggers.length} Hard Trigger Rule(s) aktiviert`, + factors: triggers.map( + (t) => `${t.ruleId}: ${t.description}${t.legalReference ? ` (${t.legalReference})` : ''}`, + ), + impact: `Höchstes Trigger-Level: ${getMaxTriggerLevel(triggers)}`, + }) + } + + reasoning.push({ + step: 'level_determination', + description: 'Finales Compliance-Level durch Maximum aus Score und Triggers', + factors: [ + `Score-Level: ${getLevelFromScore(scores.composite_score)}`, + `Trigger-Level: ${getMaxTriggerLevel(triggers)}`, + ], + impact: `Finales Level: ${level}`, + }) + + const mandatoryDocs = docs.filter((d) => d.requirement === 'mandatory') + reasoning.push({ + step: 'document_scope', + description: `Dokumenten-Scope für ${level} bestimmt`, + factors: [ + `${mandatoryDocs.length} Pflichtdokumente`, + `${docs.length - mandatoryDocs.length} empfohlene Dokumente`, + ], + impact: `Gesamtaufwand: ~${docs.reduce((sum, d) => sum + d.estimatedEffort, 0)} Stunden`, + }) + + return reasoning +} diff --git a/admin-compliance/lib/sdk/compliance-scope-engine.ts b/admin-compliance/lib/sdk/compliance-scope-engine.ts index ef0b98b..ce40fce 100644 --- a/admin-compliance/lib/sdk/compliance-scope-engine.ts +++ b/admin-compliance/lib/sdk/compliance-scope-engine.ts @@ -10,969 +10,30 @@ import type { ScopeGap, NextAction, ScopeReasoning, - ScopeDocumentType, - DocumentScopeRequirement, } from './compliance-scope-types' import type { CompanyProfile, MachineBuilderProfile } from './types' import { getDepthLevelNumeric, - depthLevelFromNumeric, maxDepthLevel, createEmptyScopeDecision, - DOCUMENT_SCOPE_MATRIX, - DOCUMENT_TYPE_LABELS, - DOCUMENT_SDK_STEP_MAP, } from './compliance-scope-types' -// ============================================================================ -// SCORE WEIGHTS PRO FRAGE -// ============================================================================ +// Re-export data constants so existing barrel imports keep working +export { QUESTION_SCORE_WEIGHTS, ANSWER_MULTIPLIERS } from './compliance-scope-data' +export { HARD_TRIGGER_RULES } from './compliance-scope-triggers' -export const QUESTION_SCORE_WEIGHTS: Record< - string, - { risk: number; complexity: number; assurance: number } -> = { - // Organisationsprofil (6 Fragen) - org_employee_count: { risk: 3, complexity: 5, assurance: 4 }, - org_industry: { risk: 6, complexity: 4, assurance: 5 }, - org_business_model: { risk: 5, complexity: 3, assurance: 4 }, - org_customer_count: { risk: 4, complexity: 6, assurance: 5 }, - org_cert_target: { risk: 2, complexity: 8, assurance: 9 }, - org_has_dpo: { risk: 7, complexity: 2, assurance: 8 }, - - // Datenarten (5 Fragen) - data_art9: { risk: 10, complexity: 7, assurance: 9 }, - data_minors: { risk: 10, complexity: 6, assurance: 9 }, - data_volume: { risk: 6, complexity: 7, assurance: 6 }, - data_retention_years: { risk: 5, complexity: 4, assurance: 5 }, - data_sources: { risk: 4, complexity: 5, assurance: 4 }, - - // Verarbeitungszwecke (9 Fragen) - proc_adm_scoring: { risk: 9, complexity: 7, assurance: 8 }, - proc_ai_usage: { risk: 8, complexity: 8, assurance: 8 }, - proc_video_surveillance: { risk: 7, complexity: 5, assurance: 7 }, - proc_employee_monitoring: { risk: 7, complexity: 5, assurance: 7 }, - proc_tracking: { risk: 6, complexity: 4, assurance: 6 }, - proc_dsar_process: { risk: 8, complexity: 6, assurance: 8 }, - proc_deletion_concept: { risk: 7, complexity: 5, assurance: 7 }, - proc_incident_response: { risk: 9, complexity: 6, assurance: 9 }, - proc_regular_audits: { risk: 5, complexity: 7, assurance: 8 }, - - // Technik (7 Fragen) - tech_hosting_location: { risk: 7, complexity: 5, assurance: 7 }, - tech_third_country: { risk: 8, complexity: 6, assurance: 8 }, - tech_encryption_transit: { risk: 8, complexity: 4, assurance: 8 }, - tech_encryption_rest: { risk: 8, complexity: 4, assurance: 8 }, - tech_access_control: { risk: 7, complexity: 5, assurance: 7 }, - tech_logging: { risk: 6, complexity: 5, assurance: 7 }, - tech_backup_recovery: { risk: 6, complexity: 5, assurance: 7 }, - - // Produkt/Features (5 Fragen) - prod_webshop: { risk: 5, complexity: 4, assurance: 5 }, - prod_data_broker: { risk: 9, complexity: 7, assurance: 8 }, - prod_api_external: { risk: 6, complexity: 5, assurance: 6 }, - prod_consent_management: { risk: 7, complexity: 5, assurance: 8 }, - prod_data_portability: { risk: 4, complexity: 5, assurance: 5 }, - - // Compliance Reife (3 Fragen) - comp_training: { risk: 5, complexity: 4, assurance: 7 }, - comp_vendor_management: { risk: 6, complexity: 6, assurance: 7 }, - comp_documentation_level: { risk: 6, complexity: 7, assurance: 8 }, -} - -// ============================================================================ -// ANSWER MULTIPLIERS FÜR SINGLE-CHOICE FRAGEN -// ============================================================================ - -export const ANSWER_MULTIPLIERS: Record> = { - org_employee_count: { - '1-9': 0.1, - '10-49': 0.3, - '50-249': 0.5, - '250-999': 0.7, - '1000+': 1.0, - }, - org_industry: { - tech: 0.4, - finance: 0.8, - healthcare: 0.9, - public: 0.7, - retail: 0.5, - education: 0.6, - other: 0.3, - }, - org_business_model: { - b2b: 0.4, - b2c: 0.7, - b2b2c: 0.6, - internal: 0.3, - }, - org_customer_count: { - '0-100': 0.1, - '100-1000': 0.2, - '1000-10000': 0.4, - '10000-100000': 0.7, - '100000+': 1.0, - }, - data_volume: { - '<1000': 0.1, - '1000-10000': 0.2, - '10000-100000': 0.4, - '100000-1000000': 0.7, - '>1000000': 1.0, - }, - data_retention_years: { - '<1': 0.2, - '1-3': 0.4, - '3-5': 0.6, - '5-10': 0.8, - '>10': 1.0, - }, - tech_hosting_location: { - eu: 0.2, - eu_us_adequacy: 0.4, - us_adequacy: 0.6, - drittland: 1.0, - }, - tech_access_control: { - none: 1.0, - basic: 0.6, - rbac: 0.3, - advanced: 0.1, - }, - tech_logging: { - none: 1.0, - basic: 0.6, - comprehensive: 0.2, - }, - tech_backup_recovery: { - none: 1.0, - basic: 0.5, - tested: 0.2, - }, - comp_documentation_level: { - none: 1.0, - basic: 0.6, - structured: 0.3, - comprehensive: 0.1, - }, -} - -// ============================================================================ -// 50 HARD TRIGGER RULES -// ============================================================================ - -export const HARD_TRIGGER_RULES: HardTriggerRule[] = [ - // ========== A: Art. 9 Besondere Kategorien (9 rules) ========== - { - id: 'HT-A01', - category: 'art9', - questionId: 'data_art9', - condition: 'CONTAINS', - conditionValue: 'gesundheit', - minimumLevel: 'L3', - requiresDSFA: true, - mandatoryDocuments: ['VVT', 'TOM', 'DSFA'], - legalReference: 'Art. 9 Abs. 1 DSGVO', - description: 'Verarbeitung von Gesundheitsdaten', - }, - { - id: 'HT-A02', - category: 'art9', - questionId: 'data_art9', - condition: 'CONTAINS', - conditionValue: 'biometrie', - minimumLevel: 'L3', - requiresDSFA: true, - mandatoryDocuments: ['VVT', 'TOM', 'DSFA'], - legalReference: 'Art. 9 Abs. 1 DSGVO', - description: 'Verarbeitung biometrischer Daten zur eindeutigen Identifizierung', - }, - { - id: 'HT-A03', - category: 'art9', - questionId: 'data_art9', - condition: 'CONTAINS', - conditionValue: 'genetik', - minimumLevel: 'L3', - requiresDSFA: true, - mandatoryDocuments: ['VVT', 'TOM', 'DSFA'], - legalReference: 'Art. 9 Abs. 1 DSGVO', - description: 'Verarbeitung genetischer Daten', - }, - { - id: 'HT-A04', - category: 'art9', - questionId: 'data_art9', - condition: 'CONTAINS', - conditionValue: 'politisch', - minimumLevel: 'L3', - requiresDSFA: true, - mandatoryDocuments: ['VVT', 'TOM', 'DSFA'], - legalReference: 'Art. 9 Abs. 1 DSGVO', - description: 'Verarbeitung politischer Meinungen', - }, - { - id: 'HT-A05', - category: 'art9', - questionId: 'data_art9', - condition: 'CONTAINS', - conditionValue: 'religion', - minimumLevel: 'L3', - requiresDSFA: true, - mandatoryDocuments: ['VVT', 'TOM', 'DSFA'], - legalReference: 'Art. 9 Abs. 1 DSGVO', - description: 'Verarbeitung religiöser oder weltanschaulicher Überzeugungen', - }, - { - id: 'HT-A06', - category: 'art9', - questionId: 'data_art9', - condition: 'CONTAINS', - conditionValue: 'gewerkschaft', - minimumLevel: 'L3', - requiresDSFA: true, - mandatoryDocuments: ['VVT', 'TOM', 'DSFA'], - legalReference: 'Art. 9 Abs. 1 DSGVO', - description: 'Verarbeitung von Gewerkschaftszugehörigkeit', - }, - { - id: 'HT-A07', - category: 'art9', - questionId: 'data_art9', - condition: 'CONTAINS', - conditionValue: 'sexualleben', - minimumLevel: 'L3', - requiresDSFA: true, - mandatoryDocuments: ['VVT', 'TOM', 'DSFA'], - legalReference: 'Art. 9 Abs. 1 DSGVO', - description: 'Verarbeitung von Daten zum Sexualleben oder zur sexuellen Orientierung', - }, - { - id: 'HT-A08', - category: 'art9', - questionId: 'data_art9', - condition: 'CONTAINS', - conditionValue: 'strafrechtlich', - minimumLevel: 'L3', - requiresDSFA: true, - mandatoryDocuments: ['VVT', 'TOM', 'DSFA'], - legalReference: 'Art. 10 DSGVO', - description: 'Verarbeitung strafrechtlicher Verurteilungen', - }, - { - id: 'HT-A09', - category: 'art9', - questionId: 'data_art9', - condition: 'CONTAINS', - conditionValue: 'ethnisch', - minimumLevel: 'L3', - requiresDSFA: true, - mandatoryDocuments: ['VVT', 'TOM', 'DSFA'], - legalReference: 'Art. 9 Abs. 1 DSGVO', - description: 'Verarbeitung der rassischen oder ethnischen Herkunft', - }, - - // ========== B: Vulnerable Gruppen (3 rules) ========== - { - id: 'HT-B01', - category: 'vulnerable', - questionId: 'data_minors', - condition: 'EQUALS', - conditionValue: true, - minimumLevel: 'L3', - requiresDSFA: true, - mandatoryDocuments: ['VVT', 'TOM', 'DSFA', 'DSE'], - legalReference: 'Art. 8 DSGVO', - description: 'Verarbeitung von Daten Minderjähriger', - }, - { - id: 'HT-B02', - category: 'vulnerable', - questionId: 'data_minors', - condition: 'EQUALS', - conditionValue: true, - minimumLevel: 'L4', - requiresDSFA: true, - mandatoryDocuments: ['VVT', 'TOM', 'DSFA', 'DSE'], - legalReference: 'Art. 8 + Art. 9 DSGVO', - description: 'Verarbeitung besonderer Kategorien von Daten Minderjähriger', - combineWithArt9: true, - }, - { - id: 'HT-B03', - category: 'vulnerable', - questionId: 'data_minors', - condition: 'EQUALS', - conditionValue: true, - minimumLevel: 'L4', - requiresDSFA: true, - mandatoryDocuments: ['VVT', 'TOM', 'DSFA', 'AI_ACT_DOKU'], - legalReference: 'Art. 8 DSGVO + AI Act', - description: 'KI-gestützte Verarbeitung von Daten Minderjähriger', - combineWithAI: true, - }, - - // ========== C: ADM/KI (6 rules) ========== - { - id: 'HT-C01', - category: 'adm', - questionId: 'proc_adm_scoring', - condition: 'EQUALS', - conditionValue: true, - minimumLevel: 'L3', - requiresDSFA: true, - mandatoryDocuments: ['VVT', 'TOM', 'DSFA'], - legalReference: 'Art. 22 DSGVO', - description: 'Automatisierte Einzelentscheidung mit Rechtswirkung oder erheblicher Beeinträchtigung', - }, - { - id: 'HT-C02', - category: 'adm', - questionId: 'proc_ai_usage', - condition: 'CONTAINS', - conditionValue: 'autonom', - minimumLevel: 'L3', - requiresDSFA: true, - mandatoryDocuments: ['VVT', 'TOM', 'DSFA', 'AI_ACT_DOKU'], - legalReference: 'Art. 22 DSGVO + AI Act', - description: 'Autonome KI-Systeme mit Entscheidungsbefugnis', - }, - { - id: 'HT-C03', - category: 'adm', - questionId: 'proc_ai_usage', - condition: 'CONTAINS', - conditionValue: 'scoring', - minimumLevel: 'L2', - requiresDSFA: false, - mandatoryDocuments: ['VVT', 'TOM'], - legalReference: 'Art. 22 DSGVO', - description: 'KI-gestütztes Scoring', - }, - { - id: 'HT-C04', - category: 'adm', - questionId: 'proc_ai_usage', - condition: 'CONTAINS', - conditionValue: 'profiling', - minimumLevel: 'L3', - requiresDSFA: true, - mandatoryDocuments: ['VVT', 'TOM', 'DSFA'], - legalReference: 'Art. 22 DSGVO', - description: 'KI-gestütztes Profiling mit erheblicher Wirkung', - }, - { - id: 'HT-C05', - category: 'adm', - questionId: 'proc_ai_usage', - condition: 'CONTAINS', - conditionValue: 'generativ', - minimumLevel: 'L2', - requiresDSFA: false, - mandatoryDocuments: ['VVT', 'TOM', 'AI_ACT_DOKU'], - legalReference: 'AI Act', - description: 'Generative KI-Systeme', - }, - { - id: 'HT-C06', - category: 'adm', - questionId: 'proc_ai_usage', - condition: 'CONTAINS', - conditionValue: 'chatbot', - minimumLevel: 'L2', - requiresDSFA: false, - mandatoryDocuments: ['VVT', 'AI_ACT_DOKU'], - legalReference: 'AI Act', - description: 'Chatbots mit Personendatenverarbeitung', - }, - - // ========== D: Überwachung (5 rules) ========== - { - id: 'HT-D01', - category: 'surveillance', - questionId: 'proc_video_surveillance', - condition: 'EQUALS', - conditionValue: true, - minimumLevel: 'L2', - requiresDSFA: false, - mandatoryDocuments: ['VVT', 'TOM', 'DSE'], - legalReference: 'Art. 6 DSGVO', - description: 'Videoüberwachung', - }, - { - id: 'HT-D02', - category: 'surveillance', - questionId: 'proc_employee_monitoring', - condition: 'EQUALS', - conditionValue: true, - minimumLevel: 'L2', - requiresDSFA: false, - mandatoryDocuments: ['VVT', 'TOM', 'DSFA'], - legalReference: 'Art. 88 DSGVO + BetrVG', - description: 'Mitarbeiterüberwachung', - }, - { - id: 'HT-D03', - category: 'surveillance', - questionId: 'proc_tracking', - condition: 'EQUALS', - conditionValue: true, - minimumLevel: 'L2', - requiresDSFA: false, - mandatoryDocuments: ['VVT', 'TOM', 'COOKIE_BANNER', 'EINWILLIGUNGEN'], - legalReference: 'Art. 6 DSGVO + ePrivacy', - description: 'Online-Tracking', - }, - { - id: 'HT-D04', - category: 'surveillance', - questionId: 'proc_video_surveillance', - condition: 'EQUALS', - conditionValue: true, - minimumLevel: 'L3', - requiresDSFA: true, - mandatoryDocuments: ['VVT', 'TOM', 'DSFA'], - legalReference: 'Art. 35 Abs. 3 DSGVO', - description: 'Videoüberwachung kombiniert mit Mitarbeitermonitoring', - combineWithEmployeeMonitoring: true, - }, - { - id: 'HT-D05', - category: 'surveillance', - questionId: 'proc_video_surveillance', - condition: 'EQUALS', - conditionValue: true, - minimumLevel: 'L3', - requiresDSFA: true, - mandatoryDocuments: ['VVT', 'TOM', 'DSFA'], - legalReference: 'Art. 35 Abs. 3 DSGVO', - description: 'Videoüberwachung kombiniert mit automatisierter Bewertung', - combineWithADM: true, - }, - - // ========== E: Drittland (5 rules) ========== - { - id: 'HT-E01', - category: 'third_country', - questionId: 'tech_third_country', - condition: 'EQUALS', - conditionValue: true, - minimumLevel: 'L2', - requiresDSFA: false, - mandatoryDocuments: ['VVT', 'TRANSFER_DOKU'], - legalReference: 'Art. 44 ff. DSGVO', - description: 'Datenübermittlung in Drittland', - }, - { - id: 'HT-E02', - category: 'third_country', - questionId: 'tech_hosting_location', - condition: 'EQUALS', - conditionValue: 'drittland', - minimumLevel: 'L2', - requiresDSFA: false, - mandatoryDocuments: ['VVT', 'TOM', 'TRANSFER_DOKU'], - legalReference: 'Art. 44 ff. DSGVO', - description: 'Hosting in Drittland', - }, - { - id: 'HT-E03', - category: 'third_country', - questionId: 'tech_hosting_location', - condition: 'EQUALS', - conditionValue: 'us_adequacy', - minimumLevel: 'L2', - requiresDSFA: false, - mandatoryDocuments: ['TRANSFER_DOKU'], - legalReference: 'Art. 45 DSGVO', - description: 'Hosting in USA mit Angemessenheitsbeschluss', - }, - { - id: 'HT-E04', - category: 'third_country', - questionId: 'tech_third_country', - condition: 'EQUALS', - conditionValue: true, - minimumLevel: 'L3', - requiresDSFA: false, - mandatoryDocuments: ['VVT', 'TOM', 'TRANSFER_DOKU', 'DSFA'], - legalReference: 'Art. 44 ff. + Art. 9 DSGVO', - description: 'Drittlandtransfer besonderer Kategorien', - combineWithArt9: true, - }, - { - id: 'HT-E05', - category: 'third_country', - questionId: 'tech_third_country', - condition: 'EQUALS', - conditionValue: true, - minimumLevel: 'L3', - requiresDSFA: false, - mandatoryDocuments: ['VVT', 'TOM', 'TRANSFER_DOKU', 'DSFA'], - legalReference: 'Art. 44 ff. + Art. 8 DSGVO', - description: 'Drittlandtransfer von Daten Minderjähriger', - combineWithMinors: true, - }, - - // ========== F: Zertifizierung (5 rules) ========== - { - id: 'HT-F01', - category: 'certification', - questionId: 'org_cert_target', - condition: 'CONTAINS', - conditionValue: 'ISO27001', - minimumLevel: 'L4', - requiresDSFA: false, - mandatoryDocuments: ['TOM', 'AUDIT_CHECKLIST'], - legalReference: 'ISO/IEC 27001', - description: 'Angestrebte ISO 27001 Zertifizierung', - }, - { - id: 'HT-F02', - category: 'certification', - questionId: 'org_cert_target', - condition: 'CONTAINS', - conditionValue: 'ISO27701', - minimumLevel: 'L4', - requiresDSFA: false, - mandatoryDocuments: ['TOM', 'VVT', 'AUDIT_CHECKLIST'], - legalReference: 'ISO/IEC 27701', - description: 'Angestrebte ISO 27701 Zertifizierung', - }, - { - id: 'HT-F03', - category: 'certification', - questionId: 'org_cert_target', - condition: 'CONTAINS', - conditionValue: 'SOC2', - minimumLevel: 'L4', - requiresDSFA: false, - mandatoryDocuments: ['TOM', 'AUDIT_CHECKLIST'], - legalReference: 'SOC 2 Type II', - description: 'Angestrebte SOC 2 Zertifizierung', - }, - { - id: 'HT-F04', - category: 'certification', - questionId: 'org_cert_target', - condition: 'CONTAINS', - conditionValue: 'TISAX', - minimumLevel: 'L4', - requiresDSFA: false, - mandatoryDocuments: ['TOM', 'AUDIT_CHECKLIST', 'VENDOR_MANAGEMENT'], - legalReference: 'TISAX', - description: 'Angestrebte TISAX Zertifizierung', - }, - { - id: 'HT-F05', - category: 'certification', - questionId: 'org_cert_target', - condition: 'CONTAINS', - conditionValue: 'BSI-Grundschutz', - minimumLevel: 'L4', - requiresDSFA: false, - mandatoryDocuments: ['TOM', 'AUDIT_CHECKLIST'], - legalReference: 'BSI IT-Grundschutz', - description: 'Angestrebte BSI-Grundschutz Zertifizierung', - }, - - // ========== G: Volumen/Skala (5 rules) ========== - { - id: 'HT-G01', - category: 'scale', - questionId: 'data_volume', - condition: 'EQUALS', - conditionValue: '>1000000', - minimumLevel: 'L3', - requiresDSFA: false, - mandatoryDocuments: ['VVT', 'TOM', 'LOESCHKONZEPT'], - legalReference: 'Art. 35 Abs. 3 lit. b DSGVO', - description: 'Umfangreiche Verarbeitung personenbezogener Daten (>1 Mio. Datensätze)', - }, - { - id: 'HT-G02', - category: 'scale', - questionId: 'data_volume', - condition: 'EQUALS', - conditionValue: '100000-1000000', - minimumLevel: 'L2', - requiresDSFA: false, - mandatoryDocuments: ['VVT', 'TOM'], - legalReference: 'Art. 35 Abs. 3 lit. b DSGVO', - description: 'Großvolumige Datenverarbeitung (100k-1M Datensätze)', - }, - { - id: 'HT-G03', - category: 'scale', - questionId: 'org_customer_count', - condition: 'EQUALS', - conditionValue: '100000+', - minimumLevel: 'L3', - requiresDSFA: false, - mandatoryDocuments: ['VVT', 'TOM', 'DSR_PROZESS'], - legalReference: 'Art. 15-22 DSGVO', - description: 'Großer Kundenstamm (>100k) mit hoher Betroffenenanzahl', - }, - { - id: 'HT-G04', - category: 'scale', - questionId: 'org_employee_count', - condition: 'GREATER_THAN', - conditionValue: 249, - minimumLevel: 'L3', - requiresDSFA: false, - mandatoryDocuments: ['VVT', 'TOM', 'LOESCHKONZEPT', 'NOTFALLPLAN'], - legalReference: 'Art. 37 DSGVO', - description: 'Große Organisation (>250 Mitarbeiter) mit erhöhten Compliance-Anforderungen', - }, - { - id: 'HT-G05', - category: 'scale', - questionId: 'org_employee_count', - condition: 'GREATER_THAN', - conditionValue: 999, - minimumLevel: 'L4', - requiresDSFA: false, - mandatoryDocuments: ['VVT', 'TOM', 'DSFA', 'LOESCHKONZEPT'], - legalReference: 'Art. 35 + Art. 37 DSGVO', - description: 'Sehr große Organisation (>1000 Mitarbeiter) mit Art. 9 Daten', - combineWithArt9: true, - }, - - // ========== H: Produkt/Business (7 rules) ========== - { - id: 'HT-H01a', - category: 'product', - questionId: 'prod_webshop', - condition: 'EQUALS', - conditionValue: true, - excludeWhen: { questionId: 'org_business_model', value: 'B2B' }, - minimumLevel: 'L2', - requiresDSFA: false, - mandatoryDocuments: ['DSE', 'AGB', 'COOKIE_BANNER', 'EINWILLIGUNGEN', - 'WIDERRUFSBELEHRUNG', 'PREISANGABEN', 'FERNABSATZ_INFO', 'STREITBEILEGUNG'], - legalReference: 'Art. 6 DSGVO + Fernabsatzrecht + PAngV + VSBG', - description: 'E-Commerce / Webshop (B2C) — Verbraucherschutzpflichten', - }, - { - id: 'HT-H01b', - category: 'product', - questionId: 'prod_webshop', - condition: 'EQUALS', - conditionValue: true, - requireWhen: { questionId: 'org_business_model', value: 'B2B' }, - minimumLevel: 'L2', - requiresDSFA: false, - mandatoryDocuments: ['DSE', 'AGB', 'COOKIE_BANNER'], - legalReference: 'Art. 6 DSGVO + eCommerce', - description: 'E-Commerce / Webshop (B2B) — Basis-Pflichten', - }, - { - id: 'HT-H02', - category: 'product', - questionId: 'prod_data_broker', - condition: 'EQUALS', - conditionValue: true, - minimumLevel: 'L3', - requiresDSFA: true, - mandatoryDocuments: ['VVT', 'TOM', 'DSFA', 'EINWILLIGUNGEN'], - legalReference: 'Art. 35 Abs. 3 DSGVO', - description: 'Datenhandel oder Datenmakler-Tätigkeit', - }, - { - id: 'HT-H03', - category: 'product', - questionId: 'prod_api_external', - condition: 'EQUALS', - conditionValue: true, - minimumLevel: 'L2', - requiresDSFA: false, - mandatoryDocuments: ['TOM', 'AVV'], - legalReference: 'Art. 28 DSGVO', - description: 'Externe API mit Datenweitergabe', - }, - { - id: 'HT-H04', - category: 'product', - questionId: 'org_business_model', - condition: 'EQUALS', - conditionValue: 'b2c', - minimumLevel: 'L2', - requiresDSFA: false, - mandatoryDocuments: ['DSE', 'COOKIE_BANNER', 'EINWILLIGUNGEN'], - legalReference: 'Art. 6 DSGVO', - description: 'B2C-Geschäftsmodell mit Endkundenkontakt', - }, - { - id: 'HT-H05', - category: 'product', - questionId: 'org_industry', - condition: 'EQUALS', - conditionValue: 'finance', - minimumLevel: 'L2', - requiresDSFA: false, - mandatoryDocuments: ['VVT', 'TOM'], - legalReference: 'Art. 6 DSGVO + Finanzaufsicht', - description: 'Finanzbranche mit erhöhten regulatorischen Anforderungen', - }, - { - id: 'HT-H06', - category: 'product', - questionId: 'org_industry', - condition: 'EQUALS', - conditionValue: 'healthcare', - minimumLevel: 'L3', - requiresDSFA: true, - mandatoryDocuments: ['VVT', 'TOM', 'DSFA'], - legalReference: 'Art. 9 DSGVO + Gesundheitsrecht', - description: 'Gesundheitsbranche mit sensiblen Daten', - }, - { - id: 'HT-H07', - category: 'product', - questionId: 'org_industry', - condition: 'EQUALS', - conditionValue: 'public', - minimumLevel: 'L2', - requiresDSFA: false, - mandatoryDocuments: ['VVT', 'TOM', 'DSR_PROZESS'], - legalReference: 'Art. 6 Abs. 1 lit. e DSGVO', - description: 'Öffentlicher Sektor', - }, - - // ========== I: Prozessreife - Gap Flags (5 rules) ========== - { - id: 'HT-I01', - category: 'process_maturity', - questionId: 'proc_dsar_process', - condition: 'EQUALS', - conditionValue: false, - minimumLevel: 'L1', - requiresDSFA: false, - mandatoryDocuments: [], - legalReference: 'Art. 15-22 DSGVO', - description: 'Fehlender Prozess für Betroffenenrechte', - }, - { - id: 'HT-I02', - category: 'process_maturity', - questionId: 'proc_deletion_concept', - condition: 'EQUALS', - conditionValue: false, - minimumLevel: 'L1', - requiresDSFA: false, - mandatoryDocuments: [], - legalReference: 'Art. 17 DSGVO', - description: 'Fehlendes Löschkonzept', - }, - { - id: 'HT-I03', - category: 'process_maturity', - questionId: 'proc_incident_response', - condition: 'EQUALS', - conditionValue: false, - minimumLevel: 'L1', - requiresDSFA: false, - mandatoryDocuments: [], - legalReference: 'Art. 33 DSGVO', - description: 'Fehlender Incident-Response-Prozess', - }, - { - id: 'HT-I04', - category: 'process_maturity', - questionId: 'proc_regular_audits', - condition: 'EQUALS', - conditionValue: false, - minimumLevel: 'L1', - requiresDSFA: false, - mandatoryDocuments: [], - legalReference: 'Art. 24 DSGVO', - description: 'Fehlende regelmäßige Audits', - }, - { - id: 'HT-I05', - category: 'process_maturity', - questionId: 'comp_training', - condition: 'EQUALS', - conditionValue: false, - minimumLevel: 'L1', - requiresDSFA: false, - mandatoryDocuments: [], - legalReference: 'Art. 39 Abs. 1 lit. b DSGVO', - description: 'Fehlende Schulungen zum Datenschutz', - }, - - // ========== J: IACE — AI Act Produkt-Triggers (3 rules) ========== - { - id: 'HT-J01', - category: 'iace_ai_act_product', - questionId: 'machineBuilder.containsAI', - condition: 'EQUALS', - conditionValue: true, - minimumLevel: 'L3', - requiresDSFA: false, - mandatoryDocuments: ['VVT', 'TOM'], - legalReference: 'EU AI Act Annex I + EU Maschinenverordnung 2023/1230', - description: 'KI mit Sicherheitsfunktion in Maschine → AI Act High-Risk', - combineWithMachineBuilder: { field: 'hasSafetyFunction', value: true }, - riskWeight: 9, - }, - { - id: 'HT-J02', - category: 'iace_ai_act_product', - questionId: 'machineBuilder.containsAI', - condition: 'EQUALS', - conditionValue: true, - minimumLevel: 'L3', - requiresDSFA: false, - mandatoryDocuments: ['VVT', 'TOM'], - legalReference: 'EU AI Act + EU Maschinenverordnung 2023/1230', - description: 'Autonome KI in Maschine → AI Act + Maschinenverordnung', - combineWithMachineBuilder: { field: 'autonomousBehavior', value: true }, - riskWeight: 8, - }, - { - id: 'HT-J03', - category: 'iace_ai_act_product', - questionId: 'machineBuilder.hasSafetyFunction', - condition: 'EQUALS', - conditionValue: true, - minimumLevel: 'L3', - requiresDSFA: false, - mandatoryDocuments: ['VVT', 'TOM'], - legalReference: 'EU AI Act Annex III', - description: 'KI-Bildverarbeitung mit Sicherheitsbezug', - combineWithMachineBuilder: { field: 'aiIntegrationType', includes: 'vision' }, - riskWeight: 8, - }, - - // ========== K: IACE — CRA Triggers (3 rules) ========== - { - id: 'HT-K01', - category: 'iace_cra', - questionId: 'machineBuilder.isNetworked', - condition: 'EQUALS', - conditionValue: true, - minimumLevel: 'L2', - requiresDSFA: false, - mandatoryDocuments: ['TOM'], - legalReference: 'EU Cyber Resilience Act (CRA)', - description: 'Vernetztes Produkt → Cyber Resilience Act', - riskWeight: 6, - }, - { - id: 'HT-K02', - category: 'iace_cra', - questionId: 'machineBuilder.hasRemoteAccess', - condition: 'EQUALS', - conditionValue: true, - minimumLevel: 'L2', - requiresDSFA: false, - mandatoryDocuments: ['TOM'], - legalReference: 'CRA + NIS2 Art. 21', - description: 'Remote-Zugriff → CRA + NIS2 Supply Chain', - riskWeight: 7, - }, - { - id: 'HT-K03', - category: 'iace_cra', - questionId: 'machineBuilder.hasOTAUpdates', - condition: 'EQUALS', - conditionValue: true, - minimumLevel: 'L2', - requiresDSFA: false, - mandatoryDocuments: ['TOM'], - legalReference: 'CRA Art. 10 - Patch Management', - description: 'OTA-Updates → CRA Patch Management Pflicht', - riskWeight: 7, - }, - - // ========== L: IACE — NIS2 indirekt (2 rules) ========== - { - id: 'HT-L01', - category: 'iace_nis2_indirect', - questionId: 'machineBuilder.criticalSectorClients', - condition: 'EQUALS', - conditionValue: true, - minimumLevel: 'L2', - requiresDSFA: false, - mandatoryDocuments: ['TOM'], - legalReference: 'NIS2 Art. 21 - Supply Chain', - description: 'Lieferant an KRITIS → NIS2 Supply Chain Anforderungen', - riskWeight: 7, - }, - { - id: 'HT-L02', - category: 'iace_nis2_indirect', - questionId: 'machineBuilder.oemClients', - condition: 'EQUALS', - conditionValue: true, - minimumLevel: 'L2', - requiresDSFA: false, - mandatoryDocuments: [], - legalReference: 'NIS2 + EU Maschinenverordnung', - description: 'OEM-Zulieferer → Compliance-Nachweispflicht', - riskWeight: 5, - }, - - // ========== M: IACE — Maschinenverordnung Triggers (4 rules) ========== - { - id: 'HT-M01', - category: 'iace_machinery_regulation', - questionId: 'machineBuilder.containsSoftware', - condition: 'EQUALS', - conditionValue: true, - minimumLevel: 'L3', - requiresDSFA: false, - mandatoryDocuments: ['TOM'], - legalReference: 'EU Maschinenverordnung 2023/1230 Anhang III', - description: 'Software als Sicherheitskomponente → Maschinenverordnung', - combineWithMachineBuilder: { field: 'hasSafetyFunction', value: true }, - riskWeight: 9, - }, - { - id: 'HT-M02', - category: 'iace_machinery_regulation', - questionId: 'machineBuilder.ceMarkingRequired', - condition: 'EQUALS', - conditionValue: true, - minimumLevel: 'L2', - requiresDSFA: false, - mandatoryDocuments: [], - legalReference: 'EU Maschinenverordnung 2023/1230', - description: 'CE-Kennzeichnung erforderlich', - riskWeight: 6, - }, - { - id: 'HT-M03', - category: 'iace_machinery_regulation', - questionId: 'machineBuilder.ceMarkingRequired', - condition: 'EQUALS', - conditionValue: true, - minimumLevel: 'L3', - requiresDSFA: false, - mandatoryDocuments: [], - legalReference: 'EU Maschinenverordnung 2023/1230 Art. 10', - description: 'CE ohne bestehende Risikobeurteilung → Dringend!', - combineWithMachineBuilder: { field: 'hasRiskAssessment', value: false }, - riskWeight: 9, - }, - { - id: 'HT-M04', - category: 'iace_machinery_regulation', - questionId: 'machineBuilder.containsFirmware', - condition: 'EQUALS', - conditionValue: true, - minimumLevel: 'L2', - requiresDSFA: false, - mandatoryDocuments: ['TOM'], - legalReference: 'EU Maschinenverordnung + CRA', - description: 'Firmware mit Remote-Update → Change Management Pflicht', - combineWithMachineBuilder: { field: 'hasOTAUpdates', value: true }, - riskWeight: 7, - }, -] +import { QUESTION_SCORE_WEIGHTS, ANSWER_MULTIPLIERS } from './compliance-scope-data' +import { HARD_TRIGGER_RULES } from './compliance-scope-triggers' +import { + parseEmployeeCount, + getLevelFromScore, + getMaxTriggerLevel, + buildDocumentScope, + evaluateRiskFlags, + calculateGaps, + buildNextActions, + buildReasoning, +} from './compliance-scope-documents' // ============================================================================ // COMPLIANCE SCOPE ENGINE @@ -1101,7 +162,6 @@ export class ComplianceScopeEngine { // Multi choice if (Array.isArray(value)) { if (value.length === 0) return 0.0 - // Simplified: count selected items return Math.min(value.length / 5, 1.0) } @@ -1111,12 +171,10 @@ export class ComplianceScopeEngine { /** * Normalisiert numerische Antworten */ - private normalizeNumericAnswer(questionId: string, value: number): number { - // Hier könnten spezifische Ranges definiert werden - // Vereinfacht: logarithmische Normalisierung + private normalizeNumericAnswer(_questionId: string, value: number): number { if (value <= 0) return 0.0 if (value >= 1000) return 1.0 - return Math.log10(value + 1) / 3 // 0-1000 → ~0-1 + return Math.log10(value + 1) / 3 } /** @@ -1156,7 +214,7 @@ export class ComplianceScopeEngine { /** * Prüft, ob eine Trigger-Regel erfüllt ist */ - private checkTriggerCondition( + checkTriggerCondition( rule: HardTriggerRule, answerMap: Map, answers: ScopeProfilingAnswer[], @@ -1187,7 +245,6 @@ export class ComplianceScopeEngine { if (!baseCondition) return false - // combineWithMachineBuilder: additional AND condition on another MB field const combine = (rule as any).combineWithMachineBuilder if (combine) { const combineVal = this.getMachineBuilderValue(mb, combine.field) @@ -1204,7 +261,6 @@ export class ComplianceScopeEngine { const value = answerMap.get(rule.questionId) if (value === undefined) return false - // Basis-Check let baseCondition = false switch (rule.condition) { @@ -1227,8 +283,7 @@ export class ComplianceScopeEngine { if (typeof value === 'number' && typeof rule.conditionValue === 'number') { baseCondition = value > rule.conditionValue } else if (typeof value === 'string') { - // Parse employee count from string like "1000+" - const parsed = this.parseEmployeeCount(value) + const parsed = parseEmployeeCount(value) baseCondition = parsed > (rule.conditionValue as number) } break @@ -1239,7 +294,7 @@ export class ComplianceScopeEngine { if (!baseCondition) return false - // Exclude-Bedingung: Regel feuert NICHT wenn excludeWhen zutrifft + // Exclude-Bedingung if (rule.excludeWhen) { const exVal = answerMap.get(rule.excludeWhen.questionId) if (Array.isArray(rule.excludeWhen.value) @@ -1249,7 +304,7 @@ export class ComplianceScopeEngine { } } - // Require-Bedingung: Regel feuert NUR wenn requireWhen zutrifft + // Require-Bedingung if (rule.requireWhen) { const reqVal = answerMap.get(rule.requireWhen.questionId) if (Array.isArray(rule.requireWhen.value) @@ -1290,18 +345,6 @@ export class ComplianceScopeEngine { return true } - /** - * Parsed Mitarbeiterzahl aus String - */ - private parseEmployeeCount(value: string): number { - if (value === '1-9') return 9 - if (value === '10-49') return 49 - if (value === '50-249') return 249 - if (value === '250-999') return 999 - if (value === '1000+') return 1000 - return 0 - } - /** * Bestimmt das finale Compliance-Level basierend auf Scores und Triggers */ @@ -1309,498 +352,50 @@ export class ComplianceScopeEngine { scores: ComplianceScores, triggers: TriggeredHardTrigger[] ): ComplianceDepthLevel { - // Score-basiertes Level - let levelFromScore: ComplianceDepthLevel - if (scores.composite_score <= 25) levelFromScore = 'L1' - else if (scores.composite_score <= 50) levelFromScore = 'L2' - else if (scores.composite_score <= 75) levelFromScore = 'L3' - else levelFromScore = 'L4' - - // Höchstes Level aus Triggers - let maxTriggerLevel: ComplianceDepthLevel = 'L1' - for (const trigger of triggers) { - if (getDepthLevelNumeric(trigger.minimumLevel) > getDepthLevelNumeric(maxTriggerLevel)) { - maxTriggerLevel = trigger.minimumLevel - } - } - - // Maximum von beiden + const levelFromScore = getLevelFromScore(scores.composite_score) + const maxTriggerLevel = getMaxTriggerLevel(triggers) return maxDepthLevel(levelFromScore, maxTriggerLevel) } - /** - * Normalisiert UPPERCASE Dokumenttyp-Bezeichner aus den Hard-Trigger-Rules - * auf die lowercase ScopeDocumentType-Schlüssel. - */ - private normalizeDocType(raw: string): ScopeDocumentType | null { - const mapping: Record = { - VVT: 'vvt', - TOM: 'tom', - DSFA: 'dsfa', - DSE: 'dsi', - AGB: 'vertragsmanagement', - AVV: 'av_vertrag', - COOKIE_BANNER: 'einwilligung', - EINWILLIGUNGEN: 'einwilligung', - TRANSFER_DOKU: 'daten_transfer', - AUDIT_CHECKLIST: 'audit_log', - VENDOR_MANAGEMENT: 'vertragsmanagement', - LOESCHKONZEPT: 'lf', - DSR_PROZESS: 'betroffenenrechte', - NOTFALLPLAN: 'notfallplan', - AI_ACT_DOKU: 'ai_act_doku', - WIDERRUFSBELEHRUNG: 'widerrufsbelehrung', - PREISANGABEN: 'preisangaben', - FERNABSATZ_INFO: 'fernabsatz_info', - STREITBEILEGUNG: 'streitbeilegung', - PRODUKTSICHERHEIT: 'produktsicherheit', - } - // Falls raw bereits ein gueltiger ScopeDocumentType ist - if (raw in DOCUMENT_SCOPE_MATRIX) return raw as ScopeDocumentType - return mapping[raw] ?? null - } + // Delegate to extracted helpers (keep public API surface identical) - /** - * Baut den Dokumenten-Scope basierend auf Level und Triggers - */ buildDocumentScope( level: ComplianceDepthLevel, triggers: TriggeredHardTrigger[], answers: ScopeProfilingAnswer[] ): RequiredDocument[] { - const requiredDocs: RequiredDocument[] = [] - const mandatoryFromTriggers = new Set() - // Mapping: normalisierter DocType → original Rule-Strings (fuer triggeredBy Lookup) - const triggerDocOrigins = new Map() - - // Sammle mandatory docs aus Triggern (normalisiert) - for (const trigger of triggers) { - for (const doc of trigger.mandatoryDocuments) { - const normalized = this.normalizeDocType(doc) - if (normalized) { - mandatoryFromTriggers.add(normalized) - if (!triggerDocOrigins.has(normalized)) triggerDocOrigins.set(normalized, []) - triggerDocOrigins.get(normalized)!.push(doc) - } - } - } - - // Für jeden Dokumenttyp prüfen - for (const docType of Object.keys(DOCUMENT_SCOPE_MATRIX) as ScopeDocumentType[]) { - const requirement = DOCUMENT_SCOPE_MATRIX[docType][level] - const isMandatoryFromTrigger = mandatoryFromTriggers.has(docType) - - if (requirement === 'mandatory' || isMandatoryFromTrigger) { - const originDocs = triggerDocOrigins.get(docType) ?? [] - requiredDocs.push({ - documentType: docType, - label: DOCUMENT_TYPE_LABELS[docType], - requirement: 'mandatory', - priority: this.getDocumentPriority(docType, isMandatoryFromTrigger), - estimatedEffort: this.estimateEffort(docType), - sdkStepUrl: DOCUMENT_SDK_STEP_MAP[docType], - triggeredBy: isMandatoryFromTrigger - ? triggers - .filter((t) => t.mandatoryDocuments.some((d) => originDocs.includes(d))) - .map((t) => t.ruleId) - : [], - }) - } else if (requirement === 'recommended') { - requiredDocs.push({ - documentType: docType, - label: DOCUMENT_TYPE_LABELS[docType], - requirement: 'recommended', - priority: 'medium', - estimatedEffort: this.estimateEffort(docType), - sdkStepUrl: DOCUMENT_SDK_STEP_MAP[docType], - triggeredBy: [], - }) - } - } - - // Sortieren: mandatory zuerst, dann nach Priority - requiredDocs.sort((a, b) => { - if (a.requirement === 'mandatory' && b.requirement !== 'mandatory') return -1 - if (a.requirement !== 'mandatory' && b.requirement === 'mandatory') return 1 - - const priorityOrder: Record = { high: 3, medium: 2, low: 1 } - return priorityOrder[b.priority] - priorityOrder[a.priority] - }) - - return requiredDocs + return buildDocumentScope(level, triggers, answers) } - /** - * Bestimmt die Priorität eines Dokuments - */ - private getDocumentPriority( - docType: ScopeDocumentType, - isMandatoryFromTrigger: boolean - ): 'high' | 'medium' | 'low' { - if (isMandatoryFromTrigger) return 'high' - - // Basis-Dokumente haben hohe Priorität - if (['VVT', 'TOM', 'DSE'].includes(docType)) return 'high' - if (['DSFA', 'AVV', 'EINWILLIGUNGEN'].includes(docType)) return 'high' - - return 'medium' - } - - /** - * Schätzt den Aufwand für ein Dokument (in Stunden) - */ - private estimateEffort(docType: ScopeDocumentType): number { - const effortMap: Partial> = { - vvt: 8, - tom: 12, - dsfa: 16, - av_vertrag: 4, - dsi: 6, - einwilligung: 6, - lf: 10, - daten_transfer: 8, - betroffenenrechte: 8, - notfallplan: 12, - vertragsmanagement: 10, - audit_log: 8, - risikoanalyse: 6, - schulung: 4, - datenpannen: 6, - zertifizierung: 8, - datenschutzmanagement: 12, - iace_ce_assessment: 8, - widerrufsbelehrung: 3, - preisangaben: 2, - fernabsatz_info: 4, - streitbeilegung: 1, - produktsicherheit: 8, - ai_act_doku: 12, - } - return effortMap[docType] ?? 6 - } - - /** - * Evaluiert Risk Flags basierend auf Process Maturity Gaps und anderen Risiken - */ evaluateRiskFlags( answers: ScopeProfilingAnswer[], level: ComplianceDepthLevel ): RiskFlag[] { - const flags: RiskFlag[] = [] - const answerMap = new Map(answers.map((a) => [a.questionId, a.value])) - - // Process Maturity Gaps (Kategorie I Trigger) - const maturityRules = HARD_TRIGGER_RULES.filter((r) => r.category === 'process_maturity') - for (const rule of maturityRules) { - if (this.checkTriggerCondition(rule, answerMap, answers)) { - flags.push({ - severity: 'medium', - category: 'process', - message: rule.description, - legalReference: rule.legalReference, - recommendation: this.getMaturityRecommendation(rule.id), - }) - } - } - - // Verschlüsselung fehlt bei L2+ - if (getDepthLevelNumeric(level) >= 2) { - const encTransit = answerMap.get('tech_encryption_transit') - const encRest = answerMap.get('tech_encryption_rest') - - if (encTransit === false) { - flags.push({ - severity: 'high', - category: 'technical', - message: 'Fehlende Verschlüsselung bei Datenübertragung', - legalReference: 'Art. 32 DSGVO', - recommendation: 'TLS 1.2+ für alle Datenübertragungen implementieren', - }) - } - - if (encRest === false) { - flags.push({ - severity: 'high', - category: 'technical', - message: 'Fehlende Verschlüsselung gespeicherter Daten', - legalReference: 'Art. 32 DSGVO', - recommendation: 'Verschlüsselung at-rest für sensitive Daten implementieren', - }) - } - } - - // Drittland ohne adäquate Grundlage - const thirdCountry = answerMap.get('tech_third_country') - const hostingLocation = answerMap.get('tech_hosting_location') - if ( - thirdCountry === true && - hostingLocation !== 'eu' && - hostingLocation !== 'eu_us_adequacy' - ) { - flags.push({ - severity: 'high', - category: 'legal', - message: 'Drittlandtransfer ohne angemessene Garantien', - legalReference: 'Art. 44 ff. DSGVO', - recommendation: - 'Standardvertragsklauseln (SCCs) oder Binding Corporate Rules (BCRs) implementieren', - }) - } - - // Fehlender DSB bei großen Organisationen - const hasDPO = answerMap.get('org_has_dpo') - const employeeCount = answerMap.get('org_employee_count') - if (hasDPO === false && this.parseEmployeeCount(employeeCount as string) >= 250) { - flags.push({ - severity: 'medium', - category: 'organizational', - message: 'Kein Datenschutzbeauftragter bei großer Organisation', - legalReference: 'Art. 37 DSGVO', - recommendation: 'Bestellung eines Datenschutzbeauftragten prüfen', - }) - } - - return flags + return evaluateRiskFlags(answers, level, (rule, answerMap, ans) => + this.checkTriggerCondition(rule, answerMap, ans)) } - /** - * Gibt Empfehlung für Maturity Gap - */ - private getMaturityRecommendation(ruleId: string): string { - const recommendations: Record = { - 'HT-I01': 'Prozess für Betroffenenrechte (DSAR) etablieren und dokumentieren', - 'HT-I02': 'Löschkonzept gemäß Art. 17 DSGVO entwickeln und implementieren', - 'HT-I03': - 'Incident-Response-Plan für Datenschutzverletzungen (Art. 33 DSGVO) erstellen', - 'HT-I04': 'Regelmäßige interne Audits und Reviews einführen', - 'HT-I05': 'Schulungsprogramm für Mitarbeiter zum Datenschutz etablieren', - } - return recommendations[ruleId] || 'Prozess etablieren und dokumentieren' - } - - /** - * Berechnet Gaps zwischen Ist-Zustand und Soll-Anforderungen - */ calculateGaps( answers: ScopeProfilingAnswer[], level: ComplianceDepthLevel ): ScopeGap[] { - const gaps: ScopeGap[] = [] - const answerMap = new Map(answers.map((a) => [a.questionId, a.value])) - - // DSFA Gap (bei L3+) - if (getDepthLevelNumeric(level) >= 3) { - const hasDSFA = answerMap.get('proc_regular_audits') // Proxy - if (hasDSFA === false) { - gaps.push({ - gapType: 'documentation', - severity: 'high', - description: 'Datenschutz-Folgenabschätzung (DSFA) fehlt', - requiredFor: level, - currentState: 'Keine DSFA durchgeführt', - targetState: 'DSFA für Hochrisiko-Verarbeitungen durchgeführt und dokumentiert', - effort: 16, - priority: 'high', - }) - } - } - - // Löschkonzept Gap - const hasDeletion = answerMap.get('proc_deletion_concept') - if (hasDeletion === false && getDepthLevelNumeric(level) >= 2) { - gaps.push({ - gapType: 'process', - severity: 'medium', - description: 'Löschkonzept fehlt', - requiredFor: level, - currentState: 'Kein systematisches Löschkonzept', - targetState: 'Dokumentiertes Löschkonzept mit definierten Fristen', - effort: 10, - priority: 'high', - }) - } - - // DSAR Prozess Gap - const hasDSAR = answerMap.get('proc_dsar_process') - if (hasDSAR === false) { - gaps.push({ - gapType: 'process', - severity: 'high', - description: 'Prozess für Betroffenenrechte fehlt', - requiredFor: level, - currentState: 'Kein etablierter DSAR-Prozess', - targetState: 'Dokumentierter Prozess zur Bearbeitung von Betroffenenrechten', - effort: 8, - priority: 'high', - }) - } - - // Incident Response Gap - const hasIncident = answerMap.get('proc_incident_response') - if (hasIncident === false) { - gaps.push({ - gapType: 'process', - severity: 'high', - description: 'Incident-Response-Plan fehlt', - requiredFor: level, - currentState: 'Kein Prozess für Datenschutzverletzungen', - targetState: 'Dokumentierter Incident-Response-Plan gemäß Art. 33 DSGVO', - effort: 12, - priority: 'high', - }) - } - - // Schulungen Gap - const hasTraining = answerMap.get('comp_training') - if (hasTraining === false && getDepthLevelNumeric(level) >= 2) { - gaps.push({ - gapType: 'organizational', - severity: 'medium', - description: 'Datenschutzschulungen fehlen', - requiredFor: level, - currentState: 'Keine regelmäßigen Schulungen', - targetState: 'Etabliertes Schulungsprogramm für alle Mitarbeiter', - effort: 6, - priority: 'medium', - }) - } - - return gaps + return calculateGaps(answers, level) } - /** - * Baut priorisierte Next Actions aus Required Documents und Gaps - */ buildNextActions( requiredDocuments: RequiredDocument[], gaps: ScopeGap[] ): NextAction[] { - const actions: NextAction[] = [] - - // Dokumente zu Actions - for (const doc of requiredDocuments) { - if (doc.requirement === 'mandatory') { - actions.push({ - actionType: 'create_document', - title: `${doc.label} erstellen`, - description: `Pflichtdokument für Compliance-Level erstellen`, - priority: doc.priority, - estimatedEffort: doc.estimatedEffort, - documentType: doc.documentType, - sdkStepUrl: doc.sdkStepUrl, - blockers: [], - }) - } - } - - // Gaps zu Actions - for (const gap of gaps) { - let actionType: NextAction['actionType'] = 'establish_process' - if (gap.gapType === 'documentation') actionType = 'create_document' - else if (gap.gapType === 'technical') actionType = 'implement_technical' - else if (gap.gapType === 'organizational') actionType = 'organizational_change' - - actions.push({ - actionType, - title: `Gap schließen: ${gap.description}`, - description: `Von "${gap.currentState}" zu "${gap.targetState}"`, - priority: gap.priority, - estimatedEffort: gap.effort, - blockers: [], - }) - } - - // Nach Priority sortieren - const priorityOrder: Record = { high: 3, medium: 2, low: 1 } - actions.sort((a, b) => priorityOrder[b.priority] - priorityOrder[a.priority]) - - return actions + return buildNextActions(requiredDocuments, gaps) } - /** - * Baut Reasoning (Audit Trail) für Transparenz - */ buildReasoning( scores: ComplianceScores, triggers: TriggeredHardTrigger[], level: ComplianceDepthLevel, docs: RequiredDocument[] ): ScopeReasoning[] { - const reasoning: ScopeReasoning[] = [] - - // 1. Score-Berechnung - reasoning.push({ - step: 'score_calculation', - description: 'Risikobasierte Score-Berechnung aus Profiling-Antworten', - factors: [ - `Risiko-Score: ${scores.risk_score}/10`, - `Komplexitäts-Score: ${scores.complexity_score}/10`, - `Assurance-Score: ${scores.assurance_need}/10`, - `Composite Score: ${scores.composite_score}/10`, - ], - impact: `Score-basiertes Level: ${this.getLevelFromScore(scores.composite_score)}`, - }) - - // 2. Hard Trigger Evaluation - if (triggers.length > 0) { - reasoning.push({ - step: 'hard_trigger_evaluation', - description: `${triggers.length} Hard Trigger Rule(s) aktiviert`, - factors: triggers.map( - (t) => `${t.ruleId}: ${t.description}${t.legalReference ? ` (${t.legalReference})` : ''}` - ), - impact: `Höchstes Trigger-Level: ${this.getMaxTriggerLevel(triggers)}`, - }) - } - - // 3. Level-Bestimmung - reasoning.push({ - step: 'level_determination', - description: 'Finales Compliance-Level durch Maximum aus Score und Triggers', - factors: [ - `Score-Level: ${this.getLevelFromScore(scores.composite_score)}`, - `Trigger-Level: ${this.getMaxTriggerLevel(triggers)}`, - ], - impact: `Finales Level: ${level}`, - }) - - // 4. Dokumenten-Scope - const mandatoryDocs = docs.filter((d) => d.requirement === 'mandatory') - reasoning.push({ - step: 'document_scope', - description: `Dokumenten-Scope für ${level} bestimmt`, - factors: [ - `${mandatoryDocs.length} Pflichtdokumente`, - `${docs.length - mandatoryDocs.length} empfohlene Dokumente`, - ], - impact: `Gesamtaufwand: ~${docs.reduce((sum, d) => sum + d.estimatedEffort, 0)} Stunden`, - }) - - return reasoning - } - - /** - * Hilfsfunktion: Level aus Score ableiten - */ - private getLevelFromScore(composite: number): ComplianceDepthLevel { - if (composite <= 25) return 'L1' - if (composite <= 50) return 'L2' - if (composite <= 75) return 'L3' - return 'L4' - } - - /** - * Hilfsfunktion: Höchstes Level aus Triggern - */ - private getMaxTriggerLevel(triggers: TriggeredHardTrigger[]): ComplianceDepthLevel { - if (triggers.length === 0) return 'L1' - let max: ComplianceDepthLevel = 'L1' - for (const t of triggers) { - if (getDepthLevelNumeric(t.minimumLevel) > getDepthLevelNumeric(max)) { - max = t.minimumLevel - } - } - return max + return buildReasoning(scores, triggers, level, docs) } } diff --git a/admin-compliance/lib/sdk/compliance-scope-triggers.ts b/admin-compliance/lib/sdk/compliance-scope-triggers.ts new file mode 100644 index 0000000..56539f2 --- /dev/null +++ b/admin-compliance/lib/sdk/compliance-scope-triggers.ts @@ -0,0 +1,823 @@ +/** + * 50 Hard Trigger Rules — data table. + * + * This file legitimately exceeds 500 LOC because it is a pure data + * definition with no logic. Splitting it further would hurt readability. + */ +import type { HardTriggerRule } from './compliance-scope-types' + +// ============================================================================ +// 50 HARD TRIGGER RULES +// ============================================================================ + +export const HARD_TRIGGER_RULES: HardTriggerRule[] = [ + // ========== A: Art. 9 Besondere Kategorien (9 rules) ========== + { + id: 'HT-A01', + category: 'art9', + questionId: 'data_art9', + condition: 'CONTAINS', + conditionValue: 'gesundheit', + minimumLevel: 'L3', + requiresDSFA: true, + mandatoryDocuments: ['VVT', 'TOM', 'DSFA'], + legalReference: 'Art. 9 Abs. 1 DSGVO', + description: 'Verarbeitung von Gesundheitsdaten', + }, + { + id: 'HT-A02', + category: 'art9', + questionId: 'data_art9', + condition: 'CONTAINS', + conditionValue: 'biometrie', + minimumLevel: 'L3', + requiresDSFA: true, + mandatoryDocuments: ['VVT', 'TOM', 'DSFA'], + legalReference: 'Art. 9 Abs. 1 DSGVO', + description: 'Verarbeitung biometrischer Daten zur eindeutigen Identifizierung', + }, + { + id: 'HT-A03', + category: 'art9', + questionId: 'data_art9', + condition: 'CONTAINS', + conditionValue: 'genetik', + minimumLevel: 'L3', + requiresDSFA: true, + mandatoryDocuments: ['VVT', 'TOM', 'DSFA'], + legalReference: 'Art. 9 Abs. 1 DSGVO', + description: 'Verarbeitung genetischer Daten', + }, + { + id: 'HT-A04', + category: 'art9', + questionId: 'data_art9', + condition: 'CONTAINS', + conditionValue: 'politisch', + minimumLevel: 'L3', + requiresDSFA: true, + mandatoryDocuments: ['VVT', 'TOM', 'DSFA'], + legalReference: 'Art. 9 Abs. 1 DSGVO', + description: 'Verarbeitung politischer Meinungen', + }, + { + id: 'HT-A05', + category: 'art9', + questionId: 'data_art9', + condition: 'CONTAINS', + conditionValue: 'religion', + minimumLevel: 'L3', + requiresDSFA: true, + mandatoryDocuments: ['VVT', 'TOM', 'DSFA'], + legalReference: 'Art. 9 Abs. 1 DSGVO', + description: 'Verarbeitung religiöser oder weltanschaulicher Überzeugungen', + }, + { + id: 'HT-A06', + category: 'art9', + questionId: 'data_art9', + condition: 'CONTAINS', + conditionValue: 'gewerkschaft', + minimumLevel: 'L3', + requiresDSFA: true, + mandatoryDocuments: ['VVT', 'TOM', 'DSFA'], + legalReference: 'Art. 9 Abs. 1 DSGVO', + description: 'Verarbeitung von Gewerkschaftszugehörigkeit', + }, + { + id: 'HT-A07', + category: 'art9', + questionId: 'data_art9', + condition: 'CONTAINS', + conditionValue: 'sexualleben', + minimumLevel: 'L3', + requiresDSFA: true, + mandatoryDocuments: ['VVT', 'TOM', 'DSFA'], + legalReference: 'Art. 9 Abs. 1 DSGVO', + description: 'Verarbeitung von Daten zum Sexualleben oder zur sexuellen Orientierung', + }, + { + id: 'HT-A08', + category: 'art9', + questionId: 'data_art9', + condition: 'CONTAINS', + conditionValue: 'strafrechtlich', + minimumLevel: 'L3', + requiresDSFA: true, + mandatoryDocuments: ['VVT', 'TOM', 'DSFA'], + legalReference: 'Art. 10 DSGVO', + description: 'Verarbeitung strafrechtlicher Verurteilungen', + }, + { + id: 'HT-A09', + category: 'art9', + questionId: 'data_art9', + condition: 'CONTAINS', + conditionValue: 'ethnisch', + minimumLevel: 'L3', + requiresDSFA: true, + mandatoryDocuments: ['VVT', 'TOM', 'DSFA'], + legalReference: 'Art. 9 Abs. 1 DSGVO', + description: 'Verarbeitung der rassischen oder ethnischen Herkunft', + }, + + // ========== B: Vulnerable Gruppen (3 rules) ========== + { + id: 'HT-B01', + category: 'vulnerable', + questionId: 'data_minors', + condition: 'EQUALS', + conditionValue: true, + minimumLevel: 'L3', + requiresDSFA: true, + mandatoryDocuments: ['VVT', 'TOM', 'DSFA', 'DSE'], + legalReference: 'Art. 8 DSGVO', + description: 'Verarbeitung von Daten Minderjähriger', + }, + { + id: 'HT-B02', + category: 'vulnerable', + questionId: 'data_minors', + condition: 'EQUALS', + conditionValue: true, + minimumLevel: 'L4', + requiresDSFA: true, + mandatoryDocuments: ['VVT', 'TOM', 'DSFA', 'DSE'], + legalReference: 'Art. 8 + Art. 9 DSGVO', + description: 'Verarbeitung besonderer Kategorien von Daten Minderjähriger', + combineWithArt9: true, + }, + { + id: 'HT-B03', + category: 'vulnerable', + questionId: 'data_minors', + condition: 'EQUALS', + conditionValue: true, + minimumLevel: 'L4', + requiresDSFA: true, + mandatoryDocuments: ['VVT', 'TOM', 'DSFA', 'AI_ACT_DOKU'], + legalReference: 'Art. 8 DSGVO + AI Act', + description: 'KI-gestützte Verarbeitung von Daten Minderjähriger', + combineWithAI: true, + }, + + // ========== C: ADM/KI (6 rules) ========== + { + id: 'HT-C01', + category: 'adm', + questionId: 'proc_adm_scoring', + condition: 'EQUALS', + conditionValue: true, + minimumLevel: 'L3', + requiresDSFA: true, + mandatoryDocuments: ['VVT', 'TOM', 'DSFA'], + legalReference: 'Art. 22 DSGVO', + description: 'Automatisierte Einzelentscheidung mit Rechtswirkung oder erheblicher Beeinträchtigung', + }, + { + id: 'HT-C02', + category: 'adm', + questionId: 'proc_ai_usage', + condition: 'CONTAINS', + conditionValue: 'autonom', + minimumLevel: 'L3', + requiresDSFA: true, + mandatoryDocuments: ['VVT', 'TOM', 'DSFA', 'AI_ACT_DOKU'], + legalReference: 'Art. 22 DSGVO + AI Act', + description: 'Autonome KI-Systeme mit Entscheidungsbefugnis', + }, + { + id: 'HT-C03', + category: 'adm', + questionId: 'proc_ai_usage', + condition: 'CONTAINS', + conditionValue: 'scoring', + minimumLevel: 'L2', + requiresDSFA: false, + mandatoryDocuments: ['VVT', 'TOM'], + legalReference: 'Art. 22 DSGVO', + description: 'KI-gestütztes Scoring', + }, + { + id: 'HT-C04', + category: 'adm', + questionId: 'proc_ai_usage', + condition: 'CONTAINS', + conditionValue: 'profiling', + minimumLevel: 'L3', + requiresDSFA: true, + mandatoryDocuments: ['VVT', 'TOM', 'DSFA'], + legalReference: 'Art. 22 DSGVO', + description: 'KI-gestütztes Profiling mit erheblicher Wirkung', + }, + { + id: 'HT-C05', + category: 'adm', + questionId: 'proc_ai_usage', + condition: 'CONTAINS', + conditionValue: 'generativ', + minimumLevel: 'L2', + requiresDSFA: false, + mandatoryDocuments: ['VVT', 'TOM', 'AI_ACT_DOKU'], + legalReference: 'AI Act', + description: 'Generative KI-Systeme', + }, + { + id: 'HT-C06', + category: 'adm', + questionId: 'proc_ai_usage', + condition: 'CONTAINS', + conditionValue: 'chatbot', + minimumLevel: 'L2', + requiresDSFA: false, + mandatoryDocuments: ['VVT', 'AI_ACT_DOKU'], + legalReference: 'AI Act', + description: 'Chatbots mit Personendatenverarbeitung', + }, + + // ========== D: Überwachung (5 rules) ========== + { + id: 'HT-D01', + category: 'surveillance', + questionId: 'proc_video_surveillance', + condition: 'EQUALS', + conditionValue: true, + minimumLevel: 'L2', + requiresDSFA: false, + mandatoryDocuments: ['VVT', 'TOM', 'DSE'], + legalReference: 'Art. 6 DSGVO', + description: 'Videoüberwachung', + }, + { + id: 'HT-D02', + category: 'surveillance', + questionId: 'proc_employee_monitoring', + condition: 'EQUALS', + conditionValue: true, + minimumLevel: 'L2', + requiresDSFA: false, + mandatoryDocuments: ['VVT', 'TOM', 'DSFA'], + legalReference: 'Art. 88 DSGVO + BetrVG', + description: 'Mitarbeiterüberwachung', + }, + { + id: 'HT-D03', + category: 'surveillance', + questionId: 'proc_tracking', + condition: 'EQUALS', + conditionValue: true, + minimumLevel: 'L2', + requiresDSFA: false, + mandatoryDocuments: ['VVT', 'TOM', 'COOKIE_BANNER', 'EINWILLIGUNGEN'], + legalReference: 'Art. 6 DSGVO + ePrivacy', + description: 'Online-Tracking', + }, + { + id: 'HT-D04', + category: 'surveillance', + questionId: 'proc_video_surveillance', + condition: 'EQUALS', + conditionValue: true, + minimumLevel: 'L3', + requiresDSFA: true, + mandatoryDocuments: ['VVT', 'TOM', 'DSFA'], + legalReference: 'Art. 35 Abs. 3 DSGVO', + description: 'Videoüberwachung kombiniert mit Mitarbeitermonitoring', + combineWithEmployeeMonitoring: true, + }, + { + id: 'HT-D05', + category: 'surveillance', + questionId: 'proc_video_surveillance', + condition: 'EQUALS', + conditionValue: true, + minimumLevel: 'L3', + requiresDSFA: true, + mandatoryDocuments: ['VVT', 'TOM', 'DSFA'], + legalReference: 'Art. 35 Abs. 3 DSGVO', + description: 'Videoüberwachung kombiniert mit automatisierter Bewertung', + combineWithADM: true, + }, + + // ========== E: Drittland (5 rules) ========== + { + id: 'HT-E01', + category: 'third_country', + questionId: 'tech_third_country', + condition: 'EQUALS', + conditionValue: true, + minimumLevel: 'L2', + requiresDSFA: false, + mandatoryDocuments: ['VVT', 'TRANSFER_DOKU'], + legalReference: 'Art. 44 ff. DSGVO', + description: 'Datenübermittlung in Drittland', + }, + { + id: 'HT-E02', + category: 'third_country', + questionId: 'tech_hosting_location', + condition: 'EQUALS', + conditionValue: 'drittland', + minimumLevel: 'L2', + requiresDSFA: false, + mandatoryDocuments: ['VVT', 'TOM', 'TRANSFER_DOKU'], + legalReference: 'Art. 44 ff. DSGVO', + description: 'Hosting in Drittland', + }, + { + id: 'HT-E03', + category: 'third_country', + questionId: 'tech_hosting_location', + condition: 'EQUALS', + conditionValue: 'us_adequacy', + minimumLevel: 'L2', + requiresDSFA: false, + mandatoryDocuments: ['TRANSFER_DOKU'], + legalReference: 'Art. 45 DSGVO', + description: 'Hosting in USA mit Angemessenheitsbeschluss', + }, + { + id: 'HT-E04', + category: 'third_country', + questionId: 'tech_third_country', + condition: 'EQUALS', + conditionValue: true, + minimumLevel: 'L3', + requiresDSFA: false, + mandatoryDocuments: ['VVT', 'TOM', 'TRANSFER_DOKU', 'DSFA'], + legalReference: 'Art. 44 ff. + Art. 9 DSGVO', + description: 'Drittlandtransfer besonderer Kategorien', + combineWithArt9: true, + }, + { + id: 'HT-E05', + category: 'third_country', + questionId: 'tech_third_country', + condition: 'EQUALS', + conditionValue: true, + minimumLevel: 'L3', + requiresDSFA: false, + mandatoryDocuments: ['VVT', 'TOM', 'TRANSFER_DOKU', 'DSFA'], + legalReference: 'Art. 44 ff. + Art. 8 DSGVO', + description: 'Drittlandtransfer von Daten Minderjähriger', + combineWithMinors: true, + }, + + // ========== F: Zertifizierung (5 rules) ========== + { + id: 'HT-F01', + category: 'certification', + questionId: 'org_cert_target', + condition: 'CONTAINS', + conditionValue: 'ISO27001', + minimumLevel: 'L4', + requiresDSFA: false, + mandatoryDocuments: ['TOM', 'AUDIT_CHECKLIST'], + legalReference: 'ISO/IEC 27001', + description: 'Angestrebte ISO 27001 Zertifizierung', + }, + { + id: 'HT-F02', + category: 'certification', + questionId: 'org_cert_target', + condition: 'CONTAINS', + conditionValue: 'ISO27701', + minimumLevel: 'L4', + requiresDSFA: false, + mandatoryDocuments: ['TOM', 'VVT', 'AUDIT_CHECKLIST'], + legalReference: 'ISO/IEC 27701', + description: 'Angestrebte ISO 27701 Zertifizierung', + }, + { + id: 'HT-F03', + category: 'certification', + questionId: 'org_cert_target', + condition: 'CONTAINS', + conditionValue: 'SOC2', + minimumLevel: 'L4', + requiresDSFA: false, + mandatoryDocuments: ['TOM', 'AUDIT_CHECKLIST'], + legalReference: 'SOC 2 Type II', + description: 'Angestrebte SOC 2 Zertifizierung', + }, + { + id: 'HT-F04', + category: 'certification', + questionId: 'org_cert_target', + condition: 'CONTAINS', + conditionValue: 'TISAX', + minimumLevel: 'L4', + requiresDSFA: false, + mandatoryDocuments: ['TOM', 'AUDIT_CHECKLIST', 'VENDOR_MANAGEMENT'], + legalReference: 'TISAX', + description: 'Angestrebte TISAX Zertifizierung', + }, + { + id: 'HT-F05', + category: 'certification', + questionId: 'org_cert_target', + condition: 'CONTAINS', + conditionValue: 'BSI-Grundschutz', + minimumLevel: 'L4', + requiresDSFA: false, + mandatoryDocuments: ['TOM', 'AUDIT_CHECKLIST'], + legalReference: 'BSI IT-Grundschutz', + description: 'Angestrebte BSI-Grundschutz Zertifizierung', + }, + + // ========== G: Volumen/Skala (5 rules) ========== + { + id: 'HT-G01', + category: 'scale', + questionId: 'data_volume', + condition: 'EQUALS', + conditionValue: '>1000000', + minimumLevel: 'L3', + requiresDSFA: false, + mandatoryDocuments: ['VVT', 'TOM', 'LOESCHKONZEPT'], + legalReference: 'Art. 35 Abs. 3 lit. b DSGVO', + description: 'Umfangreiche Verarbeitung personenbezogener Daten (>1 Mio. Datensätze)', + }, + { + id: 'HT-G02', + category: 'scale', + questionId: 'data_volume', + condition: 'EQUALS', + conditionValue: '100000-1000000', + minimumLevel: 'L2', + requiresDSFA: false, + mandatoryDocuments: ['VVT', 'TOM'], + legalReference: 'Art. 35 Abs. 3 lit. b DSGVO', + description: 'Großvolumige Datenverarbeitung (100k-1M Datensätze)', + }, + { + id: 'HT-G03', + category: 'scale', + questionId: 'org_customer_count', + condition: 'EQUALS', + conditionValue: '100000+', + minimumLevel: 'L3', + requiresDSFA: false, + mandatoryDocuments: ['VVT', 'TOM', 'DSR_PROZESS'], + legalReference: 'Art. 15-22 DSGVO', + description: 'Großer Kundenstamm (>100k) mit hoher Betroffenenanzahl', + }, + { + id: 'HT-G04', + category: 'scale', + questionId: 'org_employee_count', + condition: 'GREATER_THAN', + conditionValue: 249, + minimumLevel: 'L3', + requiresDSFA: false, + mandatoryDocuments: ['VVT', 'TOM', 'LOESCHKONZEPT', 'NOTFALLPLAN'], + legalReference: 'Art. 37 DSGVO', + description: 'Große Organisation (>250 Mitarbeiter) mit erhöhten Compliance-Anforderungen', + }, + { + id: 'HT-G05', + category: 'scale', + questionId: 'org_employee_count', + condition: 'GREATER_THAN', + conditionValue: 999, + minimumLevel: 'L4', + requiresDSFA: false, + mandatoryDocuments: ['VVT', 'TOM', 'DSFA', 'LOESCHKONZEPT'], + legalReference: 'Art. 35 + Art. 37 DSGVO', + description: 'Sehr große Organisation (>1000 Mitarbeiter) mit Art. 9 Daten', + combineWithArt9: true, + }, + + // ========== H: Produkt/Business (7 rules) ========== + { + id: 'HT-H01a', + category: 'product', + questionId: 'prod_webshop', + condition: 'EQUALS', + conditionValue: true, + excludeWhen: { questionId: 'org_business_model', value: 'B2B' }, + minimumLevel: 'L2', + requiresDSFA: false, + mandatoryDocuments: ['DSE', 'AGB', 'COOKIE_BANNER', 'EINWILLIGUNGEN', + 'WIDERRUFSBELEHRUNG', 'PREISANGABEN', 'FERNABSATZ_INFO', 'STREITBEILEGUNG'], + legalReference: 'Art. 6 DSGVO + Fernabsatzrecht + PAngV + VSBG', + description: 'E-Commerce / Webshop (B2C) — Verbraucherschutzpflichten', + }, + { + id: 'HT-H01b', + category: 'product', + questionId: 'prod_webshop', + condition: 'EQUALS', + conditionValue: true, + requireWhen: { questionId: 'org_business_model', value: 'B2B' }, + minimumLevel: 'L2', + requiresDSFA: false, + mandatoryDocuments: ['DSE', 'AGB', 'COOKIE_BANNER'], + legalReference: 'Art. 6 DSGVO + eCommerce', + description: 'E-Commerce / Webshop (B2B) — Basis-Pflichten', + }, + { + id: 'HT-H02', + category: 'product', + questionId: 'prod_data_broker', + condition: 'EQUALS', + conditionValue: true, + minimumLevel: 'L3', + requiresDSFA: true, + mandatoryDocuments: ['VVT', 'TOM', 'DSFA', 'EINWILLIGUNGEN'], + legalReference: 'Art. 35 Abs. 3 DSGVO', + description: 'Datenhandel oder Datenmakler-Tätigkeit', + }, + { + id: 'HT-H03', + category: 'product', + questionId: 'prod_api_external', + condition: 'EQUALS', + conditionValue: true, + minimumLevel: 'L2', + requiresDSFA: false, + mandatoryDocuments: ['TOM', 'AVV'], + legalReference: 'Art. 28 DSGVO', + description: 'Externe API mit Datenweitergabe', + }, + { + id: 'HT-H04', + category: 'product', + questionId: 'org_business_model', + condition: 'EQUALS', + conditionValue: 'b2c', + minimumLevel: 'L2', + requiresDSFA: false, + mandatoryDocuments: ['DSE', 'COOKIE_BANNER', 'EINWILLIGUNGEN'], + legalReference: 'Art. 6 DSGVO', + description: 'B2C-Geschäftsmodell mit Endkundenkontakt', + }, + { + id: 'HT-H05', + category: 'product', + questionId: 'org_industry', + condition: 'EQUALS', + conditionValue: 'finance', + minimumLevel: 'L2', + requiresDSFA: false, + mandatoryDocuments: ['VVT', 'TOM'], + legalReference: 'Art. 6 DSGVO + Finanzaufsicht', + description: 'Finanzbranche mit erhöhten regulatorischen Anforderungen', + }, + { + id: 'HT-H06', + category: 'product', + questionId: 'org_industry', + condition: 'EQUALS', + conditionValue: 'healthcare', + minimumLevel: 'L3', + requiresDSFA: true, + mandatoryDocuments: ['VVT', 'TOM', 'DSFA'], + legalReference: 'Art. 9 DSGVO + Gesundheitsrecht', + description: 'Gesundheitsbranche mit sensiblen Daten', + }, + { + id: 'HT-H07', + category: 'product', + questionId: 'org_industry', + condition: 'EQUALS', + conditionValue: 'public', + minimumLevel: 'L2', + requiresDSFA: false, + mandatoryDocuments: ['VVT', 'TOM', 'DSR_PROZESS'], + legalReference: 'Art. 6 Abs. 1 lit. e DSGVO', + description: 'Öffentlicher Sektor', + }, + + // ========== I: Prozessreife - Gap Flags (5 rules) ========== + { + id: 'HT-I01', + category: 'process_maturity', + questionId: 'proc_dsar_process', + condition: 'EQUALS', + conditionValue: false, + minimumLevel: 'L1', + requiresDSFA: false, + mandatoryDocuments: [], + legalReference: 'Art. 15-22 DSGVO', + description: 'Fehlender Prozess für Betroffenenrechte', + }, + { + id: 'HT-I02', + category: 'process_maturity', + questionId: 'proc_deletion_concept', + condition: 'EQUALS', + conditionValue: false, + minimumLevel: 'L1', + requiresDSFA: false, + mandatoryDocuments: [], + legalReference: 'Art. 17 DSGVO', + description: 'Fehlendes Löschkonzept', + }, + { + id: 'HT-I03', + category: 'process_maturity', + questionId: 'proc_incident_response', + condition: 'EQUALS', + conditionValue: false, + minimumLevel: 'L1', + requiresDSFA: false, + mandatoryDocuments: [], + legalReference: 'Art. 33 DSGVO', + description: 'Fehlender Incident-Response-Prozess', + }, + { + id: 'HT-I04', + category: 'process_maturity', + questionId: 'proc_regular_audits', + condition: 'EQUALS', + conditionValue: false, + minimumLevel: 'L1', + requiresDSFA: false, + mandatoryDocuments: [], + legalReference: 'Art. 24 DSGVO', + description: 'Fehlende regelmäßige Audits', + }, + { + id: 'HT-I05', + category: 'process_maturity', + questionId: 'comp_training', + condition: 'EQUALS', + conditionValue: false, + minimumLevel: 'L1', + requiresDSFA: false, + mandatoryDocuments: [], + legalReference: 'Art. 39 Abs. 1 lit. b DSGVO', + description: 'Fehlende Schulungen zum Datenschutz', + }, + + // ========== J: IACE — AI Act Produkt-Triggers (3 rules) ========== + { + id: 'HT-J01', + category: 'iace_ai_act_product', + questionId: 'machineBuilder.containsAI', + condition: 'EQUALS', + conditionValue: true, + minimumLevel: 'L3', + requiresDSFA: false, + mandatoryDocuments: ['VVT', 'TOM'], + legalReference: 'EU AI Act Annex I + EU Maschinenverordnung 2023/1230', + description: 'KI mit Sicherheitsfunktion in Maschine → AI Act High-Risk', + combineWithMachineBuilder: { field: 'hasSafetyFunction', value: true }, + riskWeight: 9, + }, + { + id: 'HT-J02', + category: 'iace_ai_act_product', + questionId: 'machineBuilder.containsAI', + condition: 'EQUALS', + conditionValue: true, + minimumLevel: 'L3', + requiresDSFA: false, + mandatoryDocuments: ['VVT', 'TOM'], + legalReference: 'EU AI Act + EU Maschinenverordnung 2023/1230', + description: 'Autonome KI in Maschine → AI Act + Maschinenverordnung', + combineWithMachineBuilder: { field: 'autonomousBehavior', value: true }, + riskWeight: 8, + }, + { + id: 'HT-J03', + category: 'iace_ai_act_product', + questionId: 'machineBuilder.hasSafetyFunction', + condition: 'EQUALS', + conditionValue: true, + minimumLevel: 'L3', + requiresDSFA: false, + mandatoryDocuments: ['VVT', 'TOM'], + legalReference: 'EU AI Act Annex III', + description: 'KI-Bildverarbeitung mit Sicherheitsbezug', + combineWithMachineBuilder: { field: 'aiIntegrationType', includes: 'vision' }, + riskWeight: 8, + }, + + // ========== K: IACE — CRA Triggers (3 rules) ========== + { + id: 'HT-K01', + category: 'iace_cra', + questionId: 'machineBuilder.isNetworked', + condition: 'EQUALS', + conditionValue: true, + minimumLevel: 'L2', + requiresDSFA: false, + mandatoryDocuments: ['TOM'], + legalReference: 'EU Cyber Resilience Act (CRA)', + description: 'Vernetztes Produkt → Cyber Resilience Act', + riskWeight: 6, + }, + { + id: 'HT-K02', + category: 'iace_cra', + questionId: 'machineBuilder.hasRemoteAccess', + condition: 'EQUALS', + conditionValue: true, + minimumLevel: 'L2', + requiresDSFA: false, + mandatoryDocuments: ['TOM'], + legalReference: 'CRA + NIS2 Art. 21', + description: 'Remote-Zugriff → CRA + NIS2 Supply Chain', + riskWeight: 7, + }, + { + id: 'HT-K03', + category: 'iace_cra', + questionId: 'machineBuilder.hasOTAUpdates', + condition: 'EQUALS', + conditionValue: true, + minimumLevel: 'L2', + requiresDSFA: false, + mandatoryDocuments: ['TOM'], + legalReference: 'CRA Art. 10 - Patch Management', + description: 'OTA-Updates → CRA Patch Management Pflicht', + riskWeight: 7, + }, + + // ========== L: IACE — NIS2 indirekt (2 rules) ========== + { + id: 'HT-L01', + category: 'iace_nis2_indirect', + questionId: 'machineBuilder.criticalSectorClients', + condition: 'EQUALS', + conditionValue: true, + minimumLevel: 'L2', + requiresDSFA: false, + mandatoryDocuments: ['TOM'], + legalReference: 'NIS2 Art. 21 - Supply Chain', + description: 'Lieferant an KRITIS → NIS2 Supply Chain Anforderungen', + riskWeight: 7, + }, + { + id: 'HT-L02', + category: 'iace_nis2_indirect', + questionId: 'machineBuilder.oemClients', + condition: 'EQUALS', + conditionValue: true, + minimumLevel: 'L2', + requiresDSFA: false, + mandatoryDocuments: [], + legalReference: 'NIS2 + EU Maschinenverordnung', + description: 'OEM-Zulieferer → Compliance-Nachweispflicht', + riskWeight: 5, + }, + + // ========== M: IACE — Maschinenverordnung Triggers (4 rules) ========== + { + id: 'HT-M01', + category: 'iace_machinery_regulation', + questionId: 'machineBuilder.containsSoftware', + condition: 'EQUALS', + conditionValue: true, + minimumLevel: 'L3', + requiresDSFA: false, + mandatoryDocuments: ['TOM'], + legalReference: 'EU Maschinenverordnung 2023/1230 Anhang III', + description: 'Software als Sicherheitskomponente → Maschinenverordnung', + combineWithMachineBuilder: { field: 'hasSafetyFunction', value: true }, + riskWeight: 9, + }, + { + id: 'HT-M02', + category: 'iace_machinery_regulation', + questionId: 'machineBuilder.ceMarkingRequired', + condition: 'EQUALS', + conditionValue: true, + minimumLevel: 'L2', + requiresDSFA: false, + mandatoryDocuments: [], + legalReference: 'EU Maschinenverordnung 2023/1230', + description: 'CE-Kennzeichnung erforderlich', + riskWeight: 6, + }, + { + id: 'HT-M03', + category: 'iace_machinery_regulation', + questionId: 'machineBuilder.ceMarkingRequired', + condition: 'EQUALS', + conditionValue: true, + minimumLevel: 'L3', + requiresDSFA: false, + mandatoryDocuments: [], + legalReference: 'EU Maschinenverordnung 2023/1230 Art. 10', + description: 'CE ohne bestehende Risikobeurteilung → Dringend!', + combineWithMachineBuilder: { field: 'hasRiskAssessment', value: false }, + riskWeight: 9, + }, + { + id: 'HT-M04', + category: 'iace_machinery_regulation', + questionId: 'machineBuilder.containsFirmware', + condition: 'EQUALS', + conditionValue: true, + minimumLevel: 'L2', + requiresDSFA: false, + mandatoryDocuments: ['TOM'], + legalReference: 'EU Maschinenverordnung + CRA', + description: 'Firmware mit Remote-Update → Change Management Pflicht', + combineWithMachineBuilder: { field: 'hasOTAUpdates', value: true }, + riskWeight: 7, + }, +]