fix(scope): Evaluierung crasht (answerValue→value), Profil-Persistenz, Block-Umbenennungen
Some checks failed
CI / go-lint (push) Has been skipped
CI / python-lint (push) Has been skipped
CI / nodejs-lint (push) Has been skipped
CI / test-go-ai-compliance (push) Failing after 36s
CI / test-python-backend-compliance (push) Successful in 42s
CI / test-python-document-crawler (push) Successful in 27s
CI / test-python-dsms-gateway (push) Successful in 25s

- compliance-scope-engine: answerValue→value (Property existierte nicht, Crash bei Evaluierung)
- company-profile: saveProfileDraft synct jetzt Redux-State (Daten bleiben bei Navigation)
- Scope-Bloecke umbenannt: Kunden & Nutzer, Datenverarbeitung, Hosting & Verarbeitung, Website und Services
- org_cert_target + data_volume als Hidden Scoring Questions (Duplikate entfernt)
- ai_risk_assessment: boolean→single mit Ja/Nein/Noch nicht
- 6 neue Abteilungs-Datenkategorien: IT, Recht, Produktion, Logistik, Einkauf, Facility

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Benjamin Admin
2026-03-10 16:33:59 +01:00
parent ee6743c7c6
commit 579fe1b5e1
5 changed files with 216 additions and 64 deletions

View File

@@ -1062,32 +1062,32 @@ export class ComplianceScopeEngine {
* Bestimmt den Multiplikator für eine Antwort (0.0 - 1.0)
*/
private getAnswerMultiplier(answer: ScopeProfilingAnswer): number {
const { questionId, answerValue } = answer
const { questionId, value } = answer
// Boolean
if (typeof answerValue === 'boolean') {
return answerValue ? 1.0 : 0.0
if (typeof value === 'boolean') {
return value ? 1.0 : 0.0
}
// Number
if (typeof answerValue === 'number') {
return this.normalizeNumericAnswer(questionId, answerValue)
if (typeof value === 'number') {
return this.normalizeNumericAnswer(questionId, value)
}
// Single choice
if (typeof answerValue === 'string') {
if (typeof value === 'string') {
const multipliers = ANSWER_MULTIPLIERS[questionId]
if (multipliers && multipliers[answerValue] !== undefined) {
return multipliers[answerValue]
if (multipliers && multipliers[value] !== undefined) {
return multipliers[value]
}
return 0.5 // Fallback
}
// Multi choice
if (Array.isArray(answerValue)) {
if (answerValue.length === 0) return 0.0
if (Array.isArray(value)) {
if (value.length === 0) return 0.0
// Simplified: count selected items
return Math.min(answerValue.length / 5, 1.0)
return Math.min(value.length / 5, 1.0)
}
return 0.0
@@ -1110,7 +1110,7 @@ export class ComplianceScopeEngine {
*/
evaluateHardTriggers(answers: ScopeProfilingAnswer[], companyProfile?: CompanyProfile | null): TriggeredHardTrigger[] {
const triggered: TriggeredHardTrigger[] = []
const answerMap = new Map(answers.map((a) => [a.questionId, a.answerValue]))
const answerMap = new Map(answers.map((a) => [a.questionId, a.value]))
for (const rule of HARD_TRIGGER_RULES) {
const isTriggered = this.checkTriggerCondition(rule, answerMap, answers, companyProfile)
@@ -1186,39 +1186,39 @@ export class ComplianceScopeEngine {
}
// Standard answer-based triggers
const answerValue = answerMap.get(rule.questionId)
if (answerValue === undefined) return false
const value = answerMap.get(rule.questionId)
if (value === undefined) return false
// Basis-Check
let baseCondition = false
switch (rule.condition) {
case 'EQUALS':
baseCondition = answerValue === rule.conditionValue
baseCondition = value === rule.conditionValue
break
case 'CONTAINS':
if (Array.isArray(answerValue)) {
baseCondition = answerValue.includes(rule.conditionValue)
} else if (typeof answerValue === 'string') {
baseCondition = answerValue.includes(rule.conditionValue)
if (Array.isArray(value)) {
baseCondition = value.includes(rule.conditionValue)
} else if (typeof value === 'string') {
baseCondition = value.includes(rule.conditionValue)
}
break
case 'IN':
if (Array.isArray(rule.conditionValue)) {
baseCondition = rule.conditionValue.includes(answerValue)
baseCondition = rule.conditionValue.includes(value)
}
break
case 'GREATER_THAN':
if (typeof answerValue === 'number' && typeof rule.conditionValue === 'number') {
baseCondition = answerValue > rule.conditionValue
} else if (typeof answerValue === 'string') {
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(answerValue)
const parsed = this.parseEmployeeCount(value)
baseCondition = parsed > (rule.conditionValue as number)
}
break
case 'NOT_EQUALS':
baseCondition = answerValue !== rule.conditionValue
baseCondition = value !== rule.conditionValue
break
}
@@ -1404,7 +1404,7 @@ export class ComplianceScopeEngine {
level: ComplianceDepthLevel
): RiskFlag[] {
const flags: RiskFlag[] = []
const answerMap = new Map(answers.map((a) => [a.questionId, a.answerValue]))
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')
@@ -1503,7 +1503,7 @@ export class ComplianceScopeEngine {
level: ComplianceDepthLevel
): ScopeGap[] {
const gaps: ScopeGap[] = []
const answerMap = new Map(answers.map((a) => [a.questionId, a.answerValue]))
const answerMap = new Map(answers.map((a) => [a.questionId, a.value]))
// DSFA Gap (bei L3+)
if (getDepthLevelNumeric(level) >= 3) {