feat(banner): Consent-Historie/Widerruf live erkennen (Borlabs-Stil, #62)

consent_history.detect_consent_history: erkennt CMP-Anbieter (Borlabs/
Usercentrics/OneTrust/Cookiebot/…) aus Storage+Cookies, versionierten Consent
(historie-fähig) + dauerhaftes Widerruf-/Einstellungs-Widget. consent_scanner
ruft es in Phase A; scan_matrix_summary surft summary.consent_history;
browser_cross_finding: positiver Befund wenn vorhanden, sonst Best-Practice-LOW
(„Nutzer sehen, wann sie welcher Version zugestimmt haben"); BrowserBehaviorView
zeigt es im Engine-Detail. Tests: 7 (classify/versioned) + 2 Cross-Finding.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
Benjamin Admin
2026-06-13 16:38:38 +02:00
parent 8d0da710d5
commit d92dd3b5fc
7 changed files with 208 additions and 4 deletions
@@ -14,11 +14,15 @@ import React, { useEffect, useState } from 'react'
type Finding = { text: string; severity: string; legal_ref?: string; service?: string }
type Surface = { has_impressum_link?: boolean; has_dse_link?: boolean; banner_text_issues?: number }
type Violations = { before_consent?: number; after_reject?: number; banner_text?: number }
type ConsentHistory = {
provider?: string; history_capable?: boolean; withdraw_ui?: boolean
versioned_consent?: boolean; stored?: boolean
}
type Summary = {
cookies_before_consent?: number; cookies_after_reject?: number
reject_respected?: boolean; banner_detected?: boolean; banner_provider?: string
banner_screenshot_b64?: string; surface?: Surface; banner_findings?: Finding[]
violations?: Violations
violations?: Violations; consent_history?: ConsentHistory
}
type Row = {
profile_id: string; label: string; engine?: string; is_mobile?: boolean
@@ -227,6 +231,14 @@ export function BrowserBehaviorView({ snapshotId }: { snapshotId: string }) {
) : (
<div className="text-xs text-gray-400">Kein Banner-Screenshot erfasst.</div>
)}
{selRow.summary?.consent_history && (
<div className="text-xs text-gray-600 border-t border-gray-100 pt-2">
<span className="font-medium text-gray-700">Einwilligungs-Historie:</span>{' '}
{selRow.summary.consent_history.provider || 'kein bekanntes CMP erkannt'}
{selRow.summary.consent_history.history_capable ? ' · versioniert (nachvollziehbar)' : ''}
{selRow.summary.consent_history.withdraw_ui ? ' · Widerruf-Widget vorhanden' : ' · kein Widerruf-Widget erkannt'}
</div>
)}
{(selRow.summary?.banner_findings?.length ?? 0) > 0 ? (
<ul className="space-y-1.5">
{selRow.summary!.banner_findings!.map((f, i) => (