refactor(scope+profile): Duplikate eliminieren, UI vereinheitlichen
Some checks failed
CI / go-lint (push) Has been skipped
CI / python-lint (push) Has been skipped
CI / nodejs-lint (push) Has been skipped
CI / test-go-ai-compliance (push) Failing after 36s
CI / test-python-backend-compliance (push) Successful in 35s
CI / test-python-document-crawler (push) Successful in 25s
CI / test-python-dsms-gateway (push) Successful in 20s

- Profil: Steps 6 (VVT) + 7 (KI) entfernt, nach Scope verschoben
- Profil: Steps 9→7 renummeriert (Rechtlicher Rahmen→6, Maschinenbau→7)
- Profil: Branche + Jahresumsatz von Dropdown auf Tile-Grid umgestellt
- Profil: usesAI/aiUseCases aus CompanyProfile Interface entfernt
- Scope: 5 Duplikate aus Block 1 entfernt (Branche, MA, Umsatz, Modell, DSB)
- Scope: 2 Duplikate aus Block 6 entfernt (Angebote, Webshop)
- Scope: Block 7 (KI-Systeme) + Block 8 (VVT) neu hinzugefuegt
- Scope: "Aus Profil" Info-Box zeigt Profildaten in betroffenen Blocks
- Scope: Hidden Scoring fuer entfernte Fragen bleibt erhalten via Auto-Fill

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Benjamin Admin
2026-03-10 08:52:09 +01:00
parent 90d99bba08
commit fa4cda7627
6 changed files with 418 additions and 235 deletions

View File

