diff --git a/admin-compliance/app/sdk/advisory-board/page.tsx b/admin-compliance/app/sdk/advisory-board/page.tsx index d866bae..9c0d280 100644 --- a/admin-compliance/app/sdk/advisory-board/page.tsx +++ b/admin-compliance/app/sdk/advisory-board/page.tsx @@ -1,1521 +1,1096 @@ 'use client' -import React, { useState } from 'react' +import React, { useState, useEffect, Suspense } from 'react' +import { useRouter, useSearchParams } from 'next/navigation' import Link from 'next/link' -import { useSDK, UseCaseAssessment, UseCaseIntake } from '@/lib/sdk' +import { useSDK } from '@/lib/sdk' import { AssessmentResultCard } from '@/components/sdk/use-case-assessment/AssessmentResultCard' // ============================================================================= -// WIZARD STEPS +// WIZARD STEPS CONFIG // ============================================================================= const WIZARD_STEPS = [ - { id: 1, name: 'Grunddaten', description: 'Name, Beschreibung, Kategorie und Branche' }, - { id: 2, name: 'Datenkategorien', description: 'Welche Daten werden verarbeitet?' }, - { id: 3, name: 'Verarbeitungszweck', description: 'Rechtsgrundlage und Zweck' }, - { id: 4, name: 'Technologie & Modell', description: 'KI-Technologien und Modell-Nutzung' }, - { id: 5, name: 'Automatisierung', description: 'Grad der Automatisierung' }, - { id: 6, name: 'Hosting & Transfer', description: 'Hosting und Datentransfer' }, - { id: 7, name: 'Datenhaltung', description: 'Aufbewahrung und Vertraege' }, - { id: 8, name: 'Zusammenfassung', description: 'Ueberpruefung und Abschluss' }, -] - -const TOTAL_STEPS = WIZARD_STEPS.length - -const DOMAINS = [ - { value: 'healthcare', label: 'Gesundheit' }, - { value: 'finance', label: 'Finanzen' }, - { value: 'education', label: 'Bildung' }, - { value: 'retail', label: 'Handel' }, - { value: 'it_services', label: 'IT-Dienstleistungen' }, - { value: 'consulting', label: 'Beratung' }, - { value: 'manufacturing', label: 'Produktion' }, - { value: 'hr', label: 'Personalwesen' }, - { value: 'marketing', label: 'Marketing' }, - { value: 'legal', label: 'Recht' }, - { value: 'public', label: 'Oeffentlicher Sektor' }, - { value: 'general', label: 'Allgemein' }, + { id: 1, title: 'Grundlegendes', description: 'Titel, Beschreibung und KI-Kategorie' }, + { id: 2, title: 'Datenkategorien', description: 'Welche Daten werden verarbeitet?' }, + { id: 3, title: 'Verarbeitungszweck', description: 'Zweck der Datenverarbeitung' }, + { id: 4, title: 'Automatisierung', description: 'Grad der Automatisierung' }, + { id: 5, title: 'Hosting & Modell', description: 'Technische Details' }, + { id: 6, title: 'Datentransfer', description: 'Internationaler Datentransfer' }, + { id: 7, title: 'Datenhaltung', description: 'Aufbewahrung und Speicherung' }, + { id: 8, title: 'Vertraege', description: 'Compliance und Vereinbarungen' }, ] // ============================================================================= -// RISK CALCULATION (client-side) +// KI-Anwendungskategorien als Auswahlkacheln // ============================================================================= -function calculateRiskScore(form: WizardFormData): { score: number; level: 'LOW' | 'MEDIUM' | 'HIGH' | 'CRITICAL'; dsfaRequired: boolean } { - let score = 0 - if (form.processesPersonalData) score += 10 - if (form.specialCategories) score += 25 - if (form.biometricData) score += 20 - if (form.healthData) score += 15 - if (form.minorsData) score += 15 - if (form.financialData) score += 5 - if (form.purposeProfiling) score += 15 - if (form.purposeAutomatedDecision) score += 20 - if (form.automation === 'fully_automated') score += 25 - else if (form.automation === 'semi_automated') score += 10 - if (form.internationalTransfer) score += 10 - if (form.modelTraining) score += 10 - if (form.modelFinetune) score += 5 +const AI_USE_CATEGORIES = [ + { value: 'content_generation', label: 'Content-Erstellung', icon: 'โœ๏ธ', desc: 'Texte, Berichte, E-Mails, Dokumentation automatisch erstellen' }, + { value: 'image_generation', label: 'Bilder erstellen', icon: '๐ŸŽจ', desc: 'KI-generierte Bilder, Grafiken, Produktfotos' }, + { value: 'marketing_material', label: 'Marketingmaterial', icon: '๐Ÿ“ข', desc: 'Werbetexte, Social Media Posts, Newsletter generieren' }, + { value: 'customer_service', label: 'Kundenservice / Chatbot', icon: '๐Ÿ’ฌ', desc: 'Automatisierte Kundenanfragen, FAQ-Bots, Support-Tickets' }, + { value: 'crm_analytics', label: 'CRM & Kundenanalyse', icon: '๐Ÿ‘ฅ', desc: 'Kundensegmentierung, Churn-Vorhersage, Lead-Scoring' }, + { value: 'hr_recruiting', label: 'Bewerberauswahl / HR', icon: '๐Ÿง‘โ€๐Ÿ’ผ', desc: 'CV-Screening, Matching, Mitarbeiteranalysen' }, + { value: 'financial_analysis', label: 'Finanzdaten analysieren', icon: '๐Ÿ“Š', desc: 'Buchhaltung, Forecasting, Betrugsยญerkennung, Risikobewertung' }, + { value: 'predictive_maintenance', label: 'Predictive Maintenance', icon: '๐Ÿ”ง', desc: 'Vorausschauende Wartung, Ausfallvorhersage, IoT-Sensoranalyse' }, + { value: 'production_analytics', label: 'Produktionsdatenยญauswertung', icon: '๐Ÿญ', desc: 'Qualitaetskontrolle, Prozessยญoptimierung, OEE-Analyse' }, + { value: 'document_analysis', label: 'Dokumentenanalyse', icon: '๐Ÿ“„', desc: 'Vertraege, Rechnungen, PDFs automatisch auswerten und klassifizieren' }, + { value: 'code_development', label: 'Softwareentwicklung', icon: '๐Ÿ’ป', desc: 'Code-Generierung, Code-Review, Test-Erstellung, Dokumentation' }, + { value: 'translation', label: 'Uebersetzung', icon: '๐ŸŒ', desc: 'Automatische Uebersetzung von Texten, Dokumenten, Webinhalten' }, + { value: 'search_knowledge', label: 'Wissensmanagement / Suche', icon: '๐Ÿ”', desc: 'Interne Wissensdatenbank, RAG-basierte Suche, FAQ-Systeme' }, + { value: 'data_extraction', label: 'Datenextraktion', icon: 'โ›๏ธ', desc: 'OCR, Formularerkennung, strukturierte Daten aus Freitext' }, + { value: 'risk_compliance', label: 'Risiko & Compliance', icon: 'โš–๏ธ', desc: 'Compliance-Pruefung, Risikobewertung, Audit-Unterstuetzung' }, + { value: 'supply_chain', label: 'Lieferkette & Logistik', icon: '๐Ÿš›', desc: 'Bedarfsprognose, Routenoptimierung, Bestandsmanagement' }, + { value: 'medical_health', label: 'Medizin & Gesundheit', icon: '๐Ÿฅ', desc: 'Diagnoseunterstuetzung, Bildanalyse, Patientendaten' }, + { value: 'security_monitoring', label: 'Sicherheit & Monitoring', icon: '๐Ÿ›ก๏ธ', desc: 'Anomalieerkennung, Bedrohungsanalyse, Zugriffskontrolle' }, + { value: 'personalization', label: 'Personalisierung', icon: '๐ŸŽฏ', desc: 'Produktempfehlungen, dynamische Preisgestaltung, A/B-Testing' }, + { value: 'voice_speech', label: 'Sprache & Audio', icon: '๐ŸŽ™๏ธ', desc: 'Spracherkennung, Text-to-Speech, Meeting-Transkription' }, + { value: 'other', label: 'Sonstiges', icon: 'โž•', desc: 'Anderer KI-Anwendungsfall' }, +] - let level: 'LOW' | 'MEDIUM' | 'HIGH' | 'CRITICAL' - if (score >= 60) level = 'CRITICAL' - else if (score >= 40) level = 'HIGH' - else if (score >= 20) level = 'MEDIUM' - else level = 'LOW' - - const dsfaRequired = score >= 40 || form.specialCategories || (form.purposeAutomatedDecision && form.automation === 'fully_automated') - - return { score, level, dsfaRequired } +// Map Profil-Branche to domain value for backend compatibility +function industryToDomain(industries: string[]): string { + if (!industries || industries.length === 0) return 'general' + const first = industries[0].toLowerCase() + if (first.includes('gesundheit') || first.includes('pharma')) return 'healthcare' + if (first.includes('finanz') || first.includes('versicherung')) return 'finance' + if (first.includes('bildung')) return 'education' + if (first.includes('handel') || first.includes('commerce')) return 'retail' + if (first.includes('it') || first.includes('technologie')) return 'it_services' + if (first.includes('beratung') || first.includes('consulting')) return 'consulting' + if (first.includes('produktion') || first.includes('industrie') || first.includes('maschinenbau')) return 'manufacturing' + if (first.includes('marketing') || first.includes('agentur')) return 'marketing' + if (first.includes('recht')) return 'legal' + return 'general' } // ============================================================================= -// USE CASE CARD +// DATA CATEGORIES (Step 2) โ€” grouped tile selection // ============================================================================= -function UseCaseCard({ - useCase, - isActive, - onSelect, - onDelete, -}: { - useCase: UseCaseAssessment - isActive: boolean - onSelect: () => void - onDelete: () => void -}) { - const completionPercent = Math.round((useCase.stepsCompleted / TOTAL_STEPS) * 100) +const DATA_CATEGORY_GROUPS = [ + { + group: 'Stamm- & Kontaktdaten', + items: [ + { value: 'basic_identity', label: 'Name & Identitaet', icon: '๐Ÿ‘ค', desc: 'Vor-/Nachname, Geburtsdatum, Geschlecht' }, + { value: 'contact_data', label: 'Kontaktdaten', icon: '๐Ÿ“ง', desc: 'E-Mail, Telefon, Fax' }, + { value: 'address_data', label: 'Adressdaten', icon: '๐Ÿ ', desc: 'Wohn-/Meldeadresse, PLZ, Lieferadresse' }, + { value: 'government_ids', label: 'Ausweisdaten', icon: '๐Ÿชช', desc: 'Personalausweis-Nr., Reisepass, Fuehrerschein' }, + { value: 'customer_ids', label: 'Kundennummern', icon: '๐Ÿท๏ธ', desc: 'Kunden-ID, Vertrags-Nr., Mitgliedsnummer' }, + ], + }, + { + group: 'Besondere Kategorien (Art. 9 DSGVO)', + art9: true, + items: [ + { value: 'health_data', label: 'Gesundheitsdaten', icon: '๐Ÿฅ', desc: 'Diagnosen, Medikation, AU, Pflegegrad' }, + { value: 'biometric_data', label: 'Biometrische Daten', icon: '๐Ÿ”', desc: 'Fingerabdruck, Gesichtserkennung, Iris-Scan' }, + { value: 'genetic_data', label: 'Genetische Daten', icon: '๐Ÿงฌ', desc: 'DNA-Profil, Genomsequenzen, Erbkrankheitstests' }, + { value: 'racial_ethnic', label: 'Ethnische Herkunft', icon: '๐ŸŒ', desc: 'Rassische/ethnische Zugehoerigkeit' }, + { value: 'political_opinions', label: 'Politische Meinungen', icon: '๐Ÿ—ณ๏ธ', desc: 'Politische Ueberzeugungen, Parteizugehoerigkeit' }, + { value: 'religious_beliefs', label: 'Religion', icon: '๐Ÿ•Š๏ธ', desc: 'Religionszugehoerigkeit, Weltanschauung' }, + { value: 'trade_union', label: 'Gewerkschaft', icon: '๐Ÿค', desc: 'Gewerkschaftsmitgliedschaft' }, + { value: 'sexual_orientation', label: 'Sexuelle Orientierung', icon: '๐Ÿณ๏ธโ€๐ŸŒˆ', desc: 'Sexualleben und Orientierung' }, + ], + }, + { + group: 'Finanz- & Steuerdaten', + items: [ + { value: 'bank_account', label: 'Bankverbindung', icon: '๐Ÿฆ', desc: 'IBAN, BIC, Kontonummer' }, + { value: 'payment_card', label: 'Zahlungskarten', icon: '๐Ÿ’ณ', desc: 'Kreditkarten-Nr., CVV (PCI-DSS)' }, + { value: 'transaction_data', label: 'Transaktionsdaten', icon: '๐Ÿงพ', desc: 'Zahlungshistorie, Ueberweisungen, Kaufhistorie' }, + { value: 'credit_score', label: 'Bonitaet / Schufa', icon: '๐Ÿ“ˆ', desc: 'Kreditwuerdigkeit, Schuldenhistorie' }, + { value: 'income_salary', label: 'Einkommen & Gehalt', icon: '๐Ÿ’ฐ', desc: 'Bruttogehalt, Nettolohn, Boni' }, + { value: 'tax_ids', label: 'Steuer-IDs', icon: '๐Ÿ“‹', desc: 'Steuer-ID, Steuernummer, USt-IdNr.' }, + { value: 'insurance_data', label: 'Versicherungsdaten', icon: 'โ˜‚๏ธ', desc: 'Versicherungsnummern, Policen, Schadenmeldungen' }, + ], + }, + { + group: 'Fahrzeug- & Mobilitaetsdaten', + items: [ + { value: 'vehicle_ids', label: 'Fahrzeug-IDs (VIN)', icon: '๐Ÿš—', desc: 'Fahrgestellnummer (VIN/FIN), Fahrzeugschein' }, + { value: 'license_plates', label: 'Kennzeichen', icon: '๐Ÿ”ข', desc: 'Amtliches Kennzeichen, Wunschkennzeichen' }, + { value: 'gps_tracking', label: 'GPS & Routen', icon: '๐Ÿ“', desc: 'Echtzeitposition, Fahrtenprotokolle' }, + { value: 'telematics', label: 'Telematikdaten', icon: '๐Ÿ“ก', desc: 'Fahrverhalten, Geschwindigkeit, Motordiagnose' }, + { value: 'fleet_data', label: 'Fuhrpark / Logistik', icon: '๐Ÿš›', desc: 'Einsatzzeiten, Kilometerstand, Fahrerzuweisung' }, + ], + }, + { + group: 'Technische Identifikatoren', + items: [ + { value: 'ip_address', label: 'IP-Adresse', icon: '๐ŸŒ', desc: 'IPv4/IPv6 (EuGH: personenbezogen)' }, + { value: 'device_ids', label: 'Geraete-IDs', icon: '๐Ÿ“ฑ', desc: 'IMEI, UUID, Advertising-ID, Seriennummer' }, + { value: 'cookies_tracking', label: 'Cookies & Tracking', icon: '๐Ÿช', desc: 'Session-/Persistent Cookies, Pixel-Tags' }, + { value: 'browser_fingerprint', label: 'Browser-Fingerprint', icon: '๐Ÿ”Ž', desc: 'Browser-Typ, OS, Plugins, Canvas-Fingerprint' }, + { value: 'mac_address', label: 'MAC-Adresse', icon: '๐Ÿ“ถ', desc: 'Netzwerkadapter-Kennung, WLAN-Praesenz' }, + ], + }, + { + group: 'Verhaltens- & Nutzungsdaten', + items: [ + { value: 'clickstream', label: 'Klick- & Nutzungspfade', icon: '๐Ÿ–ฑ๏ธ', desc: 'Klickpfade, Scrolltiefe, Verweildauer, Heatmaps' }, + { value: 'purchase_history', label: 'Kaufverhalten', icon: '๐Ÿ›’', desc: 'Bestellhistorie, Warenkorb, Wunschlisten' }, + { value: 'app_usage', label: 'App-Nutzung', icon: '๐Ÿ“ฒ', desc: 'Genutzte Apps, Nutzungsdauer, In-App-Aktivitaeten' }, + { value: 'profiling_scores', label: 'Profiling / Scoring', icon: '๐Ÿ“Š', desc: 'KI-generierte Profile, Segmente, Affinitaetsscores' }, + ], + }, + { + group: 'Kommunikation & Medien', + items: [ + { value: 'email_content', label: 'E-Mail-Inhalte', icon: 'โœ‰๏ธ', desc: 'E-Mail-Texte, Anhaenge, Metadaten' }, + { value: 'chat_messages', label: 'Chat & Messaging', icon: '๐Ÿ’ฌ', desc: 'Textnachrichten, Messenger, Teams, Slack' }, + { value: 'call_recordings', label: 'Telefonaufzeichnungen', icon: '๐Ÿ“ž', desc: 'Gespraeche, Transkripte, Anrufmetadaten' }, + { value: 'video_conference', label: 'Videokonferenzen', icon: '๐Ÿ“น', desc: 'Meeting-Aufzeichnungen, Teilnehmerlisten' }, + { value: 'photographs', label: 'Fotos & Bilder', icon: '๐Ÿ“ท', desc: 'Portraitfotos, Profilbilder, Produktfotos' }, + { value: 'cctv_surveillance', label: 'Videoueberwachung', icon: '๐Ÿ“น', desc: 'CCTV-Aufnahmen, Zutrittskontrolle' }, + { value: 'voice_recordings', label: 'Sprachaufnahmen', icon: '๐ŸŽ™๏ธ', desc: 'Voicemails, Sprachmemos, Diktate' }, + ], + }, + { + group: 'HR & Beschaeftigung', + items: [ + { value: 'employment_data', label: 'Beschaeftigungsdaten', icon: '๐Ÿ’ผ', desc: 'Arbeitgeber, Berufsbezeichnung, Vertragsart' }, + { value: 'performance_data', label: 'Leistungsbeurteilungen', icon: '๐Ÿ†', desc: 'Zielerreichung, Feedback, Abmahnungen' }, + { value: 'work_time', label: 'Arbeitszeit', icon: 'โฐ', desc: 'Zeiterfassung, Ueberstunden, Schichtplaene' }, + { value: 'candidate_data', label: 'Bewerberdaten', icon: '๐Ÿ“', desc: 'Lebenslaeufe, Interviews, Assessment-Ergebnisse' }, + { value: 'social_security', label: 'Sozialversicherungs-Nr.', icon: '๐Ÿ›ก๏ธ', desc: 'RVNR (Art. 9 โ€” kodiert Geburtsdatum/Geschlecht)' }, + ], + }, + { + group: 'IoT & Sensordaten', + items: [ + { value: 'industrial_sensor', label: 'Industriesensoren', icon: '๐Ÿญ', desc: 'Maschinendaten, Fehlerprotokolle, Produktionsmesswerte' }, + { value: 'wearable_data', label: 'Wearable-Daten', icon: 'โŒš', desc: 'Herzfrequenz, Schritte, Schlaf (Art. 9 โ€” Gesundheit)' }, + { value: 'smart_home', label: 'Smart-Home', icon: '๐Ÿก', desc: 'Heizung, Licht, Bewegungsmelder, Nutzungszeiten' }, + { value: 'energy_data', label: 'Energieverbrauch', icon: '๐Ÿ”Œ', desc: 'Smart-Meter, Verbrauchsprofil (enthuellt Verhalten)' }, + ], + }, + { + group: 'Sonstige Kategorien', + items: [ + { value: 'children_data', label: 'Kinderdaten (unter 16)', icon: '๐Ÿ‘ถ', desc: 'Besonderer Schutz, Eltern-Einwilligung erforderlich' }, + { value: 'criminal_data', label: 'Strafrechtliche Daten', icon: 'โš–๏ธ', desc: 'Vorstrafen, Ermittlungsverfahren (Art. 10 DSGVO)' }, + { value: 'location_data', label: 'Standortdaten', icon: '๐Ÿ“', desc: 'GPS, Mobilfunk, WLAN-Ortung, Bewegungsprofile' }, + { value: 'social_media', label: 'Social-Media-Daten', icon: '๐Ÿ“ฑ', desc: 'Profile, Posts, Follower, Interaktionen' }, + { value: 'auth_credentials', label: 'Login & Zugangsdaten', icon: '๐Ÿ”‘', desc: 'Passwoerter, 2FA, Session-Tokens, Zugriffsprotokolle' }, + ], + }, +] - return ( -
- {/* Delete Button */} - +// ============================================================================= +// PROCESSING PURPOSES (Step 3) โ€” tile selection +// ============================================================================= -
-
- {completionPercent === 100 ? ( - - - - ) : ( - - - - )} -
-
-

