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) <noreply@anthropic.com>
This commit is contained in:
Sharang Parnerkar
2026-04-10 13:33:51 +02:00
parent fc6a3306d4
commit 911d872178
4 changed files with 1483 additions and 1435 deletions

View File

@@ -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<string, Record<string, number>> = {
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,
},
}

View File

@@ -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<string, ScopeDocumentType> = {
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<Record<ScopeDocumentType, number>> = {
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<ScopeDocumentType>()
const triggerDocOrigins = new Map<ScopeDocumentType, string[]>()
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<string, number> = { 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<string, string> = {
'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<string, any>,
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<string, number> = { 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
}

File diff suppressed because it is too large Load Diff

View File

@@ -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,
},
]