feat(sdk): Multi-Tenancy, Versionierung, Change-Requests, Dokumentengenerierung (Phase 1-6)
All checks were successful
CI / go-lint (push) Has been skipped
CI / python-lint (push) Has been skipped
CI / nodejs-lint (push) Has been skipped
CI / test-go-ai-compliance (push) Successful in 32s
CI / test-python-backend-compliance (push) Successful in 30s
CI / test-python-document-crawler (push) Successful in 21s
CI / test-python-dsms-gateway (push) Successful in 18s

6-Phasen-Implementation fuer cloud-faehiges, mandantenfaehiges Compliance SDK:

Phase 1: Multi-Tenancy Fix
- Shared tenant_utils.py Dependency (UUID-Validierung, kein "default" mehr)
- VVT tenant_id Column + tenant-scoped Queries
- DSFA/Vendor DEFAULT_TENANT_ID von "default" auf UUID migriert
- Migration 035

Phase 2: Stammdaten-Erweiterung
- Company Profile um JSONB-Felder erweitert (processing_systems, ai_systems, technical_contacts)
- Regulierungs-Flags (NIS2, AI Act, ISO 27001)
- GET /template-context Endpoint
- Migration 036

Phase 3: Dokument-Versionierung
- 5 Versions-Tabellen (DSFA, VVT, TOM, Loeschfristen, Obligations)
- Shared versioning_utils.py Helper
- /{id}/versions Endpoints auf allen 5 Dokumenttypen
- Migration 037

Phase 4: Change-Request System
- Zentrale CR-Inbox mit CRUD + Accept/Reject/Edit Workflow
- Regelbasierte CR-Engine (VVT DPIA → DSFA CR, Datenkategorien → Loeschfristen CR)
- Audit-Trail
- Migration 038

Phase 5: Dokumentengenerierung
- 5 Template-Generatoren (DSFA, VVT, TOM, Loeschfristen, Obligations)
- Preview + Apply Endpoints (erzeugt CRs, keine direkten Dokumente)

Phase 6: Frontend-Integration
- Change-Request Inbox Page mit Stats, Filtern, Modals
- VersionHistory Timeline-Komponente
- SDKSidebar CR-Badge (60s Polling)
- Company Profile: 2 neue Wizard-Steps + "Dokumente generieren" CTA

Docs: 5 neue MkDocs-Seiten, CLAUDE.md aktualisiert
Tests: 97 neue Tests (alle bestanden)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Benjamin Admin
2026-03-07 14:12:34 +01:00
parent ef9aed666f
commit 1e84df9769
41 changed files with 4818 additions and 52 deletions

View File

@@ -0,0 +1,15 @@
"""Document generation templates for compliance documents."""
from .dsfa_template import generate_dsfa_draft
from .vvt_template import generate_vvt_drafts
from .loeschfristen_template import generate_loeschfristen_drafts
from .tom_template import generate_tom_drafts
from .obligation_template import generate_obligation_drafts
__all__ = [
"generate_dsfa_draft",
"generate_vvt_drafts",
"generate_loeschfristen_drafts",
"generate_tom_drafts",
"generate_obligation_drafts",
]

View File

