From 0266dfd0110ce82090730bb29d9b11a81ef25051 Mon Sep 17 00:00:00 2001 From: Benjamin Admin Date: Wed, 29 Apr 2026 11:32:27 +0200 Subject: [PATCH] =?UTF-8?q?docs:=20Compliance=20Agent=20product=20roadmap?= =?UTF-8?q?=20=E2=80=94=208=20phases,=20PoC=20to=20production?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit P0: UCCA score calibration + control relevance filter P1: Headless browser consent test (before/after cookie banner) + 80+ services P2: Scan acceleration, DB persistence, PDF export P3: Recurring scans, multi-website comparison Investor demo scenario included. Co-Authored-By: Claude Opus 4.6 (1M context) --- zeroclaw/PLAN-compliance-agent-product.md | 488 ++++++++++++++++++++++ 1 file changed, 488 insertions(+) create mode 100644 zeroclaw/PLAN-compliance-agent-product.md diff --git a/zeroclaw/PLAN-compliance-agent-product.md b/zeroclaw/PLAN-compliance-agent-product.md new file mode 100644 index 0000000..1709d2f --- /dev/null +++ b/zeroclaw/PLAN-compliance-agent-product.md @@ -0,0 +1,488 @@ +# Plan: Compliance Agent — Vom PoC zum Produkt + +## Kontext + +Der Compliance Agent PoC funktioniert: URL scannen, Qwen klassifiziert, +UCCA bewertet, Dienstleister erkannt, Korrekturvorschlaege generiert, Email gesendet. + +Aber: Scores sind zu niedrig, zu viele False-Positive Controls, kein Consent-Test, +keine Persistenz, keine PDF-Exports. Dieser Plan macht das PoC produktreif. + +**Strategische Bedeutung:** Erstmalig wird das RAG (166k Controls) gegen echte +Webseiten getestet. Der Consent-Test (vor/nach Cookie-Einwilligung) waere ein +Alleinstellungsmerkmal das kein Wettbewerber hat. + +--- + +## Phase 0: UCCA Score-Kalibrierung (P0, 2-3 Tage) + +### Problem + +Der UCCA-Score fuer Opodo war LOW (20/100). Realistisch waere MEDIUM (40-50). +Die Intake-Flags werden aus dem Text extrahiert, aber zu wenige werden gesetzt. + +### Loesung + +**0.1 Intelligentere Intake-Flag-Erkennung** + +Aktuell: einfache Keyword-Suche (`"werbung" in text.lower()`). +Neu: LLM-gestuetzte Extraktion der Intake-Flags. + +```python +# Statt: +"marketing": "werbung" in text.lower() + +# Neu: Qwen extrahiert strukturiert +prompt = """ +Analysiere diesen Text und setze folgende Flags auf true/false: +- personal_data: Werden personenbezogene Daten verarbeitet? +- customer_data: Werden Kundendaten gespeichert? +- marketing: Werden Daten fuer Werbung/Marketing genutzt? +- profiling: Findet Profiling oder Personalisierung statt? +- minor_data: Werden Daten von Minderjaehrigen verarbeitet? +- biometric_data: Werden biometrische Daten verarbeitet? +- location_data: Werden Standortdaten erhoben? +- third_party_sharing: Werden Daten an Dritte weitergegeben? +- automated_decisions: Werden automatisierte Entscheidungen getroffen? +- cross_border_transfer: Findet Drittlandtransfer statt? +Antworte als JSON. +""" +``` + +**0.2 Score-Gewichtung anpassen** + +Die UCCA-Engine (Go, `ai-compliance-sdk/internal/ucca/`) hat die Score-Berechnung. +Pruefen ob die Gewichte realistisch sind: +- Personenbezogene Daten allein = 10 Punkte (zu wenig) +- Marketing + Drittlandtransfer + Profiling sollte mindestens +30 geben +- Zahlungsdaten + Passdaten sollte +20 geben + +**Dateien:** +- `backend-compliance/compliance/api/agent_analyze_routes.py` — Flag-Extraktion +- `ai-compliance-sdk/internal/ucca/engine.go` — Score-Berechnung (Go) +- `ai-compliance-sdk/internal/ucca/rules.go` — Regel-Definitionen + +**Testfaelle:** +- Opodo: Soll MEDIUM (40-50) ergeben +- Google: Soll HIGH (60-70) ergeben +- Einfacher Blog ohne Tracking: Soll MINIMAL (0-10) ergeben + +--- + +## Phase 1: Control Relevance Filter (P0, 1 Tag) + +### Bereits geplant in PLAN-control-relevance-filter.md + +Nur Phase 1 (regelbasiert) hier umsetzen: + +1. Neues `relevance_conditions` JSONB-Feld auf `canonical_controls` +2. Top-20 generische Controls mit Keywords versehen +3. Filter-Funktion im Agent: Control nur empfehlen wenn Keywords im Text vorkommen +4. Test: C_TRANSPARENCY faellt bei Opodo weg (kein KI-Nachweis) + +**Datei:** `backend-compliance/compliance/services/relevance_filter.py` (~200 LOC) + +--- + +## Phase 2: Headless Browser Consent-Test (P1, 2-3 Tage) + +### Das Killer-Feature + +Automatischer 3-Phasen-Test: + +``` +Phase A: Erster Besuch (ohne Interaktion) + → Welche Scripts/Cookies laden VOR dem Consent-Banner? + → Finding: "Script X laedt ohne Einwilligung" + +Phase B: Consent ablehnen ("Nur notwendige") + → Button klicken, 3 Sek warten + → Welche Scripts/Cookies laden NACH Ablehnung? + → Finding: "Google Analytics laedt trotz Ablehnung" = schwerer Verstoss + +Phase C: Consent akzeptieren ("Alle akzeptieren") + → Neuer Browser-Kontext, akzeptieren klicken + → Welche Scripts/Cookies laden NACH Zustimmung? + → Abgleich mit Cookie-Policy: "TikTok Pixel laedt, ist aber nicht dokumentiert" +``` + +### Technische Implementierung + +**2.1 Playwright im Backend-Container** + +```dockerfile +# Ergaenzung im backend-compliance Dockerfile +RUN pip install playwright && playwright install chromium +``` + +Alternativ: eigener `consent-tester` Service (besser isoliert, ~200MB Image). + +**2.2 Consent Test Service** + +```python +# backend-compliance/compliance/services/consent_tester.py (~250 LOC) + +class ConsentTester: + async def test(self, url: str) -> ConsentTestResult: + async with async_playwright() as p: + browser = await p.chromium.launch(headless=True) + + # Phase A: Ohne Consent + pre = await self._scan_phase(browser, url, action=None) + + # Phase B: Ablehnen + reject = await self._scan_phase(browser, url, action="reject") + + # Phase C: Akzeptieren + accept = await self._scan_phase(browser, url, action="accept") + + await browser.close() + + return ConsentTestResult( + banner_detected=pre.banner_visible, + banner_type=pre.banner_provider, # Didomi, OneTrust, Cookiebot etc. + scripts_before_consent=pre.scripts, + cookies_before_consent=pre.cookies, + violations_before_consent=self._find_violations(pre), + scripts_after_reject=reject.scripts, + cookies_after_reject=reject.cookies, + violations_after_reject=self._find_violations(reject), + scripts_after_accept=accept.scripts, + cookies_after_accept=accept.cookies, + undocumented_after_accept=self._find_undocumented(accept, dse_text), + ) +``` + +**2.3 Banner-Button-Erkennung** + +```python +# Typische Consent-Banner Button-Patterns +ACCEPT_PATTERNS = [ + 'button:has-text("Alle akzeptieren")', + 'button:has-text("Alles akzeptieren")', + 'button:has-text("Accept all")', + 'button:has-text("Alle Cookies akzeptieren")', + '[class*="accept-all"]', + '[data-action="accept-all"]', + '#didomi-notice-agree-button', # Didomi + '.cky-btn-accept', # CookieYes + '#onetrust-accept-btn-handler', # OneTrust + '#CybotCookiebotDialogBodyLevelButtonLevelOptinAllowAll', # Cookiebot +] + +REJECT_PATTERNS = [ + 'button:has-text("Nur notwendige")', + 'button:has-text("Ablehnen")', + 'button:has-text("Reject")', + 'button:has-text("Nur essentielle")', + '[class*="reject"]', + '#didomi-notice-disagree-button', + '#onetrust-reject-all-handler', + '#CybotCookiebotDialogBodyButtonDecline', +] +``` + +**2.4 Violation-Erkennung** + +```python +def _find_violations(self, phase: ScanPhase) -> list[Violation]: + violations = [] + + for script in phase.scripts: + service = match_service(script) # Gegen SERVICE_REGISTRY + if service and service.requires_consent: + if phase.action is None: + # Script laedt VOR Consent → Verstoss + violations.append(Violation( + severity="HIGH", + service=service.name, + legal_ref="§25 TDDDG", + text=f"{service.name} laedt OHNE vorherige Einwilligung", + )) + elif phase.action == "reject": + # Script laedt NACH Ablehnung → schwerer Verstoss + violations.append(Violation( + severity="CRITICAL", + service=service.name, + legal_ref="§25 TDDDG, Art. 5(3) ePrivacy", + text=f"{service.name} laedt TROTZ Ablehnung — Dark Pattern", + )) + + return violations +``` + +**2.5 Frontend: Consent-Test Tab** + +Dritter Tab im Agent: "Schnellanalyse | Website-Scan | Cookie-Test" + +Anzeige: +``` +Cookie-Consent-Test: opodo.de +═══════════════════════════════ + +Banner erkannt: Ja (Didomi) + +Phase A: Vor Einwilligung + ✗ Google Analytics — laedt ohne Einwilligung (§25 TDDDG) + ✓ Didomi CMP — notwendig, OK + ✗ Google Tag Manager — laedt ohne Einwilligung + +Phase B: Nach Ablehnung ("Nur notwendige") + ✗ Google Analytics — laedt TROTZ Ablehnung (KRITISCH!) + ✓ Keine neuen Tracking-Cookies gesetzt + +Phase C: Nach Zustimmung ("Alle akzeptieren") + ✓ Google Analytics — jetzt aktiv (mit Consent OK) + ✓ Didomi Consent Cookie gesetzt + ✗ TikTok Pixel — nicht in Cookie-Policy dokumentiert + +Zusammenfassung: + 2 kritische Verstoesse (Tracking ohne/trotz Ablehnung) + 1 Dokumentationsluecke (TikTok nicht in Policy) +``` + +**2.6 Neuer Endpoint** + +``` +POST /api/compliance/agent/consent-test +Body: { "url": "https://www.opodo.de" } +Response: ConsentTestResult (3 Phasen + Violations) +``` + +**Dateien:** +- `backend-compliance/compliance/services/consent_tester.py` — Playwright Test (~250 LOC) +- `backend-compliance/compliance/api/agent_consent_routes.py` — Endpoint (~100 LOC) +- `admin-compliance/app/sdk/agent/_components/ConsentTestResult.tsx` — UI (~150 LOC) +- `admin-compliance/app/api/sdk/v1/agent/consent-test/route.ts` — Proxy (~35 LOC) + +**Aufwand:** 2-3 Tage (inkl. Playwright Setup + Button-Erkennung) + +--- + +## Phase 3: Dienstleister-Registry erweitern (P1, 1 Tag) + +### Aktuell: ~20 Services in website_scanner.py + +### Ziel: 80+ Services + +Neue Kategorien: +- **Newsletter/Email Marketing** — Mailchimp, Brevo, CleverReach, ActiveCampaign, HubSpot, Rapidmail +- **Social Media Embeds** — Twitter/X, Instagram, LinkedIn, Pinterest, TikTok +- **A/B Testing** — Optimizely, VWO, Google Optimize (Legacy) +- **Heatmaps/Session Recording** — FullStory, Mouseflow, Crazy Egg, Lucky Orange +- **Werbenetwerke** — Google Ads, Meta Ads, TikTok Ads, Criteo, Taboola, Outbrain +- **Tag Manager** — Google, Tealium, Segment +- **CRM** — HubSpot, Salesforce Pardot, Pipedrive +- **Push Notifications** — OneSignal, Pushwoosh, Firebase +- **Customer Support** — Freshdesk, Zendesk (erweitern), HelpScout +- **Cloud/CDN** — AWS CloudFront, Azure CDN, Vercel, Netlify +- **Error Tracking** — Sentry, Bugsnag, Datadog RUM, New Relic + +Jeder Eintrag: Regex, Provider, Land, EU-Adaequanz, Consent-Pflicht, Rechtsgrundlage. + +**Datei:** `backend-compliance/compliance/services/website_scanner.py` — SERVICE_REGISTRY erweitern +Evtl. in eigene Datei auslagern: `service_registry.py` (~300 LOC, reine Daten) + +--- + +## Phase 4: Scan beschleunigen (P2, 1 Tag) + +### Problem + +Aktuell: Seiten sequentiell fetchen + 3-4 LLM-Calls = 3-5 Minuten. + +### Loesung + +**4.1 Parallel Fetchen** +```python +# Statt sequentiell: +for url in pages: + html = await fetch(url) + +# Parallel: +htmls = await asyncio.gather(*[fetch(url) for url in pages]) +``` + +**4.2 Qwen-Calls reduzieren** +- DSE-Extraktion: Nur wenn Datenschutzseite gefunden +- Korrekturvorschlaege: Nur fuer HIGH-Severity Findings (nicht fuer alle) +- Batch: Alle Korrekturen in einem LLM-Call statt einzeln + +**4.3 Kleineres Modell fuer Klassifizierung** +- Qwen 2.5:14b statt 3.5:35b fuer einfache Klassifizierung (~5x schneller) +- 3.5:35b nur fuer Korrekturvorschlaege und DSE-Extraktion + +**Ziel:** Scan in <60 Sekunden statt 3-5 Minuten. + +--- + +## Phase 5: Persistenz — Ergebnisse in DB speichern (P2, 1 Tag) + +### Problem + +Ergebnisse sind aktuell nur im Browser-Session-State und in Mailpit-Emails. +Bei Seitenreload oder neuem Tab: alles weg. + +### Loesung + +**5.1 Neue DB-Tabelle** + +```sql +CREATE TABLE compliance_agent_scans ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + tenant_id UUID NOT NULL, + user_id TEXT NOT NULL, + url TEXT NOT NULL, + mode TEXT NOT NULL, -- 'quick', 'scan', 'consent_test' + analysis_mode TEXT NOT NULL, -- 'pre_launch', 'post_launch' + classification TEXT, + risk_level TEXT, + risk_score FLOAT, + escalation_level TEXT, + services JSONB DEFAULT '[]', + findings JSONB DEFAULT '[]', + corrections JSONB DEFAULT '[]', + consent_test JSONB, -- Phase 2 Ergebnisse + summary_html TEXT, + email_sent BOOLEAN DEFAULT FALSE, + created_at TIMESTAMPTZ DEFAULT now() +); + +CREATE INDEX idx_agent_scans_tenant ON compliance_agent_scans(tenant_id); +CREATE INDEX idx_agent_scans_url ON compliance_agent_scans(url); +``` + +**5.2 Frontend: Scan-Verlauf aus DB laden** + +Statt Session-basierter History → API-Call: `GET /api/compliance/agent/scans` +Sortiert nach Datum, filterbar nach URL/Risiko/Typ. + +**Dateien:** +- `backend-compliance/compliance/api/agent_scan_routes.py` — DB-Save nach jedem Scan +- `backend-compliance/compliance/db/agent_scan_models.py` — SQLAlchemy Model (~40 LOC) +- Migration SQL + +--- + +## Phase 6: PDF-Export (P2, 0.5 Tage) + +### Nutzen + +Manager wollen druckbare Reports, nicht nur Emails. + +### Implementierung + +ReportLab oder WeasyPrint (bereits im Backend vorhanden fuer andere PDF-Exports). + +```python +# Neuer Endpoint +GET /api/compliance/agent/scans/{id}/pdf + +# Generiert PDF mit: +# - Deckblatt (Firmenlogo, Datum, URL) +# - Executive Summary (Risiko-Ampel, Rolle) +# - Findings-Tabelle +# - Dienstleister-Abgleich (SOLL/IST) +# - Consent-Test Ergebnisse (wenn vorhanden) +# - Korrekturvorschlaege +# - Anhang: Gescannte Seiten, Rechtsgrundlagen +``` + +**Datei:** `backend-compliance/compliance/services/agent_pdf_export.py` (~200 LOC) + +--- + +## Phase 7: Recurring Scans / ZeroClaw (P3, 1 Tag) + +### Nutzen + +Website aendert sich → neue Dienstleister eingebunden → automatisches Alert. + +### Implementierung + +ZeroClaw SOP mit Cron-Trigger: + +```toml +[[triggers]] +type = "cron" +schedule = "0 6 * * 1" # Jeden Montag 06:00 +``` + +Der Agent: +1. Laedt alle gespeicherten URLs aus der DB +2. Scannt jede URL +3. Vergleicht mit letztem Scan-Ergebnis +4. Bei Aenderungen: Email an DSB mit Diff + +**Oder:** Einfacher Cron-Job im Backend (kein ZeroClaw noetig): +```python +# backend-compliance/compliance/services/recurring_scan.py +async def run_weekly_scans(): + scans = await db.get_all_monitored_urls() + for scan in scans: + result = await analyze(scan.url, scan.mode) + if has_changes(result, scan.last_result): + await send_change_alert(scan, result) +``` + +--- + +## Phase 8: Multi-Website Vergleich (P3, 1 Tag) + +### Nutzen + +"Wie steht mein Unternehmen im Vergleich zu 5 Wettbewerbern?" + +### Implementierung + +Frontend: Mehrere URLs eingeben → paralleler Scan → Vergleichstabelle: + +``` + | Meine Firma | Opodo | Booking | Expedia | +Datenschutzerkl. | ✓ | ✓ | ✓ | ✓ | +Impressum | ✓ | ✗ (404) | ✓ | ✓ | +Cookie-Banner | ✓ | ✓ | ✓ | ✗ | +Google Fonts lokal | ✓ | ✗ | ✓ | ✗ | +Kuendigungsbutton | ✓ | ✗ | n/a | n/a | +Tracking vor Consent| ✗ | ✗ | ✓ | ✗ | +Risiko-Score | 15/100 | 45/100 | 20/100 | 55/100 | +``` + +**Endpoint:** `POST /api/compliance/agent/compare` +**Body:** `{ "urls": ["url1", "url2", "url3"] }` + +--- + +## Implementierungsreihenfolge + +| Woche | Phase | Was | Ergebnis | +|-------|-------|-----|----------| +| 1 | Phase 0 | UCCA Score-Kalibrierung | Realistische Risiko-Scores | +| 1 | Phase 1 | Control Relevance Filter | Keine False Positives mehr | +| 2 | Phase 2 | Consent-Test (Playwright) | Killer-Feature, vor/nach Einwilligung | +| 2 | Phase 3 | Registry 80+ Services | Umfassende Dienstleister-Erkennung | +| 3 | Phase 4 | Scan beschleunigen | <60 Sekunden statt 3-5 Minuten | +| 3 | Phase 5 | DB-Persistenz | Scan-Verlauf, keine verlorenen Ergebnisse | +| 4 | Phase 6 | PDF-Export | Druckbare Reports fuer Management | +| 4 | Phase 7 | Recurring Scans | Automatische Ueberwachung | +| 5 | Phase 8 | Multi-Website Vergleich | Wettbewerber-Benchmark | + +## Investoren-Demo Szenario + +Nach Phase 2 (Woche 2) koennen wir folgende Demo zeigen: + +1. **URL eingeben:** `https://www.opodo.de` +2. **Website-Scan:** 6 Seiten gescannt, Google Analytics + Fonts + GTM erkannt +3. **SOLL/IST:** 3 Dienste NICHT in DSE dokumentiert → Art. 13 Verstoss +4. **Consent-Test:** Google Analytics laedt VOR Einwilligung → §25 TDDDG Verstoss +5. **Consent ablehnen:** Analytics laedt TROTZ Ablehnung → KRITISCH +6. **Score:** MEDIUM (45/100) mit 5 Findings +7. **Korrekturvorschlag:** Einbaufertige DSE-Textbausteine per Qwen +8. **Email an DSB:** Formatierter HTML-Report mit Handlungsanweisung +9. **Vergleich:** Opodo vs. Booking.com — wer ist besser aufgestellt? + +Das demonstriert: +- RAG funktioniert gegen echte Systeme (166k Controls) +- LLM generiert juristische Textbausteine +- Automatisierte Compliance-Pruefung in <60 Sekunden +- Consent-Test den kein Wettbewerber hat