{useCase.name}

-

{useCase.description}

-
-
- Fortschritt - {completionPercent}% -
-
-
-
-
- {useCase.assessmentResult && ( -
- - Risiko: {useCase.assessmentResult.riskLevel} - - {useCase.assessmentResult.dsfaRequired && ( - - DSFA erforderlich - - )} -
- )} -
-
-
- ) +const PURPOSE_TILES = [ + { value: 'service_delivery', label: 'Serviceerbringung', icon: 'โš™๏ธ', desc: 'Kernfunktion des Produkts oder Services' }, + { value: 'analytics', label: 'Analyse & BI', icon: '๐Ÿ“Š', desc: 'Statistische Auswertung, Business Intelligence, Reporting' }, + { value: 'marketing', label: 'Marketing & Werbung', icon: '๐Ÿ“ข', desc: 'Werbung, Personalisierung, Targeting, Newsletter' }, + { value: 'profiling', label: 'Profiling', icon: '๐ŸŽฏ', desc: 'Automatisierte Analyse personenbezogener Aspekte' }, + { value: 'automated_decision', label: 'Automatisierte Entscheidung', icon: '๐Ÿค–', desc: 'Art. 22 DSGVO โ€” Entscheidung ohne menschliches Zutun' }, + { value: 'customer_support', label: 'Kundensupport', icon: '๐ŸŽง', desc: 'Anfragenbearbeitung, Ticketsystem, Chatbot' }, + { value: 'quality_control', label: 'Qualitaetskontrolle', icon: 'โœ…', desc: 'Produktpruefung, Fehleranalyse, Prozessoptimierung' }, + { value: 'hr_management', label: 'Personalverwaltung', icon: '๐Ÿ‘ฅ', desc: 'Recruiting, Onboarding, Mitarbeiterentwicklung' }, + { value: 'fraud_detection', label: 'Betrugserkennung', icon: '๐Ÿ•ต๏ธ', desc: 'Anomalieerkennung, Transaktionsueberwachung' }, + { value: 'research', label: 'Forschung & Entwicklung', icon: '๐Ÿ”ฌ', desc: 'Wissenschaftliche Auswertung, Produktentwicklung' }, + { value: 'compliance_audit', label: 'Compliance & Audit', icon: '๐Ÿ“œ', desc: 'Regulatorische Pruefung, Dokumentation, Audit-Trail' }, + { value: 'communication', label: 'Kommunikation', icon: '๐Ÿ’ฌ', desc: 'Interne/externe Kommunikation, Uebersetzung' }, + { value: 'content_creation', label: 'Content-Erstellung', icon: 'โœ๏ธ', desc: 'Text-, Bild-, Video-Generierung' }, + { value: 'predictive', label: 'Vorhersage & Prognose', icon: '๐Ÿ”ฎ', desc: 'Demand Forecasting, Predictive Analytics, Wartungsvorhersage' }, + { value: 'security', label: 'IT-Sicherheit', icon: '๐Ÿ›ก๏ธ', desc: 'Bedrohungserkennung, Zugriffskontrolle, Monitoring' }, + { value: 'archiving', label: 'Archivierung', icon: '๐Ÿ—„๏ธ', desc: 'Gesetzliche Aufbewahrung, Dokumentenarchiv' }, +] + +// ============================================================================= +// AUTOMATION LEVELS (Step 4) โ€” single-select tiles +// ============================================================================= + +const AUTOMATION_TILES = [ + { value: 'assistive', label: 'Assistiv (Mensch entscheidet)', icon: '๐Ÿง‘โ€๐Ÿ’ป', desc: 'KI liefert Vorschlaege, Mensch trifft Entscheidung', examples: 'Rechtschreibkorrektur, Suchvorschlaege, Zusammenfassungen' }, + { value: 'semi_automated', label: 'Teilautomatisiert (Mensch prueft)', icon: '๐Ÿค', desc: 'KI erstellt Ergebnisse, Mensch prueft und bestaetigt', examples: 'E-Mail-Entwuerfe mit Freigabe, KI-Vertraege mit juristischer Pruefung' }, + { value: 'fully_automated', label: 'Vollautomatisiert (KI entscheidet)', icon: '๐Ÿค–', desc: 'KI trifft Entscheidungen eigenstaendig', examples: 'Automatische Kreditentscheidungen, autonome Chatbot-Antworten' }, +] + +// ============================================================================= +// HOSTING & MODEL (Step 5) โ€” tiles +// ============================================================================= + +const HOSTING_PROVIDER_TILES = [ + { value: 'self_hosted', label: 'Eigenes Hosting', icon: '๐Ÿข', desc: 'On-Premise oder eigene Server' }, + { value: 'hetzner', label: 'Hetzner (DE)', icon: '๐Ÿ‡ฉ๐Ÿ‡ช', desc: 'Deutsche Cloud-Infrastruktur' }, + { value: 'aws', label: 'AWS', icon: 'โ˜๏ธ', desc: 'Amazon Web Services' }, + { value: 'azure', label: 'Microsoft Azure', icon: '๐Ÿ”ท', desc: 'Microsoft Cloud' }, + { value: 'gcp', label: 'Google Cloud', icon: '๐Ÿ”ต', desc: 'Google Cloud Platform' }, + { value: 'other', label: 'Anderer Anbieter', icon: '๐ŸŒ', desc: 'Sonstiger Cloud-Anbieter' }, +] + +const HOSTING_REGION_TILES = [ + { value: 'de', label: 'Deutschland', icon: '๐Ÿ‡ฉ๐Ÿ‡ช', desc: 'Rechenzentrum in Deutschland' }, + { value: 'eu', label: 'EU / EWR', icon: '๐Ÿ‡ช๐Ÿ‡บ', desc: 'Innerhalb der Europaeischen Union' }, + { value: 'us', label: 'USA', icon: '๐Ÿ‡บ๐Ÿ‡ธ', desc: 'Vereinigte Staaten' }, + { value: 'other', label: 'Andere Region', icon: '๐ŸŒ', desc: 'Drittland ausserhalb EU/USA' }, +] + +const MODEL_USAGE_TILES = [ + { value: 'inference', label: 'Inferenz', icon: 'โšก', desc: 'Fertiges Modell direkt nutzen (z.B. ChatGPT, Claude, DeepL)' }, + { value: 'rag', label: 'RAG', icon: '๐Ÿ“š', desc: 'Modell erhaelt Kontext aus eigenen Dokumenten' }, + { value: 'finetune', label: 'Fine-Tuning', icon: '๐ŸŽ›๏ธ', desc: 'Bestehendes Modell mit eigenen Daten nachtrainieren' }, + { value: 'training', label: 'Eigenes Modell trainieren', icon: '๐Ÿง ', desc: 'Komplett eigenes KI-Modell von Grund auf' }, +] + +// ============================================================================= +// DATA TRANSFER (Step 6) โ€” tiles +// ============================================================================= + +const TRANSFER_TARGET_TILES = [ + { value: 'no_transfer', label: 'Kein Drittlandtransfer', icon: '๐Ÿ‡ช๐Ÿ‡บ', desc: 'Daten verbleiben in der EU/EWR' }, + { value: 'usa', label: 'USA', icon: '๐Ÿ‡บ๐Ÿ‡ธ', desc: 'Datentransfer in die USA' }, + { value: 'uk', label: 'Grossbritannien', icon: '๐Ÿ‡ฌ๐Ÿ‡ง', desc: 'Datentransfer nach UK (Angemessenheitsbeschluss)' }, + { value: 'switzerland', label: 'Schweiz', icon: '๐Ÿ‡จ๐Ÿ‡ญ', desc: 'Datentransfer in die Schweiz (Angemessenheitsbeschluss)' }, + { value: 'other_adequate', label: 'Anderes Land (Angemessenheit)', icon: 'โœ…', desc: 'Land mit Angemessenheitsbeschluss der EU' }, + { value: 'other_third', label: 'Sonstiges Drittland', icon: '๐ŸŒ', desc: 'Land ohne Angemessenheitsbeschluss' }, +] + +const TRANSFER_MECHANISM_TILES = [ + { value: 'not_needed', label: 'Nicht erforderlich', icon: 'โœ…', desc: 'Kein Drittlandtransfer oder Angemessenheit' }, + { value: 'scc', label: 'Standardvertragsklauseln', icon: '๐Ÿ“', desc: 'SCC nach Art. 46 Abs. 2c DSGVO' }, + { value: 'bcr', label: 'Binding Corporate Rules', icon: '๐Ÿ›๏ธ', desc: 'BCR nach Art. 47 DSGVO' }, + { value: 'adequacy', label: 'Angemessenheitsbeschluss', icon: '๐Ÿค', desc: 'EU-Kommissionsbeschluss (z.B. EU-US DPF)' }, + { value: 'derogation', label: 'Ausnahme (Art. 49)', icon: 'โš ๏ธ', desc: 'Einwilligung oder zwingende Interessen' }, +] + +// ============================================================================= +// RETENTION (Step 7) โ€” tiles +// ============================================================================= + +const RETENTION_TILES = [ + { value: 'session', label: 'Nur waehrend Session', icon: 'โฑ๏ธ', desc: 'Daten werden nach Sitzungsende geloescht' }, + { value: '30_days', label: '30 Tage', icon: '๐Ÿ“…', desc: 'Kurzfristige Aufbewahrung' }, + { value: '90_days', label: '90 Tage', icon: '๐Ÿ“…', desc: 'Standardaufbewahrung' }, + { value: '1_year', label: '1 Jahr', icon: '๐Ÿ“†', desc: 'Jaehrliche Aufbewahrung' }, + { value: '3_years', label: '3 Jahre', icon: '๐Ÿ“†', desc: 'Mittelfristige Aufbewahrung' }, + { value: '6_years', label: '6 Jahre', icon: '๐Ÿ“†', desc: 'Handelsrechtliche Aufbewahrungsfrist' }, + { value: '10_years', label: '10 Jahre', icon: '๐Ÿ“†', desc: 'Steuerrechtliche Aufbewahrungsfrist' }, + { value: 'indefinite', label: 'Unbefristet', icon: 'โ™พ๏ธ', desc: 'Keine zeitliche Begrenzung' }, +] + +// ============================================================================= +// CONTRACTS (Step 8) โ€” tiles +// ============================================================================= + +const CONTRACT_TILES = [ + { value: 'has_dpa', label: 'AVV / DPA vorhanden', icon: '๐Ÿ“„', desc: 'Auftragsverarbeitungsvertrag nach Art. 28 DSGVO' }, + { value: 'has_aia_doc', label: 'AI Act Dokumentation', icon: '๐Ÿค–', desc: 'Risikoklassifizierung und technische Doku nach EU AI Act' }, + { value: 'has_dsfa', label: 'DSFA durchgefuehrt', icon: '๐Ÿ“‹', desc: 'Datenschutz-Folgenabschaetzung nach Art. 35 DSGVO' }, + { value: 'has_tia', label: 'TIA durchgefuehrt', icon: '๐ŸŒ', desc: 'Transfer Impact Assessment fuer Drittlandtransfers' }, + { value: 'has_tom', label: 'TOM dokumentiert', icon: '๐Ÿ”’', desc: 'Technisch-organisatorische Massnahmen nach Art. 32 DSGVO' }, + { value: 'has_vvt', label: 'Im VVT erfasst', icon: '๐Ÿ“š', desc: 'Im Verzeichnis von Verarbeitungstaetigkeiten eingetragen' }, + { value: 'has_consent', label: 'Einwilligungen eingeholt', icon: 'โœ…', desc: 'Nutzereinwilligungen vorhanden und dokumentiert' }, + { value: 'none', label: 'Noch keine Dokumente', icon: 'โš ๏ธ', desc: 'Compliance-Dokumentation steht noch aus' }, +] + +// ============================================================================= +// SHARED TILE TOGGLE HELPER +// ============================================================================= + +function toggleInArray(arr: string[], value: string): string[] { + return arr.includes(value) ? arr.filter(v => v !== value) : [...arr, value] } // ============================================================================= -// WIZARD FORM DATA +// MAIN COMPONENT // ============================================================================= -interface WizardFormData { - // Step 1: Grunddaten - name: string - description: string - category: string - domain: string - // Step 2: Datenkategorien - dataCategories: string[] - processesPersonalData: boolean - specialCategories: boolean - healthData: boolean - biometricData: boolean - minorsData: boolean - financialData: boolean - customDataTypes: string[] - // Step 3: Verarbeitungszweck - legalBasis: string - purposeProfiling: boolean - purposeAutomatedDecision: boolean - purposeMarketing: boolean - purposeAnalytics: boolean - purposeServiceDelivery: boolean - // Step 4: Technologie & Modell - aiTechnologies: string[] - modelInference: boolean - modelRag: boolean - modelFinetune: boolean - modelTraining: boolean - // Step 5: Automatisierung - automation: 'assistive' | 'semi_automated' | 'fully_automated' - // Step 6: Hosting & Transfer - hostingProvider: string - hostingRegion: string - internationalTransfer: boolean - transferCountries: string[] - transferMechanism: string - // Step 7: Datenhaltung & Vertraege - retentionDays: number - retentionPurpose: string - hasDpa: boolean - hasAiaDocumentation: boolean - hasRiskAssessment: boolean - subprocessors: string - // Notes - notes: string -} +function AdvisoryBoardPageInner() { + const router = useRouter() + const searchParams = useSearchParams() + const { state: sdkState } = useSDK() + const editId = searchParams.get('edit') + const isEditMode = !!editId -// ============================================================================= -// WIZARD COMPONENT -// ============================================================================= - -function UseCaseWizard({ - onComplete, - onCancel, -}: { - onComplete: (useCase: UseCaseAssessment) => void - onCancel: () => void -}) { const [currentStep, setCurrentStep] = useState(1) const [isSubmitting, setIsSubmitting] = useState(false) - const [uccaError, setUccaError] = useState(null) - const [uccaResult, setUccaResult] = useState | null>(null) - const [completedUseCase, setCompletedUseCase] = useState(null) - const [resultSource, setResultSource] = useState<'api' | 'local'>('local') - const [formData, setFormData] = useState({ - name: '', - description: '', - category: '', + const [editLoading, setEditLoading] = useState(false) + const [result, setResult] = useState(null) + const [error, setError] = useState(null) + + // Derive domain from company profile industry + const profileIndustry = sdkState.companyProfile?.industry + const derivedDomain = industryToDomain( + Array.isArray(profileIndustry) ? profileIndustry : profileIndustry ? [profileIndustry] : [] + ) + + // Form state โ€” tile-based multi-select via arrays + const [form, setForm] = useState({ + title: '', + use_case_text: '', domain: 'general', - dataCategories: [], - processesPersonalData: false, - specialCategories: false, - healthData: false, - biometricData: false, - minorsData: false, - financialData: false, - customDataTypes: [], - legalBasis: 'consent', - purposeProfiling: false, - purposeAutomatedDecision: false, - purposeMarketing: false, - purposeAnalytics: false, - purposeServiceDelivery: false, - aiTechnologies: [], - modelInference: true, - modelRag: false, - modelFinetune: false, - modelTraining: false, - automation: 'assistive', - hostingProvider: 'self_hosted', - hostingRegion: 'eu', - internationalTransfer: false, - transferCountries: [], - transferMechanism: 'none', - retentionDays: 90, - retentionPurpose: '', - hasDpa: false, - hasAiaDocumentation: false, - hasRiskAssessment: false, + category: '' as string, + // Data categories (multi-select tiles) + data_categories: [] as string[], + custom_data_types: [] as string[], + // Purpose (multi-select tiles) + purposes: [] as string[], + // Automation (single-select tile) + automation: '' as string, + // Hosting (single-select tile) + hosting_provider: '' as string, + hosting_region: '' as string, + // Model Usage (multi-select tiles) + model_usage: [] as string[], + // Data Transfer (Step 6 โ€” tiles) + transfer_targets: [] as string[], + transfer_countries: [] as string[], + transfer_mechanism: '' as string, + // Retention (Step 7) + retention_period: '' as string, + retention_purpose: '', + // Contracts (Step 8 โ€” multi-select tiles) + contracts: [] as string[], subprocessors: '', - notes: '', }) - const updateFormData = (updates: Partial) => { - setFormData(prev => ({ ...prev, ...updates })) + const updateForm = (updates: Partial) => { + setForm(prev => ({ ...prev, ...updates })) } - const buildIntake = (): UseCaseIntake => ({ - domain: formData.domain, - dataCategories: formData.dataCategories, - processesPersonalData: formData.processesPersonalData, - specialCategories: formData.specialCategories, - healthData: formData.healthData, - biometricData: formData.biometricData, - minorsData: formData.minorsData, - financialData: formData.financialData, - customDataTypes: formData.customDataTypes.filter(s => s.trim()), - legalBasis: formData.legalBasis, - purposes: { - profiling: formData.purposeProfiling, - automatedDecision: formData.purposeAutomatedDecision, - marketing: formData.purposeMarketing, - analytics: formData.purposeAnalytics, - serviceDelivery: formData.purposeServiceDelivery, - }, - automation: formData.automation, - hosting: { - provider: formData.hostingProvider, - region: formData.hostingRegion, - }, - modelUsage: { - inference: formData.modelInference, - rag: formData.modelRag, - finetune: formData.modelFinetune, - training: formData.modelTraining, - }, - aiTechnologies: formData.aiTechnologies, - internationalTransfer: { - enabled: formData.internationalTransfer, - countries: formData.transferCountries, - mechanism: formData.transferMechanism, - }, - retention: { - days: formData.retentionDays, - purpose: formData.retentionPurpose, - }, - contracts: { - hasDpa: formData.hasDpa, - hasAiaDocumentation: formData.hasAiaDocumentation, - hasRiskAssessment: formData.hasRiskAssessment, - subprocessors: formData.subprocessors, - }, - }) - - const handleNext = async () => { - if (currentStep < TOTAL_STEPS) { - setCurrentStep(prev => prev + 1) - return + // Auto-set domain from profile + useEffect(() => { + if (!isEditMode && derivedDomain !== 'general') { + updateForm({ domain: derivedDomain }) } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [derivedDomain]) - // Final step โ€” create use case + call UCCA API + // Pre-fill form when in edit mode + useEffect(() => { + if (!editId) return + setEditLoading(true) + fetch(`/api/sdk/v1/ucca/assessments/${editId}`) + .then(r => r.json()) + .then(data => { + const intake = data.intake || {} + setForm({ + title: data.title || '', + use_case_text: intake.use_case_text || '', + domain: data.domain || 'general', + category: data.category || intake.category || '', + data_categories: intake.data_categories || [], + custom_data_types: intake.data_types?.custom_data_types || intake.custom_data_types || [], + purposes: intake.purposes || [], + automation: intake.automation || '', + hosting_provider: intake.hosting?.provider || '', + hosting_region: intake.hosting?.region || '', + model_usage: intake.model_usage_list || [], + transfer_targets: intake.transfer_targets || [], + transfer_countries: intake.international_transfer?.countries || intake.transfer_countries || [], + transfer_mechanism: intake.transfer_mechanism || intake.international_transfer?.mechanism || '', + retention_period: intake.retention_period || '', + retention_purpose: intake.retention?.purpose || intake.retention_purpose || '', + contracts: intake.contracts_list || [], + subprocessors: intake.contracts?.subprocessors || intake.subprocessors || '', + }) + }) + .catch(() => {}) + .finally(() => setEditLoading(false)) + }, [editId]) + + const handleSubmit = async () => { setIsSubmitting(true) - setUccaError(null) - - const risk = calculateRiskScore(formData) - const intake = buildIntake() - - const newUseCase: UseCaseAssessment = { - id: `uc-${Date.now()}`, - name: formData.name, - description: formData.description, - category: formData.category, - stepsCompleted: TOTAL_STEPS, - steps: WIZARD_STEPS.map(s => ({ - id: `step-${s.id}`, - name: s.name, - completed: true, - data: {}, - })), - assessmentResult: { - riskLevel: risk.level, - applicableRegulations: ['DSGVO', 'AI Act'], - recommendedControls: buildRecommendations(formData, risk), - dsfaRequired: risk.dsfaRequired, - aiActClassification: formData.aiTechnologies.length > 0 - ? (risk.level === 'CRITICAL' || risk.level === 'HIGH' ? 'HIGH' : 'LIMITED') - : 'MINIMAL', - }, - intake, - createdAt: new Date(), - updatedAt: new Date(), - } - - // Call UCCA API in background + setError(null) try { - const uccaIntake = { - title: formData.name, - use_case_text: formData.description, - domain: formData.domain, - data_types: { - personal_data: formData.processesPersonalData, - special_categories: formData.specialCategories, - health_data: formData.healthData, - biometric_data: formData.biometricData, - minors_data: formData.minorsData, - financial_data: formData.financialData, - custom_data_types: formData.customDataTypes.filter(s => s.trim()), - }, - purpose: { - profiling: formData.purposeProfiling, - automated_decision: formData.purposeAutomatedDecision, - marketing: formData.purposeMarketing, - analytics: formData.purposeAnalytics, - service_delivery: formData.purposeServiceDelivery, - }, - automation: formData.automation, - hosting: { provider: formData.hostingProvider, region: formData.hostingRegion }, - model_usage: { - inference: formData.modelInference, - rag: formData.modelRag, - finetune: formData.modelFinetune, - training: formData.modelTraining, - }, - legal_basis: formData.legalBasis, - international_transfer: { - enabled: formData.internationalTransfer, - countries: formData.transferCountries, - mechanism: formData.transferMechanism, - }, - retention: { days: formData.retentionDays, purpose: formData.retentionPurpose }, - contracts: { - has_dpa: formData.hasDpa, - has_aia_documentation: formData.hasAiaDocumentation, - has_risk_assessment: formData.hasRiskAssessment, - subprocessors: formData.subprocessors, + const intake = { + title: form.title, + use_case_text: form.use_case_text, + domain: form.domain, + category: form.category, + data_categories: form.data_categories, + custom_data_types: form.custom_data_types.filter(s => s.trim()), + purposes: form.purposes, + automation: form.automation, + hosting: { + provider: form.hosting_provider, + region: form.hosting_region, }, + model_usage_list: form.model_usage, + transfer_targets: form.transfer_targets, + transfer_countries: form.transfer_countries, + transfer_mechanism: form.transfer_mechanism, + retention_period: form.retention_period, + retention_purpose: form.retention_purpose, + contracts_list: form.contracts, + subprocessors: form.subprocessors, store_raw_text: true, } - const resp = await fetch('/api/sdk/v1/ucca/assess', { - method: 'POST', + const url = isEditMode + ? `/api/sdk/v1/ucca/assessments/${editId}` + : '/api/sdk/v1/ucca/assess' + const method = isEditMode ? 'PUT' : 'POST' + + const response = await fetch(url, { + method, headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify(uccaIntake), + body: JSON.stringify(intake), }) - if (resp.ok) { - const data = await resp.json() - // Merge UCCA result if available - if (data.assessment?.id) { - newUseCase.uccaAssessmentId = data.assessment.id - } - if (data.result) { - newUseCase.assessmentResult = { - ...newUseCase.assessmentResult!, - riskLevel: data.result.risk_level || newUseCase.assessmentResult!.riskLevel, - dsfaRequired: data.result.dsfa_required ?? newUseCase.assessmentResult!.dsfaRequired, - } - setUccaResult(data.result) - setResultSource('api') - } - } else { - setUccaError('UCCA-API nicht erreichbar โ€” lokale Risikobewertung wird verwendet.') - setResultSource('local') + if (!response.ok) { + const errData = await response.json().catch(() => null) + throw new Error(errData?.error || `HTTP ${response.status}`) } - } catch { - setUccaError('UCCA-API nicht erreichbar โ€” lokale Risikobewertung wird verwendet.') - setResultSource('local') + + if (isEditMode) { + router.push(`/sdk/use-cases/${editId}`) + return + } + + const data = await response.json() + setResult(data) + } catch (err) { + setError(err instanceof Error ? err.message : 'Fehler bei der Bewertung') + } finally { + setIsSubmitting(false) } - - setIsSubmitting(false) - setCompletedUseCase(newUseCase) } - const handleBack = () => { - if (currentStep > 1) setCurrentStep(prev => prev - 1) - } - - const risk = calculateRiskScore(formData) - - // ========== RESULT VIEW (after completion) ========== - if (completedUseCase) { + // If we have a result, show it + if (result) { + const r = result as { assessment?: { id: string }; result?: Record } return ( -
- {/* Header */} +
-
-