@@ -0,0 +1,82 @@
"""DSFA template generator — creates DSFA skeleton from company profile."""
def generate_dsfa_draft(ctx: dict) -> dict:
"""Generate a DSFA draft document from template context.
Args:
ctx: Flat dict from company-profile/template-context endpoint
Returns:
Dict with DSFA fields ready for creation
"""
company = ctx.get("company_name", "Unbekannt")
dpo = ctx.get("dpo_name", "")
dpo_email = ctx.get("dpo_email", "")
sections = {
"section_1": {
"title": "Beschreibung der Verarbeitung",
"content": f"Die {company} führt eine Datenschutz-Folgenabschätzung gemäß Art. 35 DSGVO durch.\n\n"
f"**Verantwortlicher:** {company}\n"
f"**Datenschutzbeauftragter:** {dpo} ({dpo_email})\n"
f"**Zuständige Aufsichtsbehörde:** {ctx.get('supervisory_authority', 'Nicht angegeben')}",
},
"section_2": {
"title": "Notwendigkeit und Verhältnismäßigkeit",
"content": "Die Verarbeitung ist zur Erreichung des beschriebenen Zwecks erforderlich. "
"Alternative, weniger eingriffsintensive Maßnahmen wurden geprüft.",
},
"section_3": {
"title": "Risiken für die Rechte und Freiheiten",
"content": _generate_risk_section(ctx),
},
"section_6": {
"title": "Stellungnahme des DSB",
"content": f"Der Datenschutzbeauftragte ({dpo}) wurde konsultiert." if dpo else
"Ein Datenschutzbeauftragter wurde noch nicht benannt.",
},
}
ai_systems = ctx.get("ai_systems", [])
involves_ai = len(ai_systems) > 0
return {
"title": f"DSFA — {company}",
"description": f"Automatisch generierte Datenschutz-Folgenabschätzung für {company}",
"status": "draft",
"risk_level": "high" if involves_ai else "medium",
"involves_ai": involves_ai,
"dpo_name": dpo,
"sections": sections,
"processing_systems": [s.get("name", "") for s in ctx.get("processing_systems", [])],
"ai_systems_summary": [
{"name": s.get("name"), "risk": s.get("risk_category", "unknown")}
for s in ai_systems
],
}
def _generate_risk_section(ctx: dict) -> str:
lines = ["## Risikoanalyse\n"]
if ctx.get("has_ai_systems"):
lines.append("### KI-Systeme\n")
for s in ctx.get("ai_systems", []):
risk = s.get("risk_category", "unbekannt")
lines.append(f"- **{s.get('name', 'N/A')}**: Zweck: {s.get('purpose', 'N/A')}, "
f"Risiko: {risk}, Human Oversight: {'Ja' if s.get('has_human_oversight') else 'Nein'}")
lines.append("")
if ctx.get("subject_to_ai_act"):
lines.append("**Hinweis:** Das Unternehmen unterliegt dem EU AI Act. "
"KI-spezifische Risiken müssen gemäß der KI-Verordnung bewertet werden.\n")
if ctx.get("subject_to_nis2"):
lines.append("**Hinweis:** NIS2-Richtlinie ist anwendbar. "
"Cybersicherheitsrisiken sind zusätzlich zu bewerten.\n")
if not ctx.get("has_ai_systems") and not ctx.get("subject_to_nis2"):
lines.append("Standardrisiken der Datenverarbeitung sind zu bewerten.\n")
return "\n".join(lines)

View File

@@ -0,0 +1,49 @@
"""Loeschfristen template generator — creates retention policies per data category."""
# Standard DSGVO retention periods
_STANDARD_PERIODS = {
"Bankdaten": {"duration": "10 Jahre", "legal_basis": "§ 257 HGB, § 147 AO"},
"Steuer-ID": {"duration": "10 Jahre", "legal_basis": "§ 147 AO"},
"Bewerbungsunterlagen": {"duration": "6 Monate", "legal_basis": "§ 15 AGG"},
"Lohnabrechnungen": {"duration": "6 Jahre", "legal_basis": "§ 257 HGB"},
"Gesundheitsdaten": {"duration": "10 Jahre", "legal_basis": "§ 630f BGB"},
"Kundendaten": {"duration": "3 Jahre", "legal_basis": "§ 195 BGB (Verjährung)"},
"Vertragsdaten": {"duration": "10 Jahre", "legal_basis": "§ 257 HGB"},
"Kommunikationsdaten": {"duration": "6 Monate", "legal_basis": "Art. 5 Abs. 1e DSGVO"},
"Zugriffsprotokolle": {"duration": "12 Monate", "legal_basis": "Art. 5 Abs. 1e DSGVO"},
"Mitarbeiterdaten": {"duration": "3 Jahre nach Austritt", "legal_basis": "§ 195 BGB"},
}
def generate_loeschfristen_drafts(ctx: dict) -> list[dict]:
"""Generate retention policy drafts based on processing systems.
Args:
ctx: Flat dict from company-profile/template-context
Returns:
List of Loeschfristen dicts ready for creation
"""
# Collect all data categories from processing systems
all_categories = set()
for system in ctx.get("processing_systems", []):
for cat in system.get("personal_data_categories", []):
all_categories.add(cat)
policies = []
for i, category in enumerate(sorted(all_categories), 1):
standard = _STANDARD_PERIODS.get(category, {})
policy = {
"policy_id": f"LF-AUTO-{i:03d}",
"data_category": category,
"retention_period": standard.get("duration", "Noch festzulegen"),
"legal_basis": standard.get("legal_basis", "Zu prüfen"),
"deletion_method": "Automatische Löschung nach Ablauf",
"responsible": ctx.get("dpo_name", "DSB"),
"status": "draft",
"review_cycle_months": ctx.get("review_cycle_months", 12),
"notes": f"Automatisch generiert aus Stammdaten. Bitte prüfen und anpassen.",
}
policies.append(policy)
return policies

