Files
breakpilot-core/document-templates/generators/vvt_template.py
Benjamin Admin fc71117bf2 feat: Document Templates V2 — DSFA, TOM, VVT, AVV, Verpflichtung, Art.13/14
Erweiterte Compliance-Vorlagen fuer den Document Generator:
- DSFA V2: Schwellwertanalyse (9 WP248-Kriterien), SDM-basierte TOM,
  strukturierte Risikobewertung, KI-Modul (AI Act), Art.36-Pruefung
- TOM V2: 7 SDM-Gewaehrleistungsziele, Sektor-Erweiterungen,
  NIS2/ISO27001/AI Act Varianten
- VVT V2: 6 Branchen-Muster (IT/SaaS, Gesundheit, Handel, Handwerk,
  Bildung, Beratung) + allgemeine Art.30-Vorlage
- AVV V2: Vollstaendiger Art.28-Vertrag mit TOM-Anlage
- Verpflichtungserklaerung: Mitarbeiter-Vertraulichkeit
- Art.13/14 Informationspflichten-Muster

Enthalt SQL-Migrations (compliance_legal_templates), Python-Generatoren
und Qdrant-Cleanup-Skript. Feature-Branch fuer spaetere Integration
in breakpilot-compliance.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 11:39:39 +02:00

394 lines
19 KiB
Python