Assessment-Ergebnis: {completedUseCase.name}

-

- {resultSource === 'api' - ? 'Regelbasierte Bewertung durch UCCA Policy Engine' - : 'Lokale Risikobewertung (UCCA-API nicht verfuegbar)'} -

-
-
- - {resultSource === 'api' ? 'UCCA API' : 'Lokal'} - -
-
- - {/* UCCA API Result (detailed) */} - {uccaResult && ( - [0]['result']} /> - )} - - {/* Local result fallback (when API not available) */} - {!uccaResult && completedUseCase.assessmentResult && ( -
-
-
- {risk.score} -
-
-
- Risikostufe: {completedUseCase.assessmentResult.riskLevel} -
-
- AI Act: {completedUseCase.assessmentResult.aiActClassification} -
-
- {completedUseCase.assessmentResult.dsfaRequired && ( - - DSFA empfohlen - - )} -
- - {/* Recommended Controls */} - {completedUseCase.assessmentResult.recommendedControls.length > 0 && ( -
-

Empfohlene Massnahmen

-
- {completedUseCase.assessmentResult.recommendedControls.map((ctrl, i) => ( -
- - - - {ctrl} -
- ))} -
-
+

Assessment Ergebnis

+
+ {r.assessment?.id && ( + )} - - {/* Applicable Regulations */} -
- {completedUseCase.assessmentResult.applicableRegulations.map(reg => ( - - {reg} - - ))} -
+
- )} - - {/* UCCA Error info */} - {uccaError && ( -
- {uccaError} -
- )} - - {/* Action buttons */} -
- -
+ {r.result && ( + [0]['result']} /> + )}
) } return ( -
+
{/* Header */} -
-
-

Neuer Use Case

- +
+
+

+ {isEditMode ? 'Assessment bearbeiten' : 'Use Case Workshop'} +

+

+ {isEditMode + ? 'Angaben anpassen und Assessment neu bewerten' + : 'Erfassen Sie Ihren KI-Anwendungsfall Schritt fuer Schritt'} +

- {/* Progress */} -
- {WIZARD_STEPS.map((step, index) => ( - -
- {step.id < currentStep ? ( - - - - ) : ( - step.id - )} -
- {index < WIZARD_STEPS.length - 1 && ( -
- )} - - ))} -
-

- Schritt {currentStep} von {TOTAL_STEPS}: {WIZARD_STEPS[currentStep - 1].description} -

+ + UCCA-Dokumentation +
- {/* Content */} -
- {/* ============================================ */} - {/* STEP 1: Grunddaten */} - {/* ============================================ */} + {/* Edit loading indicator */} + {editLoading && ( +
+ Lade Assessment-Daten... +
+ )} + + {/* Step Indicator */} +
+ {WIZARD_STEPS.map((step, idx) => ( + + + {idx < WIZARD_STEPS.length - 1 &&
} + + ))} +
+ + {/* Error */} + {error && ( +
{error}
+ )} + + {/* Step Content */} +
+ {/* Step 1: Grundlegendes */} {currentStep === 1 && ( -
+
+

Grundlegende Informationen

+ + {/* Branche aus Profil (nur Anzeige) */} + {profileIndustry && (Array.isArray(profileIndustry) ? profileIndustry.length > 0 : true) && ( +
+ Branche (aus Unternehmensprofil) +

+ {Array.isArray(profileIndustry) ? profileIndustry.join(', ') : profileIndustry} +

+
+ )} +
- + updateFormData({ name: e.target.value })} - placeholder="z.B. Marketing-KI fuer Kundensegmentierung" + value={form.title} + onChange={e => updateForm({ title: e.target.value })} + placeholder="z.B. Chatbot fuer Kundenservice" className="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-purple-500 focus:border-transparent" />
- +