View File

@@ -0,0 +1,141 @@
"""Obligation template generator — creates standard DSGVO obligations."""
_DSGVO_OBLIGATIONS = [
{
"title": "Verzeichnis der Verarbeitungstätigkeiten führen",
"regulation": "DSGVO",
"article": "Art. 30",
"description": "Das Verzeichnis muss alle Verarbeitungstätigkeiten mit personenbezogenen Daten dokumentieren.",
"category": "documentation",
"priority": "high",
},
{
"title": "Datenschutz-Folgenabschätzung durchführen",
"regulation": "DSGVO",
"article": "Art. 35",
"description": "Für Verarbeitungen mit hohem Risiko muss eine DSFA vor Beginn der Verarbeitung durchgeführt werden.",
"category": "risk_assessment",
"priority": "high",
},
{
"title": "Technisch-organisatorische Maßnahmen implementieren",
"regulation": "DSGVO",
"article": "Art. 32",
"description": "Angemessene TOMs zum Schutz personenbezogener Daten unter Berücksichtigung des Stands der Technik.",
"category": "technical",
"priority": "high",
},
{
"title": "Betroffenenrechte sicherstellen",
"regulation": "DSGVO",
"article": "Art. 12-22",
"description": "Auskunft, Berichtigung, Löschung, Datenportabilität, Widerspruch — alle Rechte müssen binnen eines Monats erfüllt werden.",
"category": "data_subject_rights",
"priority": "high",
},
{
"title": "Datenschutzverletzungen melden",
"regulation": "DSGVO",
"article": "Art. 33-34",
"description": "Meldung an die Aufsichtsbehörde binnen 72 Stunden; Benachrichtigung Betroffener bei hohem Risiko.",
"category": "incident_response",
"priority": "critical",
},
{
"title": "Auftragsverarbeitungsverträge abschließen",
"regulation": "DSGVO",
"article": "Art. 28",
"description": "Schriftliche AV-Verträge mit allen Dienstleistern, die personenbezogene Daten verarbeiten.",
"category": "vendor_management",
"priority": "high",
},
{
"title": "Datenschutzbeauftragten benennen",
"regulation": "DSGVO",
"article": "Art. 37",
"description": "Pflicht bei ≥20 Mitarbeitern in der automatisierten Verarbeitung oder bei Verarbeitung besonderer Kategorien.",
"category": "governance",
"priority": "medium",
},
{
"title": "Löschkonzept implementieren",
"regulation": "DSGVO",
"article": "Art. 17",
"description": "Recht auf Löschung — systematisches Löschkonzept mit definierten Fristen pro Datenkategorie.",
"category": "data_lifecycle",
"priority": "high",
},
]
_AI_ACT_OBLIGATIONS = [
{
"title": "KI-System-Register führen",
"regulation": "EU AI Act",
"article": "Art. 49",
"description": "Alle KI-Systeme müssen in der EU-Datenbank registriert werden (Hochrisiko).",
"category": "documentation",
"priority": "high",
},
{
"title": "KI-Risikomanagement einrichten",
"regulation": "EU AI Act",
"article": "Art. 9",
"description": "Risikomanagementsystem für den gesamten Lebenszyklus von Hochrisiko-KI-Systemen.",
"category": "risk_assessment",
"priority": "critical",
},
{
"title": "KI-Transparenzpflichten erfüllen",
"regulation": "EU AI Act",
"article": "Art. 52",
"description": "Nutzer müssen über die Interaktion mit KI-Systemen informiert werden.",
"category": "transparency",
"priority": "high",
},
]
_NIS2_OBLIGATIONS = [
{
"title": "Cybersicherheits-Risikomanagement",
"regulation": "NIS2",
"article": "Art. 21",
"description": "Angemessene und verhältnismäßige technische, betriebliche und organisatorische Maßnahmen.",
"category": "cybersecurity",
"priority": "critical",
},
{
"title": "Meldepflichten NIS2",
"regulation": "NIS2",
"article": "Art. 23",
"description": "Frühwarnung binnen 24h, Vorfallmeldung binnen 72h, Abschlussbericht binnen 1 Monat.",
"category": "incident_response",
"priority": "critical",
},
]
def generate_obligation_drafts(ctx: dict) -> list[dict]:
"""Generate obligation drafts based on regulatory flags.
Args:
ctx: Flat dict from company-profile/template-context
Returns:
List of obligation dicts ready for creation
"""
obligations = list(_DSGVO_OBLIGATIONS)
if ctx.get("subject_to_ai_act") or ctx.get("has_ai_systems"):
obligations.extend(_AI_ACT_OBLIGATIONS)
if ctx.get("subject_to_nis2"):
obligations.extend(_NIS2_OBLIGATIONS)
# Enrich with company context
for i, o in enumerate(obligations, 1):
o["obligation_id"] = f"OBL-AUTO-{i:03d}"
o["status"] = "open"
o["responsible"] = ctx.get("dpo_name", "")
o["review_cycle_months"] = ctx.get("review_cycle_months", 12)
return obligations

