From 397de741c1323a10cea2b157e8f4649388c3fd50 Mon Sep 17 00:00:00 2001 From: Benjamin Admin Date: Mon, 11 May 2026 22:52:26 +0200 Subject: [PATCH] =?UTF-8?q?feat(cmp):=20Phase=202=20=E2=80=94=20script=20b?= =?UTF-8?q?locking=20+=20cookie=20tracking?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Migration 108: scripts_blocked, scripts_released, cookies_set JSONB columns. Backend models/schema/service/serializer/routes extended. Admin detail modal shows released scripts and set cookies with categories. Co-Authored-By: Claude Opus 4.6 (1M context) --- .../_components/BannerConsentsTab.tsx | 31 +++++++++++++++++++ .../app/sdk/einwilligungen/_types.ts | 4 +++ .../compliance/api/banner_routes.py | 3 ++ .../compliance/db/banner_models.py | 4 +++ .../compliance/schemas/banner.py | 4 +++ .../services/_banner_serializers.py | 3 ++ .../services/banner_consent_service.py | 6 ++++ .../108_banner_script_cookie_tracking.sql | 18 +++++++++++ 8 files changed, 73 insertions(+) create mode 100644 backend-compliance/migrations/108_banner_script_cookie_tracking.sql diff --git a/admin-compliance/app/sdk/einwilligungen/_components/BannerConsentsTab.tsx b/admin-compliance/app/sdk/einwilligungen/_components/BannerConsentsTab.tsx index bb0b5d3..d18a43f 100644 --- a/admin-compliance/app/sdk/einwilligungen/_components/BannerConsentsTab.tsx +++ b/admin-compliance/app/sdk/einwilligungen/_components/BannerConsentsTab.tsx @@ -223,6 +223,37 @@ export default function BannerConsentsTab() { + {/* Scripts & Cookies */} + {(detail.scripts_released?.length > 0 || detail.cookies_set?.length > 0) && ( +
+

Scripts & Cookies

+ {detail.scripts_released?.length > 0 && ( +
+ Freigegebene Scripts + {detail.scripts_released.map((s, i) => ( +

{s.src} {s.category}

+ ))} +
+ )} + {detail.scripts_blocked?.length > 0 && ( +
+ Blockierte Scripts + {detail.scripts_blocked.map((s, i) => ( +

{s.src} {s.category}

+ ))} +
+ )} + {detail.cookies_set?.length > 0 && ( +
+ Gesetzte Cookies + {detail.cookies_set.map((c, i) => ( +

{c.name} ({c.domain}) {c.category}

+ ))} +
+ )} +
+ )} + {/* Technische Details */}

Technisch

diff --git a/admin-compliance/app/sdk/einwilligungen/_types.ts b/admin-compliance/app/sdk/einwilligungen/_types.ts index 756a4ca..e44bb07 100644 --- a/admin-compliance/app/sdk/einwilligungen/_types.ts +++ b/admin-compliance/app/sdk/einwilligungen/_types.ts @@ -126,6 +126,10 @@ export interface BannerConsentRecord { os: string | null screen_resolution: string | null session_id: string | null + // Script/Cookie-Tracking (Migration 108) + scripts_blocked: { src: string; category: string }[] + scripts_released: { src: string; category: string }[] + cookies_set: { name: string; domain: string; expiry_days: number; category: string }[] expires_at: string | null created_at: string | null updated_at: string | null diff --git a/backend-compliance/compliance/api/banner_routes.py b/backend-compliance/compliance/api/banner_routes.py index e4ed0f1..d4c1b47 100644 --- a/backend-compliance/compliance/api/banner_routes.py +++ b/backend-compliance/compliance/api/banner_routes.py @@ -87,6 +87,9 @@ async def record_consent( screen_resolution=body.screen_resolution, session_id=body.session_id, consent_scope=body.consent_scope, + scripts_blocked=body.scripts_blocked, + scripts_released=body.scripts_released, + cookies_set=body.cookies_set, ) diff --git a/backend-compliance/compliance/db/banner_models.py b/backend-compliance/compliance/db/banner_models.py index 2c96981..1654110 100644 --- a/backend-compliance/compliance/db/banner_models.py +++ b/backend-compliance/compliance/db/banner_models.py @@ -50,6 +50,10 @@ class BannerConsentDB(Base): os = Column(Text) screen_resolution = Column(Text) session_id = Column(Text) + # Script/Cookie-Tracking (Migration 108) + scripts_blocked = Column(JSON, default=list) + scripts_released = Column(JSON, default=list) + cookies_set = Column(JSON, default=list) expires_at = Column(DateTime) created_at = Column(DateTime, nullable=False, default=datetime.utcnow) updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow) diff --git a/backend-compliance/compliance/schemas/banner.py b/backend-compliance/compliance/schemas/banner.py index ea04a33..ebc0b28 100644 --- a/backend-compliance/compliance/schemas/banner.py +++ b/backend-compliance/compliance/schemas/banner.py @@ -30,6 +30,10 @@ class ConsentCreate(BaseModel): screen_resolution: Optional[str] = None session_id: Optional[str] = None consent_scope: Optional[str] = None + # Script/Cookie-Tracking (Migration 108) + scripts_blocked: List[dict[str, Any]] = [] + scripts_released: List[dict[str, Any]] = [] + cookies_set: List[dict[str, Any]] = [] class SiteConfigCreate(BaseModel): diff --git a/backend-compliance/compliance/services/_banner_serializers.py b/backend-compliance/compliance/services/_banner_serializers.py index 7175f43..debced1 100644 --- a/backend-compliance/compliance/services/_banner_serializers.py +++ b/backend-compliance/compliance/services/_banner_serializers.py @@ -41,6 +41,9 @@ def consent_to_dict(c: BannerConsentDB) -> dict[str, Any]: "os": c.os, "screen_resolution": c.screen_resolution, "session_id": c.session_id, + "scripts_blocked": c.scripts_blocked or [], + "scripts_released": c.scripts_released or [], + "cookies_set": c.cookies_set or [], "expires_at": c.expires_at.isoformat() if c.expires_at else None, "created_at": c.created_at.isoformat() if c.created_at else None, "updated_at": c.updated_at.isoformat() if c.updated_at else None, diff --git a/backend-compliance/compliance/services/banner_consent_service.py b/backend-compliance/compliance/services/banner_consent_service.py index 5f2c360..4c6e7ee 100644 --- a/backend-compliance/compliance/services/banner_consent_service.py +++ b/backend-compliance/compliance/services/banner_consent_service.py @@ -181,6 +181,9 @@ class BannerConsentService: screen_resolution: Optional[str] = None, session_id: Optional[str] = None, consent_scope: Optional[str] = None, + scripts_blocked: Optional[list[dict]] = None, + scripts_released: Optional[list[dict]] = None, + cookies_set: Optional[list[dict]] = None, ) -> dict[str, Any]: """Upsert a device consent row for (tenant, site, device_fingerprint). @@ -213,6 +216,9 @@ class BannerConsentService: "screen_resolution": screen_resolution, "session_id": session_id, "consent_scope": consent_scope or "domain", + "scripts_blocked": scripts_blocked or [], + "scripts_released": scripts_released or [], + "cookies_set": cookies_set or [], } existing = ( diff --git a/backend-compliance/migrations/108_banner_script_cookie_tracking.sql b/backend-compliance/migrations/108_banner_script_cookie_tracking.sql new file mode 100644 index 0000000..d42cf46 --- /dev/null +++ b/backend-compliance/migrations/108_banner_script_cookie_tracking.sql @@ -0,0 +1,18 @@ +-- Migration 108: Script- und Cookie-Tracking fuer Banner-Consents +-- Erfasst welche Scripts blockiert/freigegeben und welche Cookies gesetzt wurden. +-- Alle Felder JSONB + nullable → backward-compatible. + +-- Scripts die VOR Consent blockiert waren +ALTER TABLE compliance_banner_consents + ADD COLUMN IF NOT EXISTS scripts_blocked JSONB DEFAULT '[]'::jsonb; + -- [{"src": "https://www.googletagmanager.com/gtag/js", "category": "analytics"}] + +-- Scripts die NACH Consent freigegeben wurden +ALTER TABLE compliance_banner_consents + ADD COLUMN IF NOT EXISTS scripts_released JSONB DEFAULT '[]'::jsonb; + -- [{"src": "https://www.googletagmanager.com/gtag/js", "category": "analytics"}] + +-- Cookies die NACH Consent gesetzt wurden +ALTER TABLE compliance_banner_consents + ADD COLUMN IF NOT EXISTS cookies_set JSONB DEFAULT '[]'::jsonb; + -- [{"name": "_ga", "domain": ".breakpilot.ai", "expiry_days": 730, "category": "analytics"}]