From c0b179510d8e06426f014c625eb8ccec52e5f882 Mon Sep 17 00:00:00 2001 From: Benjamin Admin Date: Tue, 3 Mar 2026 10:37:41 +0100 Subject: [PATCH] =?UTF-8?q?feat:=20Package=204=20Phase=203=20=E2=80=94=20F?= =?UTF-8?q?inale=20Fixes=20+=20Dokumentation=20(MkDocs,=20SDK=20Flow,=20St?= =?UTF-8?q?epHeader)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- .../(admin)/development/sdk-flow/flow-data.ts | 32 +- .../app/(sdk)/sdk/consent/page.tsx | 105 ++++++- .../app/(sdk)/sdk/cookie-banner/page.tsx | 36 ++- .../app/(sdk)/sdk/workflow/page.tsx | 2 +- .../cookie-banner/embed-code/route.ts | 84 +++--- .../components/sdk/StepHeader/StepHeader.tsx | 24 +- .../compliance/api/einwilligungen_routes.py | 2 + .../sdk-modules/dokumentations-module.md | 12 +- .../services/sdk-modules/rechtliche-texte.md | 281 ++++++++++++++++++ mkdocs.yml | 1 + 10 files changed, 491 insertions(+), 88 deletions(-) create mode 100644 docs-src/services/sdk-modules/rechtliche-texte.md diff --git a/admin-compliance/app/(admin)/development/sdk-flow/flow-data.ts b/admin-compliance/app/(admin)/development/sdk-flow/flow-data.ts index 66c42f8..e5a9552 100644 --- a/admin-compliance/app/(admin)/development/sdk-flow/flow-data.ts +++ b/admin-compliance/app/(admin)/development/sdk-flow/flow-data.ts @@ -506,14 +506,14 @@ export const SDK_FLOW_STEPS: SDKFlowStep[] = [ checkpointId: 'CP-CONS', checkpointType: 'REQUIRED', checkpointReviewer: 'NONE', - description: 'Definition aller erforderlichen Einwilligungserklaerungen fuer Datenverarbeitungen.', - descriptionLong: 'Basierend auf dem VVT und den aktivierten Modulen werden alle Verarbeitungen identifiziert, die eine Einwilligung erfordern (Art. 6 Abs. 1a DSGVO). Fuer jede Einwilligung wird ein rechtskonformer Text generiert, der: den Zweck klar benennt, freiwillig erteilt werden kann, informiert und spezifisch ist. Einwilligungen werden mit Widerrufsmechanismus, Versionierung und Nachweispflicht versehen.', + description: 'Definition aller Einwilligungserklaerungen — vollstaendig backend-persistent mit Nachweis-Tracking.', + descriptionLong: 'Basierend auf dem VVT und den aktivierten Modulen werden alle Verarbeitungen identifiziert, die eine Einwilligung erfordern (Art. 6 Abs. 1a DSGVO). Der Datenkatalog definiert einwilligungspflichtige Datenpunkte. Erteilte und widerrufene Einwilligungen werden mit vollstaendigem Audit-Trail gespeichert: Zeitpunkt, Version, IP-Adresse, User-Agent, Quelle. Widerruf setzt `revoked_at` ohne den urspruenglichen Eintrag zu loeschen (Nachweispflicht). Cookie-Banner-Konfiguration ist ebenfalls hier zentral verwaltet.', legalBasis: 'Art. 6 Abs. 1a, Art. 7 DSGVO (Einwilligung)', inputs: ['vvt', 'modules'], outputs: ['consents'], prerequisiteSteps: ['vvt'], - dbTables: [], - dbMode: 'none', + dbTables: ['compliance_einwilligungen_catalog', 'compliance_einwilligungen_company', 'compliance_einwilligungen_consents', 'compliance_einwilligungen_cookies'], + dbMode: 'read/write', ragCollections: ['bp_compliance_datenschutz'], ragPurpose: 'Einwilligungsvorlagen DSGVO', isOptional: false, @@ -528,14 +528,14 @@ export const SDK_FLOW_STEPS: SDKFlowStep[] = [ checkpointId: 'CP-DOC', checkpointType: 'REQUIRED', checkpointReviewer: 'NONE', - description: 'Generierung von Datenschutzerklaerung, AGB und Nutzungsbedingungen.', - descriptionLong: 'In diesem Schritt werden die zentralen rechtlichen Dokumente generiert: Datenschutzerklaerung (nach Art. 13/14 DSGVO), AGB, Nutzungsbedingungen und Informationspflichten. Die Dokumente werden aus dem Unternehmensprofil, VVT und den Einwilligungen automatisch zusammengestellt. Die RAG-Collection bp_legal_templates liefert branchenspezifische Vorlagen, die an die spezifischen Verarbeitungen des Unternehmens angepasst werden.', + description: 'Verwaltung von Datenschutzerklaerung, AGB und Nutzungsbedingungen — vollstaendig backend-persistent.', + descriptionLong: 'In diesem Schritt werden die zentralen rechtlichen Dokumente verwaltet: Datenschutzerklaerung (Art. 13/14 DSGVO), AGB, Cookie-Richtlinie, Impressum und AVV. Jedes Dokument wird in `compliance_legal_documents` gespeichert. Ueber den Vorschau-Button kann die aktuell veroffentlichte HTML-Version im Browser angezeigt werden. Per Bearbeiten-Button gelangt man direkt in den Document Workflow. Schnellaktionen navigieren zum Dokumentengenerator fuer KI-gestuetzte Template-Generierung.', legalBasis: 'Art. 13, 14 DSGVO (Informationspflichten)', inputs: ['companyProfile', 'vvt', 'consents'], outputs: ['documents'], prerequisiteSteps: ['einwilligungen'], - dbTables: [], - dbMode: 'none', + dbTables: ['compliance_legal_documents', 'compliance_legal_document_versions'], + dbMode: 'read/write', ragCollections: ['bp_legal_templates'], ragPurpose: 'AGB, DSE, Nutzungsbedingungen Templates', generates: ['Datenschutzerklaerung', 'AGB', 'Nutzungsbedingungen'], @@ -551,14 +551,14 @@ export const SDK_FLOW_STEPS: SDKFlowStep[] = [ checkpointId: 'CP-COOK', checkpointType: 'REQUIRED', checkpointReviewer: 'NONE', - description: 'Konfiguration eines rechtskonformen Cookie-Banners mit Consent-Management.', - descriptionLong: 'Der Cookie-Banner wird basierend auf den definierten Einwilligungen und dem Unternehmensprofil konfiguriert. Er unterscheidet zwischen technisch notwendigen Cookies (kein Consent noetig), funktionalen Cookies, Analyse-Cookies und Marketing-Cookies. Der Banner implementiert "Privacy by Default" — nur notwendige Cookies sind vorausgewaehlt. Die Konfiguration umfasst: Kategorien, Zweckbeschreibungen, Anbieter, Laufzeiten und Opt-in/Opt-out-Mechanismen.', + description: 'Konfiguration eines rechtskonformen Cookie-Banners — Texte und Kategorien persistent in DB.', + descriptionLong: 'Der Cookie-Banner wird basierend auf den definierten Einwilligungen konfiguriert. Alle Einstellungen (Position, Stil, Farbe, Texte) und Kategorien werden in `compliance_einwilligungen_cookies` gespeichert. Banner-Texte (Ueberschrift, Beschreibung, Datenschutz-Link) sind Controlled Inputs und werden beim Speichern persistiert. Die Live-Vorschau aktualisiert sich in Echtzeit. Der Embed-Code wird beim Export aus der DB-Konfiguration generiert — kein In-Memory-Speicher, kein Datenverlust bei Neustart. Implementiert "Privacy by Default": nur notwendige Cookies sind vorausgewaehlt.', legalBasis: 'Art. 5 Abs. 3 ePrivacy-RL, TTDSG § 25', inputs: ['consents', 'companyProfile'], outputs: ['cookieBanner'], prerequisiteSteps: ['consent'], - dbTables: [], - dbMode: 'none', + dbTables: ['compliance_einwilligungen_cookies'], + dbMode: 'read/write', ragCollections: ['bp_compliance_datenschutz'], ragPurpose: 'Cookie-Consent Richtlinien', isOptional: false, @@ -596,13 +596,13 @@ export const SDK_FLOW_STEPS: SDKFlowStep[] = [ checkpointId: 'CP-WRKF', checkpointType: 'REQUIRED', checkpointReviewer: 'NONE', - description: 'Freigabe-Workflow fuer alle generierten rechtlichen Dokumente.', - descriptionLong: 'Der Document Workflow steuert den Freigabeprozess fuer alle generierten Dokumente. Jedes Dokument durchlaeuft definierte Phasen: Entwurf, Review, Freigabe, Veroeffentlichung. Je nach Dokumenttyp werden unterschiedliche Reviewer zugewiesen (DSB, Rechtsabteilung, Geschaeftsfuehrung). Der Workflow protokolliert alle Aenderungen, Kommentare und Freigaben fuer die Audit-Spur.', + description: 'Freigabe-Workflow fuer alle rechtlichen Dokumente — vollstaendig backend-persistent mit Versionierung.', + descriptionLong: 'Der Document Workflow steuert den Freigabeprozess fuer alle rechtlichen Dokumente. Split-View-Editor: linkes Panel zeigt die veroffentlichte Version, rechtes Panel den Entwurf. Status-Workflow: draft → review → approved → published (oder rejected). Alle Versionen werden in `compliance_legal_document_versions` gespeichert. Der Versions-Endpoint gibt ein direktes JSON-Array zurueck. DOCX-Import via multipart/form-data moeglich. Freigabe-Historie wird in `compliance_legal_document_approvals` protokolliert (Zeitstempel, Benutzer, Kommentar). Veroeffentlichte Versionen sind unveraenderlich — Aenderungen erzeugen stets eine neue Version.', inputs: ['documents', 'generatedDocuments'], outputs: ['approvedDocuments'], prerequisiteSteps: ['cookie-banner'], - dbTables: [], - dbMode: 'none', + dbTables: ['compliance_legal_documents', 'compliance_legal_document_versions', 'compliance_legal_document_approvals'], + dbMode: 'read/write', ragCollections: [], isOptional: false, url: '/sdk/workflow', diff --git a/admin-compliance/app/(sdk)/sdk/consent/page.tsx b/admin-compliance/app/(sdk)/sdk/consent/page.tsx index 59947bc..babc767 100644 --- a/admin-compliance/app/(sdk)/sdk/consent/page.tsx +++ b/admin-compliance/app/(sdk)/sdk/consent/page.tsx @@ -1,6 +1,7 @@ 'use client' import React, { useState, useEffect } from 'react' +import { useRouter } from 'next/navigation' import { useSDK } from '@/lib/sdk' import { StepHeader, STEP_EXPLANATIONS } from '@/components/sdk/StepHeader' @@ -67,7 +68,17 @@ function transformApiDocument(doc: ApiDocument): LegalDocument { // COMPONENTS // ============================================================================= -function DocumentCard({ document, onDelete }: { document: LegalDocument; onDelete: (id: string) => void }) { +function DocumentCard({ + document, + onDelete, + onEdit, + onPreview, +}: { + document: LegalDocument + onDelete: (id: string) => void + onEdit: (id: string) => void + onPreview: (doc: LegalDocument) => void +}) { const typeColors = { 'privacy-policy': 'bg-blue-100 text-blue-700', terms: 'bg-green-100 text-green-700', @@ -138,14 +149,23 @@ function DocumentCard({ document, onDelete }: { document: LegalDocument; onDelet Aktualisiert: {document.lastUpdated.toLocaleDateString('de-DE')}
- - {document.status === 'draft' && ( - )} @@ -167,6 +187,7 @@ function DocumentCard({ document, onDelete }: { document: LegalDocument; onDelet export default function ConsentPage() { const { state } = useSDK() + const router = useRouter() const [documents, setDocuments] = useState([]) const [loading, setLoading] = useState(true) const [error, setError] = useState(null) @@ -174,6 +195,7 @@ export default function ConsentPage() { const [showCreateModal, setShowCreateModal] = useState(false) const [newDocForm, setNewDocForm] = useState({ type: 'privacy_policy', name: '', description: '' }) const [creating, setCreating] = useState(false) + const [previewDoc, setPreviewDoc] = useState<{ name: string; content: string } | null>(null) useEffect(() => { loadDocuments() @@ -246,6 +268,30 @@ export default function ConsentPage() { } } + function handleEdit(id: string) { + router.push('/sdk/workflow') + } + + async function handlePreview(doc: LegalDocument) { + try { + const token = localStorage.getItem('bp_admin_token') + const res = await fetch(`/api/admin/consent/documents/${doc.id}/versions`, { + headers: token ? { 'Authorization': `Bearer ${token}` } : {} + }) + if (res.ok) { + const data = await res.json() + const versions = Array.isArray(data) ? data : (data.versions || []) + const published = versions.find((v: { status: string; content?: string }) => v.status === 'published') + const latest = published || versions[0] + setPreviewDoc({ name: doc.name, content: latest?.content || '

Kein Inhalt verfügbar.

' }) + } else { + setPreviewDoc({ name: doc.name, content: '

Vorschau nicht verfügbar.

' }) + } + } catch { + setPreviewDoc({ name: doc.name, content: '

Fehler beim Laden der Vorschau.

' }) + } + } + const filteredDocuments = filter === 'all' ? documents : documents.filter(d => d.type === filter || d.status === filter) @@ -312,25 +358,37 @@ export default function ConsentPage() {

Schnellaktionen

- - - -
)} + {/* Preview Modal */} + {previewDoc && ( +
+
+
+

{previewDoc.name}

+ +
+
+
+
+ )} + {/* Create Document Modal */} {showCreateModal && (
diff --git a/admin-compliance/app/(sdk)/sdk/cookie-banner/page.tsx b/admin-compliance/app/(sdk)/sdk/cookie-banner/page.tsx index 9d1ddd6..5344828 100644 --- a/admin-compliance/app/(sdk)/sdk/cookie-banner/page.tsx +++ b/admin-compliance/app/(sdk)/sdk/cookie-banner/page.tsx @@ -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 (
@@ -110,9 +116,9 @@ function BannerPreview({ config, categories }: { config: BannerConfig; categorie }`} style={{ borderColor: config.primaryColor }} > -

Wir verwenden Cookies

+

{bannerTexts.title}

- Wir nutzen Cookies, um Ihnen die bestmoegliche Nutzung unserer Website zu ermoeglichen. + {bannerTexts.description}

@@ -453,7 +471,8 @@ export default function CookieBannerPage() {