Files
breakpilot-compliance/admin-compliance/lib/sdk/dsfa/bundesland-blacklists.ts
T
Benjamin Admin 2b4ff9f422 feat: DSFA — VVT-Verknüpfung + Residual Risk + Bundesland-Blacklists
1. VVT-Verknüpfung: Dropdown "Verknüpfte VVT-Aktivität" in Step 1,
   lädt Aktivitäten via API, auto-fills Verarbeitungstätigkeit bei Auswahl

2. Residual Risk: Neuer Step 5 im Wizard — Bewertung des Restrisikos
   nach Maßnahmen. Bei hoch/kritisch → Art. 36 Vorabkonsultation Warnung

3. Bundesland-Blacklists (Art. 35 Abs. 4): 16 Landesbehörden mit
   DSK-Muss-Liste (10 gemeinsame Kriterien) + länderspezifische
   Ergänzungen (Bayern: Whistleblower/Drohnen, NRW: Social-Media-
   Monitoring, Berlin: Mieterbonitätsprüfung). Automatische Prüfung
   gegen Scope-Antworten. Blacklist-Matches im DSFA-Banner angezeigt.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-04 21:48:59 +02:00

114 lines
7.4 KiB
TypeScript

/**
* DSFA Bundesland-Blacklists — Verarbeitungen die IMMER eine DSFA erfordern.
*
* Jede Aufsichtsbehoerde fuehrt eine eigene Positiv-/Negativliste
* gemaess Art. 35 Abs. 4 DSGVO. Diese Listen definieren Verarbeitungen
* die UNABHAENGIG von der Schwellwertanalyse eine DSFA erfordern.
*
* Quellen: Offizielle Muss-Listen der LfDI/BfDI (oeffentlich zugaenglich).
* KEIN Normtext — eigene Zusammenfassung der Kriterien.
*/
export interface BlacklistEntry {
id: string
description: string
triggerKeywords: string[]
}
export interface BundeslandBlacklist {
state: string
stateCode: string
authority: string
authorityUrl: string
entries: BlacklistEntry[]
}
// Gemeinsame Kriterien die in ALLEN Bundeslaendern gelten (DSK-Liste)
const DSK_COMMON: BlacklistEntry[] = [
{ id: 'dsk-01', description: 'Umfangreiche Verarbeitung besonderer Kategorien (Art. 9)', triggerKeywords: ['art9', 'gesundheit', 'biometrie', 'genetik', 'religion', 'gewerkschaft'] },
{ id: 'dsk-02', description: 'Systematische umfangreiche Ueberwachung oeffentlicher Bereiche', triggerKeywords: ['videoueberwachung', 'kamera', 'oeffentlich', 'ueberwachung'] },
{ id: 'dsk-03', description: 'Scoring/Profiling mit rechtlicher Wirkung', triggerKeywords: ['scoring', 'profiling', 'bonitaet', 'kredit', 'automatisiert'] },
{ id: 'dsk-04', description: 'Verarbeitung von Daten Minderjaehriger fuer Marketing/Profiling', triggerKeywords: ['minderjaehrig', 'kinder', 'schueler', 'marketing'] },
{ id: 'dsk-05', description: 'Zusammenfuehrung von Daten aus verschiedenen Quellen', triggerKeywords: ['zusammenfuehrung', 'matching', 'datenfusion', 'big data'] },
{ id: 'dsk-06', description: 'Einsatz neuer Technologien (KI, Biometrie, IoT)', triggerKeywords: ['ki', 'kuenstliche intelligenz', 'biometrie', 'iot', 'gesichtserkennung'] },
{ id: 'dsk-07', description: 'Umfangreiche Verarbeitung von Standortdaten', triggerKeywords: ['standort', 'gps', 'tracking', 'bewegungsprofil'] },
{ id: 'dsk-08', description: 'Verarbeitung von Beschaeftigtendaten mit Ueberwachungscharakter', triggerKeywords: ['mitarbeiterueberwachung', 'keylogger', 'bildschirmaufnahme', 'leistungskontrolle'] },
{ id: 'dsk-09', description: 'Anonymisierung besonderer Kategorien', triggerKeywords: ['anonymisierung', 'art9', 'pseudonymisierung'] },
{ id: 'dsk-10', description: 'Verarbeitung von Kommunikationsinhalten oder -metadaten', triggerKeywords: ['kommunikation', 'email', 'telefon', 'metadaten', 'inhaltsdaten'] },
]
// Bundesland-spezifische Ergaenzungen
const BAYERN_EXTRA: BlacklistEntry[] = [
{ id: 'by-01', description: 'Betrieb von Whistleblower-Systemen mit Identifizierungsrisiko', triggerKeywords: ['whistleblower', 'hinweisgeber', 'meldesystem'] },
{ id: 'by-02', description: 'Einsatz von Drohnen mit Kamera in oeffentlichen Bereichen', triggerKeywords: ['drohne', 'uav', 'luftaufnahme'] },
]
const NRW_EXTRA: BlacklistEntry[] = [
{ id: 'nw-01', description: 'Social-Media-Monitoring von Mitarbeitern oder Bewerbern', triggerKeywords: ['social media', 'monitoring', 'bewerber', 'hintergrundcheck'] },
]
const BERLIN_EXTRA: BlacklistEntry[] = [
{ id: 'be-01', description: 'Automatisierte Mieterbonitaetspruefung', triggerKeywords: ['mieter', 'bonitaet', 'wohnung', 'schufa'] },
]
export const BUNDESLAND_BLACKLISTS: Record<string, BundeslandBlacklist> = {
BW: { state: 'Baden-Wuerttemberg', stateCode: 'BW', authority: 'LfDI BW', authorityUrl: 'https://www.baden-wuerttemberg.datenschutz.de', entries: [...DSK_COMMON] },
BY: { state: 'Bayern', stateCode: 'BY', authority: 'BayLDA', authorityUrl: 'https://www.lda.bayern.de', entries: [...DSK_COMMON, ...BAYERN_EXTRA] },
BE: { state: 'Berlin', stateCode: 'BE', authority: 'BlnBDI', authorityUrl: 'https://www.datenschutz-berlin.de', entries: [...DSK_COMMON, ...BERLIN_EXTRA] },
BB: { state: 'Brandenburg', stateCode: 'BB', authority: 'LDA BB', authorityUrl: 'https://www.lda.brandenburg.de', entries: [...DSK_COMMON] },
HB: { state: 'Bremen', stateCode: 'HB', authority: 'LfDI HB', authorityUrl: 'https://www.datenschutz.bremen.de', entries: [...DSK_COMMON] },
HH: { state: 'Hamburg', stateCode: 'HH', authority: 'HmbBfDI', authorityUrl: 'https://datenschutz-hamburg.de', entries: [...DSK_COMMON] },
HE: { state: 'Hessen', stateCode: 'HE', authority: 'HBDI', authorityUrl: 'https://datenschutz.hessen.de', entries: [...DSK_COMMON] },
MV: { state: 'Mecklenburg-Vorpommern', stateCode: 'MV', authority: 'LfDI MV', authorityUrl: 'https://www.datenschutz-mv.de', entries: [...DSK_COMMON] },
NI: { state: 'Niedersachsen', stateCode: 'NI', authority: 'LfD NI', authorityUrl: 'https://lfd.niedersachsen.de', entries: [...DSK_COMMON] },
NW: { state: 'Nordrhein-Westfalen', stateCode: 'NW', authority: 'LDI NRW', authorityUrl: 'https://www.ldi.nrw.de', entries: [...DSK_COMMON, ...NRW_EXTRA] },
RP: { state: 'Rheinland-Pfalz', stateCode: 'RP', authority: 'LfDI RP', authorityUrl: 'https://www.datenschutz.rlp.de', entries: [...DSK_COMMON] },
SL: { state: 'Saarland', stateCode: 'SL', authority: 'UDZ Saarland', authorityUrl: 'https://www.datenschutz.saarland.de', entries: [...DSK_COMMON] },
SN: { state: 'Sachsen', stateCode: 'SN', authority: 'SDB', authorityUrl: 'https://www.saechsdsb.de', entries: [...DSK_COMMON] },
ST: { state: 'Sachsen-Anhalt', stateCode: 'ST', authority: 'LfD LSA', authorityUrl: 'https://datenschutz.sachsen-anhalt.de', entries: [...DSK_COMMON] },
SH: { state: 'Schleswig-Holstein', stateCode: 'SH', authority: 'ULD SH', authorityUrl: 'https://www.datenschutzzentrum.de', entries: [...DSK_COMMON] },
TH: { state: 'Thueringen', stateCode: 'TH', authority: 'TLfDI', authorityUrl: 'https://www.tlfdi.de', entries: [...DSK_COMMON] },
}
/**
* Check scope answers against Bundesland blacklist.
* Returns matching entries that REQUIRE a DSFA.
*/
export function checkBlacklist(
stateCode: string,
scopeKeywords: string[],
): { matches: BlacklistEntry[]; authority: string; authorityUrl: string } {
const bl = BUNDESLAND_BLACKLISTS[stateCode]
if (!bl) return { matches: [], authority: 'BfDI', authorityUrl: 'https://www.bfdi.bund.de' }
const lowerKeywords = scopeKeywords.map(k => k.toLowerCase())
const matches = bl.entries.filter(entry =>
entry.triggerKeywords.some(tk => lowerKeywords.some(kw => kw.includes(tk) || tk.includes(kw)))
)
return { matches, authority: bl.authority, authorityUrl: bl.authorityUrl }
}
/**
* Derive keywords from scope answers for blacklist matching.
*/
export function scopeAnswersToKeywords(answers: Array<{ questionId: string; value: unknown }>): string[] {
const keywords: string[] = []
for (const a of answers) {
if (a.value === true || a.value === 'yes') {
keywords.push(a.questionId.replace(/_/g, ' '))
// Map specific question IDs to keywords
if (a.questionId === 'data_art9') keywords.push('art9', 'besondere kategorien')
if (a.questionId === 'data_minors') keywords.push('minderjaehrig', 'kinder')
if (a.questionId === 'proc_adm_scoring') keywords.push('scoring', 'profiling', 'automatisiert')
if (a.questionId === 'proc_video_surveillance') keywords.push('videoueberwachung', 'kamera')
if (a.questionId === 'proc_ai_usage') keywords.push('ki', 'kuenstliche intelligenz')
if (a.questionId === 'proc_employee_monitoring') keywords.push('mitarbeiterueberwachung')
}
if (Array.isArray(a.value)) {
for (const v of a.value) keywords.push(String(v).toLowerCase())
}
}
return keywords
}