// ============================================================================= // TOM Module - TOM-Dokumentation Document Generator // Generates a printable, audit-ready HTML document according to DSGVO Art. 32 // ============================================================================= import type { TOMGeneratorState, DerivedTOM, CompanyProfile, RiskProfile, ControlCategory, } from './tom-generator/types' import { SDM_CATEGORY_MAPPING } from './tom-generator/types' import { getControlById, getControlsByCategory, getAllCategories, getCategoryMetadata, } from './tom-generator/controls/loader' import type { TOMComplianceCheckResult, TOMComplianceIssueSeverity } from './tom-compliance' // ============================================================================= // TYPES // ============================================================================= export interface TOMDocumentOrgHeader { organizationName: string industry: string dpoName: string dpoContact: string responsiblePerson: string itSecurityContact: string locations: string[] employeeCount: string documentVersion: string lastReviewDate: string nextReviewDate: string reviewInterval: string } export interface TOMDocumentRevision { version: string date: string author: string changes: string } // ============================================================================= // DEFAULTS // ============================================================================= export function createDefaultTOMDocumentOrgHeader(): TOMDocumentOrgHeader { const now = new Date() const nextYear = new Date() nextYear.setFullYear(nextYear.getFullYear() + 1) return { organizationName: '', industry: '', dpoName: '', dpoContact: '', responsiblePerson: '', itSecurityContact: '', locations: [], employeeCount: '', documentVersion: '1.0', lastReviewDate: now.toISOString().split('T')[0], nextReviewDate: nextYear.toISOString().split('T')[0], reviewInterval: 'Jaehrlich', } } // ============================================================================= // SEVERITY LABELS (for Compliance Status section) // ============================================================================= const SEVERITY_LABELS_DE: Record = { CRITICAL: 'Kritisch', HIGH: 'Hoch', MEDIUM: 'Mittel', LOW: 'Niedrig', } const SEVERITY_COLORS: Record = { CRITICAL: '#dc2626', HIGH: '#ea580c', MEDIUM: '#d97706', LOW: '#6b7280', } // ============================================================================= // CATEGORY LABELS (German) // ============================================================================= const CATEGORY_LABELS_DE: Record = { ACCESS_CONTROL: 'Zutrittskontrolle', ADMISSION_CONTROL: 'Zugangskontrolle', ACCESS_AUTHORIZATION: 'Zugriffskontrolle', TRANSFER_CONTROL: 'Weitergabekontrolle', INPUT_CONTROL: 'Eingabekontrolle', ORDER_CONTROL: 'Auftragskontrolle', AVAILABILITY: 'Verfuegbarkeit', SEPARATION: 'Trennbarkeit', ENCRYPTION: 'Verschluesselung', PSEUDONYMIZATION: 'Pseudonymisierung', RESILIENCE: 'Belastbarkeit', RECOVERY: 'Wiederherstellbarkeit', REVIEW: 'Ueberpruefung & Bewertung', } // ============================================================================= // STATUS & APPLICABILITY LABELS // ============================================================================= const STATUS_LABELS_DE: Record = { IMPLEMENTED: 'Umgesetzt', PARTIAL: 'Teilweise umgesetzt', NOT_IMPLEMENTED: 'Nicht umgesetzt', } const STATUS_BADGE_CLASSES: Record = { IMPLEMENTED: 'badge-active', PARTIAL: 'badge-review', NOT_IMPLEMENTED: 'badge-critical', } const APPLICABILITY_LABELS_DE: Record = { REQUIRED: 'Erforderlich', RECOMMENDED: 'Empfohlen', OPTIONAL: 'Optional', NOT_APPLICABLE: 'Nicht anwendbar', } // ============================================================================= // HTML DOCUMENT BUILDER // ============================================================================= export function buildTOMDocumentHtml( derivedTOMs: DerivedTOM[], orgHeader: TOMDocumentOrgHeader, companyProfile: CompanyProfile | null, riskProfile: RiskProfile | null, complianceResult: TOMComplianceCheckResult | null, revisions: TOMDocumentRevision[] ): string { const today = new Date().toLocaleDateString('de-DE', { day: '2-digit', month: '2-digit', year: 'numeric', }) const orgName = orgHeader.organizationName || 'Organisation' // Filter out NOT_APPLICABLE TOMs for display const applicableTOMs = derivedTOMs.filter(t => t.applicability !== 'NOT_APPLICABLE') // Group TOMs by category via control library lookup const tomsByCategory = new Map() for (const tom of applicableTOMs) { const control = getControlById(tom.controlId) const cat = control?.category || 'REVIEW' if (!tomsByCategory.has(cat)) tomsByCategory.set(cat, []) tomsByCategory.get(cat)!.push(tom) } // Build role map: role/department → list of control codes const roleMap = new Map() for (const tom of applicableTOMs) { const role = tom.responsiblePerson || tom.responsibleDepartment || 'Nicht zugewiesen' if (!roleMap.has(role)) roleMap.set(role, []) const control = getControlById(tom.controlId) roleMap.get(role)!.push(control?.code || tom.controlId) } // ========================================================================= // HTML Template // ========================================================================= let html = ` TOM-Dokumentation — ${escHtml(orgName)} ` // ========================================================================= // Section 0: Cover Page // ========================================================================= html += `

