feat(agent): migrate compliance-check results to banner + documents (M1-M5)

After a compliance-check run finishes, the user can now apply the
extracted vendor inventory directly to their own:

  - CookieBanner config (admin /sdk/einwilligungen)
  - Cookie-Policy / VVT-Register / Privacy-Policy templates
    (admin /sdk/document-generator)

Backend:
  - migration_to_banner.py: vendor list -> CookieBannerConfig with
    ESSENTIAL/PERFORMANCE/PERSONALIZATION/EXTERNAL_MEDIA buckets +
    review flags (broken opt-out URLs, missing expiry, no cookies listed)
  - migration_to_document.py: vendor list -> pre-fills for 3 doc
    templates, recipient-type aware (INTERNAL/GROUP/PROCESSOR/CONTROLLER)
  - agent_migration_routes.py: GET /banner-preview, /document-preview,
    /summary keyed on check_id
  - compliance_audit_log: new check_payloads table persists cmp_vendors +
    extracted_profile so the preview survives an app restart
  - tests: 9 mapper units + 4 endpoint integration tests

Frontend:
  - MigrationPanel.tsx: modal showing banner-config diff + document
    pre-fills, plus links into the existing editors
  - ComplianceCheckTab.tsx: replaces standalone audit link with the
    panel; net -3 lines, stays at the 500-cap

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Benjamin Admin
2026-05-17 14:06:28 +02:00
parent f4c9cea770
commit df7d83134b
13 changed files with 1207 additions and 15 deletions
@@ -0,0 +1,25 @@
/**
* Proxy: GET /api/sdk/v1/agent/migration/<checkId>/banner-preview
* -> backend GET /api/compliance/agent/migration/<checkId>/banner-preview
*/
import { NextRequest, NextResponse } from 'next/server'
const BACKEND_URL = process.env.BACKEND_API_URL || 'http://backend-compliance:8002'
export async function GET(
request: NextRequest,
{ params }: { params: { checkId: string } },
) {
const qs = request.nextUrl.searchParams.toString()
const url = `${BACKEND_URL}/api/compliance/agent/migration/${params.checkId}/banner-preview${qs ? `?${qs}` : ''}`
try {
const resp = await fetch(url, { signal: AbortSignal.timeout(15000) })
const data = await resp.json()
return NextResponse.json(data, { status: resp.status })
} catch {
return NextResponse.json(
{ error: 'Banner-Preview fehlgeschlagen' },
{ status: 503 },
)
}
}
@@ -0,0 +1,24 @@
/**
* Proxy: GET /api/sdk/v1/agent/migration/<checkId>/document-preview
* -> backend GET /api/compliance/agent/migration/<checkId>/document-preview
*/
import { NextRequest, NextResponse } from 'next/server'
const BACKEND_URL = process.env.BACKEND_API_URL || 'http://backend-compliance:8002'
export async function GET(
_request: NextRequest,
{ params }: { params: { checkId: string } },
) {
const url = `${BACKEND_URL}/api/compliance/agent/migration/${params.checkId}/document-preview`
try {
const resp = await fetch(url, { signal: AbortSignal.timeout(15000) })
const data = await resp.json()
return NextResponse.json(data, { status: resp.status })
} catch {
return NextResponse.json(
{ error: 'Dokument-Preview fehlgeschlagen' },
{ status: 503 },
)
}
}
@@ -0,0 +1,24 @@
/**
* Proxy: GET /api/sdk/v1/agent/migration/<checkId>/summary
* -> backend GET /api/compliance/agent/migration/<checkId>/summary
*/
import { NextRequest, NextResponse } from 'next/server'
const BACKEND_URL = process.env.BACKEND_API_URL || 'http://backend-compliance:8002'
export async function GET(
_request: NextRequest,
{ params }: { params: { checkId: string } },
) {
const url = `${BACKEND_URL}/api/compliance/agent/migration/${params.checkId}/summary`
try {
const resp = await fetch(url, { signal: AbortSignal.timeout(15000) })
const data = await resp.json()
return NextResponse.json(data, { status: resp.status })
} catch {
return NextResponse.json(
{ error: 'Migrations-Summary fehlgeschlagen' },
{ status: 503 },
)
}
}