View File

@@ -0,0 +1,69 @@
"""TOM template generator — creates TOM checklist based on regulatory flags."""
_BASE_TOMS = [
{"category": "Zutrittskontrolle", "name": "Physische Zugangskontrollen", "description": "Schlüssel, Kartenleser, Videoüberwachung"},
{"category": "Zugangskontrolle", "name": "Authentifizierung", "description": "Passwortrichtlinien, MFA, SSO"},
{"category": "Zugriffskontrolle", "name": "Berechtigungskonzept", "description": "RBAC, Least Privilege, regelmäßige Reviews"},
{"category": "Weitergabekontrolle", "name": "Verschlüsselung im Transit", "description": "TLS 1.3 für alle Verbindungen"},
{"category": "Eingabekontrolle", "name": "Audit-Logging", "description": "Protokollierung aller Datenänderungen"},
{"category": "Auftragskontrolle", "name": "AV-Verträge", "description": "Art. 28 DSGVO Auftragsverarbeitungsverträge"},
{"category": "Verfügbarkeitskontrolle", "name": "Backup & Recovery", "description": "Regelmäßige Backups, Disaster Recovery Plan"},
{"category": "Trennungsgebot", "name": "Mandantentrennung", "description": "Logische Datentrennung nach Mandanten"},
]
_NIS2_TOMS = [
{"category": "Cybersicherheit", "name": "Incident Response Plan", "description": "NIS2-konformer Vorfallreaktionsplan (72h Meldepflicht)"},
{"category": "Cybersicherheit", "name": "Supply Chain Security", "description": "Bewertung der Lieferkettensicherheit"},
{"category": "Cybersicherheit", "name": "Vulnerability Management", "description": "Regelmäßige Schwachstellenscans und Patch-Management"},
]
_ISO27001_TOMS = [
{"category": "ISMS", "name": "Risikomanagement", "description": "ISO 27001 Anhang A — Informationssicherheits-Risikobewertung"},
{"category": "ISMS", "name": "Dokumentenlenkung", "description": "Versionierte Sicherheitsrichtlinien und -verfahren"},
{"category": "ISMS", "name": "Management Review", "description": "Jährliche Überprüfung des ISMS durch die Geschäftsleitung"},
]
_AI_ACT_TOMS = [
{"category": "KI-Compliance", "name": "KI-Risikoklassifizierung", "description": "Bewertung aller KI-Systeme nach EU AI Act Risikokategorien"},
{"category": "KI-Compliance", "name": "Human Oversight", "description": "Menschliche Aufsicht für Hochrisiko-KI-Systeme sicherstellen"},
{"category": "KI-Compliance", "name": "KI-Transparenz", "description": "Transparenzpflichten bei KI-Einsatz gegenüber Betroffenen"},
]
def generate_tom_drafts(ctx: dict) -> list[dict]:
"""Generate TOM measure drafts based on regulatory flags.
Args:
ctx: Flat dict from company-profile/template-context
Returns:
List of TOM measure dicts ready for creation
"""
measures = list(_BASE_TOMS)
if ctx.get("subject_to_nis2"):
measures.extend(_NIS2_TOMS)
if ctx.get("subject_to_iso27001"):
measures.extend(_ISO27001_TOMS)
if ctx.get("subject_to_ai_act") or ctx.get("has_ai_systems"):
measures.extend(_AI_ACT_TOMS)
# Enrich with metadata
company = ctx.get("company_name", "")
result = []
for i, m in enumerate(measures, 1):
result.append({
"control_id": f"TOM-AUTO-{i:03d}",
"name": m["name"],
"description": m["description"],
"category": m["category"],
"type": "technical" if m["category"] in ("Zugangskontrolle", "Zugriffskontrolle", "Weitergabekontrolle", "Cybersicherheit") else "organizational",
"implementation_status": "planned",
"responsible_department": "IT-Sicherheit",
"priority": "high" if "KI" in m.get("category", "") or "Cyber" in m.get("category", "") else "medium",
"review_frequency": f"{ctx.get('review_cycle_months', 12)} Monate",
})
return result