@@ -33,13 +33,11 @@ const BASE_WIZARD_STEPS = [
{ id: 2, name: 'Geschaeftsmodell', description: 'B2B, B2C und Angebote' },
{ 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: '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' },
{ id: 5, name: 'Datenschutz', description: 'Rollen und DSB' },
{ id: 6, name: 'Rechtlicher Rahmen', description: 'Regulierungen und Prüfzyklen' },
]
const MACHINE_BUILDER_STEP = { id: 9, name: 'Produkt & Maschine', description: 'Software, KI und CE in Ihrem Produkt' }
const MACHINE_BUILDER_STEP = { id: 7, name: 'Produkt & Maschine', description: 'Software, KI und CE in Ihrem Produkt' }
function getWizardSteps(industry: string) {
if (isMachineBuilderIndustry(industry)) {
@@ -148,19 +146,23 @@ function StepBasicInfo({
</div>
<div>
<label className="block text-sm font-medium text-gray-700 mb-2">Branche</label>
<select
value={data.industry || ''}
onChange={e => onChange({ industry: e.target.value })}
className="w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-purple-500 focus:border-transparent"
>
<option value="">Bitte wählen...</option>
<label className="block text-sm font-medium text-gray-700 mb-3">Branche</label>
<div className="grid grid-cols-2 sm:grid-cols-3 gap-3">
{INDUSTRIES.map(industry => (
<option key={industry} value={industry}>
<button
key={industry}
type="button"
onClick={() => onChange({ industry })}
className={`p-3 rounded-lg border-2 text-sm text-left transition-all ${
data.industry === industry
? 'border-purple-500 bg-purple-50 text-purple-700 font-medium'
: 'border-gray-200 hover:border-purple-300 text-gray-700'
}`}
>
{industry}
</option>
</button>
))}
</select>
</div>
</div>
<div>
@@ -200,11 +202,9 @@ const STEP_EXPLANATIONS: Record<number, string> = {
2: 'Ihr Geschäftsmodell und Ihre Angebote bestimmen, welche DSGVO-Pflichten greifen: B2C erfordert z.B. strengere Einwilligungsregeln, Webshops brauchen Cookie-Banner und Datenschutzerklärungen, SaaS-Angebote eine Auftragsverarbeitung.',
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).',
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.',
5: 'Ob Sie Verantwortlicher oder Auftragsverarbeiter sind, bestimmt Ihre DSGVO-Pflichten grundlegend.',
6: 'Regulierungsrahmen und Prüfzyklen definieren, welche Compliance-Module für Sie aktiviert werden und in welchem Rhythmus Audits stattfinden.',
7: 'Als Maschinenbauer gelten zusätzliche Anforderungen: CE-Kennzeichnung, Maschinenverordnung, Produktsicherheit und ggf. Hochrisiko-KI im Sinne des AI Act.',
}
function StepBusinessModel({
@@ -357,18 +357,28 @@ function StepCompanySize({
</div>
<div>
<label className="block text-sm font-medium text-gray-700 mb-2">Jahresumsatz</label>
<select
value={data.annualRevenue || ''}
onChange={e => onChange({ annualRevenue: e.target.value })}
className="w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-purple-500 focus:border-transparent"
>
<option value="">Bitte wählen...</option>
<option value="< 2 Mio">&lt; 2 Mio. Euro</option>
<option value="2-10 Mio">2-10 Mio. Euro</option>
<option value="10-50 Mio">10-50 Mio. Euro</option>
<option value="> 50 Mio">&gt; 50 Mio. Euro</option>
</select>
<label className="block text-sm font-medium text-gray-700 mb-3">Jahresumsatz</label>
<div className="grid grid-cols-2 gap-3">
{[
{ value: '< 2 Mio', label: '< 2 Mio. Euro' },
{ value: '2-10 Mio', label: '2-10 Mio. Euro' },
{ value: '10-50 Mio', label: '10-50 Mio. Euro' },
{ value: '> 50 Mio', label: '> 50 Mio. Euro' },
].map(opt => (
<button
key={opt.value}
type="button"
onClick={() => onChange({ annualRevenue: opt.value })}
className={`p-4 rounded-xl border-2 text-left transition-all ${
data.annualRevenue === opt.value
? 'border-purple-500 bg-purple-50 text-purple-700 font-medium'
: 'border-gray-200 hover:border-purple-300 text-gray-700'
}`}
>
{opt.label}
</button>
))}
</div>
{(data.companySize === 'medium' || data.companySize === 'large' || data.companySize === 'enterprise') && (
<p className="text-xs text-amber-600 mt-2">
Geben Sie den konsolidierten Konzernumsatz an, wenn der Compliance-Check für Mutter- und Tochtergesellschaften gelten soll.
@@ -601,23 +611,6 @@ function StepDataProtection({
</div>
</div>
<div>
<label className="flex items-start gap-4 p-4 rounded-xl border-2 border-gray-200 hover:border-purple-300 cursor-pointer">
<input
type="checkbox"
checked={data.usesAI ?? false}
onChange={e => onChange({ usesAI: e.target.checked })}
className="mt-1 w-5 h-5 text-purple-600 rounded focus:ring-purple-500"
/>
<div>
<div className="font-medium text-gray-900">Wir setzen KI/ML-Systeme ein</div>
<div className="text-sm text-gray-500">
Chatbots, Empfehlungssysteme, automatisierte Entscheidungen, etc.
</div>
</div>
</label>
</div>
<div className="grid grid-cols-2 gap-6">
<div>
<label className="block text-sm font-medium text-gray-700 mb-2">
@@ -647,10 +640,13 @@ function StepDataProtection({
}
// =============================================================================
// STEP 6: VERARBEITUNGSTAETIGKEITEN & KI
// STEP 6: RECHTLICHER RAHMEN (was Step 8)
// =============================================================================
// DSGVO-Standard Datenkategorien
// NOTE: Verarbeitungstaetigkeiten (former Step 6) and KI-Systeme (former Step 7)
// have been moved to Compliance Scope (Blocks 7 and 8).
// DSGVO-Standard Datenkategorien — kept as shared reference for scope
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 der betroffenen Personen' },
@@ -1646,7 +1642,7 @@ function StepAISystems({
}
// =============================================================================
// STEP 8: RECHTLICHER RAHMEN
// STEP 6: RECHTLICHER RAHMEN (was Step 8, renumbered)
// =============================================================================
function StepLegalFramework({
@@ -1776,7 +1772,7 @@ function StepLegalFramework({
}
// =============================================================================
// STEP 8: PRODUKT & MASCHINE (nur fuer Maschinenbauer)
// STEP 7: PRODUKT & MASCHINE (nur fuer Maschinenbauer, was Step 9)
// =============================================================================
const EMPTY_MACHINE_BUILDER: MachineBuilderProfile = {
@@ -2293,8 +2289,6 @@ export default function CompanyProfilePage() {
primaryJurisdiction: 'DE',
isDataController: true,
isDataProcessor: false,
usesAI: false,
aiUseCases: [],
dpoName: null,
dpoEmail: null,
legalContactName: null,
@@ -2351,8 +2345,6 @@ export default function CompanyProfilePage() {
primaryJurisdiction: data.primary_jurisdiction || 'DE',
isDataController: data.is_data_controller ?? true,
isDataProcessor: data.is_data_processor ?? false,
usesAI: data.uses_ai ?? false,
aiUseCases: data.ai_use_cases || [],
dpoName: data.dpo_name || '',
dpoEmail: data.dpo_email || '',
isComplete: data.is_complete || false,
@@ -2370,7 +2362,7 @@ export default function CompanyProfilePage() {
} as any
setFormData(backendProfile)
if (backendProfile.isComplete) {
setCurrentStep(7)
setCurrentStep(6)
}
return
}
@@ -2383,7 +2375,7 @@ export default function CompanyProfilePage() {
if (!cancelled && state.companyProfile) {
setFormData(state.companyProfile)
if (state.companyProfile.isComplete) {
setCurrentStep(8)
setCurrentStep(6)
}
}
}
@@ -2423,8 +2415,6 @@ export default function CompanyProfilePage() {
primary_jurisdiction: formData.primaryJurisdiction || 'DE',
is_data_controller: formData.isDataController ?? true,
is_data_processor: formData.isDataProcessor ?? false,
uses_ai: formData.usesAI ?? false,
ai_use_cases: formData.aiUseCases || [],
dpo_name: formData.dpoName || '',
dpo_email: formData.dpoEmail || '',
is_complete: isComplete,
@@ -2494,9 +2484,9 @@ export default function CompanyProfilePage() {
const handleNext = () => {
if (currentStep < lastStep) {
// Skip step 9 if not a machine builder
// Skip step 7 if not a machine builder
const nextStep = currentStep + 1
if (nextStep === 9 && !showMachineBuilderStep) {
if (nextStep === 7 && !showMachineBuilderStep) {
// Complete profile (was step 8, last step for non-machine-builders)
completeAndSaveProfile()
return
@@ -2568,8 +2558,6 @@ export default function CompanyProfilePage() {
primaryJurisdiction: 'DE',
isDataController: true,
isDataProcessor: false,
usesAI: false,
aiUseCases: [],
dpoName: null,
dpoEmail: null,
legalContactName: null,
@@ -2601,12 +2589,8 @@ export default function CompanyProfilePage() {
case 5:
return true
case 6:
return true // Processing step is optional
case 7:
return true // AI systems step is optional
case 8:
return true // Legal framework step is optional
case 9:
case 7:
// Machine builder step: require at least product description
return (formData.machineBuilder?.productDescription?.length || 0) > 0
default:
@@ -2614,7 +2598,7 @@ export default function CompanyProfilePage() {
}
}
const isLastStep = currentStep === lastStep || (currentStep === 8 && !showMachineBuilderStep)
const isLastStep = currentStep === lastStep || (currentStep === 6 && !showMachineBuilderStep)
return (
<div className="min-h-screen bg-gray-50 py-8">
@@ -2697,10 +2681,8 @@ export default function CompanyProfilePage() {
{currentStep === 3 && <StepCompanySize data={formData} onChange={updateFormData} />}
{currentStep === 4 && <StepLocations data={formData} onChange={updateFormData} />}
{currentStep === 5 && <StepDataProtection data={formData} onChange={updateFormData} />}
{currentStep === 6 && <StepProcessing data={formData} onChange={updateFormData} />}
{currentStep === 7 && <StepAISystems data={formData} onChange={updateFormData} />}
{currentStep === 8 && <StepLegalFramework data={formData} onChange={updateFormData} />}
{currentStep === 9 && showMachineBuilderStep && <StepMachineBuilder data={formData} onChange={updateFormData} />}
{currentStep === 6 && <StepLegalFramework data={formData} onChange={updateFormData} />}
{currentStep === 7 && showMachineBuilderStep && <StepMachineBuilder data={formData} onChange={updateFormData} />}
{/* Navigation */}
<div className="flex justify-between items-center mt-8 pt-6 border-t border-gray-200">