TOM-Dokumentation

Technische und Organisatorische Massnahmen gemaess Art. 32 DSGVO
Organisation: ${escHtml(orgName)}
${orgHeader.industry ? `
Branche: ${escHtml(orgHeader.industry)}
` : ''} ${orgHeader.dpoName ? `
DSB: ${escHtml(orgHeader.dpoName)}
` : ''} ${orgHeader.dpoContact ? `
DSB-Kontakt: ${escHtml(orgHeader.dpoContact)}
` : ''} ${orgHeader.responsiblePerson ? `
Verantwortlicher: ${escHtml(orgHeader.responsiblePerson)}
` : ''} ${orgHeader.itSecurityContact ? `
IT-Sicherheit: ${escHtml(orgHeader.itSecurityContact)}
` : ''} ${orgHeader.employeeCount ? `
Mitarbeiter: ${escHtml(orgHeader.employeeCount)}
` : ''} ${orgHeader.locations.length > 0 ? `
Standorte: ${escHtml(orgHeader.locations.join(', '))}
` : ''}
` // ========================================================================= // Table of Contents // ========================================================================= const sections = [ 'Ziel und Zweck', 'Geltungsbereich', 'Grundprinzipien Art. 32', 'Schutzbedarf und Risikoanalyse', 'Massnahmen-Uebersicht', 'Detaillierte Massnahmen', 'SDM Gewaehrleistungsziele', 'Verantwortlichkeiten', 'Pruef- und Revisionszyklus', 'Compliance-Status', 'Aenderungshistorie', ] html += `

Inhaltsverzeichnis

${sections.map((s, i) => `
${i + 1}. ${escHtml(s)}
`).join('\n ')}
` // ========================================================================= // Section 1: Ziel und Zweck // ========================================================================= html += `
1. Ziel und Zweck

Diese TOM-Dokumentation beschreibt die technischen und organisatorischen Massnahmen zum Schutz personenbezogener Daten bei ${escHtml(orgName)}. Sie dient der Umsetzung folgender DSGVO-Anforderungen:

RechtsgrundlageInhalt
Art. 32 Abs. 1 lit. a DSGVOPseudonymisierung und Verschluesselung personenbezogener Daten
Art. 32 Abs. 1 lit. b DSGVOFaehigkeit, die Vertraulichkeit, Integritaet, Verfuegbarkeit und Belastbarkeit der Systeme und Dienste im Zusammenhang mit der Verarbeitung auf Dauer sicherzustellen
Art. 32 Abs. 1 lit. c DSGVOFaehigkeit, die Verfuegbarkeit der personenbezogenen Daten und den Zugang zu ihnen bei einem physischen oder technischen Zwischenfall rasch wiederherzustellen
Art. 32 Abs. 1 lit. d DSGVOVerfahren zur regelmaessigen Ueberpruefung, Bewertung und Evaluierung der Wirksamkeit der technischen und organisatorischen Massnahmen

Die TOM-Dokumentation ist fester Bestandteil des Datenschutz-Managementsystems und wird regelmaessig ueberprueft und aktualisiert.

` // ========================================================================= // Section 2: Geltungsbereich // ========================================================================= const industryInfo = companyProfile?.industry || orgHeader.industry || '' const hostingInfo = companyProfile ? `Unternehmen: ${escHtml(companyProfile.name || orgName)}, Groesse: ${escHtml(companyProfile.size || '-')}` : '' html += `
2. Geltungsbereich

Diese TOM-Dokumentation gilt fuer alle IT-Systeme, Anwendungen und Verarbeitungsprozesse von ${escHtml(orgName)}${industryInfo ? ` (Branche: ${escHtml(industryInfo)})` : ''}.

${hostingInfo ? `

${hostingInfo}

` : ''} ${orgHeader.locations.length > 0 ? `

Standorte: ${escHtml(orgHeader.locations.join(', '))}

` : ''}

