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
+18
View File
@@ -222,6 +222,24 @@ export default function SDKDashboard() {
</div>
</div>
{/* Compliance Report Download */}
<div className="bg-gradient-to-r from-purple-50 to-indigo-50 border border-purple-200 rounded-xl p-6 flex items-center justify-between">
<div>
<h3 className="font-semibold text-gray-900">Compliance-Report</h3>
<p className="text-sm text-gray-500 mt-1">Umfassender PDF-Bericht ueber alle Module, Rollen, Risiken und Massnahmen.</p>
</div>
<button
onClick={() => {
const url = `/api/sdk/v1/compliance/report/pdf${projectId ? `?project_id=${projectId}` : ''}`
window.open(url, '_blank')
}}
className="px-5 py-2.5 bg-purple-600 text-white text-sm font-medium rounded-lg hover:bg-purple-700 transition-colors flex items-center gap-2"
>
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 10v6m0 0l-3-3m3 3l3-3m2 8H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z" /></svg>
PDF herunterladen
</button>
</div>
{/* Recent Activity */}
{state.commandBarHistory.length > 0 && (
<div>