refactor(admin): split lib document generators and data catalogs into domain barrels

obligations-document, tom-document, loeschfristen-document, compliance-scope-triggers,
sdk-flow/flow-data, processing-activities, loeschfristen-baseline-catalog,
catalog-registry, dsfa mitigation-library + risk-catalog, vvt-baseline-catalog,
vendor contract-review checklists + findings, demo-data, tom-compliance.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Sharang Parnerkar
2026-04-18 00:07:03 +02:00
parent b00fe6cb73
commit 91063f09b8
65 changed files with 9514 additions and 9544 deletions

View File

@@ -0,0 +1,241 @@
// =============================================================================
// TOM Document — HTML Sections 711
// =============================================================================
import type { DerivedTOM, ControlCategory } from '../tom-generator/types'
import { SDM_CATEGORY_MAPPING } from '../tom-generator/types'
import type { TOMComplianceCheckResult, TOMComplianceIssueSeverity } from '../tom-compliance'
import type { TOMDocumentOrgHeader, TOMDocumentRevision } from './types-defaults'
import { SEVERITY_LABELS_DE, SEVERITY_COLORS } from './types-defaults'
import { escHtml, formatDateDE } from './helpers'
export function buildSections7to11(
orgName: string,
orgHeader: TOMDocumentOrgHeader,
tomsByCategory: Map<ControlCategory, DerivedTOM[]>,
roleMap: Map<string, string[]>,
complianceResult: TOMComplianceCheckResult | null,
revisions: TOMDocumentRevision[],
today: string
): string {
let html = ''
html += buildSection7(tomsByCategory)
html += buildSection8(roleMap)
html += buildSection9(orgHeader)
html += buildSection10(complianceResult)
html += buildSection11(revisions, orgHeader, today)
return html
}
function buildSection7(tomsByCategory: Map<ControlCategory, DerivedTOM[]>): string {
const allSDMGoals = [
'Verfuegbarkeit',
'Integritaet',
'Vertraulichkeit',
'Nichtverkettung',
'Intervenierbarkeit',
'Transparenz',
'Datenminimierung',
] as const
const sdmGoals: Array<{ goal: string; categories: ControlCategory[] }> = []
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 })
}
let html = `
<div class="section page-break">
<div class="section-header">7. SDM Gewaehrleistungsziele</div>
<div class="section-body">
<p>Die folgende Tabelle zeigt die Abdeckung der sieben Gewaehrleistungsziele des
Standard-Datenschutzmodells (SDM) durch die implementierten Massnahmen:</p>
<table>
<tr>
<th>Gewaehrleistungsziel</th>
<th>Abgedeckt</th>
<th>Gesamt</th>
<th>Abdeckung (%)</th>
</tr>
`
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 += ` <tr>
<td>${escHtml(goal)}</td>
<td>${implementedInGoal}</td>
<td>${totalInGoal}</td>
<td>${percentage}%</td>
</tr>
`
}
html += ` </table>
</div>
</div>
`
return html
}
function buildSection8(roleMap: Map<string, string[]>): string {
let html = `
<div class="section">
<div class="section-header">8. Verantwortlichkeiten</div>
<div class="section-body">
<p>Die folgende Rollenmatrix zeigt, welche Personen oder Abteilungen fuer welche Massnahmen
die Umsetzungsverantwortung tragen:</p>
<table>
<tr><th>Rolle / Verantwortlich</th><th>Massnahmen</th><th>Anzahl</th></tr>
`
for (const [role, controls] of roleMap.entries()) {
html += ` <tr>
<td>${escHtml(role)}</td>
<td>${controls.map(c => escHtml(c)).join(', ')}</td>
<td>${controls.length}</td>
</tr>
`
}
html += ` </table>
</div>
</div>
`
return html
}
function buildSection9(orgHeader: TOMDocumentOrgHeader): string {
return `
<div class="section">
<div class="section-header">9. Pruef- und Revisionszyklus</div>
<div class="section-body">
<table>
<tr><th>Eigenschaft</th><th>Wert</th></tr>
<tr><td>Aktuelles Pruefintervall</td><td>${escHtml(orgHeader.reviewInterval)}</td></tr>
<tr><td>Letzte Pruefung</td><td>${formatDateDE(orgHeader.lastReviewDate)}</td></tr>
<tr><td>Naechste Pruefung</td><td>${formatDateDE(orgHeader.nextReviewDate)}</td></tr>
<tr><td>Aktuelle Version</td><td>${escHtml(orgHeader.documentVersion)}</td></tr>
</table>
<p style="margin-top: 8px;">Bei jeder Pruefung wird die TOM-Dokumentation auf folgende Punkte ueberprueft:</p>
<ul style="margin: 8px 0 8px 24px;">
<li>Vollstaendigkeit aller Massnahmen (neue Systeme oder Verarbeitungen erfasst?)</li>
<li>Aktualitaet des Umsetzungsstatus (Aenderungen seit letzter Pruefung?)</li>
<li>Wirksamkeit der technischen Massnahmen (Penetration-Tests, Audit-Ergebnisse)</li>
<li>Angemessenheit der organisatorischen Massnahmen (Schulungen, Richtlinien aktuell?)</li>
<li>Abdeckung aller SDM-Gewaehrleistungsziele</li>
<li>Zuordnung von Verantwortlichkeiten zu allen Massnahmen</li>
</ul>
</div>
</div>
`
}
function buildSection10(complianceResult: TOMComplianceCheckResult | null): string {
let html = `
<div class="section page-break">
<div class="section-header">10. Compliance-Status</div>
<div class="section-body">
`
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 += ` <p><span class="score-box ${scoreClass}">${complianceResult.score}/100</span> ${escHtml(scoreLabel)}</p>
<table style="margin-top: 12px;">
<tr><th>Kennzahl</th><th>Wert</th></tr>
<tr><td>Gepruefte Massnahmen</td><td>${complianceResult.stats.total}</td></tr>
<tr><td>Bestanden</td><td>${complianceResult.stats.passed}</td></tr>
<tr><td>Beanstandungen</td><td>${complianceResult.stats.failed}</td></tr>
</table>
`
if (complianceResult.issues.length > 0) {
html += ` <p style="margin-top: 12px;"><strong>Befunde nach Schweregrad:</strong></p>
<table>
<tr><th>Schweregrad</th><th>Anzahl</th><th>Befunde</th></tr>
`
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 += ` <tr>
<td><span class="badge badge-${sev.toLowerCase()}" style="color: ${SEVERITY_COLORS[sev]}">${SEVERITY_LABELS_DE[sev]}</span></td>
<td>${count}</td>
<td>${issuesForSev.map(i => escHtml(i.title)).join('; ')}</td>
</tr>
`
}
html += ` </table>
`
} else {
html += ` <p style="margin-top: 8px;"><em>Keine Beanstandungen. Alle Massnahmen sind konform.</em></p>
`
}
} else {
html += ` <p><em>Compliance-Check wurde noch nicht ausgefuehrt. Fuehren Sie den Check im
Export-Tab durch, um den Status in das Dokument aufzunehmen.</em></p>
`
}
html += ` </div>
</div>
`
return html
}
function buildSection11(
revisions: TOMDocumentRevision[],
orgHeader: TOMDocumentOrgHeader,
today: string
): string {
let html = `
<div class="section">
<div class="section-header">11. Aenderungshistorie</div>
<div class="section-body">
<table>
<tr><th>Version</th><th>Datum</th><th>Autor</th><th>Aenderungen</th></tr>
`
if (revisions.length > 0) {
for (const rev of revisions) {
html += ` <tr>
<td>${escHtml(rev.version)}</td>
<td>${formatDateDE(rev.date)}</td>
<td>${escHtml(rev.author)}</td>
<td>${escHtml(rev.changes)}</td>
</tr>
`
}
} else {
html += ` <tr>
<td>${escHtml(orgHeader.documentVersion)}</td>
<td>${today}</td>
<td>${escHtml(orgHeader.dpoName || orgHeader.responsiblePerson || '-')}</td>
<td>Erstversion der TOM-Dokumentation</td>
</tr>
`
}
html += ` </table>
</div>
</div>
`
return html
}