Die dokumentierten Massnahmen stammen aus zwei Quellen:

  • Embedded Library (TOM-xxx): Integrierte Kontrollbibliothek mit spezifischen Massnahmen fuer Art. 32 DSGVO
  • Canonical Control Library (CP-CLIB): Uebergreifende Kontrollbibliothek mit framework-uebergreifenden Massnahmen

Insgesamt umfasst dieses Dokument ${applicableTOMs.length} anwendbare Massnahmen in ${tomsByCategory.size} Kategorien.

` // ========================================================================= // Section 3: Grundprinzipien Art. 32 // ========================================================================= html += `
3. Grundprinzipien Art. 32
Vertraulichkeit: Schutz personenbezogener Daten vor unbefugter Kenntnisnahme durch Zutrittskontrolle, Zugangskontrolle, Zugriffskontrolle und Verschluesselung (Art. 32 Abs. 1 lit. b DSGVO).
Integritaet: Sicherstellung, dass personenbezogene Daten nicht unbefugt oder unbeabsichtigt veraendert werden koennen, durch Eingabekontrolle, Weitergabekontrolle und Protokollierung (Art. 32 Abs. 1 lit. b DSGVO).
Verfuegbarkeit und Belastbarkeit: Gewaehrleistung, dass Systeme und Dienste bei Lastspitzen und Stoerungen zuverlaessig funktionieren, durch Backup, Redundanz und Disaster Recovery (Art. 32 Abs. 1 lit. b DSGVO).
Rasche Wiederherstellbarkeit: Faehigkeit, nach einem physischen oder technischen Zwischenfall Daten und Systeme schnell wiederherzustellen, durch getestete Recovery-Prozesse (Art. 32 Abs. 1 lit. c DSGVO).
Regelmaessige Wirksamkeitspruefung: Verfahren zur regelmaessigen Ueberpruefung, Bewertung und Evaluierung der Wirksamkeit aller technischen und organisatorischen Massnahmen (Art. 32 Abs. 1 lit. d DSGVO).
` // ========================================================================= // Section 4: Schutzbedarf und Risikoanalyse // ========================================================================= html += `
4. Schutzbedarf und Risikoanalyse
` if (riskProfile) { html += `

Die folgende Schutzbedarfsanalyse bildet die Grundlage fuer die Auswahl und Priorisierung der technischen und organisatorischen Massnahmen:

${riskProfile.specialRisks.length > 0 ? `` : ''} ${riskProfile.regulatoryRequirements.length > 0 ? `` : ''}
KriteriumBewertung
Vertraulichkeit${riskProfile.ciaAssessment.confidentiality}/5
Integritaet${riskProfile.ciaAssessment.integrity}/5
Verfuegbarkeit${riskProfile.ciaAssessment.availability}/5
Schutzniveau${escHtml(riskProfile.protectionLevel)}
DSFA-Pflicht${riskProfile.dsfaRequired ? 'Ja' : 'Nein'}
Spezialrisiken${escHtml(riskProfile.specialRisks.join(', '))}
Regulatorische Anforderungen${escHtml(riskProfile.regulatoryRequirements.join(', '))}
` } else { html += `

Die Schutzbedarfsanalyse wurde noch nicht durchgefuehrt. Fuehren Sie den Risiko-Wizard im TOM-Generator durch, um den Schutzbedarf zu ermitteln.

` } html += `
` // ========================================================================= // Section 5: Massnahmen-Uebersicht // ========================================================================= html += `
5. Massnahmen-Uebersicht

Die folgende Tabelle zeigt eine Uebersicht aller ${applicableTOMs.length} anwendbaren Massnahmen nach Kategorie:

` const allCategories = getAllCategories() for (const cat of allCategories) { const tomsInCat = tomsByCategory.get(cat) if (!tomsInCat || tomsInCat.length === 0) continue const implemented = tomsInCat.filter(t => t.implementationStatus === 'IMPLEMENTED').length const partial = tomsInCat.filter(t => t.implementationStatus === 'PARTIAL').length const notImpl = tomsInCat.filter(t => t.implementationStatus === 'NOT_IMPLEMENTED').length const catLabel = CATEGORY_LABELS_DE[cat] || cat html += ` ` } html += `
Kategorie Gesamt Umgesetzt Teilweise Offen
${escHtml(catLabel)} ${tomsInCat.length} ${implemented} ${partial} ${notImpl}
` // ========================================================================= // Section 6: Detaillierte Massnahmen // ========================================================================= html += `
6. Detaillierte Massnahmen
` for (const cat of allCategories) { const tomsInCat = tomsByCategory.get(cat) if (!tomsInCat || tomsInCat.length === 0) continue const catLabel = CATEGORY_LABELS_DE[cat] || cat const catMeta = getCategoryMetadata(cat) const gdprRef = catMeta?.gdprReference || '' html += `

