feat: A/B Testing + Compliance Report PDF (F5 + F8)

F5: A/B Testing for Consent Rate
- Migration 116: banner_variants table + variant tracking in audit log
- BannerABService: deterministic sticky bucketing via device hash,
  chi-squared significance testing, variant CRUD
- banner_ab_routes: 6 endpoints (CRUD + stats + assign)
- ABTestPanel.tsx: variant creation, traffic sliders, opt-in comparison
  chart with winner/significance badges
- New "A/B-Test" tab in cookie-banner page

F8: Compliance Report PDF
- CompliancePDFGenerator: reportlab-based A4 PDF covering all modules
  (Company Profile, TOM, VVT, DSFA, Risks, Vendors, Incidents,
  Reviews, Consents, Roles)
- compliance_report_routes: GET /compliance/report/pdf
- "Compliance-Report herunterladen" button on SDK dashboard

[migration-approved]

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Benjamin Admin
2026-05-03 21:42:50 +02:00
parent c3fcfe88ee
commit 965af3a34c
9 changed files with 827 additions and 1 deletions
@@ -10,8 +10,9 @@ import { VendorTable } from './_components/VendorTable'
import { EmbeddableVendorHTML } from './_components/EmbeddableVendorHTML'
import { SiteSelector } from './_components/SiteSelector'
import { AnalyticsDashboard } from './_components/AnalyticsDashboard'
import { ABTestPanel } from './_components/ABTestPanel'
type BannerTab = 'config' | 'vendors' | 'embed' | 'analytics'
type BannerTab = 'config' | 'vendors' | 'embed' | 'analytics' | 'abtest'
export default function CookieBannerPage() {
const { state } = useSDK()
@@ -77,6 +78,7 @@ export default function CookieBannerPage() {
{ id: 'vendors' as const, label: 'Verarbeiter' },
{ id: 'embed' as const, label: 'Einbettung' },
{ id: 'analytics' as const, label: 'Analytik' },
{ id: 'abtest' as const, label: 'A/B-Test' },
]).map(tab => (
<button key={tab.id} onClick={() => setActiveTab(tab.id)}
className={`px-4 py-3 text-sm font-medium border-b-2 -mb-px transition-colors ${
@@ -96,6 +98,9 @@ export default function CookieBannerPage() {
{/* Tab: Analytik */}
{activeTab === 'analytics' && <AnalyticsDashboard siteId={activeSiteId || undefined} />}
{/* Tab: A/B-Test */}
{activeTab === 'abtest' && <ABTestPanel siteConfigId={activeSiteId || undefined} />}
{/* Tab: Konfiguration */}
{activeTab !== 'config' ? null : (<>
{/* Stats */}