View File

@@ -0,0 +1,53 @@
"""VVT template generator — creates VVT activity drafts per processing system."""
def generate_vvt_drafts(ctx: dict) -> list[dict]:
"""Generate VVT activity drafts, one per processing system.
Args:
ctx: Flat dict from company-profile/template-context
Returns:
List of VVT activity dicts ready for creation
"""
systems = ctx.get("processing_systems", [])
company = ctx.get("company_name", "Unbekannt")
dpo = ctx.get("dpo_name", "")
activities = []
for i, system in enumerate(systems, 1):
name = system.get("name", f"System {i}")
vendor = system.get("vendor", "")
hosting = system.get("hosting", "on-premise")
categories = system.get("personal_data_categories", [])
activity = {
"vvt_id": f"VVT-AUTO-{i:03d}",
"name": f"Verarbeitung in {name}",
"description": f"Automatisch generierter VVT-Eintrag für das System '{name}'"
+ (f" (Anbieter: {vendor})" if vendor else ""),
"purposes": [f"Datenverarbeitung via {name}"],
"legal_bases": ["Art. 6 Abs. 1b DSGVO — Vertragserfüllung"],
"data_subject_categories": [],
"personal_data_categories": categories,
"recipient_categories": [vendor] if vendor else [],
"third_country_transfers": _assess_third_country(hosting),
"retention_period": {"default": "Gemäß Löschfristenkatalog"},
"tom_description": f"Siehe TOM-Katalog für {name}",
"business_function": "IT",
"systems": [name],
"deployment_model": hosting,
"protection_level": "HIGH" if categories else "MEDIUM",
"dpia_required": len(categories) > 3,
"status": "DRAFT",
"responsible": dpo or company,
}
activities.append(activity)
return activities
def _assess_third_country(hosting: str) -> list:
if hosting in ("us-cloud", "international"):
return [{"country": "USA", "mechanism": "EU-US Data Privacy Framework"}]
return []