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
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:
@@ -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">< 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">> 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">
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
'use client'
|
||||
import React, { useState, useCallback, useEffect, useMemo } from 'react'
|
||||
import type { ScopeProfilingAnswer, ScopeProfilingQuestion } from '@/lib/sdk/compliance-scope-types'
|
||||
import { SCOPE_QUESTION_BLOCKS, getBlockProgress, getTotalProgress, getAnswerValue, prefillFromCompanyProfile } from '@/lib/sdk/compliance-scope-profiling'
|
||||
import { SCOPE_QUESTION_BLOCKS, getBlockProgress, getTotalProgress, getAnswerValue, prefillFromCompanyProfile, getProfileInfoForBlock, getAutoFilledScoringAnswers } from '@/lib/sdk/compliance-scope-profiling'
|
||||
import type { ScopeQuestionBlockId } from '@/lib/sdk/compliance-scope-types'
|
||||
import { useSDK } from '@/lib/sdk'
|
||||
|
||||
interface ScopeWizardTabProps {
|
||||
@@ -37,9 +38,12 @@ export function ScopeWizardTab({
|
||||
useEffect(() => {
|
||||
if (companyProfile && answers.length === 0) {
|
||||
const prefilled = prefillFromCompanyProfile(companyProfile)
|
||||
if (prefilled.length > 0) {
|
||||
onAnswersChange(prefilled)
|
||||
setPrefilledIds(new Set(prefilled.map(a => a.questionId)))
|
||||
// Also inject auto-filled scoring answers for questions removed from UI
|
||||
const autoFilled = getAutoFilledScoringAnswers(companyProfile)
|
||||
const allPrefilled = [...prefilled, ...autoFilled]
|
||||
if (allPrefilled.length > 0) {
|
||||
onAnswersChange(allPrefilled)
|
||||
setPrefilledIds(new Set(allPrefilled.map(a => a.questionId)))
|
||||
}
|
||||
}
|
||||
// Only run on mount
|
||||
@@ -71,11 +75,13 @@ export function ScopeWizardTab({
|
||||
const handlePrefillFromProfile = useCallback(() => {
|
||||
if (!companyProfile) return
|
||||
const prefilled = prefillFromCompanyProfile(companyProfile)
|
||||
const autoFilled = getAutoFilledScoringAnswers(companyProfile)
|
||||
const allPrefilled = [...prefilled, ...autoFilled]
|
||||
// Merge with existing answers: prefilled values for questions not yet answered
|
||||
const existingIds = new Set(answers.map(a => a.questionId))
|
||||
const newAnswers = [...answers]
|
||||
const newPrefilledIds = new Set(prefilledIds)
|
||||
for (const pa of prefilled) {
|
||||
for (const pa of allPrefilled) {
|
||||
if (!existingIds.has(pa.questionId)) {
|
||||
newAnswers.push(pa)
|
||||
newPrefilledIds.add(pa.questionId)
|
||||
@@ -411,6 +417,42 @@ export function ScopeWizardTab({
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* "Aus Profil" Info Box — shown for blocks that have auto-filled data */}
|
||||
{companyProfile && (() => {
|
||||
const profileItems = getProfileInfoForBlock(companyProfile, currentBlock.id as ScopeQuestionBlockId)
|
||||
if (profileItems.length === 0) return null
|
||||
return (
|
||||
<div className="mb-6 p-4 bg-blue-50 border border-blue-200 rounded-lg">
|
||||
<div className="flex items-start justify-between">
|
||||
<div>
|
||||
<h4 className="text-sm font-medium text-blue-900 mb-2 flex items-center gap-2">
|
||||
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z" />
|
||||
</svg>
|
||||
Aus Unternehmensprofil
|
||||
</h4>
|
||||
<div className="flex flex-wrap gap-x-4 gap-y-1 text-sm text-blue-800">
|
||||
{profileItems.map(item => (
|
||||
<span key={item.label}>
|
||||
<span className="font-medium">{item.label}:</span> {item.value}
|
||||
</span>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
<a
|
||||
href="/sdk/company-profile"
|
||||
className="text-sm text-blue-600 hover:text-blue-800 font-medium whitespace-nowrap flex items-center gap-1"
|
||||
>
|
||||
Profil bearbeiten
|
||||
<svg className="w-3 h-3" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 5l7 7-7 7" />
|
||||
</svg>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
})()}
|
||||
|
||||
{/* Questions */}
|
||||
<div className="space-y-6">
|
||||
{currentBlock.questions.map((question) => (
|
||||
|
||||
@@ -10,21 +10,26 @@ import type { CompanyProfile } from './types'
|
||||
/**
|
||||
* Block 1: Organisation & Reife
|
||||
*/
|
||||
/**
|
||||
* IDs of questions that are auto-filled from company profile.
|
||||
* These are no longer shown as interactive questions but still contribute to scoring.
|
||||
*/
|
||||
export const PROFILE_AUTOFILL_QUESTION_IDS = [
|
||||
'org_employee_count',
|
||||
'org_annual_revenue',
|
||||
'org_industry',
|
||||
'org_business_model',
|
||||
'org_has_dsb',
|
||||
'prod_type',
|
||||
'prod_webshop',
|
||||
] as const
|
||||
|
||||
const BLOCK_1_ORGANISATION: ScopeQuestionBlock = {
|
||||
id: 'organisation',
|
||||
title: 'Organisation & Reife',
|
||||
description: 'Grundlegende Informationen zu Ihrer Organisation und Compliance-Zielen',
|
||||
order: 1,
|
||||
questions: [
|
||||
{
|
||||
id: 'org_employee_count',
|
||||
type: 'number',
|
||||
question: 'Wie viele Mitarbeiter hat Ihre Organisation?',
|
||||
helpText: 'Geben Sie die Gesamtzahl aller Beschäftigten an (inkl. Teilzeit, Minijobs)',
|
||||
required: true,
|
||||
scoreWeights: { risk: 5, complexity: 8, assurance: 6 },
|
||||
mapsToCompanyProfile: 'employeeCount',
|
||||
},
|
||||
{
|
||||
id: 'org_customer_count',
|
||||
type: 'single',
|
||||
@@ -40,21 +45,6 @@ const BLOCK_1_ORGANISATION: ScopeQuestionBlock = {
|
||||
],
|
||||
scoreWeights: { risk: 6, complexity: 7, assurance: 6 },
|
||||
},
|
||||
{
|
||||
id: 'org_annual_revenue',
|
||||
type: 'single',
|
||||
question: 'Wie hoch ist Ihr jährlicher Umsatz?',
|
||||
helpText: 'Wählen Sie die zutreffende Umsatzklasse',
|
||||
required: true,
|
||||
options: [
|
||||
{ value: '<2Mio', label: 'Unter 2 Mio. EUR' },
|
||||
{ value: '2-10Mio', label: '2 bis 10 Mio. EUR' },
|
||||
{ value: '10-50Mio', label: '10 bis 50 Mio. EUR' },
|
||||
{ value: '>50Mio', label: 'Über 50 Mio. EUR' },
|
||||
],
|
||||
scoreWeights: { risk: 4, complexity: 6, assurance: 7 },
|
||||
mapsToCompanyProfile: 'annualRevenue',
|
||||
},
|
||||
{
|
||||
id: 'org_cert_target',
|
||||
type: 'multi',
|
||||
@@ -71,53 +61,6 @@ const BLOCK_1_ORGANISATION: ScopeQuestionBlock = {
|
||||
],
|
||||
scoreWeights: { risk: 3, complexity: 5, assurance: 10 },
|
||||
},
|
||||
{
|
||||
id: 'org_industry',
|
||||
type: 'single',
|
||||
question: 'In welcher Branche sind Sie tätig?',
|
||||
helpText: 'Ihre Branche beeinflusst Risikobewertung und regulatorische Anforderungen',
|
||||
required: true,
|
||||
options: [
|
||||
{ value: 'it_software', label: 'IT & Software' },
|
||||
{ value: 'healthcare', label: 'Gesundheitswesen' },
|
||||
{ value: 'education', label: 'Bildung & Forschung' },
|
||||
{ value: 'finance', label: 'Finanzdienstleistungen' },
|
||||
{ value: 'retail', label: 'Einzelhandel & E-Commerce' },
|
||||
{ value: 'manufacturing', label: 'Produktion & Fertigung' },
|
||||
{ value: 'consulting', label: 'Beratung & Dienstleistungen' },
|
||||
{ value: 'public', label: 'Öffentliche Verwaltung' },
|
||||
{ value: 'other', label: 'Sonstige' },
|
||||
],
|
||||
scoreWeights: { risk: 7, complexity: 5, assurance: 6 },
|
||||
mapsToCompanyProfile: 'industry',
|
||||
mapsToVVTQuestion: 'org_industry',
|
||||
mapsToLFQuestion: 'org-branche',
|
||||
},
|
||||
{
|
||||
id: 'org_business_model',
|
||||
type: 'single',
|
||||
question: 'Was ist Ihr primäres Geschäftsmodell?',
|
||||
helpText: 'B2C-Modelle haben höhere Datenschutzanforderungen',
|
||||
required: true,
|
||||
options: [
|
||||
{ value: 'b2b', label: 'B2B (Business-to-Business)' },
|
||||
{ value: 'b2c', label: 'B2C (Business-to-Consumer)' },
|
||||
{ value: 'both', label: 'B2B und B2C gemischt' },
|
||||
{ value: 'b2g', label: 'B2G (Business-to-Government)' },
|
||||
],
|
||||
scoreWeights: { risk: 6, complexity: 5, assurance: 5 },
|
||||
mapsToCompanyProfile: 'businessModel',
|
||||
mapsToVVTQuestion: 'org_b2b_b2c',
|
||||
mapsToLFQuestion: 'org-geschaeftsmodell',
|
||||
},
|
||||
{
|
||||
id: 'org_has_dsb',
|
||||
type: 'boolean',
|
||||
question: 'Haben Sie einen Datenschutzbeauftragten bestellt?',
|
||||
helpText: 'Ein DSB ist bei mehr als 20 Personen mit regelmäßiger Datenverarbeitung Pflicht',
|
||||
required: true,
|
||||
scoreWeights: { risk: 5, complexity: 3, assurance: 6 },
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
@@ -414,24 +357,6 @@ const BLOCK_6_PRODUCT: ScopeQuestionBlock = {
|
||||
description: 'Spezifische Merkmale Ihrer Produkte und Services',
|
||||
order: 6,
|
||||
questions: [
|
||||
{
|
||||
id: 'prod_type',
|
||||
type: 'multi',
|
||||
question: 'Welche Art von Produkten/Services bieten Sie an?',
|
||||
helpText: 'Mehrfachauswahl möglich',
|
||||
required: true,
|
||||
options: [
|
||||
{ value: 'webapp', label: 'Web-Anwendung' },
|
||||
{ value: 'mobile', label: 'Mobile App (iOS/Android)' },
|
||||
{ value: 'saas', label: 'SaaS-Plattform' },
|
||||
{ value: 'onpremise', label: 'On-Premise Software' },
|
||||
{ value: 'api', label: 'API/Schnittstellen' },
|
||||
{ value: 'iot', label: 'IoT/Hardware' },
|
||||
{ value: 'beratung', label: 'Beratungsleistungen' },
|
||||
{ value: 'handel', label: 'Handel/Vertrieb' },
|
||||
],
|
||||
scoreWeights: { risk: 5, complexity: 6, assurance: 5 },
|
||||
},
|
||||
{
|
||||
id: 'prod_cookies_consent',
|
||||
type: 'boolean',
|
||||
@@ -440,14 +365,6 @@ const BLOCK_6_PRODUCT: ScopeQuestionBlock = {
|
||||
required: true,
|
||||
scoreWeights: { risk: 5, complexity: 4, assurance: 6 },
|
||||
},
|
||||
{
|
||||
id: 'prod_webshop',
|
||||
type: 'boolean',
|
||||
question: 'Betreiben Sie einen Online-Shop?',
|
||||
helpText: 'E-Commerce mit Zahlungsabwicklung, Bestellverwaltung',
|
||||
required: true,
|
||||
scoreWeights: { risk: 7, complexity: 6, assurance: 6 },
|
||||
},
|
||||
{
|
||||
id: 'prod_api_external',
|
||||
type: 'boolean',
|
||||
@@ -467,6 +384,201 @@ const BLOCK_6_PRODUCT: ScopeQuestionBlock = {
|
||||
],
|
||||
}
|
||||
|
||||
/**
|
||||
* Hidden questions — removed from UI but still contribute to scoring.
|
||||
* These are auto-filled from the Company Profile.
|
||||
*/
|
||||
export const HIDDEN_SCORING_QUESTIONS: ScopeProfilingQuestion[] = [
|
||||
{
|
||||
id: 'org_employee_count',
|
||||
type: 'number',
|
||||
question: 'Mitarbeiterzahl (aus Profil)',
|
||||
required: false,
|
||||
scoreWeights: { risk: 5, complexity: 8, assurance: 6 },
|
||||
mapsToCompanyProfile: 'employeeCount',
|
||||
},
|
||||
{
|
||||
id: 'org_annual_revenue',
|
||||
type: 'single',
|
||||
question: 'Jahresumsatz (aus Profil)',
|
||||
required: false,
|
||||
scoreWeights: { risk: 4, complexity: 6, assurance: 7 },
|
||||
mapsToCompanyProfile: 'annualRevenue',
|
||||
},
|
||||
{
|
||||
id: 'org_industry',
|
||||
type: 'single',
|
||||
question: 'Branche (aus Profil)',
|
||||
required: false,
|
||||
scoreWeights: { risk: 7, complexity: 5, assurance: 6 },
|
||||
mapsToCompanyProfile: 'industry',
|
||||
mapsToVVTQuestion: 'org_industry',
|
||||
mapsToLFQuestion: 'org-branche',
|
||||
},
|
||||
{
|
||||
id: 'org_business_model',
|
||||
type: 'single',
|
||||
question: 'Geschäftsmodell (aus Profil)',
|
||||
required: false,
|
||||
scoreWeights: { risk: 6, complexity: 5, assurance: 5 },
|
||||
mapsToCompanyProfile: 'businessModel',
|
||||
mapsToVVTQuestion: 'org_b2b_b2c',
|
||||
mapsToLFQuestion: 'org-geschaeftsmodell',
|
||||
},
|
||||
{
|
||||
id: 'org_has_dsb',
|
||||
type: 'boolean',
|
||||
question: 'DSB vorhanden (aus Profil)',
|
||||
required: false,
|
||||
scoreWeights: { risk: 5, complexity: 3, assurance: 6 },
|
||||
},
|
||||
{
|
||||
id: 'prod_type',
|
||||
type: 'multi',
|
||||
question: 'Angebotstypen (aus Profil)',
|
||||
required: false,
|
||||
scoreWeights: { risk: 5, complexity: 6, assurance: 5 },
|
||||
},
|
||||
{
|
||||
id: 'prod_webshop',
|
||||
type: 'boolean',
|
||||
question: 'Webshop (aus Profil)',
|
||||
required: false,
|
||||
scoreWeights: { risk: 7, complexity: 6, assurance: 6 },
|
||||
},
|
||||
]
|
||||
|
||||
/**
|
||||
* Block 7: KI-Systeme (portiert aus Company Profile Step 7)
|
||||
*/
|
||||
const BLOCK_7_AI_SYSTEMS: ScopeQuestionBlock = {
|
||||
id: 'ai_systems',
|
||||
title: 'KI-Systeme',
|
||||
description: 'Erfassung eingesetzter KI-Systeme für EU AI Act und DSGVO-Dokumentation',
|
||||
order: 7,
|
||||
questions: [
|
||||
{
|
||||
id: 'ai_uses_ai',
|
||||
type: 'boolean',
|
||||
question: 'Setzt Ihr Unternehmen KI-Systeme ein?',
|
||||
helpText: 'Chatbots, Empfehlungssysteme, automatisierte Entscheidungen, Copilot, etc.',
|
||||
required: true,
|
||||
scoreWeights: { risk: 8, complexity: 7, assurance: 6 },
|
||||
},
|
||||
{
|
||||
id: 'ai_categories',
|
||||
type: 'multi',
|
||||
question: 'Welche Kategorien von KI-Systemen setzen Sie ein?',
|
||||
helpText: 'Mehrfachauswahl möglich. Wird nur angezeigt, wenn KI im Einsatz ist.',
|
||||
required: false,
|
||||
options: [
|
||||
{ value: 'chatbot', label: 'Text-KI / Chatbots (ChatGPT, Claude, Gemini)' },
|
||||
{ value: 'office', label: 'Office / Produktivität (Copilot, Workspace AI)' },
|
||||
{ value: 'code', label: 'Code-Assistenz (GitHub Copilot, Cursor)' },
|
||||
{ value: 'image', label: 'Bildgenerierung (DALL-E, Midjourney, Firefly)' },
|
||||
{ value: 'translation', label: 'Übersetzung / Sprache (DeepL)' },
|
||||
{ value: 'crm', label: 'CRM / Sales KI (Salesforce Einstein, HubSpot AI)' },
|
||||
{ value: 'internal', label: 'Eigene / interne KI-Systeme' },
|
||||
{ value: 'other', label: 'Sonstige KI-Systeme' },
|
||||
],
|
||||
scoreWeights: { risk: 5, complexity: 5, assurance: 5 },
|
||||
},
|
||||
{
|
||||
id: 'ai_personal_data',
|
||||
type: 'boolean',
|
||||
question: 'Werden personenbezogene Daten an KI-Systeme übermittelt?',
|
||||
helpText: 'Z.B. Kundendaten in ChatGPT eingeben, E-Mails mit Copilot verarbeiten',
|
||||
required: false,
|
||||
scoreWeights: { risk: 10, complexity: 5, assurance: 7 },
|
||||
},
|
||||
{
|
||||
id: 'ai_risk_assessment',
|
||||
type: 'boolean',
|
||||
question: 'Haben Sie eine KI-Risikobewertung nach EU AI Act durchgeführt?',
|
||||
helpText: 'Risikoeinstufung der KI-Systeme (verboten / hochriskant / begrenzt / minimal)',
|
||||
required: false,
|
||||
scoreWeights: { risk: -5, complexity: 3, assurance: 8 },
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
/**
|
||||
* Block 8: Verarbeitungstätigkeiten (portiert aus Company Profile Step 6)
|
||||
*/
|
||||
const BLOCK_8_VVT: ScopeQuestionBlock = {
|
||||
id: 'vvt',
|
||||
title: 'Verarbeitungstätigkeiten',
|
||||
description: 'Übersicht der Datenverarbeitungen nach Art. 30 DSGVO',
|
||||
order: 8,
|
||||
questions: [
|
||||
{
|
||||
id: 'vvt_departments',
|
||||
type: 'multi',
|
||||
question: 'In welchen Abteilungen werden personenbezogene Daten verarbeitet?',
|
||||
helpText: 'Wählen Sie alle Abteilungen, in denen Verarbeitungstätigkeiten stattfinden',
|
||||
required: true,
|
||||
options: [
|
||||
{ value: 'personal', label: 'Personal / HR' },
|
||||
{ value: 'finanzen', label: 'Finanzen / Buchhaltung' },
|
||||
{ value: 'vertrieb', label: 'Vertrieb / Sales' },
|
||||
{ value: 'marketing', label: 'Marketing' },
|
||||
{ value: 'it', label: 'IT / Administration' },
|
||||
{ value: 'recht', label: 'Recht / Compliance' },
|
||||
{ value: 'kundenservice', label: 'Kundenservice / Support' },
|
||||
{ value: 'produktion', label: 'Produktion / Fertigung' },
|
||||
{ value: 'logistik', label: 'Logistik / Versand' },
|
||||
{ value: 'einkauf', label: 'Einkauf / Beschaffung' },
|
||||
{ value: 'facility', label: 'Facility Management' },
|
||||
],
|
||||
scoreWeights: { risk: 10, complexity: 10, assurance: 8 },
|
||||
},
|
||||
{
|
||||
id: 'vvt_data_categories',
|
||||
type: 'multi',
|
||||
question: 'Welche Datenkategorien werden verarbeitet?',
|
||||
helpText: 'Wählen Sie alle zutreffenden Kategorien personenbezogener Daten',
|
||||
required: true,
|
||||
options: [
|
||||
{ value: 'stammdaten', label: 'Stammdaten (Name, Geburtsdatum)' },
|
||||
{ value: 'kontaktdaten', label: 'Kontaktdaten (E-Mail, Telefon, Adresse)' },
|
||||
{ value: 'vertragsdaten', label: 'Vertragsdaten' },
|
||||
{ value: 'zahlungsdaten', label: 'Zahlungs-/Bankdaten' },
|
||||
{ value: 'beschaeftigtendaten', label: 'Beschäftigtendaten (Gehalt, Arbeitszeiten)' },
|
||||
{ value: 'kommunikation', label: 'Kommunikationsdaten (E-Mail, Chat)' },
|
||||
{ value: 'nutzungsdaten', label: 'Nutzungs-/Logdaten (IP, Klicks)' },
|
||||
{ value: 'standortdaten', label: 'Standortdaten' },
|
||||
{ value: 'bilddaten', label: 'Bild-/Videodaten' },
|
||||
{ value: 'bewerberdaten', label: 'Bewerberdaten' },
|
||||
],
|
||||
scoreWeights: { risk: 8, complexity: 7, assurance: 7 },
|
||||
},
|
||||
{
|
||||
id: 'vvt_special_categories',
|
||||
type: 'boolean',
|
||||
question: 'Verarbeiten Sie besondere Kategorien (Art. 9 DSGVO) in Ihren Tätigkeiten?',
|
||||
helpText: 'Gesundheit, Biometrie, Religion, Gewerkschaft — über die bereits in Block 2 erfassten hinaus',
|
||||
required: true,
|
||||
scoreWeights: { risk: 10, complexity: 5, assurance: 8 },
|
||||
},
|
||||
{
|
||||
id: 'vvt_has_vvt',
|
||||
type: 'boolean',
|
||||
question: 'Haben Sie bereits ein Verarbeitungsverzeichnis (VVT)?',
|
||||
helpText: 'Dokumentation aller Verarbeitungstätigkeiten nach Art. 30 DSGVO',
|
||||
required: true,
|
||||
scoreWeights: { risk: -5, complexity: 3, assurance: 8 },
|
||||
},
|
||||
{
|
||||
id: 'vvt_external_processors',
|
||||
type: 'boolean',
|
||||
question: 'Setzen Sie externe Dienstleister als Auftragsverarbeiter ein?',
|
||||
helpText: 'Lohnbüro, Hosting-Provider, Cloud-Dienste, externe IT etc.',
|
||||
required: true,
|
||||
scoreWeights: { risk: 7, complexity: 6, assurance: 7 },
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
/**
|
||||
* All question blocks in order
|
||||
*/
|
||||
@@ -477,49 +589,23 @@ export const SCOPE_QUESTION_BLOCKS: ScopeQuestionBlock[] = [
|
||||
BLOCK_4_TECH,
|
||||
BLOCK_5_PROCESSES,
|
||||
BLOCK_6_PRODUCT,
|
||||
BLOCK_7_AI_SYSTEMS,
|
||||
BLOCK_8_VVT,
|
||||
]
|
||||
|
||||
/**
|
||||
* Prefill scope answers from CompanyProfile
|
||||
* Prefill scope answers from CompanyProfile.
|
||||
*
|
||||
* Questions that were removed from the UI (org_employee_count, org_annual_revenue,
|
||||
* org_industry, org_business_model, org_has_dsb, prod_type, prod_webshop) are
|
||||
* still auto-filled here so their scoreWeights continue to affect the scoring.
|
||||
*/
|
||||
export function prefillFromCompanyProfile(
|
||||
profile: CompanyProfile
|
||||
): ScopeProfilingAnswer[] {
|
||||
const answers: ScopeProfilingAnswer[] = []
|
||||
|
||||
// employeeCount
|
||||
if (profile.employeeCount != null) {
|
||||
answers.push({
|
||||
questionId: 'org_employee_count',
|
||||
value: profile.employeeCount,
|
||||
})
|
||||
}
|
||||
|
||||
// annualRevenue
|
||||
if (profile.annualRevenue) {
|
||||
answers.push({
|
||||
questionId: 'org_annual_revenue',
|
||||
value: profile.annualRevenue,
|
||||
})
|
||||
}
|
||||
|
||||
// industry
|
||||
if (profile.industry) {
|
||||
answers.push({
|
||||
questionId: 'org_industry',
|
||||
value: profile.industry,
|
||||
})
|
||||
}
|
||||
|
||||
// businessModel
|
||||
if (profile.businessModel) {
|
||||
answers.push({
|
||||
questionId: 'org_business_model',
|
||||
value: profile.businessModel,
|
||||
})
|
||||
}
|
||||
|
||||
// dpoName -> org_has_dsb
|
||||
// dpoName -> org_has_dsb (auto-filled, not shown in UI)
|
||||
if (profile.dpoName && profile.dpoName.trim() !== '') {
|
||||
answers.push({
|
||||
questionId: 'org_has_dsb',
|
||||
@@ -527,21 +613,7 @@ export function prefillFromCompanyProfile(
|
||||
})
|
||||
}
|
||||
|
||||
// usesAI -> proc_ai_usage
|
||||
if (profile.usesAI === true) {
|
||||
// We don't know which specific AI type, so just mark as "generativ" as a default
|
||||
answers.push({
|
||||
questionId: 'proc_ai_usage',
|
||||
value: ['generativ'],
|
||||
})
|
||||
} else if (profile.usesAI === false) {
|
||||
answers.push({
|
||||
questionId: 'proc_ai_usage',
|
||||
value: ['keine'],
|
||||
})
|
||||
}
|
||||
|
||||
// offerings -> prod_type mapping
|
||||
// offerings -> prod_type mapping (auto-filled, not shown in UI)
|
||||
if (profile.offerings && profile.offerings.length > 0) {
|
||||
const prodTypes: string[] = []
|
||||
const offeringsLower = profile.offerings.map((o) => o.toLowerCase())
|
||||
@@ -591,11 +663,99 @@ export function prefillFromCompanyProfile(
|
||||
value: prodTypes,
|
||||
})
|
||||
}
|
||||
|
||||
// webshop auto-fill
|
||||
if (offeringsLower.some((o) => o.includes('webshop') || o.includes('shop'))) {
|
||||
answers.push({
|
||||
questionId: 'prod_webshop',
|
||||
value: true,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return answers
|
||||
}
|
||||
|
||||
/**
|
||||
* Get auto-filled scoring values for questions removed from UI.
|
||||
* These contribute to scoring even though the user doesn't answer them interactively.
|
||||
*/
|
||||
export function getAutoFilledScoringAnswers(
|
||||
profile: CompanyProfile
|
||||
): ScopeProfilingAnswer[] {
|
||||
const answers: ScopeProfilingAnswer[] = []
|
||||
|
||||
// employeeCount -> org_employee_count
|
||||
if (profile.employeeCount != null) {
|
||||
answers.push({
|
||||
questionId: 'org_employee_count',
|
||||
value: profile.employeeCount,
|
||||
})
|
||||
}
|
||||
|
||||
// annualRevenue -> org_annual_revenue
|
||||
if (profile.annualRevenue) {
|
||||
answers.push({
|
||||
questionId: 'org_annual_revenue',
|
||||
value: profile.annualRevenue,
|
||||
})
|
||||
}
|
||||
|
||||
// industry -> org_industry
|
||||
if (profile.industry) {
|
||||
answers.push({
|
||||
questionId: 'org_industry',
|
||||
value: profile.industry,
|
||||
})
|
||||
}
|
||||
|
||||
// businessModel -> org_business_model
|
||||
if (profile.businessModel) {
|
||||
answers.push({
|
||||
questionId: 'org_business_model',
|
||||
value: profile.businessModel,
|
||||
})
|
||||
}
|
||||
|
||||
// dpoName -> org_has_dsb
|
||||
if (profile.dpoName && profile.dpoName.trim() !== '') {
|
||||
answers.push({
|
||||
questionId: 'org_has_dsb',
|
||||
value: true,
|
||||
})
|
||||
}
|
||||
|
||||
return answers
|
||||
}
|
||||
|
||||
/**
|
||||
* Get profile info summary for display in "Aus Profil" info boxes.
|
||||
*/
|
||||
export function getProfileInfoForBlock(
|
||||
profile: CompanyProfile,
|
||||
blockId: ScopeQuestionBlockId
|
||||
): { label: string; value: string }[] {
|
||||
const items: { label: string; value: string }[] = []
|
||||
|
||||
if (blockId === 'organisation') {
|
||||
if (profile.industry) items.push({ label: 'Branche', value: profile.industry })
|
||||
if (profile.employeeCount) items.push({ label: 'Mitarbeiter', value: profile.employeeCount })
|
||||
if (profile.annualRevenue) items.push({ label: 'Umsatz', value: profile.annualRevenue })
|
||||
if (profile.businessModel) items.push({ label: 'Geschäftsmodell', value: profile.businessModel })
|
||||
if (profile.dpoName) items.push({ label: 'DSB', value: profile.dpoName })
|
||||
}
|
||||
|
||||
if (blockId === 'product') {
|
||||
if (profile.offerings && profile.offerings.length > 0) {
|
||||
items.push({ label: 'Angebote', value: profile.offerings.join(', ') })
|
||||
}
|
||||
const hasWebshop = profile.offerings?.some(o => o.toLowerCase().includes('webshop') || o.toLowerCase().includes('shop'))
|
||||
if (hasWebshop) items.push({ label: 'Webshop', value: 'Ja' })
|
||||
}
|
||||
|
||||
return items
|
||||
}
|
||||
|
||||
/**
|
||||
* Prefill scope answers from VVT profiling answers
|
||||
*/
|
||||
@@ -814,8 +974,11 @@ export function getAnswerValue(
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all questions as a flat array
|
||||
* Get all questions as a flat array (including hidden auto-filled questions)
|
||||
*/
|
||||
export function getAllQuestions(): ScopeProfilingQuestion[] {
|
||||
return SCOPE_QUESTION_BLOCKS.flatMap((block) => block.questions)
|
||||
return [
|
||||
...SCOPE_QUESTION_BLOCKS.flatMap((block) => block.questions),
|
||||
...HIDDEN_SCORING_QUESTIONS,
|
||||
]
|
||||
}
|
||||
|
||||
@@ -47,7 +47,9 @@ export type ScopeQuestionBlockId =
|
||||
| 'processing' // Verarbeitung & Zweck
|
||||
| 'tech' // Technik & Hosting
|
||||
| 'processes' // Rechte & Prozesse
|
||||
| 'product'; // Produktkontext
|
||||
| 'product' // Produktkontext
|
||||
| 'ai_systems' // KI-Systeme (aus Profil portiert)
|
||||
| 'vvt'; // Verarbeitungstaetigkeiten (aus Profil portiert)
|
||||
|
||||
/**
|
||||
* Eine einzelne Frage im Scope-Profiling
|
||||
|
||||
@@ -79,8 +79,6 @@ export function generateDemoState(tenantId: string, userId: string): Partial<SDK
|
||||
primaryJurisdiction: 'DE',
|
||||
isDataController: true,
|
||||
isDataProcessor: true,
|
||||
usesAI: true,
|
||||
aiUseCases: ['KI-gestützte Kundenberatung', 'Automatisierte Dokumentenanalyse'],
|
||||
dpoName: 'Max Mustermann',
|
||||
dpoEmail: 'dsb@techstart.de',
|
||||
legalContactName: null,
|
||||
|
||||
@@ -195,10 +195,6 @@ export interface CompanyProfile {
|
||||
isDataController: boolean // Verantwortlicher (Art. 4 Nr. 7 DSGVO)
|
||||
isDataProcessor: boolean // Auftragsverarbeiter (Art. 4 Nr. 8 DSGVO)
|
||||
|
||||
// AI Usage
|
||||
usesAI: boolean
|
||||
aiUseCases: string[] // Brief descriptions
|
||||
|
||||
// Contact Persons
|
||||
dpoName: string | null // Data Protection Officer
|
||||
dpoEmail: string | null
|
||||
|
||||
Reference in New Issue
Block a user