84b21cad08
- New prefill-from-scope.ts utility: - headquartersState → federal_state (Bundesland for authority lookup) - data_art9 → special data categories (Gesundheit, Biometrie, etc.) - data_minors → adds "Minderjährige" to data subjects + raises risk - proc_adm_scoring → Art. 22 affected rights + measures - proc_ai_usage → involves_ai flag + AI measures - proc_video_surveillance → video data categories - industry/businessModel → processing purpose + legal basis - isDSFARequired() check: shows red banner when Art. 35 triggers detected - GeneratorWizard accepts prefill prop, initializes all fields - Passes federal_state, involves_ai, legal_basis to backend POST Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
203 lines
7.2 KiB
TypeScript
203 lines
7.2 KiB
TypeScript
/**
|
|
* DSFA Pre-Fill — derives initial DSFA data from Company Profile + Scope answers.
|
|
*
|
|
* Maps: Firmensitz → Bundesland, Scope-Antworten → Datenkategorien/Risiken,
|
|
* Use Cases → Verarbeitungstaetigkeiten, DPO → Beratungsinformationen.
|
|
*/
|
|
|
|
import type { ScopeProfilingAnswer } from '@/lib/sdk/compliance-scope-types'
|
|
|
|
interface CompanyProfileMinimal {
|
|
headquartersState?: string
|
|
industry?: string[]
|
|
businessModel?: string
|
|
dpoName?: string | null
|
|
dpoEmail?: string | null
|
|
companyName?: string
|
|
}
|
|
|
|
export interface DSFAPrefillResult {
|
|
title: string
|
|
description: string
|
|
processingActivity: string
|
|
dataCategories: string[]
|
|
dataSubjects: string[]
|
|
riskLevel: string
|
|
measures: string[]
|
|
federalState: string
|
|
involvesAi: boolean
|
|
legalBasis: string
|
|
processingPurpose: string
|
|
affectedRights: string[]
|
|
}
|
|
|
|
const ART9_CATEGORY_MAP: Record<string, string> = {
|
|
health: 'Gesundheitsdaten',
|
|
biometric: 'Biometrische Daten',
|
|
genetic: 'Genetische Daten',
|
|
ethnic: 'Ethnische Herkunft',
|
|
political: 'Politische Meinungen',
|
|
religious: 'Religioese Ueberzeugungen',
|
|
union: 'Gewerkschaftszugehoerigkeit',
|
|
sexual: 'Sexualleben/Orientierung',
|
|
}
|
|
|
|
const BUNDESLAND_LABELS: Record<string, string> = {
|
|
BW: 'Baden-Wuerttemberg', BY: 'Bayern', BE: 'Berlin', BB: 'Brandenburg',
|
|
HB: 'Bremen', HH: 'Hamburg', HE: 'Hessen', MV: 'Mecklenburg-Vorpommern',
|
|
NI: 'Niedersachsen', NW: 'Nordrhein-Westfalen', RP: 'Rheinland-Pfalz',
|
|
SL: 'Saarland', SN: 'Sachsen', ST: 'Sachsen-Anhalt',
|
|
SH: 'Schleswig-Holstein', TH: 'Thueringen',
|
|
}
|
|
|
|
function getAnswer(answers: ScopeProfilingAnswer[], questionId: string): string | string[] | boolean | undefined {
|
|
const a = answers.find(a => a.questionId === questionId)
|
|
return a?.value as string | string[] | boolean | undefined
|
|
}
|
|
|
|
export function prefillDSFAFromScope(
|
|
profile: CompanyProfileMinimal | null,
|
|
scopeAnswers: ScopeProfilingAnswer[],
|
|
): DSFAPrefillResult {
|
|
const result: DSFAPrefillResult = {
|
|
title: '',
|
|
description: '',
|
|
processingActivity: '',
|
|
dataCategories: [],
|
|
dataSubjects: [],
|
|
riskLevel: 'mittel',
|
|
measures: ['Zugriffskontrolle', 'Verschluesselung'],
|
|
federalState: '',
|
|
involvesAi: false,
|
|
legalBasis: '',
|
|
processingPurpose: '',
|
|
affectedRights: [],
|
|
}
|
|
|
|
// 1. Firmensitz → Bundesland
|
|
if (profile?.headquartersState) {
|
|
result.federalState = profile.headquartersState
|
|
}
|
|
|
|
// 2. Art. 9 Daten → Datenkategorien + Risikostufe
|
|
const art9 = getAnswer(scopeAnswers, 'data_art9')
|
|
if (art9 === true || art9 === 'yes') {
|
|
result.dataCategories.push('Besondere Kategorien (Art. 9)')
|
|
result.riskLevel = 'hoch'
|
|
result.title = 'DSFA — Verarbeitung besonderer Datenkategorien'
|
|
}
|
|
if (Array.isArray(art9)) {
|
|
for (const cat of art9) {
|
|
const label = ART9_CATEGORY_MAP[cat]
|
|
if (label) result.dataCategories.push(label)
|
|
}
|
|
if (art9.length > 0) result.riskLevel = 'hoch'
|
|
}
|
|
|
|
// 3. Minderjährige → Betroffene + Risiko
|
|
const minors = getAnswer(scopeAnswers, 'data_minors')
|
|
if (minors === true || minors === 'yes') {
|
|
result.dataSubjects.push('Minderjaehrige (unter 16 Jahre)')
|
|
result.riskLevel = 'hoch'
|
|
result.affectedRights.push('Besonderer Schutz Minderjaehriger (Art. 8 DSGVO)')
|
|
if (!result.title) result.title = 'DSFA — Verarbeitung von Daten Minderjaehriger'
|
|
}
|
|
|
|
// 4. Automatisierte Entscheidungen (Scoring)
|
|
const scoring = getAnswer(scopeAnswers, 'proc_adm_scoring')
|
|
if (scoring === true || scoring === 'yes') {
|
|
result.affectedRights.push('Recht auf nicht-automatisierte Entscheidung (Art. 22 DSGVO)')
|
|
result.riskLevel = 'hoch'
|
|
if (!result.title) result.title = 'DSFA — Automatisierte Einzelentscheidungen'
|
|
result.measures.push('Menschliche Pruefung')
|
|
}
|
|
|
|
// 5. KI-Einsatz
|
|
const aiUsage = getAnswer(scopeAnswers, 'proc_ai_usage')
|
|
if (aiUsage === true || aiUsage === 'yes' || (Array.isArray(aiUsage) && aiUsage.length > 0)) {
|
|
result.involvesAi = true
|
|
result.measures.push('KI-Transparenz', 'Human Oversight')
|
|
if (!result.title) result.title = 'DSFA — KI-gestuetzte Datenverarbeitung'
|
|
}
|
|
|
|
// 6. Videoueberwachung
|
|
const video = getAnswer(scopeAnswers, 'proc_video_surveillance')
|
|
if (video === true || video === 'yes') {
|
|
result.dataCategories.push('Videoaufnahmen / Bilddaten')
|
|
result.dataSubjects.push('Besucher', 'Mitarbeiter')
|
|
if (!result.title) result.title = 'DSFA — Videoueberwachung'
|
|
}
|
|
|
|
// 7. Datenvolumen
|
|
const volume = getAnswer(scopeAnswers, 'data_volume')
|
|
if (volume === '100000-1000000' || volume === '>1000000') {
|
|
result.riskLevel = 'hoch'
|
|
result.description += 'Grosse Datenmengen erhoehen das Risiko fuer Betroffene. '
|
|
}
|
|
|
|
// 8. Branche + Geschaeftsmodell → Verarbeitungszweck
|
|
if (profile?.industry?.length) {
|
|
const ind = profile.industry[0]
|
|
const purposeMap: Record<string, string> = {
|
|
healthcare: 'Patientenversorgung und Gesundheitsdatenverarbeitung',
|
|
finance: 'Finanzdienstleistungen und Bonitaetspruefung',
|
|
education: 'Bildungsverwaltung und Schuelerbetreuung',
|
|
tech: 'Software-Entwicklung und Cloud-Dienste',
|
|
retail: 'Handel und Kundenbeziehungsmanagement',
|
|
legal: 'Mandatsbearbeitung und Rechtsberatung',
|
|
}
|
|
result.processingPurpose = purposeMap[ind] || ''
|
|
result.processingActivity = purposeMap[ind] || ''
|
|
}
|
|
|
|
if (profile?.businessModel === 'b2c') {
|
|
result.dataSubjects.push('Endverbraucher')
|
|
result.legalBasis = 'Art. 6 Abs. 1 lit. b DSGVO (Vertragserfuellung)'
|
|
} else if (profile?.businessModel === 'b2b') {
|
|
result.dataSubjects.push('Geschaeftskunden', 'Ansprechpartner')
|
|
result.legalBasis = 'Art. 6 Abs. 1 lit. f DSGVO (Berechtigtes Interesse)'
|
|
}
|
|
|
|
// Deduplicate
|
|
result.dataCategories = [...new Set(result.dataCategories)]
|
|
result.dataSubjects = [...new Set(result.dataSubjects)]
|
|
result.measures = [...new Set(result.measures)]
|
|
result.affectedRights = [...new Set(result.affectedRights)]
|
|
|
|
// Default title if nothing triggered
|
|
if (!result.title) {
|
|
result.title = `DSFA — ${profile?.companyName || 'Datenverarbeitung'}`
|
|
}
|
|
|
|
return result
|
|
}
|
|
|
|
/**
|
|
* Check if DSFA is required based on scope answers (Art. 35 Abs. 3 triggers).
|
|
*/
|
|
export function isDSFARequired(scopeAnswers: ScopeProfilingAnswer[]): {
|
|
required: boolean
|
|
triggers: string[]
|
|
} {
|
|
const triggers: string[] = []
|
|
|
|
if (getAnswer(scopeAnswers, 'data_art9') === true || getAnswer(scopeAnswers, 'data_art9') === 'yes') {
|
|
triggers.push('Besondere Datenkategorien (Art. 9 DSGVO)')
|
|
}
|
|
if (getAnswer(scopeAnswers, 'data_minors') === true || getAnswer(scopeAnswers, 'data_minors') === 'yes') {
|
|
triggers.push('Daten Minderjaehriger (Art. 8 DSGVO)')
|
|
}
|
|
if (getAnswer(scopeAnswers, 'proc_adm_scoring') === true || getAnswer(scopeAnswers, 'proc_adm_scoring') === 'yes') {
|
|
triggers.push('Automatisierte Einzelentscheidungen (Art. 22 DSGVO)')
|
|
}
|
|
if (getAnswer(scopeAnswers, 'proc_video_surveillance') === true || getAnswer(scopeAnswers, 'proc_video_surveillance') === 'yes') {
|
|
triggers.push('Systematische Ueberwachung (Art. 35 Abs. 3 lit. c)')
|
|
}
|
|
const vol = getAnswer(scopeAnswers, 'data_volume')
|
|
if (vol === '100000-1000000' || vol === '>1000000') {
|
|
triggers.push('Umfangreiche Datenverarbeitung (Art. 35 Abs. 3 lit. b)')
|
|
}
|
|
|
|
return { required: triggers.length > 0, triggers }
|
|
}
|