Files
breakpilot-compliance/backend-compliance/compliance/api/compliance_report_routes.py
T
Benjamin Admin 965af3a34c 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>
2026-05-03 21:42:50 +02:00

39 lines
1.2 KiB
Python

"""
FastAPI route for Compliance Report PDF generation.
Endpoint:
GET /compliance/report/pdf — generate comprehensive compliance report as PDF
"""
import logging
from typing import Optional
from fastapi import APIRouter, Depends, Query
from fastapi.responses import StreamingResponse
from sqlalchemy.orm import Session
import io
from classroom_engine.database import get_db
from .tenant_utils import get_tenant_id as _get_tenant_id
from compliance.services.compliance_pdf_generator import CompliancePDFGenerator
logger = logging.getLogger(__name__)
router = APIRouter(prefix="/compliance/report", tags=["compliance-report"])
@router.get("/pdf")
def generate_compliance_report_pdf(
project_id: Optional[str] = Query(None),
language: str = Query("de"),
db: Session = Depends(get_db),
tenant_id: str = Depends(_get_tenant_id),
):
"""Generate a comprehensive compliance PDF report for a project."""
generator = CompliancePDFGenerator(db)
pdf_bytes, filename = generator.generate(tenant_id, project_id, language)
return StreamingResponse(
io.BytesIO(pdf_bytes),
media_type="application/pdf",
headers={"Content-Disposition": f'attachment; filename="{filename}"'},
)