// ============================================================================= // Loeschfristen Document — HTML Builder: Sections 6–12 // ============================================================================= import type { LoeschfristPolicy } from '../loeschfristen-types' import type { ComplianceCheckResult, ComplianceIssueSeverity } from '../loeschfristen-compliance' import type { LoeschkonzeptOrgHeader, LoeschkonzeptRevision } from './types-defaults' import { SEVERITY_LABELS_DE, SEVERITY_COLORS } from './types-defaults' import { escHtml, formatDateDE } from './helpers' export function buildSections6to9( activePolicies: LoeschfristPolicy[], vvtRefs: Array<{ policyName: string; policyId: string; vvtId: string; vvtName: string }>, vendorRefs: Array<{ policyName: string; policyId: string; vendorId: string; duration: string }>, allActiveLegalHolds: Array<{ policy: string; hold: LoeschfristPolicy['legalHolds'][0] }>, roleMap: Map ): string { let html = `
6. VVT-Verknuepfung

Die folgende Tabelle zeigt die Verknuepfung zwischen Loeschregeln und Verarbeitungstaetigkeiten im VVT (Art. 30 DSGVO):

` if (vvtRefs.length > 0) { html += ` ` for (const ref of vvtRefs) { html += ` ` } html += `
LoeschregelLF-Nr.VVT-Nr.Verarbeitungstaetigkeit
${escHtml(ref.policyName)} ${escHtml(ref.policyId)} ${escHtml(ref.vvtId)} ${escHtml(ref.vvtName)}
` } else { html += `

Noch keine VVT-Verknuepfungen dokumentiert.

` } html += `
7. Auftragsverarbeiter mit Loeschpflichten

Die folgende Tabelle zeigt Loeschregeln, die mit Auftragsverarbeitern verknuepft sind (Art. 28 DSGVO).

` if (vendorRefs.length > 0) { html += ` ` for (const ref of vendorRefs) { html += ` ` } html += `
LoeschregelLF-Nr.Auftragsverarbeiter (ID)Aufbewahrungsfrist
${escHtml(ref.policyName)} ${escHtml(ref.policyId)} ${escHtml(ref.vendorId)} ${escHtml(ref.duration)}
` } else { html += `

Noch keine Auftragsverarbeiter mit Loeschregeln verknuepft.

` } html += `
8. Legal Hold Verfahren

Ein Legal Hold setzt die regulaere Loeschung aus. Betroffene Daten duerfen trotz abgelaufener Loeschfrist nicht geloescht werden, bis der Legal Hold aufgehoben wird.

Verfahrensschritte:

  1. Rechtsabteilung/DSB identifiziert betroffene Datenkategorien
  2. Legal Hold wird im System aktiviert (Status: Aktiv)
  3. Automatische Loeschung wird fuer betroffene Policies ausgesetzt
  4. Regelmaessige Pruefung, ob der Legal Hold noch erforderlich ist
  5. Nach Aufhebung: Regulaere Loeschfristen greifen wieder
` if (allActiveLegalHolds.length > 0) { html += `

Aktuell aktive Legal Holds (${allActiveLegalHolds.length}):

` for (const { policy, hold } of allActiveLegalHolds) { html += ` ` } html += `
DatenobjektGrundRechtsgrundlageSeitVoraussichtlich bis
${escHtml(policy)} ${escHtml(hold.reason)} ${escHtml(hold.legalBasis)} ${formatDateDE(hold.startDate)} ${hold.expectedEndDate ? formatDateDE(hold.expectedEndDate) : 'Unbefristet'}
` } else { html += `

Derzeit sind keine aktiven Legal Holds vorhanden.

` } html += `
9. Verantwortlichkeiten

Die folgende Rollenmatrix zeigt, welche Organisationseinheiten fuer welche Datenobjekte die Loeschverantwortung tragen:

` for (const [role, objects] of roleMap.entries()) { html += ` ` } html += `
Rolle / VerantwortlichDatenobjekteAnzahl
${escHtml(role)} ${objects.map(o => escHtml(o)).join(', ')} ${objects.length}
` return html } export function buildSections10to12( orgHeader: LoeschkonzeptOrgHeader, complianceResult: ComplianceCheckResult | null, revisions: LoeschkonzeptRevision[], today: string ): string { let html = `
10. Pruef- und Revisionszyklus
EigenschaftWert
Aktuelles Pruefintervall${escHtml(orgHeader.reviewInterval)}
Letzte Pruefung${formatDateDE(orgHeader.lastReviewDate)}
Naechste Pruefung${formatDateDE(orgHeader.nextReviewDate)}
Aktuelle Version${escHtml(orgHeader.loeschkonzeptVersion)}

Bei jeder Pruefung wird das Loeschkonzept auf folgende Punkte ueberprueft:

  • Vollstaendigkeit aller Loeschregeln (neue Verarbeitungen erfasst?)
  • Aktualitaet der gesetzlichen Aufbewahrungsfristen
  • Wirksamkeit der technischen Loeschmechanismen
  • Einhaltung der definierten Loeschfristen
  • Angemessenheit der Verantwortlichkeiten
` html += buildSection11Compliance(complianceResult) html += buildSection12History(revisions, orgHeader, today) return html } function buildSection11Compliance(complianceResult: ComplianceCheckResult | null): string { let html = `
11. 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 Policies${complianceResult.stats.total}
Bestanden${complianceResult.stats.passed}
Beanstandungen${complianceResult.stats.failed}
` if (complianceResult.issues.length > 0) { html += `

Befunde nach Schweregrad:

` const severityOrder: ComplianceIssueSeverity[] = ['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 Policies sind konform.

` } } else { html += `

Compliance-Check wurde noch nicht ausgefuehrt.

` } html += `
` return html } function buildSection12History( revisions: LoeschkonzeptRevision[], orgHeader: LoeschkonzeptOrgHeader, today: string ): string { let html = `
12. 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.loeschkonzeptVersion)} ${today} ${escHtml(orgHeader.dpoName || orgHeader.responsiblePerson || '-')} Erstversion des Loeschkonzepts
` return html }