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

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:
Benjamin Admin
2026-03-03 10:37:41 +01:00
parent 3570dd10ea
commit c0b179510d
10 changed files with 491 additions and 88 deletions

View File

@@ -98,7 +98,13 @@ const defaultConfig: BannerConfig = {
// COMPONENTS
// =============================================================================
function BannerPreview({ config, categories }: { config: BannerConfig; categories: CookieCategory[] }) {
interface BannerTexts {
title: string
description: string
privacyLink: string
}
function BannerPreview({ config, categories, bannerTexts }: { config: BannerConfig; categories: CookieCategory[]; bannerTexts: BannerTexts }) {
return (
<div className="relative bg-gray-100 rounded-xl p-8 min-h-64 flex items-end justify-center">
<div className="absolute inset-0 flex items-center justify-center text-gray-400 text-sm">
@@ -110,9 +116,9 @@ function BannerPreview({ config, categories }: { config: BannerConfig; categorie
}`}
style={{ borderColor: config.primaryColor }}
>
<h4 className="font-semibold text-gray-900">Wir verwenden Cookies</h4>
<h4 className="font-semibold text-gray-900">{bannerTexts.title}</h4>
<p className="text-sm text-gray-600 mt-2">
Wir nutzen Cookies, um Ihnen die bestmoegliche Nutzung unserer Website zu ermoeglichen.
{bannerTexts.description}
</p>
<div className="mt-4 flex items-center gap-3">
<button
@@ -217,10 +223,17 @@ function CategoryCard({
// MAIN PAGE
// =============================================================================
const defaultBannerTexts: BannerTexts = {
title: 'Wir verwenden Cookies',
description: 'Wir nutzen Cookies, um Ihnen die bestmoegliche Nutzung unserer Website zu ermoeglichen.',
privacyLink: '/datenschutz',
}
export default function CookieBannerPage() {
const { state } = useSDK()
const [categories, setCategories] = useState<CookieCategory[]>([])
const [config, setConfig] = useState<BannerConfig>(defaultConfig)
const [bannerTexts, setBannerTexts] = useState<BannerTexts>(defaultBannerTexts)
const [isSaving, setIsSaving] = useState(false)
const [exportToast, setExportToast] = useState<string | null>(null)
@@ -238,6 +251,10 @@ export default function CookieBannerPage() {
}
if (data.config && Object.keys(data.config).length > 0) {
setConfig(prev => ({ ...prev, ...data.config }))
const savedTexts = data.config.banner_texts || data.config.texts
if (savedTexts) {
setBannerTexts(prev => ({ ...prev, ...savedTexts }))
}
}
} else {
setCategories(mockCategories)
@@ -289,7 +306,7 @@ export default function CookieBannerPage() {
await fetch('/api/sdk/v1/einwilligungen/cookie-banner/config', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ categories, config }),
body: JSON.stringify({ categories, config: { ...config, banner_texts: bannerTexts } }),
})
} catch {
// Silently ignore
@@ -365,7 +382,7 @@ export default function CookieBannerPage() {
{/* Preview */}
<div className="bg-white rounded-xl border border-gray-200 p-6">
<h3 className="font-semibold text-gray-900 mb-4">Banner-Vorschau</h3>
<BannerPreview config={config} categories={categories} />
<BannerPreview config={config} categories={categories} bannerTexts={bannerTexts} />
</div>
{/* Configuration */}
@@ -445,7 +462,8 @@ export default function CookieBannerPage() {
<label className="block text-sm font-medium text-gray-700 mb-1">Ueberschrift</label>
<input
type="text"
defaultValue="Wir verwenden Cookies"
value={bannerTexts.title}
onChange={(e) => setBannerTexts({ ...bannerTexts, title: e.target.value })}
className="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-purple-500"
/>
</div>
@@ -453,7 +471,8 @@ export default function CookieBannerPage() {
<label className="block text-sm font-medium text-gray-700 mb-1">Beschreibung</label>
<textarea
rows={3}
defaultValue="Wir nutzen Cookies, um Ihnen die bestmoegliche Nutzung unserer Website zu ermoeglichen."
value={bannerTexts.description}
onChange={(e) => setBannerTexts({ ...bannerTexts, description: e.target.value })}
className="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-purple-500"
/>
</div>
@@ -461,7 +480,8 @@ export default function CookieBannerPage() {
<label className="block text-sm font-medium text-gray-700 mb-1">Link zur Datenschutzerklaerung</label>
<input
type="text"
defaultValue="/datenschutz"
value={bannerTexts.privacyLink}
onChange={(e) => setBannerTexts({ ...bannerTexts, privacyLink: e.target.value })}
className="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-purple-500"
/>
</div>