From 51a208a2e1f5e72001d602c6b5ce33566da0f9bd Mon Sep 17 00:00:00 2001 From: Benjamin Admin Date: Mon, 9 Mar 2026 23:06:23 +0100 Subject: [PATCH] feat(company-profile): KI-Systeme als eigener Wizard-Schritt mit Vorlagen Schritt 6 (Verarbeitung & KI) aufgeteilt: Step 6 zeigt nur noch Verarbeitungstaetigkeiten, Step 7 ist ein neuer KI-Systeme-Schritt mit 18 vorgefertigten Vorlagen in 7 Kategorien (Text-KI, Office, Code, Bild, Uebersetzung, CRM, Intern). Jede Vorlage hat anklickbare Einsatzzweck-Chips, Datenschutz-Warnhinweise und vorausgefuellte Felder. Link zum AI-Act-Modul am Ende des Schritts. Co-Authored-By: Claude Opus 4.6 --- .../app/sdk/company-profile/page.tsx | 506 +++++++++++++++--- 1 file changed, 425 insertions(+), 81 deletions(-) diff --git a/admin-compliance/app/sdk/company-profile/page.tsx b/admin-compliance/app/sdk/company-profile/page.tsx index 2b5e77a..2bcb7d8 100644 --- a/admin-compliance/app/sdk/company-profile/page.tsx +++ b/admin-compliance/app/sdk/company-profile/page.tsx @@ -34,11 +34,12 @@ const BASE_WIZARD_STEPS = [ { id: 3, name: 'Firmengroesse', description: 'Mitarbeiter und Umsatz' }, { id: 4, name: 'Standorte', description: 'Hauptsitz und Zielmaerkte' }, { id: 5, name: 'Datenschutz', description: 'Rollen und KI-Nutzung' }, - { id: 6, name: 'Verarbeitung & KI', description: 'Verarbeitungstätigkeiten und KI-Systeme' }, - { id: 7, name: 'Rechtlicher Rahmen', description: 'Regulierungen und Prüfzyklen' }, + { id: 6, name: 'Verarbeitungstaetigkeiten', description: 'Datenverarbeitung nach Art. 30 DSGVO' }, + { id: 7, name: 'KI-Systeme', description: 'Eingesetzte KI-Systeme erfassen' }, + { id: 8, name: 'Rechtlicher Rahmen', description: 'Regulierungen und Prüfzyklen' }, ] -const MACHINE_BUILDER_STEP = { id: 8, name: 'Produkt & Maschine', description: 'Software, KI und CE in Ihrem Produkt' } +const MACHINE_BUILDER_STEP = { id: 9, name: 'Produkt & Maschine', description: 'Software, KI und CE in Ihrem Produkt' } function getWizardSteps(industry: string) { if (isMachineBuilderIndustry(industry)) { @@ -200,9 +201,10 @@ const STEP_EXPLANATIONS: Record = { 3: 'Die Unternehmensgröße bestimmt, ob Sie einen DSB benennen müssen (ab 20 MA), ob NIS2-Pflichten greifen und welche Audit-Anforderungen gelten.', 4: 'Standorte und Zielmärkte bestimmen, welche nationalen Datenschutzgesetze zusätzlich zur DSGVO greifen (z.B. BDSG, DSG-AT, UK GDPR, CCPA).', 5: 'Ob Sie Verantwortlicher oder Auftragsverarbeiter sind, bestimmt Ihre DSGVO-Pflichten grundlegend. KI-Nutzung löst zusätzliche AI-Act-Pflichten aus.', - 6: 'Ihre Verarbeitungstätigkeiten bilden die Grundlage für das Verarbeitungsverzeichnis (Art. 30 DSGVO). KI-Systeme werden für die AI-Act-Analyse erfasst — die Risikoeinstufung übernimmt unser Tool.', - 7: 'Regulierungsrahmen und Prüfzyklen definieren, welche Compliance-Module für Sie aktiviert werden und in welchem Rhythmus Audits stattfinden.', - 8: 'Als Maschinenbauer gelten zusätzliche Anforderungen: CE-Kennzeichnung, Maschinenverordnung, Produktsicherheit und ggf. Hochrisiko-KI im Sinne des AI Act.', + 6: 'Ihre Verarbeitungstätigkeiten bilden die Grundlage für das Verarbeitungsverzeichnis (Art. 30 DSGVO).', + 7: 'Erfassen Sie hier die KI-Systeme, die in Ihrem Unternehmen eingesetzt werden. Die Risikoeinstufung nach EU AI Act erfolgt automatisch im AI-Act-Modul.', + 8: 'Regulierungsrahmen und Prüfzyklen definieren, welche Compliance-Module für Sie aktiviert werden und in welchem Rhythmus Audits stattfinden.', + 9: 'Als Maschinenbauer gelten zusätzliche Anforderungen: CE-Kennzeichnung, Maschinenverordnung, Produktsicherheit und ggf. Hochrisiko-KI im Sinne des AI Act.', } function StepBusinessModel({ @@ -651,22 +653,22 @@ function StepDataProtection({ // DSGVO-Standard Datenkategorien const ALL_DATA_CATEGORIES = [ { id: 'stammdaten', label: 'Stammdaten', desc: 'Name, Geburtsdatum, Geschlecht', info: 'Vor- und Nachname, Geburtsdatum, Geschlecht, Anrede, Titel, Familienstand, Staatsangehörigkeit, Personalnummer, Kundennummer' }, - { id: 'kontaktdaten', label: 'Kontaktdaten', desc: 'E-Mail, Telefon, Adresse', info: 'E-Mail-Adresse, Telefonnummer, Mobilnummer, Postanschrift, Faxnummer, Messenger-IDs, Ansprechpartner-Namen bei Kunden/Lieferanten (z.B. SAP-Kontaktpersonen)' }, + { id: 'kontaktdaten', label: 'Kontaktdaten', desc: 'E-Mail, Telefon, Adresse', info: 'E-Mail-Adresse, Telefonnummer, Mobilnummer, Postanschrift, Faxnummer, Messenger-IDs der betroffenen Personen' }, { id: 'vertragsdaten', label: 'Vertragsdaten', desc: 'Vertragsnummer, Laufzeit, Konditionen', info: 'Vertragsnummer, Vertragsbeginn/-ende, Laufzeit, Konditionen, Kündigungsfristen, Vertragsgegenstand, Bestellhistorie' }, { id: 'zahlungsdaten', label: 'Zahlungs-/Bankdaten', desc: 'IBAN, Kreditkarte, Rechnungen', info: 'IBAN, BIC, Kontoinhaber, Kreditkartennummer, Rechnungsbeträge, Zahlungshistorie, Steuer-ID, USt-IdNr.' }, - { id: 'beschaeftigtendaten', label: 'Beschäftigtendaten', desc: 'Gehalt, Arbeitszeiten, Urlaub', info: 'Gehalt/Lohn, Steuerklasse, SV-Nummer, Krankenkasse (z.B. AOK, TK), Arbeitszeiten, Urlaubstage, Abwesenheiten, Beurteilungen, Eintrittsdatum' }, + { id: 'beschaeftigtendaten', label: 'Beschäftigtendaten', desc: 'Gehalt, Arbeitszeiten, Urlaub', info: 'Gehalt/Lohn, Steuerklasse, SV-Nummer, Krankenkasse (z.B. AOK, TK), Arbeitszeiten, Urlaubstage, Abwesenheiten, Beurteilungen, Eintrittsdatum. Aufbewahrung: i.d.R. 3 Jahre nach Austritt (§ 195 BGB), Lohndaten 8 Jahre (§ 147 AO)' }, { id: 'kommunikation', label: 'Kommunikationsdaten', desc: 'E-Mail-Inhalte, Chat-Verläufe', info: 'E-Mail-Inhalte und -Metadaten, Chat-Nachrichten, Gesprächsprotokolle, Support-Tickets, Briefkorrespondenz' }, { id: 'nutzungsdaten', label: 'Nutzungs-/Logdaten', desc: 'IP-Adressen, Login-Zeiten, Klicks', info: 'IP-Adressen, Login-Zeitpunkte, Seitenaufrufe, Klickverhalten, Geräteinformationen, Browser-Typ, Session-Dauer' }, { id: 'standortdaten', label: 'Standortdaten', desc: 'GPS, Check-in, Lieferadressen', info: 'GPS-Koordinaten, Check-in/Check-out-Zeiten, Lieferadressen, Reiserouten, WLAN-Standortbestimmung' }, { id: 'bilddaten', label: 'Bild-/Videodaten', desc: 'Fotos, Videoaufnahmen, Profilbilder', info: 'Profilfotos, Ausweiskopien, Videoaufnahmen (Überwachung), Bewerbungsfotos, Schulungsvideos' }, - { id: 'bewerberdaten', label: 'Bewerberdaten', desc: 'Lebenslauf, Zeugnisse, Anschreiben', info: 'Lebenslauf, Anschreiben, Zeugnisse, Referenzen, Gehaltsvorstellungen, Verfügbarkeit, Bewerbungsquelle' }, + { id: 'bewerberdaten', label: 'Bewerberdaten', desc: 'Lebenslauf, Zeugnisse, Anschreiben', info: 'Lebenslauf, Anschreiben, Zeugnisse, Referenzen, Gehaltsvorstellungen, Verfügbarkeit, Bewerbungsquelle. Löschfrist bei Absage: max. 6 Monate (AGG §§ 15, 21)' }, { id: 'qualifikationsdaten', label: 'Qualifikations-/Schulungsdaten', desc: 'Fortbildungen, Zertifikate, Abschlüsse', info: 'Besuchte Seminare und Schulungen, Zertifikate, Abschlüsse, Qualifikationsnachweise, Schulungsdaten und -ergebnisse, Weiterbildungshistorie' }, ] as const const ALL_SPECIAL_CATEGORIES = [ - { id: 'gesundheit', label: 'Gesundheitsdaten', desc: 'Krankheitstage, Atteste, Diagnosen', info: 'Krankheitstage, AU-Bescheinigungen, Diagnosen, Behinderungsgrad (GdB), BEM-Daten, arbeitsmedizinische Untersuchungen, Impfstatus, Allergien. NICHT: Krankenkassenname (z.B. AOK, TK) — das sind normale Beschäftigtendaten.' }, - { id: 'biometrie', label: 'Biometrische Daten', desc: 'Fingerabdruck, Gesichtserkennung', info: 'Fingerabdruck, Gesichtserkennung, Iris-Scan, Stimmerkennung, Handvenenscan (zur eindeutigen Identifizierung)' }, - { id: 'religion', label: 'Religiöse Überzeugungen', desc: 'Konfession, Feiertage', info: 'Konfession (relevant für Kirchensteuer), religiöse Feiertage, Ernährungsvorschriften' }, + { id: 'gesundheit', label: 'Gesundheitsdaten', desc: 'Krankheitstage, Atteste, Diagnosen', info: 'Krankheitstage, AU-Bescheinigungen, Diagnosen, Behinderungsgrad (GdB), BEM-Daten, arbeitsmedizinische Untersuchungen, Impfstatus, Allergien. Auch AU ohne Diagnose = Gesundheitsdatum (LDI NRW). Schwangerschaft, Allergien, Online-Arzneimittelbestellung (EuGH C-21/23). NICHT: Krankenkassenname (z.B. AOK, TK) — das sind normale Beschäftigtendaten.' }, + { id: 'biometrie', label: 'Biometrische Daten', desc: 'Fingerabdruck, Gesichtserkennung', info: 'Fingerabdruck, Gesichtserkennung, Iris-Scan, Stimmerkennung, Handvenenscan. Nur wenn zur eindeutigen Identifizierung verwendet (ErwGr. 51). Einfaches Passfoto = kein biometrisches Datum.' }, + { id: 'religion', label: 'Religiöse Überzeugungen', desc: 'Konfession, Feiertage', info: 'Konfession (relevant für Kirchensteuer auf Lohnabrechnung), religiöse Feiertage, Ernährungsvorschriften. Auch indirekt: Kantinenbestellung halal/koscher (EuGH C-184/20 weite Auslegung).' }, { id: 'gewerkschaft', label: 'Gewerkschaftszugehörigkeit', desc: 'Mitgliedschaft', info: 'Gewerkschaftsmitgliedschaft, Betriebsratszugehörigkeit, Tarifzugehörigkeit' }, { id: 'genetik', label: 'Genetische Daten', desc: 'DNA, Erbkrankheiten', info: 'DNA-Analysen, genetische Prädispositionen, Erbkrankheitsrisiken (nur in Spezialfällen relevant)' }, ] as const @@ -683,6 +685,7 @@ interface ActivityTemplate { default_legal_basis: string legalHint?: string // Gesetzlicher Hinweis (z.B. ArbZG-Pflicht) hasServiceProvider?: boolean // Kann ein externer Dienstleister eingesetzt werden? + categoryInfo?: Record // Override Info-Text pro Datenkategorie (kontextspezifisch) } interface ActivityDepartment { @@ -698,17 +701,17 @@ const UNIVERSAL_DEPARTMENTS: ActivityDepartment[] = [ { id: 'personal', name: 'Personal / HR', icon: '👥', activities: [ - { id: 'personalverwaltung', name: 'Personalverwaltung', purpose: 'Verwaltung von Beschäftigtendaten für das Arbeitsverhältnis', primary_categories: ['stammdaten', 'kontaktdaten', 'beschaeftigtendaten', 'zahlungsdaten'], art9_relevant: ['gesundheit', 'religion', 'gewerkschaft'], default_legal_basis: 'contract' }, - { id: 'lohnbuchhaltung', name: 'Lohn- und Gehaltsabrechnung', purpose: 'Berechnung und Auszahlung von Löhnen und Gehältern', primary_categories: ['beschaeftigtendaten', 'zahlungsdaten', 'stammdaten'], art9_relevant: ['gesundheit', 'religion'], default_legal_basis: 'legal', hasServiceProvider: true }, - { id: 'bewerbermanagement', name: 'Bewerbermanagement', purpose: 'Entgegennahme, Prüfung und Bearbeitung von Bewerbungen', primary_categories: ['bewerberdaten', 'stammdaten', 'kontaktdaten', 'kommunikation', 'qualifikationsdaten'], art9_relevant: ['gesundheit', 'religion'], default_legal_basis: 'consent' }, - { id: 'arbeitszeiterfassung', name: 'Arbeitszeiterfassung', purpose: 'Erfassung und Dokumentation der Arbeitszeiten', primary_categories: ['beschaeftigtendaten'], art9_relevant: [], default_legal_basis: 'legal', legalHint: 'Gesetzlich vorgeschrieben (§ 3 ArbZG). Fehlende Arbeitszeiterfassung ist ein Compliance-Risiko.' }, + { id: 'personalverwaltung', name: 'Personalverwaltung', purpose: 'Verwaltung von Beschäftigtendaten für das Arbeitsverhältnis', primary_categories: ['stammdaten', 'kontaktdaten', 'beschaeftigtendaten', 'zahlungsdaten'], art9_relevant: ['gesundheit', 'religion', 'gewerkschaft'], default_legal_basis: 'contract', categoryInfo: { stammdaten: 'Vor-/Nachname, Geburtsdatum, Geschlecht, Familienstand, Staatsangehörigkeit, Personalnummer', kontaktdaten: 'Privat- und Dienstadresse, Telefonnummern, dienstliche E-Mail, Notfallkontakt', beschaeftigtendaten: 'Steuerklasse, SV-Nummer, Krankenkasse (z.B. AOK, TK — kein Gesundheitsdatum!), Eintrittsdatum, Arbeitszeit, Urlaubstage. Aufbewahrung: 3 Jahre nach Austritt (§ 195 BGB)', zahlungsdaten: 'IBAN für Gehaltsauszahlung, Vermögenswirksame Leistungen, Pfändungsdaten' } }, + { id: 'lohnbuchhaltung', name: 'Lohn- und Gehaltsabrechnung', purpose: 'Berechnung und Auszahlung von Löhnen und Gehältern', primary_categories: ['beschaeftigtendaten', 'zahlungsdaten', 'stammdaten'], art9_relevant: ['gesundheit', 'religion'], default_legal_basis: 'legal', hasServiceProvider: true, categoryInfo: { beschaeftigtendaten: 'Gehalt, Zulagen, Prämien, Steuerklasse, SV-Nummer, Krankenkasse, Kirchensteuermerkmal (Achtung: Art. 9!). Aufbewahrung: Lohnabrechnungen 8 Jahre (§ 147 AO), Lohnsteuer 6 Jahre (§ 41 EStG)', zahlungsdaten: 'IBAN, Bankverbindung, Gehaltsabrechnungen, Pfändungsbeträge. Aufbewahrung: 8 Jahre (§ 147 AO)' } }, + { id: 'bewerbermanagement', name: 'Bewerbermanagement', purpose: 'Entgegennahme, Prüfung und Bearbeitung von Bewerbungen', primary_categories: ['bewerberdaten', 'stammdaten', 'kontaktdaten', 'kommunikation', 'qualifikationsdaten'], art9_relevant: ['gesundheit', 'religion'], default_legal_basis: 'consent', categoryInfo: { bewerberdaten: 'Lebenslauf, Anschreiben, Zeugnisse, Referenzen, Gehaltsvorstellungen. Löschfrist bei Absage: max. 6 Monate (AGG §§ 15, 21)', kontaktdaten: 'Privatadresse, E-Mail, Telefonnummer des Bewerbers', kommunikation: 'Bewerbungskorrespondenz, Einladungen, Absageschreiben' } }, + { id: 'arbeitszeiterfassung', name: 'Arbeitszeiterfassung', purpose: 'Erfassung und Dokumentation der Arbeitszeiten', primary_categories: ['beschaeftigtendaten'], art9_relevant: [], default_legal_basis: 'legal', legalHint: 'Gesetzlich vorgeschrieben (§ 3 ArbZG). Fehlende Arbeitszeiterfassung ist ein Compliance-Risiko.', categoryInfo: { beschaeftigtendaten: 'Beginn/Ende der Arbeitszeit, Pausen, Überstunden, Ruhezeiten. Aufbewahrung: mind. 2 Jahre (§ 16 Abs. 2 ArbZG). Nicht für Leistungskontrolle verwenden!' } }, { id: 'weiterbildung', name: 'Fort- und Weiterbildung', purpose: 'Verwaltung von Schulungen und Weiterbildungsmaßnahmen', primary_categories: ['qualifikationsdaten', 'beschaeftigtendaten', 'stammdaten'], art9_relevant: [], default_legal_basis: 'contract' }, ], }, { id: 'finanzen', name: 'Finanzen / Buchhaltung', icon: '💰', activities: [ - { id: 'finanzbuchhaltung', name: 'Finanzbuchhaltung', purpose: 'Buchführung, Rechnungsstellung, steuerliche Dokumentation', primary_categories: ['stammdaten', 'zahlungsdaten', 'vertragsdaten', 'kontaktdaten'], art9_relevant: [], default_legal_basis: 'legal' }, + { id: 'finanzbuchhaltung', name: 'Finanzbuchhaltung', purpose: 'Buchführung, Rechnungsstellung, steuerliche Dokumentation', primary_categories: ['stammdaten', 'zahlungsdaten', 'vertragsdaten', 'kontaktdaten'], art9_relevant: [], default_legal_basis: 'legal', categoryInfo: { zahlungsdaten: 'Rechnungsbeträge, IBAN, Buchungsbelege, USt-IdNr. Aufbewahrung: 8 Jahre (§ 147 AO)', vertragsdaten: 'Vertragsnummer, Konditionen, Bestellhistorie. Aufbewahrung: Handelskorrespondenz 6 Jahre (§ 257 HGB)', kontaktdaten: 'Rechnungsadresse, Ansprechpartner in der Debitorenbuchhaltung' } }, { id: 'zahlungsverkehr', name: 'Zahlungsverkehr', purpose: 'Abwicklung von ein- und ausgehenden Zahlungen', primary_categories: ['zahlungsdaten', 'stammdaten', 'kontaktdaten', 'vertragsdaten'], art9_relevant: [], default_legal_basis: 'contract' }, { id: 'mahnwesen', name: 'Mahnwesen / Inkasso', purpose: 'Überwachung offener Forderungen und Mahnverfahren', primary_categories: ['stammdaten', 'kontaktdaten', 'zahlungsdaten', 'vertragsdaten'], art9_relevant: [], default_legal_basis: 'interest' }, { id: 'reisekostenabrechnung', name: 'Reisekostenabrechnung', purpose: 'Abrechnung und Erstattung von Dienstreisekosten', primary_categories: ['beschaeftigtendaten', 'zahlungsdaten', 'standortdaten'], art9_relevant: [], default_legal_basis: 'contract' }, @@ -717,7 +720,7 @@ const UNIVERSAL_DEPARTMENTS: ActivityDepartment[] = [ { id: 'vertrieb', name: 'Vertrieb / Sales', icon: '📈', activities: [ - { id: 'crm', name: 'CRM / Kundenverwaltung', purpose: 'Verwaltung von Kundenbeziehungen, Kontakthistorie, Verkaufschancen', primary_categories: ['stammdaten', 'kontaktdaten', 'kommunikation', 'vertragsdaten'], art9_relevant: [], default_legal_basis: 'contract' }, + { id: 'crm', name: 'CRM / Kundenverwaltung', purpose: 'Verwaltung von Kundenbeziehungen, Kontakthistorie, Verkaufschancen', primary_categories: ['stammdaten', 'kontaktdaten', 'kommunikation', 'vertragsdaten'], art9_relevant: [], default_legal_basis: 'contract', categoryInfo: { stammdaten: 'Firmenname, Ansprechpartner-Name, Titel, Position, Kundennummer', kontaktdaten: 'Geschäftliche E-Mail, Telefon, Büroadresse des Ansprechpartners. B2B-Kontaktdaten sind personenbezogene Daten — Art. 13 DSGVO Informationspflicht gilt!', kommunikation: 'E-Mail-Korrespondenz, Gesprächsnotizen, Support-Tickets, Meeting-Protokolle' } }, { id: 'angebotserstellung', name: 'Angebotserstellung', purpose: 'Erstellung und Nachverfolgung von Angeboten', primary_categories: ['stammdaten', 'kontaktdaten', 'vertragsdaten'], art9_relevant: [], default_legal_basis: 'contract' }, { id: 'vertragsmanagement', name: 'Vertragsmanagement', purpose: 'Verwaltung, Archivierung und Nachverfolgung von Verträgen', primary_categories: ['vertragsdaten', 'stammdaten', 'kontaktdaten'], art9_relevant: [], default_legal_basis: 'contract' }, ], @@ -746,7 +749,7 @@ const UNIVERSAL_DEPARTMENTS: ActivityDepartment[] = [ activities: [ { id: 'datenschutzanfragen', name: 'Betroffenenrechte (DSGVO)', purpose: 'Bearbeitung von Auskunfts-, Lösch- und Berichtigungsanfragen', primary_categories: ['stammdaten', 'kontaktdaten', 'kommunikation'], art9_relevant: [], default_legal_basis: 'legal' }, { id: 'auftragsverarbeitung', name: 'Auftragsverarbeitung (AVV)', purpose: 'Dokumentation und Verwaltung von Auftragsverarbeitungsverhältnissen', primary_categories: ['stammdaten', 'kontaktdaten', 'vertragsdaten'], art9_relevant: [], default_legal_basis: 'legal' }, - { id: 'whistleblowing', name: 'Hinweisgebersystem', purpose: 'Entgegennahme und Bearbeitung von Meldungen nach HinSchG', primary_categories: ['stammdaten', 'kontaktdaten', 'kommunikation'], art9_relevant: [], default_legal_basis: 'legal' }, + { id: 'whistleblowing', name: 'Hinweisgebersystem', purpose: 'Entgegennahme und Bearbeitung von Meldungen nach HinSchG', primary_categories: ['stammdaten', 'kontaktdaten', 'kommunikation'], art9_relevant: [], default_legal_basis: 'legal', categoryInfo: { stammdaten: 'Identität des Hinweisgebers (besonders schützenswert! § 8 HinSchG Vertraulichkeitsgebot)', kontaktdaten: 'Kontaktdaten nur für zuständige Meldestelle zugänglich', kommunikation: 'Meldungsinhalt, Kommunikationsverlauf, Zeugenaussagen. Löschfrist: 3 Jahre nach Abschluss (§ 11 Abs. 5 HinSchG)' } }, ], }, ] @@ -791,7 +794,7 @@ const OPTIONAL_DEPARTMENTS: ActivityDepartment[] = [ id: 'facility', name: 'Facility Management', icon: '🏢', activities: [ { id: 'zutrittskontrolle', name: 'Zutrittskontrolle', purpose: 'Kontrolle und Protokollierung des Zutritts zu Gebäuden und Räumen', primary_categories: ['beschaeftigtendaten', 'stammdaten', 'bilddaten'], art9_relevant: ['biometrie'], default_legal_basis: 'interest' }, - { id: 'videoueberwachung', name: 'Videoüberwachung', purpose: 'Überwachung von Gebäuden und Geländen mittels Videokameras', primary_categories: ['bilddaten', 'beschaeftigtendaten'], art9_relevant: ['biometrie'], default_legal_basis: 'interest' }, + { id: 'videoueberwachung', name: 'Videoüberwachung', purpose: 'Überwachung von Gebäuden und Geländen mittels Videokameras', primary_categories: ['bilddaten', 'beschaeftigtendaten'], art9_relevant: ['biometrie'], default_legal_basis: 'interest', categoryInfo: { bilddaten: 'Videoaufzeichnungen von Kameras. Speicherdauer: empfohlen max. 72h (BeschDG-Entwurf). Datenschutzhinweis-Schilder (Art. 13 DSGVO) sind Pflicht. Betriebsrat hat Mitbestimmungsrecht (§ 87 Abs. 1 Nr. 6 BetrVG)' } }, { id: 'besuchermanagement', name: 'Besuchermanagement', purpose: 'Erfassung und Verwaltung von Besucherdaten', primary_categories: ['stammdaten', 'kontaktdaten'], art9_relevant: [], default_legal_basis: 'interest' }, ], }, @@ -872,10 +875,14 @@ interface ProcessingActivity { } interface AISystem { + id: string name: string vendor: string purpose: string + purposes?: string[] processes_personal_data: boolean + isCustom?: boolean + notes?: string } // Helper: find template for an activity ID across all departments @@ -887,15 +894,14 @@ function findTemplate(departments: ActivityDepartment[], activityId: string): Ac return null } -function StepProcessingAndAI({ +function StepProcessing({ data, onChange, }: { - data: Partial & { processingSystems?: ProcessingActivity[]; aiSystems?: AISystem[] } + data: Partial & { processingSystems?: ProcessingActivity[] } onChange: (updates: Record) => void }) { const activities: ProcessingActivity[] = (data as any).processingSystems || [] - const aiSystems: AISystem[] = (data as any).aiSystems || [] const industry = data.industry || '' const [expandedActivity, setExpandedActivity] = useState(null) const [collapsedDepts, setCollapsedDepts] = useState>(new Set()) @@ -977,26 +983,23 @@ function StepProcessingAndAI({ const deptActivityCount = (dept: ActivityDepartment) => dept.activities.filter(a => activeIds.has(a.id)).length - // AI Systems - const addAISystem = () => { - onChange({ aiSystems: [...aiSystems, { name: '', vendor: '', purpose: '', processes_personal_data: false }] }) - } - const removeAISystem = (i: number) => { - onChange({ aiSystems: aiSystems.filter((_: AISystem, idx: number) => idx !== i) }) - } - const updateAISystem = (i: number, updates: Partial) => { - const updated = [...aiSystems] - updated[i] = { ...updated[i], ...updates } - onChange({ aiSystems: updated }) - } - // Render a data category checkbox with info tooltip - const renderCategoryCheckbox = (cat: { id: string; label: string; desc: string; info: string }, activity: ProcessingActivity, variant: 'normal' | 'extra' | 'art9' | 'art9-extra') => { + const renderCategoryCheckbox = (cat: { id: string; label: string; desc: string; info: string }, activity: ProcessingActivity, variant: 'normal' | 'extra' | 'art9' | 'art9-extra', template?: ActivityTemplate | null) => { + const infoText = template?.categoryInfo?.[cat.id] || cat.info const isInfoExpanded = expandedInfoCat === `${activity.id}-${cat.id}` const colorClasses = variant.startsWith('art9') ? { check: 'text-red-600 focus:ring-red-500', hover: 'hover:bg-red-100', text: variant === 'art9-extra' ? 'text-gray-500' : 'text-gray-700' } : { check: 'text-purple-600 focus:ring-purple-500', hover: 'hover:bg-gray-100', text: variant === 'extra' ? 'text-gray-500' : 'text-gray-700' } + // Split info text to highlight retention periods + const aufbewahrungIdx = infoText.indexOf('Aufbewahrung:') + const loeschfristIdx = infoText.indexOf('Löschfrist') + const speicherdauerIdx = infoText.indexOf('Speicherdauer:') + const retentionIdx = [aufbewahrungIdx, loeschfristIdx, speicherdauerIdx].filter(i => i >= 0).sort((a, b) => a - b)[0] ?? -1 + const hasRetention = retentionIdx >= 0 + const mainText = hasRetention ? infoText.slice(0, retentionIdx).replace(/\.\s*$/, '') : infoText + const retentionText = hasRetention ? infoText.slice(retentionIdx) : '' + return (
{isInfoExpanded && (
- {cat.info} + {hasRetention ? ( + <> + {mainText} + + 🕓{retentionText} + + + ) : infoText}
)}
@@ -1085,7 +1095,7 @@ function StepProcessingAndAI({
{(isCustom ? ALL_DATA_CATEGORIES : primaryCats).map(cat => - renderCategoryCheckbox(cat, activity, isCustom ? 'normal' : 'normal') + renderCategoryCheckbox(cat, activity, 'normal', template) )}
@@ -1098,7 +1108,7 @@ function StepProcessingAndAI({ {showingExtra && (
- {extraCats.map(cat => renderCategoryCheckbox(cat, activity, 'extra'))} + {extraCats.map(cat => renderCategoryCheckbox(cat, activity, 'extra', template))}
)} @@ -1112,13 +1122,13 @@ function StepProcessingAndAI({
{(isCustom ? ALL_SPECIAL_CATEGORIES : relevantArt9).map(cat => - renderCategoryCheckbox(cat, activity, 'art9') + renderCategoryCheckbox(cat, activity, 'art9', template) )}
{/* Show remaining Art. 9 categories if expanded */} {!isCustom && otherArt9.length > 0 && showingExtra && (
- {otherArt9.map(cat => renderCategoryCheckbox(cat, activity, 'art9-extra'))} + {otherArt9.map(cat => renderCategoryCheckbox(cat, activity, 'art9-extra', template))}
)} @@ -1257,47 +1267,378 @@ function StepProcessingAndAI({ + Eigene Verarbeitungstätigkeit hinzufügen + + ) +} - {/* AI Systems — simplified */} -
-
-

KI-Systeme

- -
+// ============================================================================= +// STEP 7: KI-SYSTEME +// ============================================================================= + +interface AISystemTemplate { + id: string + name: string + vendor: string + category: string + icon: string + typicalPurposes: string[] + dataWarning?: string + processes_personal_data_likely: boolean +} + +const AI_SYSTEM_TEMPLATES: { category: string; icon: string; systems: AISystemTemplate[] }[] = [ + { + category: 'Text-KI / Chatbots', + icon: '\uD83D\uDCAC', + systems: [ + { id: 'chatgpt', name: 'ChatGPT', vendor: 'OpenAI', category: 'Text-KI / Chatbots', icon: '\uD83D\uDCAC', typicalPurposes: ['Textgenerierung', 'Kundensupport', 'Zusammenfassungen', 'Recherche'], dataWarning: 'Datenverarbeitung in den USA. Eingaben koennen fuer Training verwendet werden (opt-out moeglich).', processes_personal_data_likely: true }, + { id: 'claude', name: 'Claude', vendor: 'Anthropic', category: 'Text-KI / Chatbots', icon: '\uD83D\uDCAC', typicalPurposes: ['Textgenerierung', 'Analyse', 'Zusammenfassungen', 'Code-Review'], dataWarning: 'Datenverarbeitung in den USA. Eingaben werden NICHT fuer Training verwendet.', processes_personal_data_likely: true }, + { id: 'gemini', name: 'Google Gemini', vendor: 'Google', category: 'Text-KI / Chatbots', icon: '\uD83D\uDCAC', typicalPurposes: ['Textgenerierung', 'Recherche', 'Zusammenfassungen'], dataWarning: 'Datenverarbeitung in den USA/EU je nach Einstellung.', processes_personal_data_likely: true }, + { id: 'perplexity', name: 'Perplexity', vendor: 'Perplexity AI', category: 'Text-KI / Chatbots', icon: '\uD83D\uDCAC', typicalPurposes: ['Websuche mit KI', 'Recherche', 'Zusammenfassungen'], dataWarning: 'Websuche + KI. Eingaben werden verarbeitet.', processes_personal_data_likely: false }, + ], + }, + { + category: 'Office / Produktivitaet', + icon: '\uD83D\uDCCE', + systems: [ + { id: 'copilot365', name: 'Microsoft 365 Copilot', vendor: 'Microsoft', category: 'Office / Produktivitaet', icon: '\uD83D\uDCCE', typicalPurposes: ['E-Mail-Entwuerfe', 'Dokument-Zusammenfassung', 'Praesentationen', 'Excel-Analysen'], dataWarning: 'In M365-Tenant integriert. Daten bleiben im Tenant, aber: KI-Verarbeitung ggf. in den USA.', processes_personal_data_likely: true }, + { id: 'google-workspace-ai', name: 'Google Workspace AI', vendor: 'Google', category: 'Office / Produktivitaet', icon: '\uD83D\uDCCE', typicalPurposes: ['E-Mail-Entwuerfe', 'Dokument-Zusammenfassung', 'Tabellen-Analysen'], dataWarning: 'Duet AI in Docs, Sheets, Gmail. Datenverarbeitung je nach Workspace-Region.', processes_personal_data_likely: true }, + { id: 'notion-ai', name: 'Notion AI', vendor: 'Notion', category: 'Office / Produktivitaet', icon: '\uD83D\uDCCE', typicalPurposes: ['Texterstellung', 'Zusammenfassungen', 'Aufgabenverwaltung'], dataWarning: 'Datenverarbeitung in den USA.', processes_personal_data_likely: false }, + { id: 'grammarly', name: 'Grammarly', vendor: 'Grammarly', category: 'Office / Produktivitaet', icon: '\uD83D\uDCCE', typicalPurposes: ['Textkorrektur', 'Stiloptimierung', 'Tonalitaet'], dataWarning: 'Textanalyse, Datenverarbeitung in den USA.', processes_personal_data_likely: false }, + ], + }, + { + category: 'Code-Assistenz', + icon: '\uD83D\uDCBB', + systems: [ + { id: 'github-copilot', name: 'GitHub Copilot', vendor: 'Microsoft/GitHub', category: 'Code-Assistenz', icon: '\uD83D\uDCBB', typicalPurposes: ['Code-Vorschlaege', 'Code-Generierung', 'Dokumentation'], dataWarning: 'Code-Vorschlaege basierend auf Kontext. Code-Snippets werden verarbeitet.', processes_personal_data_likely: false }, + { id: 'cursor', name: 'Cursor / Windsurf', vendor: 'Cursor Inc.', category: 'Code-Assistenz', icon: '\uD83D\uDCBB', typicalPurposes: ['Code-Generierung', 'Refactoring', 'Debugging'], dataWarning: 'KI-Code-Editor. Code wird an KI-Backend uebermittelt.', processes_personal_data_likely: false }, + { id: 'codewhisperer', name: 'Amazon CodeWhisperer', vendor: 'AWS', category: 'Code-Assistenz', icon: '\uD83D\uDCBB', typicalPurposes: ['Code-Vorschlaege', 'Sicherheits-Scans'], dataWarning: 'Code-Vorschlaege. Opt-out fuer Code-Sharing moeglich.', processes_personal_data_likely: false }, + ], + }, + { + category: 'Bildgenerierung', + icon: '\uD83C\uDFA8', + systems: [ + { id: 'dalle', name: 'DALL-E / ChatGPT Bildgenerierung', vendor: 'OpenAI', category: 'Bildgenerierung', icon: '\uD83C\uDFA8', typicalPurposes: ['Bildgenerierung', 'Marketing-Material', 'Illustrationen'], dataWarning: 'Bildgenerierung. Prompts werden verarbeitet.', processes_personal_data_likely: false }, + { id: 'midjourney', name: 'Midjourney', vendor: 'Midjourney Inc.', category: 'Bildgenerierung', icon: '\uD83C\uDFA8', typicalPurposes: ['Bildgenerierung', 'Design-Konzepte', 'Illustrationen'], dataWarning: 'Bildgenerierung via Discord. Prompts sind oeffentlich sichtbar (ausser Pro-Plan).', processes_personal_data_likely: false }, + { id: 'firefly', name: 'Adobe Firefly', vendor: 'Adobe', category: 'Bildgenerierung', icon: '\uD83C\uDFA8', typicalPurposes: ['Bildgenerierung', 'Bildbearbeitung', 'Design'], dataWarning: 'In Creative Cloud integriert. Trainiert auf lizenzierten Inhalten.', processes_personal_data_likely: false }, + ], + }, + { + category: 'Uebersetzung / Sprache', + icon: '\uD83C\uDF10', + systems: [ + { id: 'deepl', name: 'DeepL', vendor: 'DeepL SE', category: 'Uebersetzung / Sprache', icon: '\uD83C\uDF10', typicalPurposes: ['Uebersetzung', 'Dokumentenuebersetzung'], dataWarning: 'Deutscher Anbieter, Server in EU. DeepL Pro: Texte werden NICHT gespeichert.', processes_personal_data_likely: false }, + { id: 'deepl-write', name: 'DeepL Write', vendor: 'DeepL SE', category: 'Uebersetzung / Sprache', icon: '\uD83C\uDF10', typicalPurposes: ['Textoptimierung', 'Stilverbesserung'], dataWarning: 'Deutscher Anbieter, Server in EU. Gleiche Datenschutz-Bedingungen wie DeepL.', processes_personal_data_likely: false }, + ], + }, + { + category: 'CRM / Sales KI', + icon: '\uD83D\uDCCA', + systems: [ + { id: 'salesforce-einstein', name: 'Salesforce Einstein', vendor: 'Salesforce', category: 'CRM / Sales KI', icon: '\uD83D\uDCCA', typicalPurposes: ['Lead-Scoring', 'Prognosen', 'Empfehlungen'], dataWarning: 'In Salesforce integriert. Verarbeitet CRM-Daten.', processes_personal_data_likely: true }, + { id: 'hubspot-ai', name: 'HubSpot AI', vendor: 'HubSpot', category: 'CRM / Sales KI', icon: '\uD83D\uDCCA', typicalPurposes: ['E-Mail-Generierung', 'Lead-Scoring', 'Content-Erstellung'], dataWarning: 'KI-Features in HubSpot CRM. Datenverarbeitung in USA/EU.', processes_personal_data_likely: true }, + ], + }, + { + category: 'Interne / Eigene Systeme', + icon: '\uD83C\uDFE2', + systems: [ + { id: 'internal-ai', name: 'Eigenes KI-System', vendor: 'Intern', category: 'Interne / Eigene Systeme', icon: '\uD83C\uDFE2', typicalPurposes: ['Interne Analyse', 'Automatisierung', 'Prozessoptimierung'], dataWarning: undefined, processes_personal_data_likely: false }, + ], + }, +] + +function StepAISystems({ + data, + onChange, +}: { + data: Partial & { aiSystems?: AISystem[] } + onChange: (updates: Record) => void +}) { + const aiSystems: AISystem[] = (data as any).aiSystems || [] + const [expandedSystem, setExpandedSystem] = useState(null) + const [collapsedCategories, setCollapsedCategories] = useState>(new Set()) + + const activeIds = new Set(aiSystems.map(a => a.id)) + + const toggleTemplateSystem = (template: AISystemTemplate) => { + if (activeIds.has(template.id)) { + onChange({ aiSystems: aiSystems.filter(a => a.id !== template.id) }) + if (expandedSystem === template.id) setExpandedSystem(null) + } else { + const newSystem: AISystem = { + id: template.id, + name: template.name, + vendor: template.vendor, + purpose: template.typicalPurposes.join(', '), + purposes: [], + processes_personal_data: template.processes_personal_data_likely, + isCustom: false, + } + onChange({ aiSystems: [...aiSystems, newSystem] }) + setExpandedSystem(template.id) + } + } + + const updateAISystem = (id: string, updates: Partial) => { + onChange({ + aiSystems: aiSystems.map(a => a.id === id ? { ...a, ...updates } : a), + }) + } + + const togglePurpose = (systemId: string, purpose: string) => { + const system = aiSystems.find(a => a.id === systemId) + if (!system) return + const purposes = system.purposes || [] + const updated = purposes.includes(purpose) + ? purposes.filter(p => p !== purpose) + : [...purposes, purpose] + updateAISystem(systemId, { purposes: updated, purpose: updated.join(', ') }) + } + + const addCustomSystem = () => { + const id = `custom_ai_${Date.now()}` + const newSystem: AISystem = { + id, + name: '', + vendor: '', + purpose: '', + processes_personal_data: false, + isCustom: true, + } + onChange({ aiSystems: [...aiSystems, newSystem] }) + setExpandedSystem(id) + } + + const removeSystem = (id: string) => { + onChange({ aiSystems: aiSystems.filter(a => a.id !== id) }) + if (expandedSystem === id) setExpandedSystem(null) + } + + const toggleCategoryCollapse = (category: string) => { + setCollapsedCategories(prev => { + const next = new Set(prev) + if (next.has(category)) next.delete(category); else next.add(category) + return next + }) + } + + const categoryActiveCount = (systems: AISystemTemplate[]) => + systems.filter(s => activeIds.has(s.id)).length + + return ( +
+
+

KI-Systeme im Einsatz

- Welche KI-Systeme setzen Sie ein? Die Risikoeinstufung nach AI Act ermittelt unser Tool automatisch. + Waehlen Sie die KI-Systeme aus, die in Ihrem Unternehmen eingesetzt werden. Dies dient der Erfassung fuer den EU AI Act und die DSGVO-Dokumentation.

+
- {aiSystems.length === 0 && ( -
- Noch keine KI-Systeme — falls Sie keine einsetzen, einfach leer lassen + {/* Template categories */} +
+ {AI_SYSTEM_TEMPLATES.map(group => { + const isCollapsed = collapsedCategories.has(group.category) + const activeCount = categoryActiveCount(group.systems) + + return ( +
+ {/* Category header */} + + + {/* Systems in category */} + {!isCollapsed && ( +
+ {group.systems.map(template => { + const isActive = activeIds.has(template.id) + const system = aiSystems.find(a => a.id === template.id) + const isExpanded = expandedSystem === template.id + + return ( +
+
{ + if (!isActive) { + toggleTemplateSystem(template) + } else { + setExpandedSystem(isExpanded ? null : template.id) + } + }} + > + { e.stopPropagation(); toggleTemplateSystem(template) }} + className="w-4 h-4 text-purple-600 rounded focus:ring-purple-500 flex-shrink-0" + /> +
+
{template.name}
+

{template.vendor}

+
+ {isActive && ( + + + + )} +
+ + {/* Detail panel */} + {isActive && isExpanded && system && ( +
+ {/* Purposes as chips */} +
+ +
+ {template.typicalPurposes.map(purpose => ( + + ))} +
+ updateAISystem(template.id, { notes: e.target.value })} + placeholder="Weitere Einsatzzwecke / Anmerkungen..." + className="mt-2 w-full px-3 py-2 border border-gray-300 rounded-lg text-sm focus:ring-2 focus:ring-purple-500 focus:border-transparent" + /> +
+ + {/* Data warning */} + {template.dataWarning && ( +
+ {template.dataWarning.includes('EU') || template.dataWarning.includes('Deutscher Anbieter') ? '\u2139\uFE0F' : '\u26A0\uFE0F'} + {template.dataWarning} +
+ )} + + {/* Personal data checkbox */} + + + +
+ )} +
+ ) + })} +
+ )} +
+ ) + })} +
+ + {/* Custom AI systems */} + {aiSystems.filter(a => a.isCustom).map(system => ( +
+
setExpandedSystem(expandedSystem === system.id ? null : system.id)} + > + + +
+ {system.name || 'Neues KI-System'} + {system.vendor && ({system.vendor})} +
+ + +
- )} -
- {aiSystems.map((ai: AISystem, i: number) => ( -
-
- KI-System {i + 1} - -
+ {expandedSystem === system.id && ( +
- updateAISystem(i, { name: e.target.value })} placeholder="Name (z.B. ChatGPT, Copilot)" className="px-3 py-2 border border-gray-300 rounded-lg text-sm focus:ring-2 focus:ring-purple-500 focus:border-transparent" /> - updateAISystem(i, { vendor: e.target.value })} placeholder="Anbieter (z.B. OpenAI, Microsoft)" className="px-3 py-2 border border-gray-300 rounded-lg text-sm focus:ring-2 focus:ring-purple-500 focus:border-transparent" /> + updateAISystem(system.id, { name: e.target.value })} placeholder="Name (z.B. ChatGPT, Copilot)" className="px-3 py-2 border border-gray-300 rounded-lg text-sm focus:ring-2 focus:ring-purple-500 focus:border-transparent" /> + updateAISystem(system.id, { vendor: e.target.value })} placeholder="Anbieter (z.B. OpenAI, Microsoft)" className="px-3 py-2 border border-gray-300 rounded-lg text-sm focus:ring-2 focus:ring-purple-500 focus:border-transparent" />
- updateAISystem(i, { purpose: e.target.value })} placeholder="Einsatzzweck (z.B. Kundensupport, Code-Assistenz)" className="w-full px-3 py-2 border border-gray-300 rounded-lg text-sm focus:ring-2 focus:ring-purple-500 focus:border-transparent" /> -
- ))} + )} +
+ ))} + + {/* Add custom system button */} + + + {/* AI Act module link */} +
+
+ {'\u2139\uFE0F'} +
+

AI Act Risikoeinstufung

+

+ Die detaillierte Risikoeinstufung Ihrer KI-Systeme nach EU AI Act (verboten / hochriskant / begrenzt / minimal) erfolgt automatisch im AI-Act-Modul. +

+ + Zum AI-Act-Modul + + + + +
@@ -1305,7 +1646,7 @@ function StepProcessingAndAI({ } // ============================================================================= -// STEP 7: RECHTLICHER RAHMEN +// STEP 8: RECHTLICHER RAHMEN // ============================================================================= function StepLegalFramework({ @@ -2032,7 +2373,7 @@ export default function CompanyProfilePage() { if (!cancelled && state.companyProfile) { setFormData(state.companyProfile) if (state.companyProfile.isComplete) { - setCurrentStep(7) + setCurrentStep(8) } } } @@ -2142,10 +2483,10 @@ export default function CompanyProfilePage() { const handleNext = () => { if (currentStep < lastStep) { - // Skip step 8 if not a machine builder + // Skip step 9 if not a machine builder const nextStep = currentStep + 1 - if (nextStep === 8 && !showMachineBuilderStep) { - // Complete profile (was step 7, last step for non-machine-builders) + if (nextStep === 9 && !showMachineBuilderStep) { + // Complete profile (was step 8, last step for non-machine-builders) completeAndSaveProfile() return } @@ -2249,10 +2590,12 @@ export default function CompanyProfilePage() { case 5: return true case 6: - return true // Systems & AI step is optional + return true // Processing step is optional case 7: - return true // Legal framework step is optional + return true // AI systems step is optional case 8: + return true // Legal framework step is optional + case 9: // Machine builder step: require at least product description return (formData.machineBuilder?.productDescription?.length || 0) > 0 default: @@ -2260,7 +2603,7 @@ export default function CompanyProfilePage() { } } - const isLastStep = currentStep === lastStep || (currentStep === 7 && !showMachineBuilderStep) + const isLastStep = currentStep === lastStep || (currentStep === 8 && !showMachineBuilderStep) return (
@@ -2343,9 +2686,10 @@ export default function CompanyProfilePage() { {currentStep === 3 && } {currentStep === 4 && } {currentStep === 5 && } - {currentStep === 6 && } - {currentStep === 7 && } - {currentStep === 8 && showMachineBuilderStep && } + {currentStep === 6 && } + {currentStep === 7 && } + {currentStep === 8 && } + {currentStep === 9 && showMachineBuilderStep && } {/* Navigation */}