feat(cmp): Phase 2 complete — self-hosted fonts, ScriptManager, GeoIP, vendor UI
- Session ID via sessionStorage UUID - Self-host Google Fonts (Inter, Plus Jakarta Sans, JetBrains Mono) — eliminates third-party transfer to Google, no more DSGVO violation - ScriptManager component: consent-change listener for future analytics/marketing scripts - GeoIP via browser timezone (Intl.DateTimeFormat) + IP injection in proxy - Vendor-level consent UI: loads vendor config from backend, shows per-vendor toggles under each category, sends vendor_consents dict - DSE updated: Google Fonts section now says "lokal gehostet" - Config proxy route: GET /api/consent/config Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,21 @@
|
||||
import { NextRequest, NextResponse } from 'next/server'
|
||||
|
||||
const BACKEND_URL = process.env.CONSENT_BACKEND_URL || 'https://macmini:3007/api/sdk/v1/banner'
|
||||
const TENANT_ID = process.env.CONSENT_TENANT_ID || '9282a473-5c95-4b3a-bf78-0ecc0ec71d3e'
|
||||
const SITE_ID = process.env.NEXT_PUBLIC_CONSENT_SITE_ID || 'breakpilot-marketing'
|
||||
|
||||
export async function GET(req: NextRequest) {
|
||||
try {
|
||||
const siteId = req.nextUrl.searchParams.get('site_id') || SITE_ID
|
||||
const res = await fetch(`${BACKEND_URL}/config/${siteId}`, {
|
||||
headers: { 'X-Tenant-ID': TENANT_ID },
|
||||
})
|
||||
const data = await res.text()
|
||||
return new NextResponse(data, {
|
||||
status: res.status,
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
})
|
||||
} catch {
|
||||
return NextResponse.json({ categories: [], vendors: [] }, { status: 200 })
|
||||
}
|
||||
}
|
||||
@@ -5,7 +5,13 @@ const TENANT_ID = process.env.CONSENT_TENANT_ID || '9282a473-5c95-4b3a-bf78-0ecc
|
||||
|
||||
export async function POST(req: NextRequest) {
|
||||
try {
|
||||
const body = await req.text()
|
||||
const data = await req.json()
|
||||
|
||||
// Inject client IP for backend GeoIP resolution
|
||||
const ip = req.headers.get('x-forwarded-for')?.split(',')[0]?.trim()
|
||||
|| req.headers.get('x-real-ip')
|
||||
|| null
|
||||
if (ip) data.ip_address = ip
|
||||
|
||||
const res = await fetch(`${BACKEND_URL}/consent`, {
|
||||
method: 'POST',
|
||||
@@ -13,13 +19,11 @@ export async function POST(req: NextRequest) {
|
||||
'Content-Type': 'application/json',
|
||||
'X-Tenant-ID': TENANT_ID,
|
||||
},
|
||||
body,
|
||||
// Accept self-signed certs on internal network
|
||||
...(process.env.NODE_TLS_REJECT_UNAUTHORIZED === '0' ? {} : {}),
|
||||
body: JSON.stringify(data),
|
||||
})
|
||||
|
||||
const data = await res.text()
|
||||
return new NextResponse(data, {
|
||||
const resBody = await res.text()
|
||||
return new NextResponse(resBody, {
|
||||
status: res.status,
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user