/** * 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 = { 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 }