a28db8f8f0
Eliminate the pre-existing TS errors that were masked by next.config.js `typescript.ignoreBuildErrors: true`, then turn the flag OFF so the compiler is a real safety net for future changes. `next build` and `tsc --noEmit` now pass with 0 errors. The errors were not cosmetic — several exposed real latent bugs hidden by the flag, e.g. the drafting-engine ConstraintEnforcer read non-existent fields (`t.rule.dsfaRequired`, `d.required`, `r.title`), so its DSFA hard gate and risk-flag checks were silently no-ops; scopeDefaults read snake_case CompanyProfile fields that never matched the camelCase type (generator defaults never populated). Both fixed by aligning code to the current types. Highlights: - Vitest globals: add vitest-globals.d.ts (config already had globals:true) so the test files type-check; exclude Playwright specs from vitest. - Add a minimal ambient `pg` module declaration (no @types/pg installed). - Fix Next 15 route handlers to await Promise params. - Reconcile drifted types across loeschfristen, compliance-scope, document- generator, drafting-engine, vendor-compliance, agent and more. Pre-existing (NOT caused here, proven by stashing the diff): 3 vitest logic tests still fail — getNextStep (2) and buildDocumentScope priority (1). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
317 lines
10 KiB
TypeScript
317 lines
10 KiB
TypeScript
/**
|
|
* Scope-basierte Generator-Defaults
|
|
*
|
|
* Nimmt ScopeDecision.determinedLevel + CompanyProfile und liefert
|
|
* vorausgefuellte TOM/DPA-Context-Werte. Alle Felder bleiben vom
|
|
* Kunden aenderbar — die Defaults sind Empfehlungen.
|
|
*
|
|
* Mapping:
|
|
* L1 = Lean Startup (≤10 MA, Cloud-only, Home Office)
|
|
* L2 = KMU Standard (11-249 MA)
|
|
* L3 = Erweitert (risikoreich oder >100 MA)
|
|
* L4 = Zertifizierungsbereit (≥250 MA oder regulierte Branche)
|
|
*/
|
|
|
|
import type { ComplianceDepthLevel } from '@/lib/sdk/compliance-scope-types/core-levels'
|
|
import type { CompanyProfile } from '@/lib/sdk/types'
|
|
import type { TOMCtx, DPACtx } from './contextBridge'
|
|
|
|
// ============================================================================
|
|
// TOM Defaults per Level
|
|
// ============================================================================
|
|
|
|
const TOM_DEFAULTS: Record<ComplianceDepthLevel, Partial<TOMCtx>> = {
|
|
L1: {
|
|
// Lean Startup: Cloud-only, kein eigener Serverraum, Home Office
|
|
HAS_MFA: true,
|
|
HAS_USB_LOCKED: false,
|
|
HAS_MOBILE_MEDIA: false,
|
|
HAS_FOUR_EYES_DELETE: false,
|
|
HAS_EXTERNAL_DESTRUCTION: false,
|
|
HAS_PHYSICAL_TRANSPORT: false,
|
|
HAS_THIRD_COUNTRY_TRANSFER: false,
|
|
HAS_CLOUD_SERVICES: true,
|
|
HAS_REDUNDANCY: false,
|
|
HAS_GEO_REDUNDANCY: false,
|
|
HAS_USV: false,
|
|
HAS_OWN_SERVER_ROOM: false,
|
|
HAS_MULTI_TENANT: false,
|
|
HAS_TEST_DATA_ANONYMIZED: true,
|
|
LOG_RETENTION_MONTHS: 3,
|
|
DIN_66399_LEVEL: '3',
|
|
AVAILABILITY_TARGET: '99.0',
|
|
SEPARATION_TYPE: 'logisch',
|
|
},
|
|
L2: {
|
|
// KMU Standard
|
|
HAS_MFA: true,
|
|
HAS_USB_LOCKED: false,
|
|
HAS_MOBILE_MEDIA: false,
|
|
HAS_FOUR_EYES_DELETE: false,
|
|
HAS_EXTERNAL_DESTRUCTION: false,
|
|
HAS_PHYSICAL_TRANSPORT: false,
|
|
HAS_THIRD_COUNTRY_TRANSFER: false,
|
|
HAS_CLOUD_SERVICES: true,
|
|
HAS_REDUNDANCY: false,
|
|
HAS_GEO_REDUNDANCY: false,
|
|
HAS_USV: false,
|
|
HAS_OWN_SERVER_ROOM: false,
|
|
HAS_MULTI_TENANT: false,
|
|
HAS_TEST_DATA_ANONYMIZED: true,
|
|
LOG_RETENTION_MONTHS: 6,
|
|
DIN_66399_LEVEL: '3',
|
|
AVAILABILITY_TARGET: '99.5',
|
|
SEPARATION_TYPE: 'logisch',
|
|
},
|
|
L3: {
|
|
// Erweitert
|
|
HAS_MFA: true,
|
|
HAS_USB_LOCKED: false,
|
|
HAS_MOBILE_MEDIA: false,
|
|
HAS_FOUR_EYES_DELETE: true,
|
|
HAS_EXTERNAL_DESTRUCTION: true,
|
|
HAS_PHYSICAL_TRANSPORT: false,
|
|
HAS_THIRD_COUNTRY_TRANSFER: false,
|
|
HAS_CLOUD_SERVICES: true,
|
|
HAS_REDUNDANCY: true,
|
|
HAS_GEO_REDUNDANCY: false,
|
|
HAS_USV: true,
|
|
HAS_OWN_SERVER_ROOM: true,
|
|
HAS_MULTI_TENANT: true,
|
|
HAS_TEST_DATA_ANONYMIZED: true,
|
|
LOG_RETENTION_MONTHS: 12,
|
|
DIN_66399_LEVEL: '4',
|
|
AVAILABILITY_TARGET: '99.9',
|
|
SEPARATION_TYPE: 'logisch',
|
|
},
|
|
L4: {
|
|
// Zertifizierungsbereit / Enterprise
|
|
HAS_MFA: true,
|
|
HAS_USB_LOCKED: true,
|
|
HAS_MOBILE_MEDIA: false,
|
|
HAS_FOUR_EYES_DELETE: true,
|
|
HAS_EXTERNAL_DESTRUCTION: true,
|
|
HAS_PHYSICAL_TRANSPORT: false,
|
|
HAS_THIRD_COUNTRY_TRANSFER: false,
|
|
HAS_CLOUD_SERVICES: true,
|
|
HAS_REDUNDANCY: true,
|
|
HAS_GEO_REDUNDANCY: true,
|
|
HAS_USV: true,
|
|
HAS_OWN_SERVER_ROOM: true,
|
|
HAS_MULTI_TENANT: true,
|
|
HAS_TEST_DATA_ANONYMIZED: true,
|
|
LOG_RETENTION_MONTHS: 24,
|
|
DIN_66399_LEVEL: '5',
|
|
AVAILABILITY_TARGET: '99.99',
|
|
SEPARATION_TYPE: 'logisch',
|
|
},
|
|
}
|
|
|
|
// ============================================================================
|
|
// DPA Defaults per Level
|
|
// ============================================================================
|
|
|
|
const DPA_DEFAULTS: Record<ComplianceDepthLevel, Partial<DPACtx>> = {
|
|
L1: {
|
|
BREACH_NOTIFICATION_HOURS: 48,
|
|
INSTRUCTION_RETENTION_YEARS: 3,
|
|
SUB_PROCESSOR_NOTICE_WEEKS: 2,
|
|
SUB_PROCESSOR_OBJECTION_WEEKS: 2,
|
|
DATA_EXPORT_FORMAT: 'CSV/JSON',
|
|
RETURN_CHOICE_WEEKS: 4,
|
|
DELETION_DAYS: 90,
|
|
HAS_LIABILITY_PROTECTION: false,
|
|
HAS_SUPPORT_COST_CLAUSE: false,
|
|
HAS_SUB_PROCESSOR_SILENCE_APPROVAL: true,
|
|
HAS_SUB_PROCESSOR_TERMINATION_RIGHT: false,
|
|
HAS_REACTIVATION_PERIOD: true,
|
|
REACTIVATION_MONTHS: 3,
|
|
HAS_RETURN_COST_CLAUSE: false,
|
|
HAS_GERICHTSSTAND_CLAUSE: false,
|
|
HAS_UNILATERAL_CHANGE_RIGHT: false,
|
|
HAS_THIRD_COUNTRY_OBJECTION: false,
|
|
},
|
|
L2: {
|
|
BREACH_NOTIFICATION_HOURS: 24,
|
|
INSTRUCTION_RETENTION_YEARS: 3,
|
|
SUB_PROCESSOR_NOTICE_WEEKS: 4,
|
|
SUB_PROCESSOR_OBJECTION_WEEKS: 2,
|
|
DATA_EXPORT_FORMAT: 'CSV/JSON',
|
|
RETURN_CHOICE_WEEKS: 4,
|
|
DELETION_DAYS: 90,
|
|
HAS_LIABILITY_PROTECTION: false,
|
|
HAS_SUPPORT_COST_CLAUSE: false,
|
|
HAS_SUB_PROCESSOR_SILENCE_APPROVAL: true,
|
|
HAS_SUB_PROCESSOR_TERMINATION_RIGHT: false,
|
|
HAS_REACTIVATION_PERIOD: true,
|
|
REACTIVATION_MONTHS: 3,
|
|
HAS_RETURN_COST_CLAUSE: false,
|
|
HAS_GERICHTSSTAND_CLAUSE: true,
|
|
HAS_UNILATERAL_CHANGE_RIGHT: false,
|
|
HAS_THIRD_COUNTRY_OBJECTION: false,
|
|
},
|
|
L3: {
|
|
BREACH_NOTIFICATION_HOURS: 24,
|
|
INSTRUCTION_RETENTION_YEARS: 5,
|
|
SUB_PROCESSOR_NOTICE_WEEKS: 4,
|
|
SUB_PROCESSOR_OBJECTION_WEEKS: 4,
|
|
DATA_EXPORT_FORMAT: 'CSV/JSON',
|
|
RETURN_CHOICE_WEEKS: 4,
|
|
DELETION_DAYS: 60,
|
|
HAS_LIABILITY_PROTECTION: true,
|
|
HAS_SUPPORT_COST_CLAUSE: true,
|
|
HAS_SUB_PROCESSOR_SILENCE_APPROVAL: true,
|
|
HAS_SUB_PROCESSOR_TERMINATION_RIGHT: true,
|
|
HAS_REACTIVATION_PERIOD: true,
|
|
REACTIVATION_MONTHS: 3,
|
|
HAS_RETURN_COST_CLAUSE: true,
|
|
HAS_GERICHTSSTAND_CLAUSE: true,
|
|
HAS_UNILATERAL_CHANGE_RIGHT: false,
|
|
HAS_THIRD_COUNTRY_OBJECTION: false,
|
|
},
|
|
L4: {
|
|
BREACH_NOTIFICATION_HOURS: 12,
|
|
INSTRUCTION_RETENTION_YEARS: 5,
|
|
SUB_PROCESSOR_NOTICE_WEEKS: 6,
|
|
SUB_PROCESSOR_OBJECTION_WEEKS: 4,
|
|
DATA_EXPORT_FORMAT: 'CSV/JSON',
|
|
RETURN_CHOICE_WEEKS: 8,
|
|
DELETION_DAYS: 30,
|
|
HAS_LIABILITY_PROTECTION: true,
|
|
HAS_SUPPORT_COST_CLAUSE: true,
|
|
HAS_SUB_PROCESSOR_SILENCE_APPROVAL: false,
|
|
HAS_SUB_PROCESSOR_TERMINATION_RIGHT: true,
|
|
HAS_REACTIVATION_PERIOD: false,
|
|
REACTIVATION_MONTHS: 3,
|
|
HAS_RETURN_COST_CLAUSE: true,
|
|
HAS_GERICHTSSTAND_CLAUSE: true,
|
|
HAS_UNILATERAL_CHANGE_RIGHT: false,
|
|
HAS_THIRD_COUNTRY_OBJECTION: false,
|
|
},
|
|
}
|
|
|
|
// ============================================================================
|
|
// Public API
|
|
// ============================================================================
|
|
|
|
export interface GeneratorDefaults {
|
|
tom: Partial<TOMCtx>
|
|
dpa: Partial<DPACtx>
|
|
/** Which fields were set by the scope engine (for UI highlighting) */
|
|
scopeSet: Set<string>
|
|
}
|
|
|
|
/**
|
|
* Berechnet Generator-Defaults basierend auf dem Compliance-Level
|
|
* und dem CompanyProfile. Alle Werte sind Vorschlaege — der Kunde
|
|
* kann sie aendern.
|
|
*/
|
|
export function getGeneratorDefaults(
|
|
level: ComplianceDepthLevel,
|
|
profile?: CompanyProfile | null,
|
|
): GeneratorDefaults {
|
|
const tomBase = { ...TOM_DEFAULTS[level] }
|
|
const dpaBase = { ...DPA_DEFAULTS[level] }
|
|
const scopeSet = new Set<string>()
|
|
|
|
// CompanyProfile-Felder in TOM/DPA uebernehmen
|
|
if (profile) {
|
|
if (profile.companyName) {
|
|
dpaBase.AN_NAME = profile.companyName
|
|
scopeSet.add('DPA.AN_NAME')
|
|
}
|
|
if (profile.headquartersStreet) {
|
|
dpaBase.AN_STRASSE = profile.headquartersStreet
|
|
scopeSet.add('DPA.AN_STRASSE')
|
|
}
|
|
if (profile.headquartersCity && profile.headquartersZip) {
|
|
dpaBase.AN_PLZ_ORT = `${profile.headquartersZip} ${profile.headquartersCity}`
|
|
scopeSet.add('DPA.AN_PLZ_ORT')
|
|
}
|
|
if (profile.dpoName) {
|
|
tomBase.ISB_NAME = tomBase.ISB_NAME || ''
|
|
dpaBase.AN_DSB_NAME = profile.dpoName
|
|
scopeSet.add('DPA.AN_DSB_NAME')
|
|
}
|
|
if (profile.dpoEmail) {
|
|
dpaBase.AN_DSB_EMAIL = profile.dpoEmail
|
|
scopeSet.add('DPA.AN_DSB_EMAIL')
|
|
}
|
|
// Unterzeichner/GF werden NICHT aus dem CompanyProfile befuellt — es enthaelt
|
|
// keine Person; diese Felder kommen aus dem TOM/DPA-Generator selbst.
|
|
}
|
|
|
|
// Alle gesetzten TOM/DPA Felder als scope-set markieren
|
|
for (const key of Object.keys(tomBase)) {
|
|
scopeSet.add(`TOM.${key}`)
|
|
}
|
|
for (const key of Object.keys(dpaBase)) {
|
|
scopeSet.add(`DPA.${key}`)
|
|
}
|
|
|
|
return { tom: tomBase, dpa: dpaBase, scopeSet }
|
|
}
|
|
|
|
/**
|
|
* Gibt das empfohlene Profil-Label zurueck (fuer UI-Anzeige).
|
|
*/
|
|
export function getProfileLabel(level: ComplianceDepthLevel): string {
|
|
const labels: Record<ComplianceDepthLevel, string> = {
|
|
L1: 'Startup / Kleinstunternehmen',
|
|
L2: 'KMU Standard',
|
|
L3: 'Erweiterte Compliance',
|
|
L4: 'Zertifizierungsbereit / Enterprise',
|
|
}
|
|
return labels[level]
|
|
}
|
|
|
|
/**
|
|
* Empfiehlt relevante Dokumenttypen basierend auf dem Compliance-Level.
|
|
* Hilft dem Kunden zu verstehen, welche Dokumente er braucht.
|
|
*/
|
|
export function getRecommendedDocuments(level: ComplianceDepthLevel): {
|
|
required: string[]
|
|
recommended: string[]
|
|
optional: string[]
|
|
} {
|
|
const always = [
|
|
'privacy_policy', 'impressum', 'agb', 'cookie_banner', 'cookie_policy',
|
|
]
|
|
const l2plus = [
|
|
'dpa', 'tom_documentation', 'vvt_register', 'loeschkonzept',
|
|
'community_guidelines', 'terms_of_use',
|
|
]
|
|
const l3plus = [
|
|
'it_security_concept', 'data_protection_concept', 'incident_response_plan',
|
|
'access_control_concept', 'backup_recovery_concept', 'logging_concept',
|
|
'risk_management_concept', 'pflichtenregister',
|
|
'password_policy', 'encryption_policy', 'information_security_policy',
|
|
'access_control_policy', 'whistleblower_policy',
|
|
'employee_dsi', 'applicant_dsi', 'ai_usage_policy',
|
|
]
|
|
const l4only = [
|
|
'isms_manual', 'cybersecurity_policy', 'byod_policy',
|
|
'dsfa', 'social_media_dsi', 'media_content_policy',
|
|
'video_conference_dsi', 'consent_texts',
|
|
'data_protection_policy', 'data_classification_policy',
|
|
'data_retention_policy', 'data_transfer_policy',
|
|
'privacy_incident_policy', 'employee_security_policy',
|
|
'security_awareness_policy', 'remote_work_policy',
|
|
'offboarding_policy', 'vendor_risk_management_policy',
|
|
'third_party_security_policy', 'supplier_security_policy',
|
|
'business_continuity_policy', 'disaster_recovery_policy',
|
|
'crisis_management_policy',
|
|
]
|
|
|
|
switch (level) {
|
|
case 'L1':
|
|
return { required: always, recommended: [], optional: l2plus }
|
|
case 'L2':
|
|
return { required: always, recommended: l2plus, optional: l3plus }
|
|
case 'L3':
|
|
return { required: [...always, ...l2plus], recommended: l3plus, optional: l4only }
|
|
case 'L4':
|
|
return { required: [...always, ...l2plus, ...l3plus], recommended: l4only, optional: [] }
|
|
}
|
|
}
|