feat(sdk): vendor-compliance cross-module integration — VVT, obligations, TOM, loeschfristen

Integrate the vendor-compliance module with four DSGVO modules to eliminate
data silos and resolve the VVT processor tab's ephemeral state problem.

- Reposition vendor-compliance sidebar from seq 4200 to 2500 (after VVT)
- VVT: replace ephemeral ProcessorRecord state with Vendor-API fetch (read-only)
- Obligations: add linked_vendor_ids (JSONB) + compliance check #12 MISSING_VENDOR_LINK
- TOM: add vendor TOM-controls cross-reference table in overview tab
- Loeschfristen: add linked_vendor_ids (JSONB) + vendor picker + document section
- Migrations: 069_obligations_vendor_link.sql, 070_loeschfristen_vendor_link.sql
- Tests: 12 new backend tests (125 total pass)
- Docs: update obligations.md + vendors.md with cross-module integration

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Benjamin Admin
2026-03-19 13:59:43 +01:00
parent 4b1eede45b
commit c3afa628ed
19 changed files with 2852 additions and 421 deletions

View File

@@ -148,6 +148,21 @@ export function buildLoeschkonzeptHtml(
}
}
// Build vendor cross-reference data
const vendorRefs: Array<{ policyName: string; policyId: string; vendorId: string; duration: string }> = []
for (const p of activePolicies) {
if (p.linkedVendorIds && p.linkedVendorIds.length > 0) {
for (const vendorId of p.linkedVendorIds) {
vendorRefs.push({
policyName: p.dataObjectName || p.policyId,
policyId: p.policyId,
vendorId,
duration: formatRetentionDuration(p.retentionDuration, p.retentionUnit),
})
}
}
}
// =========================================================================
// HTML Template
// =========================================================================
@@ -392,6 +407,7 @@ export function buildLoeschkonzeptHtml(
'Loeschregeln-Uebersicht',
'Detaillierte Loeschregeln',
'VVT-Verknuepfung',
'Auftragsverarbeiter mit Loeschpflichten',
'Legal Hold Verfahren',
'Verantwortlichkeiten',
'Pruef- und Revisionszyklus',
@@ -594,11 +610,47 @@ export function buildLoeschkonzeptHtml(
`
// =========================================================================
// Section 7: Legal Hold Verfahren
// Section 7: Auftragsverarbeiter mit Loeschpflichten
// =========================================================================
html += `
<div class="section">
<div class="section-header">7. Legal Hold Verfahren</div>
<div class="section-header">7. Auftragsverarbeiter mit Loeschpflichten</div>
<div class="section-body">
<p>Die folgende Tabelle zeigt Loeschregeln, die mit Auftragsverarbeitern verknuepft sind.
Diese Verknuepfungen stellen sicher, dass auch bei extern verarbeiteten Daten die Loeschpflichten
eingehalten werden (Art. 28 DSGVO).</p>
`
if (vendorRefs.length > 0) {
html += ` <table>
<tr><th>Loeschregel</th><th>LF-Nr.</th><th>Auftragsverarbeiter (ID)</th><th>Aufbewahrungsfrist</th></tr>
`
for (const ref of vendorRefs) {
html += ` <tr>
<td>${escHtml(ref.policyName)}</td>
<td>${escHtml(ref.policyId)}</td>
<td>${escHtml(ref.vendorId)}</td>
<td>${escHtml(ref.duration)}</td>
</tr>
`
}
html += ` </table>
`
} else {
html += ` <p><em>Noch keine Auftragsverarbeiter mit Loeschregeln verknuepft. Verknuepfen Sie Ihre
Loeschregeln mit den entsprechenden Auftragsverarbeitern im Editor-Tab.</em></p>
`
}
html += ` </div>
</div>
`
// =========================================================================
// Section 8: Legal Hold Verfahren
// =========================================================================
html += `
<div class="section">
<div class="section-header">8. Legal Hold Verfahren</div>
<div class="section-body">
<p>Ein Legal Hold (Aufbewahrungspflicht aufgrund rechtlicher Verfahren) setzt die regulaere
Loeschung aus. Betroffene Daten duerfen trotz abgelaufener Loeschfrist nicht geloescht werden,
@@ -639,11 +691,11 @@ export function buildLoeschkonzeptHtml(
`
// =========================================================================
// Section 8: Verantwortlichkeiten
// Section 9: Verantwortlichkeiten
// =========================================================================
html += `
<div class="section">
<div class="section-header">8. Verantwortlichkeiten</div>
<div class="section-header">9. Verantwortlichkeiten</div>
<div class="section-body">
<p>Die folgende Rollenmatrix zeigt, welche Organisationseinheiten fuer welche Datenobjekte
die Loeschverantwortung tragen:</p>
@@ -665,11 +717,11 @@ export function buildLoeschkonzeptHtml(
`
// =========================================================================
// Section 9: Pruef- und Revisionszyklus
// Section 10: Pruef- und Revisionszyklus
// =========================================================================
html += `
<div class="section">
<div class="section-header">9. Pruef- und Revisionszyklus</div>
<div class="section-header">10. Pruef- und Revisionszyklus</div>
<div class="section-body">
<table>
<tr><th>Eigenschaft</th><th>Wert</th></tr>
@@ -691,11 +743,11 @@ export function buildLoeschkonzeptHtml(
`
// =========================================================================
// Section 10: Compliance-Status
// Section 11: Compliance-Status
// =========================================================================
html += `
<div class="section page-break">
<div class="section-header">10. Compliance-Status</div>
<div class="section-header">11. Compliance-Status</div>
<div class="section-body">
`
if (complianceResult) {
@@ -750,11 +802,11 @@ export function buildLoeschkonzeptHtml(
`
// =========================================================================
// Section 11: Aenderungshistorie
// Section 12: Aenderungshistorie
// =========================================================================
html += `
<div class="section">
<div class="section-header">11. Aenderungshistorie</div>
<div class="section-header">12. Aenderungshistorie</div>
<div class="section-body">
<table>
<tr><th>Version</th><th>Datum</th><th>Autor</th><th>Aenderungen</th></tr>