Files
breakpilot-compliance/zeroclaw/PLAN-compliance-agent-product.md
T
Benjamin Admin 0266dfd011 docs: Compliance Agent product roadmap — 8 phases, PoC to production
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) <noreply@anthropic.com>
2026-04-29 11:32:27 +02:00

16 KiB

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.

# 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)


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

# 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

# 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

# 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

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

# 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

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).

# 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:

[[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):

# 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