"""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"