feat: Package 4 Phase 3 — Finale Fixes + Dokumentation (MkDocs, SDK Flow, StepHeader)
All checks were successful
CI / go-lint (push) Has been skipped
CI / python-lint (push) Has been skipped
CI / nodejs-lint (push) Has been skipped
CI / test-go-ai-compliance (push) Successful in 48s
CI / test-python-backend-compliance (push) Successful in 40s
CI / test-python-document-crawler (push) Successful in 23s
CI / test-python-dsms-gateway (push) Successful in 18s
All checks were successful
CI / go-lint (push) Has been skipped
CI / python-lint (push) Has been skipped
CI / nodejs-lint (push) Has been skipped
CI / test-go-ai-compliance (push) Successful in 48s
CI / test-python-backend-compliance (push) Successful in 40s
CI / test-python-document-crawler (push) Successful in 23s
CI / test-python-dsms-gateway (push) Successful in 18s
Finale Fixes (5 Bugs): - workflow/page.tsx: Array-Format-Fix fuer loadVersions — Array.isArray statt data.versions - einwilligungen_routes.py: ip_address + user_agent in GET /consents Response ergaenzt - consent/page.tsx: Bearbeiten/Vorschau/Veroeffentlichen + Quick Actions verdrahtet (useRouter + Preview Modal) - cookie-banner/page.tsx: BannerTexts State + Controlled Inputs + DB-Persistenz (banner_texts) - embed-code/route.ts: In-Memory configStorage → DB-fetch aus Backend, embed_code Key korrigiert Dokumentation: - docs-src/services/sdk-modules/rechtliche-texte.md: Neue MkDocs-Seite fuer Paket 4 (Einwilligungen, Rechtliche Vorlagen, Cookie Banner, Document Workflow) - mkdocs.yml: Nav-Eintrag 'Rechtliche Texte (Paket 4)' ergaenzt - dokumentations-module.md: Datenfluss-Diagramm um Paket-4-Module erweitert - flow-data.ts: Paket-4-Steps mit korrekten dbTables/dbMode und aktualisierten Beschreibungen - StepHeader.tsx: cookie-banner + workflow STEP_EXPLANATIONS auf Persistenz und Funktionsumfang aktualisiert Tests: 24/24 bestanden (test_einwilligungen_routes.py) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -5,20 +5,20 @@
|
||||
*/
|
||||
|
||||
import { NextRequest, NextResponse } from 'next/server'
|
||||
import { CookieBannerConfig, CookieBannerEmbedCode } from '@/lib/sdk/einwilligungen/types'
|
||||
import { CookieBannerConfig } from '@/lib/sdk/einwilligungen/types'
|
||||
import {
|
||||
generateCookieBannerConfig,
|
||||
generateEmbedCode,
|
||||
} from '@/lib/sdk/einwilligungen/generator/cookie-banner'
|
||||
import { PREDEFINED_DATA_POINTS } from '@/lib/sdk/einwilligungen/catalog/loader'
|
||||
|
||||
// In-Memory Storage (in Produktion mit configStorage aus config/route.ts teilen)
|
||||
const configStorage = new Map<string, CookieBannerConfig>()
|
||||
const BACKEND_URL = process.env.BACKEND_URL || 'http://backend-compliance:8002'
|
||||
const DEFAULT_TENANT_ID = process.env.DEFAULT_TENANT_ID || '9282a473-5c95-4b3a-bf78-0ecc0ec71d3e'
|
||||
|
||||
/**
|
||||
* GET /api/sdk/v1/einwilligungen/cookie-banner/embed-code
|
||||
*
|
||||
* Generiert den Embed-Code fuer den Cookie Banner
|
||||
* Generiert den Embed-Code fuer den Cookie Banner (DB-backed)
|
||||
*
|
||||
* Query Parameters:
|
||||
* - privacyPolicyUrl: string - URL zur Datenschutzerklaerung (default: /datenschutz)
|
||||
@@ -26,25 +26,37 @@ const configStorage = new Map<string, CookieBannerConfig>()
|
||||
*/
|
||||
export async function GET(request: NextRequest) {
|
||||
try {
|
||||
const tenantId = request.headers.get('X-Tenant-ID')
|
||||
|
||||
if (!tenantId) {
|
||||
return NextResponse.json(
|
||||
{ error: 'Tenant ID required' },
|
||||
{ status: 400 }
|
||||
)
|
||||
}
|
||||
const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i
|
||||
const clientTenantId = request.headers.get('X-Tenant-ID') || request.headers.get('x-tenant-id')
|
||||
const tenantId = (clientTenantId && uuidRegex.test(clientTenantId)) ? clientTenantId : DEFAULT_TENANT_ID
|
||||
|
||||
const { searchParams } = new URL(request.url)
|
||||
const privacyPolicyUrl = searchParams.get('privacyPolicyUrl') || '/datenschutz'
|
||||
const format = searchParams.get('format') || 'combined'
|
||||
|
||||
// Hole oder erstelle Konfiguration
|
||||
let config = configStorage.get(tenantId)
|
||||
|
||||
if (!config) {
|
||||
// Lade Konfiguration aus DB (Backend), fallback auf generierte Standardkonfiguration
|
||||
let config: CookieBannerConfig
|
||||
try {
|
||||
const configRes = await fetch(
|
||||
`${BACKEND_URL}/api/compliance/einwilligungen/cookies?tenant_id=${tenantId}`,
|
||||
{ signal: AbortSignal.timeout(5000) }
|
||||
)
|
||||
if (configRes.ok) {
|
||||
const configData = await configRes.json()
|
||||
config = generateCookieBannerConfig(tenantId, PREDEFINED_DATA_POINTS)
|
||||
if (configData.config && Object.keys(configData.config).length > 0) {
|
||||
const saved = configData.config
|
||||
config = {
|
||||
...config,
|
||||
styling: { ...config.styling, ...(saved.styling || {}) },
|
||||
texts: { ...config.texts, ...(saved.banner_texts || saved.texts || {}) },
|
||||
}
|
||||
}
|
||||
} else {
|
||||
config = generateCookieBannerConfig(tenantId, PREDEFINED_DATA_POINTS)
|
||||
}
|
||||
} catch {
|
||||
config = generateCookieBannerConfig(tenantId, PREDEFINED_DATA_POINTS)
|
||||
configStorage.set(tenantId, config)
|
||||
}
|
||||
|
||||
// Generiere Embed-Code
|
||||
@@ -110,6 +122,7 @@ ${embedCode.js}
|
||||
`.trim()
|
||||
|
||||
return NextResponse.json({
|
||||
embed_code: combinedCode,
|
||||
embedCode: combinedCode,
|
||||
scriptTag: embedCode.scriptTag,
|
||||
config: {
|
||||
@@ -143,14 +156,9 @@ ${embedCode.js}
|
||||
*/
|
||||
export async function POST(request: NextRequest) {
|
||||
try {
|
||||
const tenantId = request.headers.get('X-Tenant-ID')
|
||||
|
||||
if (!tenantId) {
|
||||
return NextResponse.json(
|
||||
{ error: 'Tenant ID required' },
|
||||
{ status: 400 }
|
||||
)
|
||||
}
|
||||
const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i
|
||||
const clientTenantId = request.headers.get('X-Tenant-ID') || request.headers.get('x-tenant-id')
|
||||
const tenantId = (clientTenantId && uuidRegex.test(clientTenantId)) ? clientTenantId : DEFAULT_TENANT_ID
|
||||
|
||||
const body = await request.json()
|
||||
const {
|
||||
@@ -160,25 +168,13 @@ export async function POST(request: NextRequest) {
|
||||
language = 'de',
|
||||
} = body
|
||||
|
||||
// Hole oder erstelle Konfiguration
|
||||
let config = configStorage.get(tenantId)
|
||||
|
||||
if (!config) {
|
||||
config = generateCookieBannerConfig(tenantId, PREDEFINED_DATA_POINTS, texts, styling)
|
||||
} else {
|
||||
// Wende temporaere Anpassungen an
|
||||
if (styling) {
|
||||
config = {
|
||||
...config,
|
||||
styling: { ...config.styling, ...styling },
|
||||
}
|
||||
}
|
||||
if (texts) {
|
||||
config = {
|
||||
...config,
|
||||
texts: { ...config.texts, ...texts },
|
||||
}
|
||||
}
|
||||
// Erstelle Konfiguration mit optionalen Overrides
|
||||
let config: CookieBannerConfig = generateCookieBannerConfig(tenantId, PREDEFINED_DATA_POINTS, texts, styling)
|
||||
if (styling) {
|
||||
config = { ...config, styling: { ...config.styling, ...styling } }
|
||||
}
|
||||
if (texts) {
|
||||
config = { ...config, texts: { ...config.texts, ...texts } }
|
||||
}
|
||||
|
||||
const embedCode = generateEmbedCode(config, privacyPolicyUrl)
|
||||
|
||||
Reference in New Issue
Block a user