fix(admin-v2): Restore complete admin-v2 application

The admin-v2 application was incomplete in the repository. This commit
restores all missing components:

- Admin pages (76 pages): dashboard, ai, compliance, dsgvo, education,
  infrastructure, communication, development, onboarding, rbac
- SDK pages (45 pages): tom, dsfa, vvt, loeschfristen, einwilligungen,
  vendor-compliance, tom-generator, dsr, and more
- Developer portal (25 pages): API docs, SDK guides, frameworks
- All components, lib files, hooks, and types
- Updated package.json with all dependencies

The issue was caused by incomplete initial repository state - the full
admin-v2 codebase existed in backend/admin-v2 and docs-src/admin-v2
but was never fully synced to the main admin-v2 directory.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
BreakPilot Dev
2026-02-08 23:40:15 -08:00
parent f28244753f
commit 660295e218
385 changed files with 138126 additions and 3079 deletions

View File

@@ -0,0 +1,215 @@
/**
* API Route: Cookie Banner Configuration
*
* GET - Cookie Banner Konfiguration abrufen
* POST - Cookie Banner Konfiguration speichern
*/
import { NextRequest, NextResponse } from 'next/server'
import {
CookieBannerConfig,
CookieBannerStyling,
CookieBannerTexts,
DataPoint,
} from '@/lib/sdk/einwilligungen/types'
import {
generateCookieBannerConfig,
DEFAULT_COOKIE_BANNER_STYLING,
DEFAULT_COOKIE_BANNER_TEXTS,
} from '@/lib/sdk/einwilligungen/generator/cookie-banner'
import { PREDEFINED_DATA_POINTS } from '@/lib/sdk/einwilligungen/catalog/loader'
// In-Memory Storage fuer Cookie Banner Configs
const configStorage = new Map<string, CookieBannerConfig>()
/**
* GET /api/sdk/v1/einwilligungen/cookie-banner/config
*
* Laedt die Cookie Banner Konfiguration fuer einen Tenant
*/
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 }
)
}
let config = configStorage.get(tenantId)
if (!config) {
// Generiere Default-Konfiguration
config = generateCookieBannerConfig(tenantId, PREDEFINED_DATA_POINTS)
configStorage.set(tenantId, config)
}
return NextResponse.json(config)
} catch (error) {
console.error('Error loading cookie banner config:', error)
return NextResponse.json(
{ error: 'Failed to load cookie banner config' },
{ status: 500 }
)
}
}
/**
* POST /api/sdk/v1/einwilligungen/cookie-banner/config
*
* Speichert oder aktualisiert die Cookie Banner Konfiguration
*
* Body:
* - dataPointIds?: string[] - IDs der Datenpunkte (fuer Neuberechnung)
* - styling?: Partial<CookieBannerStyling> - Styling-Optionen
* - texts?: Partial<CookieBannerTexts> - Text-Optionen
* - customDataPoints?: DataPoint[] - Kundenspezifische Datenpunkte
*/
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 body = await request.json()
const {
dataPointIds,
styling,
texts,
customDataPoints = [],
} = body
// Hole bestehende Konfiguration oder erstelle neue
let config = configStorage.get(tenantId)
if (dataPointIds && Array.isArray(dataPointIds)) {
// Neu berechnen basierend auf Datenpunkten
const allDataPoints: DataPoint[] = [
...PREDEFINED_DATA_POINTS,
...customDataPoints,
]
const selectedDataPoints = dataPointIds
.map((id: string) => allDataPoints.find((dp) => dp.id === id))
.filter((dp): dp is DataPoint => dp !== undefined)
config = generateCookieBannerConfig(
tenantId,
selectedDataPoints,
texts,
styling
)
} else if (config) {
// Nur Styling/Texts aktualisieren
if (styling) {
config.styling = {
...config.styling,
...styling,
}
}
if (texts) {
config.texts = {
...config.texts,
...texts,
}
}
config.updatedAt = new Date()
} else {
// Erstelle Default
config = generateCookieBannerConfig(
tenantId,
PREDEFINED_DATA_POINTS,
texts,
styling
)
}
configStorage.set(tenantId, config)
return NextResponse.json({
success: true,
config,
})
} catch (error) {
console.error('Error saving cookie banner config:', error)
return NextResponse.json(
{ error: 'Failed to save cookie banner config' },
{ status: 500 }
)
}
}
/**
* PUT /api/sdk/v1/einwilligungen/cookie-banner/config
*
* Aktualisiert einzelne Kategorien
*/
export async function PUT(request: NextRequest) {
try {
const tenantId = request.headers.get('X-Tenant-ID')
if (!tenantId) {
return NextResponse.json(
{ error: 'Tenant ID required' },
{ status: 400 }
)
}
const body = await request.json()
const { categoryId, enabled } = body
if (!categoryId || typeof enabled !== 'boolean') {
return NextResponse.json(
{ error: 'categoryId and enabled required' },
{ status: 400 }
)
}
let config = configStorage.get(tenantId)
if (!config) {
config = generateCookieBannerConfig(tenantId, PREDEFINED_DATA_POINTS)
}
// Finde und aktualisiere die Kategorie
const categoryIndex = config.categories.findIndex((c) => c.id === categoryId)
if (categoryIndex === -1) {
return NextResponse.json(
{ error: 'Category not found' },
{ status: 404 }
)
}
// Essenzielle Cookies koennen nicht deaktiviert werden
if (config.categories[categoryIndex].isRequired && !enabled) {
return NextResponse.json(
{ error: 'Essential cookies cannot be disabled' },
{ status: 400 }
)
}
config.categories[categoryIndex].defaultEnabled = enabled
config.updatedAt = new Date()
configStorage.set(tenantId, config)
return NextResponse.json({
success: true,
category: config.categories[categoryIndex],
})
} catch (error) {
console.error('Error updating cookie category:', error)
return NextResponse.json(
{ error: 'Failed to update cookie category' },
{ status: 500 }
)
}
}