${escHtml(catLabel)}${gdprRef ? ` (${escHtml(gdprRef)})` : ''}

` // Sort TOMs by control code const sortedTOMs = [...tomsInCat].sort((a, b) => { const codeA = getControlById(a.controlId)?.code || a.controlId const codeB = getControlById(b.controlId)?.code || b.controlId return codeA.localeCompare(codeB) }) for (const tom of sortedTOMs) { const control = getControlById(tom.controlId) const code = control?.code || tom.controlId const nameDE = control?.name?.de || tom.name const descDE = control?.description?.de || tom.description const typeLabel = control?.type === 'TECHNICAL' ? 'Technisch' : control?.type === 'ORGANIZATIONAL' ? 'Organisatorisch' : '-' const statusLabel = STATUS_LABELS_DE[tom.implementationStatus] || tom.implementationStatus const statusBadge = STATUS_BADGE_CLASSES[tom.implementationStatus] || 'badge-draft' const applicabilityLabel = APPLICABILITY_LABELS_DE[tom.applicability] || tom.applicability const responsible = [tom.responsiblePerson, tom.responsibleDepartment].filter(s => s && s.trim()).join(' / ') || '-' const implDate = tom.implementationDate ? formatDateDE(typeof tom.implementationDate === 'string' ? tom.implementationDate : tom.implementationDate.toISOString()) : '-' const reviewDate = tom.reviewDate ? formatDateDE(typeof tom.reviewDate === 'string' ? tom.reviewDate : tom.reviewDate.toISOString()) : '-' // Evidence const evidenceInfo = tom.linkedEvidence.length > 0 ? tom.linkedEvidence.join(', ') : tom.evidenceGaps.length > 0 ? `Fehlend: ${escHtml(tom.evidenceGaps.join(', '))}` : '-' // Framework mappings let mappingsHtml = '-' if (control?.mappings && control.mappings.length > 0) { mappingsHtml = control.mappings.map(m => `${escHtml(m.framework)}: ${escHtml(m.reference)}`).join('
') } html += `
${escHtml(code)} — ${escHtml(nameDE)} ${escHtml(statusLabel)}
Beschreibung${escHtml(descDE)}
Massnahmentyp${escHtml(typeLabel)}
Anwendbarkeit${escHtml(applicabilityLabel)}${tom.applicabilityReason ? ` — ${escHtml(tom.applicabilityReason)}` : ''}
Umsetzungsstatus${escHtml(statusLabel)}
Verantwortlich${escHtml(responsible)}
Umsetzungsdatum${implDate}
Naechste Pruefung${reviewDate}
Evidence${evidenceInfo}
Framework-Mappings${mappingsHtml}
` } } html += `
` // ========================================================================= // Section 7: SDM Gewaehrleistungsziele // ========================================================================= const sdmGoals: Array<{ goal: string; categories: ControlCategory[] }> = [] const allSDMGoals = [ 'Verfuegbarkeit', 'Integritaet', 'Vertraulichkeit', 'Nichtverkettung', 'Intervenierbarkeit', 'Transparenz', 'Datenminimierung', ] as const for (const goal of allSDMGoals) { const cats: ControlCategory[] = [] for (const [cat, goals] of Object.entries(SDM_CATEGORY_MAPPING)) { if (goals.includes(goal)) { cats.push(cat as ControlCategory) } } sdmGoals.push({ goal, categories: cats }) } html += `
7. SDM Gewaehrleistungsziele

Die folgende Tabelle zeigt die Abdeckung der sieben Gewaehrleistungsziele des Standard-Datenschutzmodells (SDM) durch die implementierten Massnahmen:

` for (const { goal, categories } of sdmGoals) { let totalInGoal = 0 let implementedInGoal = 0 for (const cat of categories) { const tomsInCat = tomsByCategory.get(cat) || [] totalInGoal += tomsInCat.length implementedInGoal += tomsInCat.filter(t => t.implementationStatus === 'IMPLEMENTED').length } const percentage = totalInGoal > 0 ? Math.round((implementedInGoal / totalInGoal) * 100) : 0 html += ` ` } html += `
Gewaehrleistungsziel Abgedeckt Gesamt Abdeckung (%)
${escHtml(goal)} ${implementedInGoal} ${totalInGoal} ${percentage}%
` // ========================================================================= // Section 8: Verantwortlichkeiten // ========================================================================= html += `
8. Verantwortlichkeiten

