feat(sdk): VVT master libraries, process templates, Loeschfristen profiling + document

VVT: Master library tables (7 catalogs), 500+ seed entries, process templates
with instantiation, library API endpoints + 18 tests.
Loeschfristen: Baseline catalog, compliance checks, profiling engine, HTML document
generator, MkDocs documentation.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Benjamin Admin
2026-03-19 11:56:25 +01:00
parent f2819b99af
commit 2a70441eaa
20 changed files with 6621 additions and 9 deletions

View File

@@ -6,8 +6,10 @@
import {
LoeschfristPolicy,
PolicyStatus,
RetentionDriverType,
isPolicyOverdue,
getActiveLegalHolds,
RETENTION_DRIVER_META,
} from './loeschfristen-types'
// =============================================================================
@@ -22,6 +24,10 @@ export type ComplianceIssueType =
| 'LEGAL_HOLD_CONFLICT'
| 'STALE_DRAFT'
| 'UNCOVERED_VVT_CATEGORY'
| 'MISSING_DELETION_METHOD'
| 'MISSING_STORAGE_LOCATIONS'
| 'EXCESSIVE_RETENTION'
| 'MISSING_DATA_CATEGORIES'
export type ComplianceIssueSeverity = 'LOW' | 'MEDIUM' | 'HIGH' | 'CRITICAL'
@@ -219,6 +225,108 @@ function checkStaleDraft(policy: LoeschfristPolicy): ComplianceIssue | null {
return null
}
/**
* Check 8: MISSING_DELETION_METHOD (MEDIUM)
* Active policy without a deletion method detail description.
*/
function checkMissingDeletionMethod(policy: LoeschfristPolicy): ComplianceIssue | null {
if (policy.status === 'ACTIVE' && !policy.deletionMethodDetail.trim()) {
return createIssue(
policy,
'MISSING_DELETION_METHOD',
'MEDIUM',
'Keine Loeschmethode beschrieben',
`Die aktive Policy "${policy.dataObjectName}" hat keine detaillierte Beschreibung der Loeschmethode. Fuer ein auditfaehiges Loeschkonzept muss dokumentiert sein, wie die Loeschung technisch durchgefuehrt wird.`,
'Ergaenzen Sie eine detaillierte Beschreibung der Loeschmethode (z.B. automatisches Loeschen durch Datenbank-Job, manuelle Pruefung durch Fachabteilung, kryptographische Loeschung).'
)
}
return null
}
/**
* Check 9: MISSING_STORAGE_LOCATIONS (MEDIUM)
* Active policy without any documented storage locations.
*/
function checkMissingStorageLocations(policy: LoeschfristPolicy): ComplianceIssue | null {
if (policy.status === 'ACTIVE' && policy.storageLocations.length === 0) {
return createIssue(
policy,
'MISSING_STORAGE_LOCATIONS',
'MEDIUM',
'Keine Speicherorte dokumentiert',
`Die aktive Policy "${policy.dataObjectName}" hat keine Speicherorte hinterlegt. Ohne Speicherort-Dokumentation ist unklar, wo die Daten gespeichert sind und wo die Loeschung durchgefuehrt werden muss.`,
'Dokumentieren Sie mindestens einen Speicherort (z.B. Datenbank, Cloud-Speicher, E-Mail-System, Papierarchiv).'
)
}
return null
}
/**
* Check 10: EXCESSIVE_RETENTION (HIGH)
* Retention duration exceeds 2x the legal default for the driver.
*/
function checkExcessiveRetention(policy: LoeschfristPolicy): ComplianceIssue | null {
if (
policy.retentionDriver &&
policy.retentionDriver !== 'CUSTOM' &&
policy.retentionDuration !== null &&
policy.retentionUnit !== null
) {
const meta = RETENTION_DRIVER_META[policy.retentionDriver]
if (meta.defaultDuration !== null && meta.defaultUnit !== null) {
// Normalize both to days for comparison
const policyDays = toDays(policy.retentionDuration, policy.retentionUnit)
const legalDays = toDays(meta.defaultDuration, meta.defaultUnit)
if (legalDays > 0 && policyDays > legalDays * 2) {
return createIssue(
policy,
'EXCESSIVE_RETENTION',
'HIGH',
'Ueberschreitung der gesetzlichen Aufbewahrungsfrist',
`Die Policy "${policy.dataObjectName}" hat eine Aufbewahrungsdauer von ${policy.retentionDuration} ${policy.retentionUnit === 'YEARS' ? 'Jahren' : policy.retentionUnit === 'MONTHS' ? 'Monaten' : 'Tagen'}, die mehr als das Doppelte der gesetzlichen Frist (${meta.defaultDuration} ${meta.defaultUnit === 'YEARS' ? 'Jahre' : meta.defaultUnit === 'MONTHS' ? 'Monate' : 'Tage'} nach ${meta.statute}) betraegt. Ueberlange Speicherung widerspricht dem Grundsatz der Speicherbegrenzung (Art. 5 Abs. 1 lit. e DSGVO).`,
'Pruefen Sie, ob die verlaengerte Aufbewahrungsdauer gerechtfertigt ist. Falls nicht, reduzieren Sie sie auf die gesetzliche Mindestfrist.'
)
}
}
}
return null
}
/**
* Check 11: MISSING_DATA_CATEGORIES (LOW)
* Non-draft policy without any data categories assigned.
*/
function checkMissingDataCategories(policy: LoeschfristPolicy): ComplianceIssue | null {
if (policy.status !== 'DRAFT' && policy.dataCategories.length === 0) {
return createIssue(
policy,
'MISSING_DATA_CATEGORIES',
'LOW',
'Keine Datenkategorien zugeordnet',
`Die Policy "${policy.dataObjectName}" (Status: ${policy.status}) hat keine Datenkategorien zugeordnet. Ohne Datenkategorien ist unklar, welche personenbezogenen Daten von dieser Loeschregel betroffen sind.`,
'Ordnen Sie mindestens eine Datenkategorie zu (z.B. Stammdaten, Kontaktdaten, Finanzdaten, Gesundheitsdaten).'
)
}
return null
}
/**
* Helper: convert retention duration to days for comparison.
*/
function toDays(duration: number, unit: string): number {
switch (unit) {
case 'DAYS': return duration
case 'MONTHS': return duration * 30
case 'YEARS': return duration * 365
default: return duration
}
}
// =============================================================================
// MAIN COMPLIANCE CHECK
// =============================================================================
@@ -248,6 +356,10 @@ export function runComplianceCheck(
checkNoResponsible(policy),
checkLegalHoldConflict(policy),
checkStaleDraft(policy),
checkMissingDeletionMethod(policy),
checkMissingStorageLocations(policy),
checkExcessiveRetention(policy),
checkMissingDataCategories(policy),
]
for (const issue of checks) {