"""VVT template generator V2 — sector-specific VVT activity drafts.
Generates Art. 30 DS-GVO compliant VVT entries with sector-specific
standard processing activities inspired by BayLDA patterns.
"""
from typing import Optional
# -- Sector activity catalogs ------------------------------------------------
SECTOR_ACTIVITIES = {
"it_saas": [
{
"name": "SaaS-Plattformbetrieb",
"purposes": ["Bereitstellung und Betrieb der SaaS-Plattform"],
"legal_bases": ["Art. 6 Abs. 1 lit. b DS-GVO (Vertragserfullung)"],
"data_subject_categories": ["Kunden", "Endnutzer"],
"personal_data_categories": ["Stammdaten", "Nutzungsdaten", "Inhaltsdaten", "Logdaten"],
"recipient_categories": ["Hosting-Anbieter (AVV)", "Support-Dienstleister (AVV)"],
"retention_period": "90 Tage nach Vertragsende + gesetzl. Aufbewahrung",
"tom_description": "Mandantentrennung, Verschluesselung, RBAC",
"dpia_required": True,
},
{
"name": "Kundenverwaltung / CRM",
"purposes": ["Verwaltung von Kundenbeziehungen, Vertragsmanagement"],
"legal_bases": ["Art. 6 Abs. 1 lit. b DS-GVO"],
"data_subject_categories": ["Kunden", "Ansprechpartner", "Interessenten"],
"personal_data_categories": ["Kontaktdaten", "Vertragsdaten", "Kommunikationshistorie"],
"recipient_categories": ["CRM-Anbieter (AVV)"],
"retention_period": "3 Jahre nach letztem Kontakt, 10 Jahre Rechnungsdaten",
"tom_description": "Zugriffsbeschraenkung Vertrieb/Support, Protokollierung",
},
{
"name": "E-Mail-Marketing / Newsletter",
"purposes": ["Versand von Produkt-Updates und Marketing-Newsletter"],
"legal_bases": ["Art. 6 Abs. 1 lit. a DS-GVO (Einwilligung)", "UWG §7"],
"data_subject_categories": ["Newsletter-Abonnenten"],
"personal_data_categories": ["E-Mail-Adresse", "Name", "Oeffnungs-/Klickverhalten"],
"recipient_categories": ["E-Mail-Dienstleister (AVV)"],
"retention_period": "Unverzueglich nach Widerruf",
"tom_description": "Double-Opt-In, einfache Abmeldefunktion",
},
{
"name": "Webanalyse",
"purposes": ["Analyse der Website-Nutzung zur Verbesserung"],
"legal_bases": ["Art. 6 Abs. 1 lit. a DS-GVO (Einwilligung via Cookie-Banner)"],
"data_subject_categories": ["Website-Besucher"],
"personal_data_categories": ["IP-Adresse (anonymisiert)", "Seitenaufrufe", "Geraeteinformationen"],
"recipient_categories": ["Analyse-Anbieter (AVV)"],
"retention_period": "14 Monate",
"tom_description": "IP-Anonymisierung, Cookie-Consent (TDDDG §25)",
},
{
"name": "Bewerbermanagement",
"purposes": ["Bearbeitung von Bewerbungen"],
"legal_bases": ["Art. 6 Abs. 1 lit. b DS-GVO i.V.m. §26 BDSG"],
"data_subject_categories": ["Bewerber"],
"personal_data_categories": ["Kontaktdaten", "Lebenslauf", "Qualifikationen"],
"recipient_categories": ["Fachabteilung"],
"retention_period": "6 Monate nach Verfahrensabschluss (AGG)",
"tom_description": "Zugriffsschutz Bewerbungsportal, verschluesselte Uebertragung",
},
{
"name": "Mitarbeiterverwaltung / HR",
"purposes": ["Personalverwaltung, Lohnabrechnung, Arbeitszeiterfassung"],
"legal_bases": ["Art. 6 Abs. 1 lit. b/c DS-GVO i.V.m. §26 BDSG"],
"data_subject_categories": ["Beschaeftigte"],
"personal_data_categories": ["Stammdaten", "Vertragsdaten", "Bankverbindung", "Arbeitszeiten"],
"recipient_categories": ["Lohnbuero (AVV)", "Finanzamt", "Sozialversicherungstraeger"],
"retention_period": "10 Jahre nach Austritt",
"tom_description": "Besonderer Zugriffsschutz (nur HR), verschluesselte Speicherung",
},
{
"name": "Support-Ticketing",
"purposes": ["Bearbeitung von Kundenanfragen und Stoerungsmeldungen"],
"legal_bases": ["Art. 6 Abs. 1 lit. b DS-GVO"],
"data_subject_categories": ["Kunden", "Endnutzer"],
"personal_data_categories": ["Kontaktdaten", "Ticket-Inhalt", "Systemlogs"],
"recipient_categories": ["Support-Tool-Anbieter (AVV)"],
"retention_period": "2 Jahre nach Ticket-Schliessung",
"tom_description": "Rollenbasierter Zugriff, Pseudonymisierung in Reports",
},
{
"name": "Logging und Monitoring",
"purposes": ["Sicherheitsueberwachung, Fehleranalyse"],
"legal_bases": ["Art. 6 Abs. 1 lit. f DS-GVO (berechtigtes Interesse: IT-Sicherheit)"],
"data_subject_categories": ["Plattform-Nutzer", "Administratoren"],
"personal_data_categories": ["IP-Adressen", "Zugriffszeitpunkte", "Fehlerprotokolle"],
"recipient_categories": ["Log-Management-Anbieter (AVV)"],
"retention_period": "30 Tage Anwendungslogs, 90 Tage Sicherheitslogs",
"tom_description": "Zugriffsschutz Logdaten, automatische Rotation",
},
],
"gesundheitswesen": [
{
"name": "Patientenverwaltung",
"purposes": ["Patientenakte, Behandlungsdokumentation"],
"legal_bases": ["Art. 9 Abs. 2 lit. h DS-GVO i.V.m. §630f BGB"],
"data_subject_categories": ["Patienten"],
"personal_data_categories": ["Stammdaten", "Versicherung", "Diagnosen", "Befunde (Art. 9)"],
"recipient_categories": ["PVS-Anbieter (AVV)", "Labor (AVV)", "ueberweisende Aerzte"],
"retention_period": "10 Jahre nach letzter Behandlung (§630f BGB)",
"tom_description": "Verschluesselung Patientenakte, Notfallzugriff",
"dpia_required": True,
},
{
"name": "Abrechnung (KV/PKV)",
"purposes": ["Abrechnung aerztlicher Leistungen"],
"legal_bases": ["Art. 6 Abs. 1 lit. c DS-GVO", "Art. 9 Abs. 2 lit. h"],
"data_subject_categories": ["Patienten"],
"personal_data_categories": ["Stammdaten", "Versicherung", "Diagnosen (ICD)", "Leistungsziffern"],
"recipient_categories": ["KV", "PKV", "Abrechnungsstelle (AVV)"],
"retention_period": "10 Jahre (AO)",
"tom_description": "Verschluesselte Uebermittlung (KV-Connect/KIM)",
},
],
"handel": [
{
"name": "Bestellabwicklung",
"purposes": ["Bestellannahme, Versand, Rechnungsstellung"],
"legal_bases": ["Art. 6 Abs. 1 lit. b DS-GVO"],
"data_subject_categories": ["Kunden (Besteller)"],
"personal_data_categories": ["Kontaktdaten", "Lieferadresse", "Bestelldaten", "Rechnungsdaten"],
"recipient_categories": ["Versanddienstleister", "Zahlungsanbieter (AVV)"],
"retention_period": "10 Jahre Rechnungen, 3 Jahre Bestelldaten",
"tom_description": "Verschluesselte Uebertragung, Zugriffsschutz",
},
{
"name": "Kundenkonto",
"purposes": ["Bereitstellung Kundenkonto (optional)"],
"legal_bases": ["Art. 6 Abs. 1 lit. a/b DS-GVO"],
"data_subject_categories": ["Registrierte Kunden"],
"personal_data_categories": ["Stammdaten", "Passwort (gehasht)", "Bestellhistorie"],
"recipient_categories": ["Shop-Plattform (AVV)"],
"retention_period": "Sofort nach Kontoloesch-Anfrage, Rechnungen 10 Jahre",
"tom_description": "MFA-Option, bcrypt Passwortspeicherung, Gastzugang-Alternative",
},
{
"name": "Zahlungsabwicklung",
"purposes": ["Abwicklung von Zahlungsvorgaengen"],
"legal_bases": ["Art. 6 Abs. 1 lit. b DS-GVO"],
"data_subject_categories": ["Zahlende Kunden"],
"personal_data_categories": ["Zahlungsart", "Transaktionsdaten"],
"recipient_categories": ["Payment-Service-Provider"],
"retention_period": "10 Jahre (AO)",
"tom_description": "PCI-DSS, Tokenisierung, keine direkte Kartenspeicherung",
},
],
"handwerk": [
{
"name": "Kundenauftraege und Angebotserstellung",
"purposes": ["Angebotserstellung, Auftragsabwicklung, Rechnungsstellung"],
"legal_bases": ["Art. 6 Abs. 1 lit. b DS-GVO"],
"data_subject_categories": ["Kunden (Privat/Gewerbe)"],
"personal_data_categories": ["Kontaktdaten", "Objektadresse", "Auftrag", "Rechnungsdaten"],
"recipient_categories": ["Steuerberater", "ggf. Subunternehmer"],
"retention_period": "10 Jahre Rechnungen, 5 Jahre Gewaehrleistung",
"tom_description": "Zugriffskontrolle Auftragssystem",
},
{
"name": "Baustellendokumentation",
"purposes": ["Dokumentation Baufortschritt, Maengelprotokoll"],
"legal_bases": ["Art. 6 Abs. 1 lit. b/f DS-GVO"],
"data_subject_categories": ["Kunden", "Mitarbeitende"],
"personal_data_categories": ["Fotos", "Protokolle", "Abnahmedokumente"],
"recipient_categories": ["Auftraggeber", "Architekten"],
"retention_period": "5 Jahre nach Abnahme",
"tom_description": "Projektordner mit Zugriffsbeschraenkung",
},
],
"bildung": [
{
"name": "Schueler-/Studierendenverwaltung",
"purposes": ["Verwaltung von Schueler-/Studierendendaten"],
"legal_bases": ["Art. 6 Abs. 1 lit. c/e DS-GVO i.V.m. Schulgesetz"],
"data_subject_categories": ["Schueler/Studierende (ggf. Minderjaehrige)", "Erziehungsberechtigte"],
"personal_data_categories": ["Stammdaten", "Kontaktdaten Erziehungsberechtigte"],
"recipient_categories": ["Schulverwaltungssoftware (AVV)", "Schulbehoerde"],
"retention_period": "Gemaess Schulgesetz (i.d.R. 5 Jahre nach Abgang)",
"tom_description": "Besonderer Zugriffsschutz, Einwilligung Erziehungsberechtigte",
"dpia_required": True,
},
{
"name": "Notenverarbeitung",
"purposes": ["Leistungsbewertung, Zeugniserstellung"],
"legal_bases": ["Art. 6 Abs. 1 lit. c/e DS-GVO i.V.m. Schulgesetz"],
"data_subject_categories": ["Schueler/Studierende"],
"personal_data_categories": ["Noten", "Leistungsbewertungen", "Pruefungsergebnisse"],
"recipient_categories": ["Lehrkraefte", "Schulleitung"],
"retention_period": "Zeugniskopien 50 Jahre, Einzelnoten 2 Jahre",
"tom_description": "Zugriffsbeschraenkung auf Fachlehrkraft, verschluesselt",
},
],
"beratung": [
{
"name": "Mandantenverwaltung",
"purposes": ["Verwaltung von Mandantenbeziehungen"],
"legal_bases": ["Art. 6 Abs. 1 lit. b DS-GVO"],
"data_subject_categories": ["Mandanten", "Ansprechpartner"],
"personal_data_categories": ["Kontaktdaten", "Vertragsdaten", "Korrespondenz"],
"recipient_categories": ["Kanzleisoftware (AVV)", "Steuerberater"],
"retention_period": "10 Jahre Rechnungen, 5 Jahre Handakten",
"tom_description": "Mandantengeheimnis, Need-to-know-Prinzip",
},
{
"name": "Projektmanagement",
"purposes": ["Planung und Steuerung von Beratungsprojekten"],
"legal_bases": ["Art. 6 Abs. 1 lit. b/f DS-GVO"],
"data_subject_categories": ["Projektbeteiligte"],
"personal_data_categories": ["Projektdaten", "Aufgaben", "Zeiterfassung"],
"recipient_categories": ["PM-Tool (AVV)", "Mandant"],
"retention_period": "2 Jahre nach Projektabschluss",
"tom_description": "Projektspezifische Zugriffsrechte, Mandantentrennung",
},
{
"name": "Zeiterfassung und Abrechnung",
"purposes": ["Stundenerfassung, Abrechnung gegenueber Mandanten"],
"legal_bases": ["Art. 6 Abs. 1 lit. b DS-GVO"],
"data_subject_categories": ["Berater/Mitarbeitende", "Mandanten"],
"personal_data_categories": ["Arbeitszeiten", "Taetigkeitsbeschreibungen", "Stundensaetze"],
"recipient_categories": ["Abrechnungssystem (AVV)", "Buchhaltung"],
"retention_period": "10 Jahre (AO)",
"tom_description": "Zugriff nur eigene Zeiten + Projektleitung",
},
],
}
# Industry -> Sector mapping
INDUSTRY_SECTOR_MAP = {
"technologie": "it_saas", "it": "it_saas", "saas": "it_saas", "software": "it_saas",
"it dienstleistungen": "it_saas",
"gesundheit": "gesundheitswesen", "pharma": "gesundheitswesen",
"e-commerce": "handel", "handel": "handel", "einzelhandel": "handel",
"handwerk": "handwerk", "bau": "handwerk", "kfz": "handwerk",
"bildung": "bildung", "schule": "bildung", "hochschule": "bildung",
"beratung": "beratung", "consulting": "beratung", "kanzlei": "beratung",
"recht": "beratung",
}
def generate_vvt_drafts(ctx: dict) -> list[dict]:
"""Generate VVT activity drafts, sector-specific if possible.
Args:
ctx: Flat dict from company-profile/template-context.
Returns:
List of VVT activity dicts ready for creation.
"""
company = ctx.get("company_name", "Unbekannt")
dpo = ctx.get("dpo_name", "")
sector = _detect_sector(ctx)
# Use sector-specific activities if available, else generate from systems
if sector and sector in SECTOR_ACTIVITIES:
activities = _generate_sector_vvt(ctx, sector, company, dpo)
else:
activities = _generate_system_vvt(ctx, company, dpo)
# Always add standard HR activity if not already present
has_hr = any("mitarbeiter" in a.get("name", "").lower() or "hr" in a.get("name", "").lower()
for a in activities)
if not has_hr and len(activities) > 0:
activities.append(_build_hr_activity(len(activities) + 1, company, dpo))
return activities
def _detect_sector(ctx: dict) -> Optional[str]:
industry = (ctx.get("industry") or "").lower().strip()
for keyword, sector in INDUSTRY_SECTOR_MAP.items():
if keyword in industry:
return sector
return None
def _generate_sector_vvt(ctx: dict, sector: str, company: str, dpo: str) -> list[dict]:
activities = []
sector_data = SECTOR_ACTIVITIES[sector]
for i, template in enumerate(sector_data, 1):
activity = {
"vvt_id": f"VVT-{sector.upper()[:3]}-{i:03d}",
"name": template["name"],
"description": f"Automatisch generierter VVT-Eintrag: {template['name']}",
"purposes": template["purposes"],
"legal_bases": template["legal_bases"],
"data_subject_categories": template["data_subject_categories"],
"personal_data_categories": template["personal_data_categories"],
"recipient_categories": template["recipient_categories"],
"third_country_transfers": _assess_third_country(ctx),
"retention_period": {"default": template["retention_period"]},
"tom_description": template["tom_description"],
"business_function": _infer_business_function(template["name"]),
"systems": [],
"protection_level": "HIGH" if template.get("dpia_required") else "MEDIUM",
"dpia_required": template.get("dpia_required", False),
"status": "DRAFT",
"responsible": dpo or company,
"source_sector": sector,
}
activities.append(activity)
return activities
def _generate_system_vvt(ctx: dict, company: str, dpo: str) -> list[dict]:
"""Fallback: generate VVT per processing system (original approach)."""
systems = ctx.get("processing_systems", [])
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-SYS-{i:03d}",
"name": f"Verarbeitung in {name}",
"description": f"VVT-Eintrag fuer System '{name}'"
+ (f" (Anbieter: {vendor})" if vendor else ""),
"purposes": [f"Datenverarbeitung via {name}"],
"legal_bases": ["Art. 6 Abs. 1 lit. b DS-GVO (Vertragserfullung)"],
"data_subject_categories": [],
"personal_data_categories": categories,
"recipient_categories": [vendor] if vendor else [],
"third_country_transfers": _assess_third_country_hosting(hosting),
"retention_period": {"default": "Gemaess Loeschfristenkatalog"},
"tom_description": f"Siehe TOM-Katalog fuer {name}",
"business_function": "IT",
"systems": [name],
"deployment_model": hosting,
"protection_level": "HIGH" if len(categories) > 3 else "MEDIUM",
"dpia_required": len(categories) > 3,
"status": "DRAFT",
"responsible": dpo or company,
}
activities.append(activity)
return activities
def _build_hr_activity(index: int, company: str, dpo: str) -> dict:
return {
"vvt_id": f"VVT-STD-{index:03d}",
"name": "Mitarbeiterverwaltung / HR",
"description": "Standard-Verarbeitungstaetigkeit Personalverwaltung",
"purposes": ["Personalverwaltung, Lohnabrechnung, Arbeitszeiterfassung"],
"legal_bases": ["Art. 6 Abs. 1 lit. b/c DS-GVO i.V.m. §26 BDSG"],
"data_subject_categories": ["Beschaeftigte"],
"personal_data_categories": ["Stammdaten", "Vertragsdaten", "Bankverbindung", "Arbeitszeiten"],
"recipient_categories": ["Lohnbuero (AVV)", "Finanzamt", "Sozialversicherungstraeger"],
"third_country_transfers": [],
"retention_period": {"default": "10 Jahre nach Austritt"},
"tom_description": "Besonderer Zugriffsschutz (nur HR), verschluesselte Speicherung",
"business_function": "HR",
"systems": [],
"protection_level": "HIGH",
"dpia_required": False,
"status": "DRAFT",
"responsible": dpo or company,
}
def _assess_third_country(ctx: dict) -> list:
if ctx.get("third_country_transfer"):
return [{"country": "Abhaengig von Dienstleister", "mechanism": "Pruefung erforderlich"}]
return []
def _assess_third_country_hosting(hosting: str) -> list:
if hosting in ("us-cloud", "international"):
return [{"country": "USA", "mechanism": "EU-US Data Privacy Framework"}]
return []
def _infer_business_function(name: str) -> str:
name_lower = name.lower()
if any(kw in name_lower for kw in ["mitarbeiter", "hr", "personal", "bewerbung"]):
return "HR"
if any(kw in name_lower for kw in ["abrechnung", "rechnung", "zahlung", "buchhaltung"]):
return "Finanzen"
if any(kw in name_lower for kw in ["marketing", "newsletter", "webanalyse", "crm", "akquise"]):
return "Marketing/Vertrieb"
if any(kw in name_lower for kw in ["support", "ticket", "kundenservice"]):
return "Support"
if any(kw in name_lower for kw in ["patient", "befund", "labor", "termin"]):
return "Medizin"
if any(kw in name_lower for kw in ["schueler", "noten", "lernplattform"]):
return "Paedagogik"
return "IT"