Die folgende Rollenmatrix zeigt, welche Personen oder Abteilungen fuer welche Massnahmen die Umsetzungsverantwortung tragen:

` for (const [role, controls] of roleMap.entries()) { html += ` ` } html += `
Rolle / VerantwortlichMassnahmenAnzahl
${escHtml(role)} ${controls.map(c => escHtml(c)).join(', ')} ${controls.length}
` // ========================================================================= // Section 9: Pruef- und Revisionszyklus // ========================================================================= html += `
9. Pruef- und Revisionszyklus
EigenschaftWert
Aktuelles Pruefintervall${escHtml(orgHeader.reviewInterval)}
Letzte Pruefung${formatDateDE(orgHeader.lastReviewDate)}
Naechste Pruefung${formatDateDE(orgHeader.nextReviewDate)}
Aktuelle Version${escHtml(orgHeader.documentVersion)}

Bei jeder Pruefung wird die TOM-Dokumentation auf folgende Punkte ueberprueft:

  • Vollstaendigkeit aller Massnahmen (neue Systeme oder Verarbeitungen erfasst?)
  • Aktualitaet des Umsetzungsstatus (Aenderungen seit letzter Pruefung?)
  • Wirksamkeit der technischen Massnahmen (Penetration-Tests, Audit-Ergebnisse)
  • Angemessenheit der organisatorischen Massnahmen (Schulungen, Richtlinien aktuell?)
  • Abdeckung aller SDM-Gewaehrleistungsziele
  • Zuordnung von Verantwortlichkeiten zu allen Massnahmen
` // ========================================================================= // Section 10: Compliance-Status // ========================================================================= html += `
10. Compliance-Status
` if (complianceResult) { const scoreClass = complianceResult.score >= 90 ? 'score-excellent' : complianceResult.score >= 75 ? 'score-good' : complianceResult.score >= 50 ? 'score-needs-work' : 'score-poor' const scoreLabel = complianceResult.score >= 90 ? 'Ausgezeichnet' : complianceResult.score >= 75 ? 'Gut' : complianceResult.score >= 50 ? 'Verbesserungswuerdig' : 'Mangelhaft' html += `

${complianceResult.score}/100 ${escHtml(scoreLabel)}

KennzahlWert
Gepruefte Massnahmen${complianceResult.stats.total}
Bestanden${complianceResult.stats.passed}
Beanstandungen${complianceResult.stats.failed}
` if (complianceResult.issues.length > 0) { html += `

Befunde nach Schweregrad:

` const severityOrder: TOMComplianceIssueSeverity[] = ['CRITICAL', 'HIGH', 'MEDIUM', 'LOW'] for (const sev of severityOrder) { const count = complianceResult.stats.bySeverity[sev] if (count === 0) continue const issuesForSev = complianceResult.issues.filter(i => i.severity === sev) html += ` ` } html += `
SchweregradAnzahlBefunde
${SEVERITY_LABELS_DE[sev]} ${count} ${issuesForSev.map(i => escHtml(i.title)).join('; ')}
` } else { html += `

Keine Beanstandungen. Alle Massnahmen sind konform.

` } } else { html += `

Compliance-Check wurde noch nicht ausgefuehrt. Fuehren Sie den Check im Export-Tab durch, um den Status in das Dokument aufzunehmen.

` } html += `
` // ========================================================================= // Section 11: Aenderungshistorie // ========================================================================= html += `
11. Aenderungshistorie
` if (revisions.length > 0) { for (const rev of revisions) { html += ` ` } } else { html += ` ` } html += `
VersionDatumAutorAenderungen
${escHtml(rev.version)} ${formatDateDE(rev.date)} ${escHtml(rev.author)} ${escHtml(rev.changes)}
${escHtml(orgHeader.documentVersion)} ${today} ${escHtml(orgHeader.dpoName || orgHeader.responsiblePerson || '-')} Erstversion der TOM-Dokumentation
` // ========================================================================= // Footer // ========================================================================= html += ` ` return html } // ============================================================================= // INTERNAL HELPERS // ============================================================================= function escHtml(str: string): string { return str .replace(/&/g, '&') .replace(//g, '>') .replace(/"/g, '"') } function formatDateDE(dateStr: string | null | undefined): string { if (!dateStr) return '-' try { const date = new Date(dateStr) if (isNaN(date.getTime())) return '-' return date.toLocaleDateString('de-DE', { day: '2-digit', month: '2-digit', year: 'numeric', }) } catch { return '-' } }