feat(admin): Tab "Browser-Verhalten" — Per-Browser-Matrix + Screenshots (Phase 3)

- BrowserBehaviorView: laedt gespeicherte Matrix (GET), sonst "Browser-Test
  starten" (POST run, Live-Lauf). Per-Browser-Tabelle (Cookies vor Consent /
  nach Ablehnen / Ablehnen respektiert / Oberflaeche / Score), Engine-Detail
  mit Banner-Screenshot + Oberflaechen-Befunden, Mobil-Badge, "nicht
  verfuegbar"-Zeilen fuer fehlende Browser (arm64-Dev).
- Proxys browser-behavior (GET) + browser-behavior/run (POST, langer Timeout).
- page.tsx: Tab "Browser-Verhalten" (sichtbar sobald scanbare URL im Snapshot).
- consent-tester scan_matrix_summary: banner_findings je Engine im summary
  (Text/Severity/Norm) → Oberflaechen-Befunde im Tab.
- tsc strict clean; Vitest BrowserBehaviorView (2).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
Benjamin Admin
2026-06-12 23:15:06 +02:00
parent c7fde93061
commit 9587726936
6 changed files with 359 additions and 0 deletions
@@ -63,6 +63,16 @@ def matrix_scan_dict(result: Any) -> dict:
getattr(result, "banner_has_dse_link", False)),
"banner_text_issues": len(banner_text_violations),
},
# Oberflächen-Befunde je Engine (die 20 Banner-Checks: Button-Prominenz,
# Toggle-Vorauswahl, Einleitungstext/Links …) — Text + Severity +
# Norm-Bezug. Aggregierte Maßnahmen folgen im Cross-Finding.
"banner_findings": [
{"text": d.get("text", ""),
"severity": d.get("severity", "MEDIUM"),
"legal_ref": d.get("legal_ref", ""),
"service": d.get("service", "")}
for d in (_vdict(v) for v in banner_text_violations)
][:20],
"violations": {
"before_consent": len(before_violations),
"after_reject": len(reject_violations),