feat(vvt): Aufklappbare Abteilungskacheln mit Datenkategorien + Wiki-Infoboxen
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 35s
CI / test-python-backend-compliance (push) Successful in 37s
CI / test-python-document-crawler (push) Successful in 24s
CI / test-python-dsms-gateway (push) Successful in 23s

Step 2 im VVT-Generator: Ja/Nein-Buttons durch expandierbare Kacheln ersetzt.
Pro Abteilung werden typische Datenkategorien als Checkboxen angezeigt (isTypical
vorausgefuellt), Art. 9 Kategorien orange hervorgehoben mit DSGVO-Warnung.
7 neue Wiki-Artikel fuer Datenkategorien pro Geschaeftsbereich (HR, Finanzen,
Vertrieb, Marketing, Support, IT, Produktion).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Benjamin Admin
2026-03-10 13:11:00 +01:00
parent 3512963006
commit e3fb81fc0d
3 changed files with 768 additions and 48 deletions

View File

@@ -34,6 +34,7 @@ import type { VVTActivity, VVTOrganizationHeader, BusinessFunction } from '@/lib
import {
PROFILING_STEPS,
PROFILING_QUESTIONS,
DEPARTMENT_DATA_CATEGORIES,
getQuestionsForStep,
getStepProgress,
getTotalProgress,
@@ -1100,61 +1101,187 @@ function TabGenerator({
<p className="text-sm text-gray-500 mt-1">{currentStepInfo?.description}</p>
<div className="mt-6 space-y-6">
{questions.map(q => (
<div key={q.id}>
<label className="block text-sm font-medium text-gray-700 mb-2">{q.question}</label>
{q.helpText && <p className="text-xs text-gray-400 mb-2">{q.helpText}</p>}
{questions.map(q => {
const deptConfig = DEPARTMENT_DATA_CATEGORIES[q.id]
const isDeptQuestion = q.type === 'boolean' && q.step === 2 && deptConfig
const isActive = answers[q.id] === true
const categoriesKey = `${q.id}_categories`
const selectedCategories = (answers[categoriesKey] as string[] | undefined) || []
{q.type === 'boolean' && (
<div className="flex items-center gap-4">
<label className="flex items-center gap-2 cursor-pointer">
<input type="radio" name={q.id} checked={answers[q.id] === true}
onChange={() => setAnswers({ ...answers, [q.id]: true })}
className="w-4 h-4 text-purple-600" />
<span className="text-sm">Ja</span>
</label>
<label className="flex items-center gap-2 cursor-pointer">
<input type="radio" name={q.id} checked={answers[q.id] === false}
onChange={() => setAnswers({ ...answers, [q.id]: false })}
className="w-4 h-4 text-purple-600" />
<span className="text-sm">Nein</span>
</label>
// Initialize typical categories when dept is activated
const handleDeptToggle = (value: boolean) => {
const updated = { ...answers, [q.id]: value }
if (value && deptConfig && !answers[categoriesKey]) {
// Prefill typical categories
updated[categoriesKey] = deptConfig.categories
.filter(c => c.isTypical)
.map(c => c.id)
}
setAnswers(updated)
}
const handleCategoryToggle = (catId: string) => {
const current = (answers[categoriesKey] as string[] | undefined) || []
const updated = current.includes(catId)
? current.filter(id => id !== catId)
: [...current, catId]
setAnswers({ ...answers, [categoriesKey]: updated })
}
// Expandable department tile (Step 2)
if (isDeptQuestion) {
const hasArt9Selected = deptConfig.categories
.filter(c => c.isArt9)
.some(c => selectedCategories.includes(c.id))
return (
<div key={q.id} className={`border rounded-xl overflow-hidden transition-all ${
isActive ? 'border-purple-400 bg-white shadow-sm' : 'border-gray-200 bg-white'
}`}>
{/* Header row with Ja/Nein */}
<div className="flex items-center justify-between p-4">
<div className="flex items-center gap-3">
<span className="text-xl">{deptConfig.icon}</span>
<div>
<span className="text-sm font-medium text-gray-900">{deptConfig.label}</span>
{q.helpText && <p className="text-xs text-gray-400">{q.helpText}</p>}
</div>
</div>
<div className="flex items-center gap-2">
<button
type="button"
onClick={() => handleDeptToggle(true)}
className={`px-3 py-1.5 text-xs font-medium rounded-lg transition-colors ${
isActive ? 'bg-purple-600 text-white' : 'bg-gray-100 text-gray-600 hover:bg-gray-200'
}`}
>
Ja
</button>
<button
type="button"
onClick={() => handleDeptToggle(false)}
className={`px-3 py-1.5 text-xs font-medium rounded-lg transition-colors ${
answers[q.id] === false ? 'bg-gray-600 text-white' : 'bg-gray-100 text-gray-600 hover:bg-gray-200'
}`}
>
Nein
</button>
</div>
</div>
{/* Expandable categories panel */}
{isActive && (
<div className="border-t border-gray-100 px-4 pt-3 pb-4">
<p className="text-xs font-medium text-gray-500 uppercase tracking-wide mb-3">
Typische Datenkategorien
</p>
<div className="space-y-1.5">
{deptConfig.categories.map(cat => {
const isChecked = selectedCategories.includes(cat.id)
return (
<label
key={cat.id}
className={`flex items-start gap-3 p-2.5 rounded-lg cursor-pointer transition-colors ${
cat.isArt9
? isChecked ? 'bg-orange-50 hover:bg-orange-100' : 'bg-gray-50 hover:bg-orange-50'
: isChecked ? 'bg-purple-50 hover:bg-purple-100' : 'bg-gray-50 hover:bg-gray-100'
}`}
>
<input
type="checkbox"
checked={isChecked}
onChange={() => handleCategoryToggle(cat.id)}
className={`w-4 h-4 mt-0.5 rounded ${cat.isArt9 ? 'text-orange-500' : 'text-purple-600'}`}
/>
<div className="flex-1 min-w-0">
<div className="flex items-center gap-2">
<span className="text-sm font-medium text-gray-900">{cat.label}</span>
{cat.isArt9 && (
<span className="px-1.5 py-0.5 text-[10px] font-semibold bg-orange-100 text-orange-700 rounded">
Art. 9
</span>
)}
</div>
<p className="text-xs text-gray-500 mt-0.5">{cat.info}</p>
</div>
</label>
)
})}
</div>
{/* Art. 9 warning */}
{hasArt9Selected && (
<div className="mt-3 p-3 bg-orange-50 border border-orange-200 rounded-lg">
<p className="text-xs text-orange-800">
<span className="font-semibold">Art. 9 DSGVO:</span> Sie verarbeiten besondere Kategorien
personenbezogener Daten. Eine zusaetzliche Rechtsgrundlage nach Art. 9 Abs. 2 DSGVO ist
erforderlich (z.B. § 26 Abs. 3 BDSG fuer Beschaeftigtendaten).
</p>
</div>
)}
</div>
)}
</div>
)}
)
}
{q.type === 'single_choice' && q.options && (
<div className="grid grid-cols-2 md:grid-cols-3 gap-2">
{q.options.map(opt => (
<label
key={opt.value}
className={`flex items-center gap-2 p-3 border rounded-lg cursor-pointer transition-colors ${
answers[q.id] === opt.value ? 'border-purple-500 bg-purple-50' : 'border-gray-200 hover:border-gray-300'
}`}
>
<input type="radio" name={q.id} value={opt.value}
checked={answers[q.id] === opt.value}
onChange={() => setAnswers({ ...answers, [q.id]: opt.value })}
// Standard rendering for non-department questions
return (
<div key={q.id}>
<label className="block text-sm font-medium text-gray-700 mb-2">{q.question}</label>
{q.helpText && <p className="text-xs text-gray-400 mb-2">{q.helpText}</p>}
{q.type === 'boolean' && (
<div className="flex items-center gap-4">
<label className="flex items-center gap-2 cursor-pointer">
<input type="radio" name={q.id} checked={answers[q.id] === true}
onChange={() => setAnswers({ ...answers, [q.id]: true })}
className="w-4 h-4 text-purple-600" />
<span className="text-sm">{opt.label}</span>
<span className="text-sm">Ja</span>
</label>
))}
</div>
)}
<label className="flex items-center gap-2 cursor-pointer">
<input type="radio" name={q.id} checked={answers[q.id] === false}
onChange={() => setAnswers({ ...answers, [q.id]: false })}
className="w-4 h-4 text-purple-600" />
<span className="text-sm">Nein</span>
</label>
</div>
)}
{q.type === 'number' && (
<input type="number" value={typeof answers[q.id] === 'number' ? answers[q.id] as number : ''}
onChange={(e) => setAnswers({ ...answers, [q.id]: parseInt(e.target.value) || 0 })}
className="w-40 px-3 py-2 border border-gray-300 rounded-lg"
placeholder="Anzahl" />
)}
{q.type === 'single_choice' && q.options && (
<div className="grid grid-cols-2 md:grid-cols-3 gap-2">
{q.options.map(opt => (
<label
key={opt.value}
className={`flex items-center gap-2 p-3 border rounded-lg cursor-pointer transition-colors ${
answers[q.id] === opt.value ? 'border-purple-500 bg-purple-50' : 'border-gray-200 hover:border-gray-300'
}`}
>
<input type="radio" name={q.id} value={opt.value}
checked={answers[q.id] === opt.value}
onChange={() => setAnswers({ ...answers, [q.id]: opt.value })}
className="w-4 h-4 text-purple-600" />
<span className="text-sm">{opt.label}</span>
</label>
))}
</div>
)}
{q.type === 'text' && (
<input type="text" value={(answers[q.id] as string) || ''}
onChange={(e) => setAnswers({ ...answers, [q.id]: e.target.value })}
className="w-full px-3 py-2 border border-gray-300 rounded-lg" />
)}
</div>
))}
{q.type === 'number' && (
<input type="number" value={typeof answers[q.id] === 'number' ? answers[q.id] as number : ''}
onChange={(e) => setAnswers({ ...answers, [q.id]: parseInt(e.target.value) || 0 })}
className="w-40 px-3 py-2 border border-gray-300 rounded-lg"
placeholder="Anzahl" />
)}
{q.type === 'text' && (
<input type="text" value={(answers[q.id] as string) || ''}
onChange={(e) => setAnswers({ ...answers, [q.id]: e.target.value })}
className="w-full px-3 py-2 border border-gray-300 rounded-lg" />
)}
</div>
)
})}
</div>
</div>

View File

@@ -285,6 +285,103 @@ export const PROFILING_QUESTIONS: ProfilingQuestion[] = [
},
]
// =============================================================================
// DEPARTMENT DATA CATEGORIES (Aufklappbare Kacheln Step 2)
// =============================================================================
export interface DepartmentCategory {
id: string
label: string
info: string
isArt9?: boolean
isTypical?: boolean
}
export interface DepartmentDataConfig {
label: string
icon: string
categories: DepartmentCategory[]
}
export const DEPARTMENT_DATA_CATEGORIES: Record<string, DepartmentDataConfig> = {
dept_hr: {
label: 'Personal (HR)',
icon: '👥',
categories: [
{ id: 'NAME', label: 'Stammdaten', info: 'Vor-/Nachname, Titel, Geschlecht, Geburtsdatum', isTypical: true },
{ id: 'ADDRESS', label: 'Adressdaten', info: 'Wohn-/Melde-/Lieferadresse, Telefon, E-Mail', isTypical: true },
{ id: 'SOCIAL_SECURITY', label: 'Sozialversicherungsnr.', info: 'SV-Nummer fuer Meldungen an DRV, Krankenkasse', isTypical: true },
{ id: 'TAX_ID', label: 'Steuer-ID', info: 'Steueridentifikationsnummer, Steuerklasse, Freibetraege', isTypical: true },
{ id: 'BANK_ACCOUNT', label: 'Bankverbindung', info: 'IBAN, BIC fuer Gehaltsueberweisungen', isTypical: true },
{ id: 'SALARY_DATA', label: 'Gehaltsdaten', info: 'Bruttogehalt, Zulagen, Praemien, VWL, Abzuege', isTypical: true },
{ id: 'EMPLOYMENT_DATA', label: 'Beschaeftigungsdaten', info: 'Vertrag, Eintrittsdatum, Abteilung, Position, Arbeitszeitmodell', isTypical: true },
{ id: 'HEALTH_DATA', label: 'Gesundheitsdaten', info: 'Krankheitstage (AU-Bescheinigungen), BEM-Daten, Schwerbehinderung', isArt9: true },
{ id: 'RELIGIOUS_BELIEFS', label: 'Religionszugehoerigkeit', info: 'Konfession fuer Kirchensteuer-Abfuehrung', isArt9: true },
{ id: 'EDUCATION_DATA', label: 'Qualifikationen', info: 'Abschluesse, Zertifikate, Weiterbildungen, Schulungsnachweise' },
{ id: 'PHOTO_VIDEO', label: 'Mitarbeiterfotos', info: 'Passbilder fuer Ausweise, Intranet-Profilbilder' },
]
},
dept_recruiting: {
label: 'Recruiting / Bewerbermanagement',
icon: '📋',
categories: [
{ id: 'NAME', label: 'Bewerberstammdaten', info: 'Name, Anschrift, Kontaktdaten der Bewerber', isTypical: true },
{ id: 'APPLICATION_DATA', label: 'Bewerbungsunterlagen', info: 'Lebenslauf, Anschreiben, Zeugnisse, Zertifikate', isTypical: true },
{ id: 'EDUCATION_DATA', label: 'Qualifikationen', info: 'Abschluesse, Berufserfahrung, Sprachkenntnisse', isTypical: true },
{ id: 'ASSESSMENT_DATA', label: 'Bewertungsdaten', info: 'Interviewnotizen, Assessment-Ergebnisse, Eignungstests' },
{ id: 'HEALTH_DATA', label: 'Gesundheitsdaten', info: 'Schwerbehinderung (freiwillige Angabe), Eignungsuntersuchung', isArt9: true },
{ id: 'PHOTO_VIDEO', label: 'Bewerbungsfotos', info: 'Bewerbungsfoto (freiwillig), Video-Interview-Aufnahmen' },
]
},
dept_finance: {
label: 'Finanzen & Buchhaltung',
icon: '💰',
categories: [
{ id: 'NAME', label: 'Kunden-/Lieferantenstammdaten', info: 'Firmenname, Ansprechpartner, Kontaktdaten', isTypical: true },
{ id: 'ADDRESS', label: 'Rechnungsadressen', info: 'Rechnungs-/Lieferadressen, USt-IdNr.', isTypical: true },
{ id: 'BANK_ACCOUNT', label: 'Bankverbindungen', info: 'IBAN, BIC, SEPA-Mandate, Zahlungsbedingungen', isTypical: true },
{ id: 'TAX_ID', label: 'Steuer-IDs', info: 'Steuernummer, USt-IdNr., Steueridentifikationsnr.', isTypical: true },
{ id: 'INVOICE_DATA', label: 'Rechnungsdaten', info: 'Rechnungen, Gutschriften, Mahnungen, Zahlungshistorie', isTypical: true },
{ id: 'CONTRACT_DATA', label: 'Vertragsdaten', info: 'Vertragskonditionen, Laufzeiten, Kuendigungsfristen' },
]
},
dept_sales: {
label: 'Vertrieb & CRM',
icon: '🤝',
categories: [
{ id: 'NAME', label: 'Kontaktdaten', info: 'Name, E-Mail, Telefon, Position der Ansprechpartner', isTypical: true },
{ id: 'ADDRESS', label: 'Firmenadresse', info: 'Firmenanschrift, Standorte', isTypical: true },
{ id: 'CRM_DATA', label: 'CRM-Daten', info: 'Lead-Status, Opportunities, Sales-Pipeline, Umsatzhistorie', isTypical: true },
{ id: 'COMMUNICATION_DATA', label: 'Kommunikation', info: 'E-Mail-Verlauf, Gespraechsnotizen, Meeting-Protokolle', isTypical: true },
{ id: 'CONTRACT_DATA', label: 'Vertragsdaten', info: 'Angebote, Bestellungen, Rahmenvertraege' },
{ id: 'PREFERENCE_DATA', label: 'Praeferenzen', info: 'Produktinteressen, Kaufhistorie, Kundensegmentierung' },
]
},
dept_marketing: {
label: 'Marketing',
icon: '📢',
categories: [
{ id: 'EMAIL', label: 'E-Mail-Adressen', info: 'Newsletter-Abonnenten, Kampagnen-Empfaenger', isTypical: true },
{ id: 'TRACKING_DATA', label: 'Tracking-/Analytics-Daten', info: 'IP-Adressen, Cookies, Seitenaufrufe, Klickpfade', isTypical: true },
{ id: 'CONSENT_DATA', label: 'Einwilligungsdaten', info: 'Cookie-Consent, Newsletter-Opt-in, Widerrufe', isTypical: true },
{ id: 'SOCIAL_MEDIA_DATA', label: 'Social-Media-Daten', info: 'Follower-Interaktionen, Kommentare, Reichweitendaten' },
{ id: 'PREFERENCE_DATA', label: 'Interessenprofil', info: 'Produktinteressen, Segmentierung, A/B-Test-Zuordnungen' },
{ id: 'PHOTO_VIDEO', label: 'Bild-/Videomaterial', info: 'Kundenfotos (Testimonials), Event-Aufnahmen, UGC' },
]
},
dept_support: {
label: 'Kundenservice / Support',
icon: '🎧',
categories: [
{ id: 'NAME', label: 'Kundenstammdaten', info: 'Name, E-Mail, Telefon, Kundennummer', isTypical: true },
{ id: 'TICKET_DATA', label: 'Ticket-/Anfragedaten', info: 'Ticketnummer, Betreff, Beschreibung, Status, Prioritaet', isTypical: true },
{ id: 'COMMUNICATION_DATA', label: 'Kommunikationsverlauf', info: 'E-Mails, Chat-Protokolle, Anrufnotizen', isTypical: true },
{ id: 'CONTRACT_DATA', label: 'Vertragsdaten', info: 'Produktversion, Lizenz, SLA-Status', isTypical: true },
{ id: 'TECHNICAL_DATA', label: 'Technische Daten', info: 'Systeminfos, Logdateien, Screenshots bei Fehlermeldungen' },
]
},
}
// =============================================================================
// GENERATOR LOGIC
// =============================================================================

View File

@@ -0,0 +1,496 @@
-- Migration 043: Wiki-Artikel fuer Datenkategorien pro Abteilung
-- Liefert Hintergrundwissen zu den typischen personenbezogenen Daten
-- je Geschaeftsbereich (Step 2 des VVT-Generators).
-- =============================================================================
-- 1. Artikel: Datenkategorien in der Personalabteilung
-- =============================================================================
INSERT INTO compliance_wiki_articles (id, category_id, title, summary, content, legal_refs, tags, relevance, version)
VALUES (
'dk-personal-hr',
'datenkategorien',
'Datenkategorien in der Personalabteilung',
'Ueberblick ueber personenbezogene Daten, die typischerweise in HR verarbeitet werden — von Stammdaten bis Art. 9 Kategorien.',
'## Ueberblick
Die Personalabteilung verarbeitet die **umfangreichsten** personenbezogenen Daten im Unternehmen. Die Rechtsgrundlage ist primaer **§ 26 BDSG** (Beschaeftigtendatenschutz) i.V.m. Art. 88 DSGVO.
## Typische Datenkategorien
### Stamm- und Kontaktdaten
- **Personalien:** Vor-/Nachname, Geburtsdatum, Geschlecht, Staatsangehoerigkeit
- **Kontaktdaten:** Wohnadresse, Telefon, E-Mail (privat + dienstlich)
- **Identifikation:** Personalnummer, Ausweis-/Passdaten (bei Auslandseinsatz)
### Vertragsdaten
- Arbeitsvertrag, Eintrittsdatum, Befristung, Kuendigungsfristen
- Abteilung, Position, Vorgesetzter, Kostenstelle
- Arbeitszeitmodell (Vollzeit/Teilzeit/Gleitzeit)
### Vergütungsdaten
- **Gehaltsdaten:** Bruttogehalt, Zulagen, Praemien, VWL
- **Bankverbindung:** IBAN, BIC fuer Lohn-/Gehaltszahlung
- **Steuer-ID:** IdNr., Steuerklasse, Freibetraege, Kirchensteuer
- **Sozialversicherung:** SV-Nummer, Krankenkasse, Beitragssaetze
### Besondere Kategorien (Art. 9 DSGVO)
- **Gesundheitsdaten:** AU-Bescheinigungen (auch ohne Diagnose!), BEM-Daten, Schwerbehindertenausweis, arbeitsmedizinische Vorsorge
- **Religionszugehoerigkeit:** Konfession fuer Kirchensteuer-Abfuehrung (Pflichtfeld Lohnsteuer)
- **Gewerkschaftszugehoerigkeit:** Nur wenn Gewerkschaftsbeitrag ueber Gehalt abgefuehrt wird
### Weitere Kategorien
- **Qualifikationen:** Abschluesse, Zertifikate, Weiterbildungsnachweise
- **Zeiterfassung:** Arbeitsstunden, Ueberstunden, Urlaubstage, Fehlzeiten
- **Fotos:** Mitarbeiterausweis, Intranet-Profilbild (Einwilligung!)
## Rechtsgrundlagen
| Verarbeitung | Rechtsgrundlage |
|--------------|-----------------|
| Personalverwaltung | § 26 Abs. 1 BDSG |
| Gehaltsabrechnung | Art. 6 Abs. 1 lit. b + c DSGVO |
| Gesundheitsdaten | § 26 Abs. 3 BDSG + Art. 9 Abs. 2 lit. b DSGVO |
| Kirchensteuer | Art. 6 Abs. 1 lit. c DSGVO (gesetzl. Pflicht) |
| Mitarbeiterfotos | Art. 6 Abs. 1 lit. a DSGVO (Einwilligung) |
## Typische Systeme
SAP HCM/SuccessFactors, DATEV LODAS/Lohn&Gehalt, Personio, HRworks, ATOSS, Sage HR
## Aufbewahrungsfristen
- **Lohnunterlagen:** 6 Jahre (§ 257 HGB)
- **Steuerunterlagen:** 10 Jahre (§ 147 AO)
- **Bewerbungsunterlagen:** 6 Monate nach Ablehnung (AGG-Frist)
- **AU-Bescheinigungen:** Bis 3 Jahre nach Ende des Kalenderjahrests
- **BEM-Akten:** 3 Jahre nach Abschluss des BEM',
ARRAY['§ 26 BDSG', 'Art. 88 DSGVO', 'Art. 9 Abs. 2 lit. b DSGVO', 'Art. 6 Abs. 1 DSGVO', '§ 257 HGB', '§ 147 AO'],
ARRAY['personal', 'hr', 'stammdaten', 'gehalt', 'gesundheit', 'art9', 'beschaeftigtendaten'],
'critical',
1
) ON CONFLICT (id) DO UPDATE SET
content = EXCLUDED.content,
summary = EXCLUDED.summary,
legal_refs = EXCLUDED.legal_refs,
tags = EXCLUDED.tags,
version = compliance_wiki_articles.version + 1,
updated_at = NOW();
-- =============================================================================
-- 2. Artikel: Datenkategorien in Finanzen & Buchhaltung
-- =============================================================================
INSERT INTO compliance_wiki_articles (id, category_id, title, summary, content, legal_refs, tags, relevance, version)
VALUES (
'dk-finanzen',
'datenkategorien',
'Datenkategorien in Finanzen & Buchhaltung',
'Personenbezogene Daten in der Buchhaltung: Kunden-/Lieferantenstammdaten, Bankverbindungen, Rechnungsdaten und steuerliche Pflichten.',
'## Ueberblick
Die Finanz- und Buchhaltungsabteilung verarbeitet personenbezogene Daten von **Kunden, Lieferanten und Mitarbeitern** im Rahmen gesetzlicher Buchfuehrungs- und Aufbewahrungspflichten.
## Typische Datenkategorien
### Stammdaten (Debitoren/Kreditoren)
- Firmenname, Rechtsform, Ansprechpartner
- Rechnungs- und Lieferadressen
- USt-IdNr., Steuernummer
- Kundennummer, Lieferantennummer
### Zahlungsverkehr
- **Bankverbindungen:** IBAN, BIC, Kontoinhaber
- **SEPA-Mandate:** Mandatsreferenz, Unterschriftsdatum
- **Zahlungsbedingungen:** Skonto, Zahlungsziel, Kreditlimit
### Rechnungsdaten
- Eingangs-/Ausgangsrechnungen mit Personenbezug
- Gutschriften, Mahnungen, Zahlungshistorie
- Reisekostenabrechnungen (Mitarbeiter)
### Steuerrelevante Daten
- Steuer-IDs (Arbeitnehmer, Freelancer)
- Lohnsteuerabzugsmerkmale (ELStAM)
- Umsatzsteuer-Voranmeldungen
## Rechtsgrundlagen
| Verarbeitung | Rechtsgrundlage |
|--------------|-----------------|
| Buchfuehrungspflicht | Art. 6 Abs. 1 lit. c DSGVO + §§ 238, 257 HGB |
| Rechnungsstellung | Art. 6 Abs. 1 lit. b DSGVO (Vertragserfuellung) |
| Steuerliche Pflichten | Art. 6 Abs. 1 lit. c DSGVO + §§ 140-148 AO |
| Zahlungsverkehr | Art. 6 Abs. 1 lit. b DSGVO |
## Typische Systeme
DATEV, SAP FI, Lexware, Sage, ERPNext, Microsoft Dynamics
## Aufbewahrungsfristen
- **Buchungsbelege:** 10 Jahre (§ 147 Abs. 1 Nr. 1 AO)
- **Handelsbriefe:** 6 Jahre (§ 257 Abs. 1 Nr. 2 HGB)
- **Rechnungen:** 10 Jahre (§ 14b UStG)
- **SEPA-Mandate:** 14 Monate nach letzter Lastschrift + Aufbewahrungsfrist',
ARRAY['Art. 6 Abs. 1 lit. c DSGVO', '§ 257 HGB', '§ 147 AO', '§ 14b UStG', 'Art. 6 Abs. 1 lit. b DSGVO'],
ARRAY['finanzen', 'buchhaltung', 'bankdaten', 'steuer', 'rechnungen', 'aufbewahrung'],
'important',
1
) ON CONFLICT (id) DO UPDATE SET
content = EXCLUDED.content,
summary = EXCLUDED.summary,
legal_refs = EXCLUDED.legal_refs,
tags = EXCLUDED.tags,
version = compliance_wiki_articles.version + 1,
updated_at = NOW();
-- =============================================================================
-- 3. Artikel: Datenkategorien im Vertrieb & CRM
-- =============================================================================
INSERT INTO compliance_wiki_articles (id, category_id, title, summary, content, legal_refs, tags, relevance, version)
VALUES (
'dk-vertrieb-crm',
'datenkategorien',
'Datenkategorien im Vertrieb & CRM',
'CRM-Kontaktdaten, Kommunikationshistorie, Vertragsdaten und Praeferenzprofile im Vertrieb.',
'## Ueberblick
Der Vertrieb verarbeitet personenbezogene Daten von **Interessenten, Leads und Bestandskunden** primaer im CRM-System. Die Rechtsgrundlage ist meist **Art. 6 Abs. 1 lit. b DSGVO** (Vertragsanbahnung/-erfuellung) oder **lit. f** (berechtigtes Interesse).
## Typische Datenkategorien
### Kontaktdaten
- Name, E-Mail, Telefon, Position des Ansprechpartners
- Firmenname, Branche, Unternehmensgroesse
- Firmenadresse, Standorte
### CRM-Daten
- Lead-Status, Sales-Pipeline-Stufe
- Opportunities, Umsatzpotenzial
- Kundenhistorie, Umsatzentwicklung
- Kundensegmentierung, Key-Account-Zuordnung
### Kommunikationsdaten
- E-Mail-Verlauf (Angebote, Anfragen)
- Gespraechsnotizen, Meeting-Protokolle
- Angebots- und Bestellhistorie
### Vertragsdaten
- Rahmenvertraege, Einzelbestellungen
- Konditionen, Rabattstaffeln
- Laufzeiten, Kuendigungsfristen
### Praeferenzdaten
- Produktinteressen, Kaufhistorie
- Cross-/Upselling-Potenziale
- Bevorzugte Kommunikationskanaele
## Rechtsgrundlagen
| Verarbeitung | Rechtsgrundlage |
|--------------|-----------------|
| Vertragsanbahnung | Art. 6 Abs. 1 lit. b DSGVO |
| Bestandskundenpflege | Art. 6 Abs. 1 lit. f DSGVO |
| Kaltakquise (B2B) | Art. 6 Abs. 1 lit. f DSGVO + § 7 UWG |
| Kaltakquise (B2C) | Art. 6 Abs. 1 lit. a DSGVO (Einwilligung!) |
## Typische Systeme
Salesforce, HubSpot, Pipedrive, Zoho CRM, Microsoft Dynamics 365, SAP CRM
## Aufbewahrungsfristen
- **Vertraege:** 3 Jahre nach Vertragsende (Verjaehrung) + steuerlich 10 Jahre
- **Angebote (abgelehnt):** 6 Monate
- **CRM-Kontaktdaten:** Bis Widerspruch/Loeschung oder 3 Jahre nach letztem Kontakt',
ARRAY['Art. 6 Abs. 1 lit. b DSGVO', 'Art. 6 Abs. 1 lit. f DSGVO', '§ 7 UWG', 'Art. 21 DSGVO'],
ARRAY['vertrieb', 'crm', 'kontaktdaten', 'vertraege', 'kaltakquise', 'leads'],
'important',
1
) ON CONFLICT (id) DO UPDATE SET
content = EXCLUDED.content,
summary = EXCLUDED.summary,
legal_refs = EXCLUDED.legal_refs,
tags = EXCLUDED.tags,
version = compliance_wiki_articles.version + 1,
updated_at = NOW();
-- =============================================================================
-- 4. Artikel: Datenkategorien im Marketing
-- =============================================================================
INSERT INTO compliance_wiki_articles (id, category_id, title, summary, content, legal_refs, tags, relevance, version)
VALUES (
'dk-marketing',
'datenkategorien',
'Datenkategorien im Marketing',
'Tracking-Daten, Newsletter-Adressen, Cookie-Consent und Social-Media-Daten im Marketing-Kontext.',
'## Ueberblick
Marketing verarbeitet haeufig Daten auf Basis von **Einwilligung** (Art. 6 Abs. 1 lit. a DSGVO) — insbesondere bei Tracking, Newsletter und Profiling. Die **ePrivacy-Richtlinie** (umgesetzt durch § 25 TDDDG) ist zusaetzlich zu beachten.
## Typische Datenkategorien
### E-Mail-Marketing
- E-Mail-Adressen, Vor-/Nachname
- Opt-in-Zeitpunkt, Double-Opt-in-Nachweis
- Oeffnungsraten, Klickraten (Tracking-Pixel)
- Abmeldehistorie, Bounce-Status
### Website-Tracking & Analytics
- **IP-Adressen** (personenbezogen! — BGH VI ZR 135/13)
- Cookies, Session-IDs, Fingerprinting-Daten
- Seitenaufrufe, Verweildauer, Klickpfade
- Referrer-URLs, Geraete-/Browsertyp
- Conversion-Tracking, Zielvorhaben
### Consent-Daten
- Cookie-Consent-Status je Kategorie
- Zeitpunkt der Einwilligung/des Widerrufs
- Consent-Version, Banner-Konfiguration
### Social-Media-Daten
- Follower-Interaktionen, Kommentare, Shares
- Reichweitenanalyse (aggregiert — i.d.R. kein Personenbezug)
- Custom Audiences (Achtung: Datenexport an Meta/Google!)
### Bild-/Videomaterial
- Kundenfotos fuer Testimonials (Einwilligung!)
- Event-Aufnahmen
- User Generated Content (UGC)
## Rechtsgrundlagen
| Verarbeitung | Rechtsgrundlage |
|--------------|-----------------|
| Newsletter-Versand | Art. 6 Abs. 1 lit. a DSGVO + § 7 Abs. 2 Nr. 3 UWG |
| Website-Analytics | § 25 TDDDG (Einwilligung fuer nicht-essentielle Cookies) |
| Bestandskunden-Werbung | Art. 6 Abs. 1 lit. f DSGVO + § 7 Abs. 3 UWG |
| Custom Audiences | Art. 6 Abs. 1 lit. a DSGVO (Einwilligung) |
| Testimonials mit Foto | Art. 6 Abs. 1 lit. a DSGVO + KUG |
## Typische Systeme
Google Analytics/Tag Manager, Matomo, Mailchimp, CleverReach, HubSpot Marketing, Meta Business Suite, Cookiebot/Usercentrics
## Aufbewahrungsfristen
- **Newsletter-Abmeldungen:** Sperrliste dauerhaft (Nachweis)
- **Double-Opt-in-Nachweis:** Dauer der Einwilligung + 3 Jahre
- **Cookie-Consent-Logs:** Mindestens 3 Jahre (Nachweispflicht)
- **Analytics-Rohdaten:** Max. 14-26 Monate (GA4-Standard)',
ARRAY['Art. 6 Abs. 1 lit. a DSGVO', '§ 25 TDDDG', '§ 7 UWG', 'Art. 21 DSGVO', 'Art. 7 Abs. 1 DSGVO'],
ARRAY['marketing', 'newsletter', 'tracking', 'cookies', 'analytics', 'consent', 'social-media'],
'important',
1
) ON CONFLICT (id) DO UPDATE SET
content = EXCLUDED.content,
summary = EXCLUDED.summary,
legal_refs = EXCLUDED.legal_refs,
tags = EXCLUDED.tags,
version = compliance_wiki_articles.version + 1,
updated_at = NOW();
-- =============================================================================
-- 5. Artikel: Datenkategorien im Kundenservice
-- =============================================================================
INSERT INTO compliance_wiki_articles (id, category_id, title, summary, content, legal_refs, tags, relevance, version)
VALUES (
'dk-kundenservice',
'datenkategorien',
'Datenkategorien im Kundenservice',
'Ticket-Daten, Kommunikationsverlaeufe, Kundenstammdaten und technische Informationen im Support.',
'## Ueberblick
Der Kundenservice verarbeitet personenbezogene Daten im Rahmen der **Vertragserfuellung** (Art. 6 Abs. 1 lit. b DSGVO) und zur Bearbeitung von Anfragen. Besondere Sorgfalt bei **Aufzeichnungen von Telefonaten** (Einwilligung erforderlich!).
## Typische Datenkategorien
### Kundenstammdaten
- Name, E-Mail, Telefon, Kundennummer
- Vertrag, Produkt, Lizenz-/Abonnement-Status
- Kontakthistorie, bisherige Anfragen
### Ticket-/Anfragedaten
- Ticketnummer, Betreff, Kategorie
- Fehlerbeschreibung, Reproduktionsschritte
- Status, Prioritaet, Bearbeitungshistorie
- Zufriedenheitsbewertung (NPS/CSAT)
### Kommunikationsverlauf
- E-Mail-Korrespondenz
- Live-Chat-Protokolle
- Telefon-Gespraechsnotizen
- Anrufaufzeichnungen (nur mit Einwilligung!)
### Technische Daten
- Systemumgebung (OS, Browser, App-Version)
- Logdateien, Fehlermeldungen
- Screenshots, Screencasts
- Remote-Sitzungsprotokolle
## Rechtsgrundlagen
| Verarbeitung | Rechtsgrundlage |
|--------------|-----------------|
| Support-Bearbeitung | Art. 6 Abs. 1 lit. b DSGVO |
| Anrufaufzeichnung | Art. 6 Abs. 1 lit. a DSGVO (Einwilligung!) |
| Zufriedenheitsumfrage | Art. 6 Abs. 1 lit. f DSGVO |
| Qualitaetssicherung | Art. 6 Abs. 1 lit. f DSGVO |
## Typische Systeme
Zendesk, Freshdesk, Jira Service Management, Intercom, OTRS, Zammad
## Aufbewahrungsfristen
- **Support-Tickets:** 3 Jahre nach Schliessung (Gewaehrleistung/Verjaehrung)
- **Chat-Protokolle:** 6-12 Monate
- **Anrufaufzeichnungen:** Max. 6 Monate (Qualitaetssicherung)
- **Technische Logs:** 90 Tage',
ARRAY['Art. 6 Abs. 1 lit. b DSGVO', 'Art. 6 Abs. 1 lit. a DSGVO', 'Art. 6 Abs. 1 lit. f DSGVO'],
ARRAY['kundenservice', 'support', 'tickets', 'kommunikation', 'anrufaufzeichnung'],
'info',
1
) ON CONFLICT (id) DO UPDATE SET
content = EXCLUDED.content,
summary = EXCLUDED.summary,
legal_refs = EXCLUDED.legal_refs,
tags = EXCLUDED.tags,
version = compliance_wiki_articles.version + 1,
updated_at = NOW();
-- =============================================================================
-- 6. Artikel: Datenkategorien im IT-Betrieb
-- =============================================================================
INSERT INTO compliance_wiki_articles (id, category_id, title, summary, content, legal_refs, tags, relevance, version)
VALUES (
'dk-it-betrieb',
'datenkategorien',
'Datenkategorien im IT-Betrieb',
'Logdaten, Zugangsdaten, Netzwerk-Monitoring und Backup-Daten — IT-spezifische Datenkategorien.',
'## Ueberblick
Die IT-Abteilung verarbeitet personenbezogene Daten im Rahmen der **Systemadministration, Sicherheit und Verfuegbarkeit**. Rechtsgrundlage ist primaer **Art. 6 Abs. 1 lit. f DSGVO** (berechtigtes Interesse an IT-Sicherheit) sowie **lit. c** (gesetzl. Aufbewahrungspflichten fuer Logs).
## Typische Datenkategorien
### Zugangsdaten (IAM)
- Benutzernamen, E-Mail-Adressen
- Rollen, Berechtigungen, Gruppenzugehoerigkeiten
- Letzte Anmeldung, Passwortwechsel-Datum
- MFA-Registrierungen
### Logdaten
- **Authentifizierungs-Logs:** Login/Logout, fehlgeschlagene Versuche
- **Zugriffs-Logs:** Webserver, Applikation, API
- **System-Logs:** Betriebssystem-Events, Cron-Jobs
- **Sicherheits-Logs:** Firewall, IDS/IPS, Antivirus
### Netzwerk- und Geraetedaten
- IP-Adressen (intern/extern)
- MAC-Adressen, Hostnamen
- Geraeteliste (Asset-Management)
- VPN-Verbindungsprotokolle
### Backup-Daten
- Enthalten personenbezogene Daten aller gesicherten Systeme
- Backup-Retention muss mit Loeschfristen harmonisieren
### Monitoring-Daten
- Uptime-/Performance-Metriken (i.d.R. kein Personenbezug)
- Endpunkt-Monitoring (Geraetezuordnung → personenbezogen)
## Rechtsgrundlagen
| Verarbeitung | Rechtsgrundlage |
|--------------|-----------------|
| Logging / SIEM | Art. 6 Abs. 1 lit. f DSGVO |
| Zugangsverwaltung | Art. 6 Abs. 1 lit. b + f DSGVO |
| Backup | Art. 6 Abs. 1 lit. f DSGVO |
| Videoueberwachung IT-Raeume | Art. 6 Abs. 1 lit. f DSGVO + § 4 BDSG |
## Typische Systeme
Active Directory / Entra ID, Keycloak, LDAP, Graylog, ELK Stack, Zabbix, Prometheus/Grafana, Veeam, Proxmox Backup
## Aufbewahrungsfristen
- **Authentifizierungs-Logs:** 6-12 Monate
- **Zugriffs-Logs:** 90 Tage (BSI-Empfehlung: 6 Monate)
- **Sicherheits-Logs:** 12 Monate (SOC-Empfehlung)
- **Backups:** Entsprechend Aufbewahrungskonzept (i.d.R. 30-90 Tage)',
ARRAY['Art. 6 Abs. 1 lit. f DSGVO', 'Art. 32 DSGVO', '§ 4 BDSG', 'Art. 5 Abs. 1 lit. f DSGVO'],
ARRAY['it', 'logging', 'backup', 'iam', 'netzwerk', 'monitoring', 'siem'],
'important',
1
) ON CONFLICT (id) DO UPDATE SET
content = EXCLUDED.content,
summary = EXCLUDED.summary,
legal_refs = EXCLUDED.legal_refs,
tags = EXCLUDED.tags,
version = compliance_wiki_articles.version + 1,
updated_at = NOW();
-- =============================================================================
-- 7. Artikel: Datenkategorien in der Produktion
-- =============================================================================
INSERT INTO compliance_wiki_articles (id, category_id, title, summary, content, legal_refs, tags, relevance, version)
VALUES (
'dk-produktion',
'datenkategorien',
'Datenkategorien in der Produktion',
'Personenbezogene Daten in Fertigung und Produktion: Zeiterfassung, Zutrittskontrolle, Arbeitsschutz.',
'## Ueberblick
In der Produktion werden personenbezogene Daten vor allem im Rahmen von **Zeiterfassung, Zutrittskontrolle und Arbeitsschutz** verarbeitet. Seit dem BAG-Urteil vom 13.09.2022 (1 ABR 22/21) besteht eine **Pflicht zur Arbeitszeiterfassung**.
## Typische Datenkategorien
### Zeiterfassung
- Kommen/Gehen-Zeiten, Pausenzeiten
- Schichtzuordnung, Ueberstunden
- Abwesenheiten (Urlaub, Krank, Schulung)
### Zutrittskontrolle
- Ausweiskarten-ID, RFID-Transponder
- Zutrittsprotokolle (Wer, Wann, Welcher Bereich)
- Besuchermanagement (Name, Firma, Besuchsgrund)
### Arbeitsschutz & Arbeitsmedizin
- Unterweisungsnachweise (Name, Datum, Thema)
- Arbeitsmedizinische Vorsorge (nur: durchgefuehrt ja/nein)
- Gefahrstoff-Expositionsdaten
- Unfallmeldungen (mit Personenbezug)
### Qualitaetssicherung
- Pruefprotokolle mit Pruefer-ID
- Chargenverfolgung (Zuordnung zu Mitarbeitern)
### Videoueberwachung
- Kameraaufnahmen in Produktionshallen
- Zugangs-/Ladebereiche
## Rechtsgrundlagen
| Verarbeitung | Rechtsgrundlage |
|--------------|-----------------|
| Zeiterfassung | § 26 Abs. 1 BDSG + Art. 6 Abs. 1 lit. c DSGVO |
| Zutrittskontrolle | Art. 6 Abs. 1 lit. f DSGVO |
| Arbeitsmedizin | § 26 Abs. 3 BDSG + ArbSchG/ArbMedVV |
| Videoueberwachung | Art. 6 Abs. 1 lit. f DSGVO + § 4 BDSG |
| Unfallmeldungen | Art. 6 Abs. 1 lit. c DSGVO (§ 193 SGB VII) |
## Typische Systeme
ATOSS, Interflex, Kaba/dormakaba, SAP PM/QM, MES-Systeme
## Aufbewahrungsfristen
- **Zeiterfassung:** 2 Jahre (§ 16 Abs. 2 ArbZG)
- **Zutrittsprotokolle:** 90 Tage (Sicherheitsinteresse)
- **Unterweisungsnachweise:** Dauer der Beschaeftigung + 3 Jahre
- **Unfallmeldungen:** 5 Jahre (DGUV)
- **Videoueberwachung:** Max. 72 Stunden (DSK-Empfehlung), max. 10 Tage',
ARRAY['§ 26 BDSG', 'Art. 6 Abs. 1 lit. f DSGVO', '§ 4 BDSG', '§ 16 ArbZG', '§ 193 SGB VII', 'ArbMedVV'],
ARRAY['produktion', 'zeiterfassung', 'zutrittskontrolle', 'arbeitsschutz', 'videoueberwachung'],
'info',
1
) ON CONFLICT (id) DO UPDATE SET
content = EXCLUDED.content,
summary = EXCLUDED.summary,
legal_refs = EXCLUDED.legal_refs,
tags = EXCLUDED.tags,
version = compliance_wiki_articles.version + 1,
updated_at = NOW();