Compliance & Audit — Hash-Chain-Audit-Log, DSGVO-Rechte, GoBD-Verfahrensdokumentation
Feinkonzept · §3.11 Compliance & Audit — Hash-Chain, DSGVO-Rechte, GoBD-Verfahrensdoku
Abschnitt betitelt „Feinkonzept · §3.11 Compliance & Audit — Hash-Chain, DSGVO-Rechte, GoBD-Verfahrensdoku“Einordnung. Dieses Feinkonzept setzt FUNKTIONSUMFANG §3.11 um — und ist aus drei Gründen das architektonisch wichtigste Feinkonzept der Kern-Suite: Erstens ist der Audit-Log die einzige technische Antwort auf „Wer hat wann was geändert?“, die bei einer GoBD-Prüfung oder einem arbeitsgerichtlichen Streit zählt. Zweitens kollidiert DSGVO Art. 17 (Löschung) hart mit §147 AO (10-Jahres-Aufbewahrung) — wir müssen beide bedienen, ohne gegen eines zu verstoßen, und zwar auf Zeilenebene. Drittens hat die Alt-App hier ein Loch gelassen (LESSONS-LEARNED §10): Audit-Events wurden geschrieben, aber konnten nachträglich bearbeitet werden; Verfahrensdokumentation war ein handgepflegtes Word-Dokument, das niemand mit dem tatsächlichen Systemstand abglich. Wir bauen hier die unveränderliche Wahrheit des Systems: Hash-Chain mit
ed25519-Signaturen je Monatsschluss, Jahres-Notariats-Anker, automatisch generierte Verfahrensdokumentation, ein DSGVO-Antragsflow mit klar getrennten Löschung-/Maskierung-/Export-Pfaden.
1. Header & Metadaten
Abschnitt betitelt „1. Header & Metadaten“feature_id: kern/11-compliance-audittitle: Compliance & Audit — Hash-Chain-Audit-Log, DSGVO-Rechte, GoBD-Verfahrensdokumentationfunktionsumfang_ref: §3.11roadmap_horizont: MVP # Unverhandelbar — GoBD/DSGVO sind Day-1-Pflichtenplattformen: mobile: nur-Ansicht # Mitarbeiter sieht eigene Audit-Spur + DSGVO-Flow web: vollständig # Admin: Integrity-Check, Verfahrensdoku, DSGVO-Anträge desktop: ausowner_rolle: Admin # Datenschutz-Verantwortlicher / Geschäftsleitungmodul_gate_flag: module.kern.compliance-audit # kann NICHT abgeschaltet werdencompliance_flags: gobd: true # Kern dieses Features arbzg: false vob: false dsgvo: true # Art. 15, 17, 20, 30, 32 — alle hier bfsg: true # DSGVO-Self-Service-Flow ist ESS betrvg: true # §87(1)6 — Audit-Log ist Verhaltenskontroll-geeignet stvg: false weitere: - "§147 AO (10-Jahres-Aufbewahrung)" - "§257 HGB (Handelsbücher-Aufbewahrung)" - "GoBD 2019 (Grundsätze ordnungsmäßiger Buchführung, elektronische Form)" - "DSGVO Art. 15, 17, 20, 30, 32 (Auskunft, Löschung, Portabilität, Verzeichnis, Sicherheit)" - "BDSG §26 (Beschäftigtendatenschutz)" - "BetrVG §87 Abs. 1 Nr. 6 (Leistungs-/Verhaltenskontrolle)" - "eIDAS Verordnung EU 910/2014 (qualifizierte Zeitstempel)"referenzkunde: status: TBD name: "zu klären — Zielprofil: Handwerksbetrieb mit Datenschutzbeauftragtem (ab 20 MA) + aktivem Betriebsrat" quelle: "Datenschutz-Audit-Interview + BR-Roundtable"estimate_eng_tage: 42 # Hash-Chain (8), Integrity-Check (4), DSGVO-Flows (10), # Verfahrensdoku-Generator (8), BR-Workflow (6), Retention-Engine (6)abhängigkeiten: - kern/01-zeiterfassung # Schreibt hierher - kern/08-dienstplanung # Schreibt hierher - kern/10-datev-integration # Monatsschluss-Lock hängt hiermit - kern/09-auth-self-service # DSGVO-Self-Service-Einstieg2. Kontext & Problem
Abschnitt betitelt „2. Kontext & Problem“Marktrealität (DE-Handwerk). Eine GoBD-Prüfung trifft in der Regel mittlere Handwerksbetriebe alle 5–7 Jahre (Außenprüfung des Finanzamts), Datenschutz-Prüfungen der Landesdatenschutzbehörde nach Beschwerde oder Stichprobe. Im Krisenfall — ausscheidender Mitarbeiter fordert seine Daten per Art. 15 DSGVO, Staatsanwaltschaft beschlagnahmt Server, Steuerprüfer will Lohn-Journal 2023 sehen — ist der Audit-Log das einzige Dokument, das zählt. Heute passiert in typischen Betrieben Folgendes: Stammdaten werden in Excel gepflegt, DATEV-Export wird per USB-Stick zur Kanzlei gebracht, E-Mails werden gelöscht. Ein Datenschutz-Auskunftsantrag wird „so gut wie möglich“ aus Papier-Akten und Ordnern beantwortet — das ist weder vollständig noch rechtssicher. Die Alt-App hatte zwar einen audit_log-Tabelle, aber mit updated_at-Feld (änderbar), ohne Hash-Chain, ohne externe Verankerung. Ein technisch versierter Admin konnte Audit-Einträge editieren und die Spur verwischen. Für eine echte Betriebsprüfung: wertlos.
Rechtlicher Rahmen.
- GoBD 2019 (BMF-Schreiben): fordert „unveränderbare, vollständige, richtige, zeitgerechte“ Aufzeichnungen in elektronischer Form. Verfahrensdokumentation muss vorhanden und aktuell sein.
- §147 AO: 10 Jahre Aufbewahrung für Buchungsbelege (Lohn-/Rechnungen), 6 Jahre für Geschäftsbriefe.
- §257 HGB: deckungsgleiche Aufbewahrung für Handelsbücher.
- DSGVO Art. 5 Abs. 1 f („Integrität und Vertraulichkeit“) + Art. 32 („angemessene technische Maßnahmen“): fordert kryptographische Integritätssicherung als Stand der Technik.
- Art. 15 DSGVO: Auskunftsrecht — Kopie aller personenbezogenen Daten binnen 30 Tagen (einmal verlängerbar).
- Art. 17 DSGVO: Löschung — aber mit Rückausnahme Abs. 3 b) für gesetzliche Aufbewahrungspflichten (GoBD/§147 AO schlägt Art. 17 in Lohn-Daten).
- Art. 20 DSGVO: Portabilität — strukturiertes, gängiges, maschinenlesbares Format.
- Art. 30 DSGVO: Verzeichnis der Verarbeitungstätigkeiten (VVT).
- BDSG §26: Beschäftigten-Datenschutz — Zweckbindung, keine Rasterfahndung im Audit-Log.
- BetrVG §87 Abs. 1 Nr. 6: Audit-Log kann theoretisch zur Leistungs-/Verhaltenskontrolle genutzt werden (Anzahl Pausen-Buchungen pro MA, Stempel-Abweichungen). Das macht ihn mitbestimmungspflichtig. Wir lösen das, indem der Audit-Log für Manager-Rollen nur im Kontext einer konkreten Ressource sichtbar ist, nicht als aggregierte Verhaltensanalyse — und Aggregat-Views nur nach BR-Freigabe aktivierbar sind.
Schmerzpunkt der Alt-App. LESSONS-LEARNED §10 beschreibt den Minimal-Audit-Log der Alt-App: Tabelle mit id, user_id, action, entity_id, timestamp, diff_json. Updates waren möglich, kein Hash-Bezug zum Vorgänger, kein externer Anker. Bei einer Mustermandanten-Simulation im Review: Ein Junior-Admin löschte per Raw-SQL drei Einträge, niemand merkte es. Für GoBD eine rote Flagge. Ein Art. 15-Auskunftsantrag mussten über 8 Tabellen händisch zusammengeklickt werden, dauerte 4 Stunden. Wir machen das grundlegend anders: Append-only Hash-Chain mit ed25519-Signaturen je Monatsschluss-Anker, zentrale DSGVO-Exporteinheit, generierte Verfahrensdokumentation.
Erwarteter Outcome (SMART).
- Spezifisch: Unveränderlicher Audit-Log, Integrity-Check-Button, DSGVO-Anträge als Self-Service, Verfahrensdoku als Live-PDF.
- Messbar: Mustern-Auskunftsantrag < 15 min Bearbeitung (vs. 4 h Alt-App), Integrity-Check-Scan 10 Mio. Events < 30 s, Mitbestimmungs-Beleg-Zeit < 1 Woche.
- Achievable: 42 Engineering-Tage inkl. BR-Freigabe-Workflow.
- Relevant: Kern-Compliance — ohne das ist Werkszeit kein seriöses B2B-Produkt.
- Terminiert: MVP-Release nicht verhandelbar. DOR §1.3.
3. Personas & Rollen
Abschnitt betitelt „3. Personas & Rollen“| Rolle | Aktion | Scope | Plattform |
|---|---|---|---|
| Mitarbeiter | Eigene Audit-Spur ansehen, DSGVO-Anträge stellen (Art. 15/17/20), eigenen Export herunterladen | own |
📱🌐 |
| Manager | Audit-Spur einer konkreten Ressource (z. B. Zeitbuchung) kontextbezogen ansehen | team |
🌐 |
| Admin | Integrity-Check starten, Verfahrensdoku herunterladen, DSGVO-Anträge bearbeiten, Retention-Policies konfigurieren | all |
🌐 |
| Betriebsrat | Aggregations-Views freigeben/widerrufen, eigene BR-Sicht auf Audit (nur bei freigegebenen Aggregaten) | all (BR-Scope) |
🌐 |
| Datenschutzbeauftragter (DPO) | VVT pflegen, DSFA dokumentieren, Datenpannen-Meldung auslösen | all |
🌐 |
Persona-Skizzen:
- Frau Bengescu (Datenschutzbeauftragte extern, bedient 12 Handwerksbetriebe) — verlangt standardisiertes VVT im Dreispalten-Format, braucht DSGVO-Antrags-Dashboard mit SLA-Counter (30 Tage Art. 12 Abs. 3).
- Herr Gärtner (BR-Vorsitzender Gebr. Schmidt, Installateur 58) — misstraut „IT, die alles weiß“. Braucht klaren Beleg, welche Daten Manager sehen und welche aggregierten Views er freigegeben hat.
- Hannes (Mitarbeiter) — will einmal pro Jahr „Meine Daten herunterladen“ als JSON und seinen eigenen Stempel-Verlauf der letzten 6 Monate sehen.
- Markus (Admin) — will den Integrity-Check vor einer Steuerprüfung starten und das PDF „Verfahrensdokumentation Werkszeit, Stand 20.04.2026“ drucken können.
- Herr Prüfer (Finanzamt-Betriebsprüfer, 62) — erwartet IDEA-Export der Zeitbuchungen + Verfahrensdoku + Hash-Chain-Verifikations-Log.
4. User-Stories
Abschnitt betitelt „4. User-Stories“US-01 [MVP] Als Admin möchte ich mit einem Klick prüfen, ob der Audit-Log unversehrt ist, um vor der Steuerprüfung Gewissheit zu haben.
US-02 [MVP] Als Mitarbeiter möchte ich meine Datenauskunft (Art. 15) als ZIP mit JSON + PDF + Anhängen herunterladen können, ohne E-Mail an den Admin.
US-03 [MVP] Als Admin möchte ich sehen, welche DSGVO-Anträge offen sind, deren SLA (30 Tage) läuft, um sie priorisiert abzuarbeiten.
US-04 [MVP] Als Admin möchte ich nach Ausscheiden eines Mitarbeiters seine personenbezogenen Daten pseudonymisieren, ohne Lohn-/Rechnungs-Belege zu verlieren (GoBD + Art. 17).
US-05 [MVP] Als Admin möchte ich die Verfahrensdokumentation (GoBD) als PDF mit Stand-Datum automatisch aus dem Systemzustand generieren lassen.
US-06 [V1] Als Betriebsrat möchte ich Aggregations-Views freigeben (z. B. "Monatliche Durchschnitts-Überstunden je MA"), die ohne BR-Freigabe nicht sichtbar sind.
US-07 [V1] Als Datenschutzbeauftragte möchte ich das Verzeichnis der Verarbeitungstätigkeiten (VVT) aus Werkszeit als Excel/PDF exportieren können, um es in mein Mandanten-Register zu übertragen.
US-08 [V1.5] Als Admin möchte ich einen Jahres-Notariats-Anker erstellen, der den Hash-Chain-Zustand zum Jahresende bei einem qualifizierten Vertrauensdiensteanbieter verankert.
US-09 [V2] Als Admin möchte ich Datenpannen-Meldungen (Art. 33 DSGVO) direkt aus Werkszeit an die Landesdatenschutzbehörde senden.5. Funktionale Anforderungen
Abschnitt betitelt „5. Funktionale Anforderungen“5.1 Mobile App (📱)
Abschnitt betitelt „5.1 Mobile App (📱)“- F-M-01 — Eigener Audit-Trail: Mitarbeiter sieht im „Meine Daten“-Bereich chronologische Liste seiner Events (Stempel, Urlaubsantrag, Schichttausch, Rechte-Änderung). Nur
own-Scope. Paginiert (50/Seite), unendlich rückwärts. - F-M-02 — DSGVO-Antrags-Wizard: Drei Buttons: „Auskunft (Art. 15)“, „Export (Art. 20)”, „Löschung (Art. 17)“. Wizard führt durch: Bestätigung per Passkey, Hinweistext zu Aufbewahrungspflichten, Erstellung des Antrags, Status-Ticket.
- F-M-03 — Antrags-Status: Liste eigener DSGVO-Anträge mit Status-Pills (
Offen/In Bearbeitung/Abgeschlossen) + SLA-Counter. - F-M-04 — Download-Benachrichtigung: Push-Notification bei fertigem Auskunft-Paket, direkter Download-Link in der App (presigned URL, 7 Tage gültig).
5.2 Web-App (🌐)
Abschnitt betitelt „5.2 Web-App (🌐)“- F-W-01 — Audit-Log-Browser: Admin-View mit Filtern (Tenant implizit, Zeitraum, Akteur, Aktion, Ressource, Hash-Chain-Block). Spalten: Zeit UTC, Akteur, Aktion, Ressourcen-Typ, Ressourcen-ID, Diff-Summary, Hash-Prefix. Paginiert mit Cursor (nicht Offset), da die Tabelle schnell wächst.
- F-W-02 — Integrity-Check: Prominente Aktion „Chain prüfen“. Startet Background-Job (§9), zeigt Fortschritt, liefert Report (grün = keine Abweichung; rot = Chain-Bruch an Block X mit genauem Zeitstempel + Eintrag-ID). Report als PDF + signiertes JSON downloadbar.
- F-W-03 — DSGVO-Anträge-Dashboard: Kanban mit Spalten
Offen/In Bearbeitung/Abgeschlossen. Pro Karte: Antragsteller, Typ (Art. 15/17/20), SLA-Countdown (rot bei <5 Tagen), Zuständiger. - F-W-04 — Art. 15/20-Export-Generator: Admin klickt „Export generieren“, System sammelt alle personenbezogenen Daten aus allen Tabellen (Zentral-View
v_person_data_by_user), packt in ZIP (personendaten.json,nachweise.pdf,anhaenge/). Optional: Lohn-Daten nur zusammengefasst (nicht die LODAS-Datei, weil sie Daten anderer enthält). - F-W-05 — Art. 17-Pseudonymisierung: Admin wählt Mitarbeiter zur Pseudonymisierung nach Ausscheiden + 10 J. Aufbewahrung vorüber. System ersetzt Name/E-Mail/Adresse/SV-Nr. durch Hash (mit Salt pro Tenant), belässt Stunden/Urlaub/Lohn-Bezüge. Audit-Event
dsgvo.pseudonymisiert. - F-W-06 — Verfahrensdoku-PDF: Button „Verfahrensdokumentation erzeugen“. Generiert 15-20-seitiges PDF mit Systemparametern (Jahrgang DATEV, Retention-Policies, Hash-Algorithmus, Verantwortliche Personen aus Admin-Stamm), Datum, SHA-256 des PDFs im Audit. Textbausteine aus
gobd-templates/, dynamische Felder aus Tenant-Config. - F-W-07 — Retention-Policy-Editor: Admin sieht Tabelle „Tabelle → Aufbewahrungs-Regel → Rechtsgrundlage → Löschung/Maskierung“. Standard-Defaults geladen; Überschreibung mit Begründung. Änderungen werden Audit-gelogged, greifen nur ab Genehmigung durch DPO-Rolle (4-Augen).
- F-W-08 — BR-Freigabe-Workflow für Aggregations-Views: Menü „Leistungs-Reports“ sperrt per Default. Admin fordert BR-Freigabe per Button an, BR-Rolle sieht in eigener Inbox, genehmigt/verwirft mit Begründung. Freigabe speichert BR-Zustimmungs-Dokument (PDF-Upload) + Audit-Event
betrvg.aggregation.freigegeben. - F-W-09 — VVT-Export: Verzeichnis der Verarbeitungstätigkeiten als Excel (
VVT_werkszeit_YYYYMMDD.xlsx) mit 10 Feldern pro Zeile gem. Art. 30 Abs. 1 (Verantwortlicher, Zweck, Betroffenenkategorien, Datenkategorien, Empfänger, Drittland, Löschfrist, TOM, Rechtsgrundlage, Einwilligungs-Ref). Jede Verarbeitung ein Eintrag, gelesen ausvvt_eintraege-Tabelle. - F-W-10 — Datenpannen-Workflow (V2): Button „Vorfall melden“ → Formular mit Meldekategorie, Betroffene, Zeitpunkt, Maßnahmen → Vorbereitet für Upload an Landesdatenschutzbehörde.
5.3 Cross-Plattform (🔄)
Abschnitt betitelt „5.3 Cross-Plattform (🔄)“- F-X-01 — Einheitlicher DSGVO-Status: Mitarbeiter (Mobile) und Admin (Web) sehen denselben Antrag mit synchronem Status.
- F-X-02 — Audit-Event-Kanonisierung: Jedes mutierende Endpoint in Werkszeit schreibt
audit_events-Eintrag mit fester Struktur (§7). Kein Eintrag ohne Event.
5.4 Admin-Konfiguration
Abschnitt betitelt „5.4 Admin-Konfiguration“- F-A-01 — ed25519-Schlüsselpaar-Management: Pro Tenant wird beim Anlegen ein ed25519-Schlüsselpaar in AWS KMS erzeugt (HSM-gesichert). Private Key verlässt KMS nie;
Sign-Aufrufe laufen innerhalb KMS. Rotation jährlich per Policy, alter Public Key bleibt archiviert zur Verifikation. - F-A-02 — Notariats-Anker-Setup (V1.5): Admin konfiguriert qualifizierten Vertrauensdiensteanbieter (z. B. D-Trust, Swisscom Trust) für RFC 3161-Zeitstempel; jährlich zum 31.12. wird der Merkle-Root aller Monats-Anker extern verankert.
- F-A-03 — Retention-Policy-Defaults: Tabellarisch voreingestellt nach Rechtsnorm (Lohn-Tabellen = §147 AO 10 J.; Projekt-Rechnungen = §257 HGB 10 J.; Zeitbuchungen = §16 Abs. 2 MiLoG / §41a EStG 2 J.; Bautagebücher = VOB/B §14 5 J.; Schulungs-Nachweise = DGUV V1 §4 10 J. + Vorhalte-Zeit).
- F-A-04 — DPO-Rolle: Separate Rolle mit ausschließlichem Zugriff auf DSGVO-Dashboard, VVT, Datenpannen, Integrity-Reports — ohne operativen Schreibzugriff auf Zeit-/Lohn-Daten (Rollentrennung).
5.5 Roadmap-Schichtung
Abschnitt betitelt „5.5 Roadmap-Schichtung“| Anforderung-ID | MVP | V1 | V1.5 | V2 |
|---|---|---|---|---|
| F-M-01 Audit-Trail | ✅ | |||
| F-M-02 DSGVO-Wizard | ✅ | |||
| F-W-01 Audit-Browser | ✅ | |||
| F-W-02 Integrity-Check | ✅ | |||
| F-W-03 DSGVO-Dashboard | ✅ | |||
| F-W-04 Art. 15/20 Export | ✅ | |||
| F-W-05 Art. 17 Pseudonym. | ✅ | |||
| F-W-06 Verfahrensdoku-PDF | ✅ | |||
| F-W-07 Retention-Editor | ✅ | |||
| F-W-08 BR-Freigabe | ✅ | |||
| F-W-09 VVT-Export | ✅ | |||
| F-A-02 Notariats-Anker | ✅ | |||
| F-W-10 Datenpannen-Workflow | ✅ |
6. Mockups & Flows
Abschnitt betitelt „6. Mockups & Flows“HTML-Hero-Mockup: 11-compliance-audit.html.
6.1 Mitarbeiter-Audit-Trail (Mobile)
Abschnitt betitelt „6.1 Mitarbeiter-Audit-Trail (Mobile)“┌────────────────────────────────┐│ ← Meine Daten ⚙️ │├────────────────────────────────┤│ 🛡 DSGVO · GoBD · BetrVG ││ ││ Letzte 30 Tage ││ ───────────── ││ 📍 Mo 20.04. 07:02 ││ Stempel Start · BV Müllerstr││ hash 4a8f…c9b2 ││ ││ ✍️ Fr 17.04. 14:22 ││ Dienstplan KW17 freigegeben ││ durch Th. Schmidt ││ ││ 🔑 Mi 15.04. 08:15 ││ Passkey "iPhone Hannes" ││ registriert ││ ││ 🌴 Di 14.04. 09:30 ││ Urlaubsantrag KW22 erstellt ││ ││ ───────────── ││ [Meine Daten (Art. 15/20)] ││ [Löschung beantragen (Art. 17)]││ │├────────────────────────────────┤│ [Zeit] [Plan] [Doku] [Mehr] │└────────────────────────────────┘6.2 DSGVO-Antrags-Wizard (Mobile, Schritt 2/3)
Abschnitt betitelt „6.2 DSGVO-Antrags-Wizard (Mobile, Schritt 2/3)“┌────────────────────────────────┐│ ← Auskunft beantragen │├────────────────────────────────┤│ Was erhalten Sie? ││ ││ [x] Stammdaten ││ [x] Zeitbuchungen (6 Monate) ││ [x] Urlaubsanträge (seit 2024) ││ [x] Schichttausch-Historie ││ [x] Lohn-Summen pro Monat ││ [ ] Detaillierte Lohn-Belege ││ (enthält Daten Dritter — ││ nicht möglich) ││ [x] Audit-Trail eigener ││ Aktionen ││ ││ Fertigstellung: bis 19.05.2026 ││ (30 Tage, Art. 12 Abs. 3) ││ ││ Sie erhalten ein ZIP mit: ││ • personendaten.json ││ • auskunft.pdf (signiert) ││ • anhaenge/ (PDFs, Fotos) ││ ││ [Weiter] (Schritt 2/3) │└────────────────────────────────┘6.3 Audit-Log-Browser (Web, Admin)
Abschnitt betitelt „6.3 Audit-Log-Browser (Web, Admin)“┌────────────────────────────────────────────────────────────────────────────────┐│ Werkszeit · Audit-Log Markus S. · Admin [Profil ▾] │├────────────────────────────────────────────────────────────────────────────────┤│ 🛡 GoBD Hash-Chain · DSGVO · §147 AO · Stand Block 48.172 (Mo 20.04. 08:40) ││ ││ Filter: Zeitraum [01.04.–20.04.2026 ▼] Akteur [Alle ▼] Aktion [Alle ▼] ││ ││ ┌──────────────────────────────────────────────────────────────────────────┐ ││ │ Zeit UTC │ Akteur │ Aktion │ Res. │ Hash │ ││ │ 20.04 06:42Z │ Hannes K. │ zeit.stempel.start │ zb… │ 4a8f… │ ││ │ 20.04 06:40Z │ Mehmet Y. │ zeit.stempel.start │ zb… │ 3d2e… │ ││ │ 19.04 16:08Z │ System │ datev.monatslauf.erst. │ ml… │ 7c91… │ ││ │ 19.04 14:22Z │ H. Gärtner BR │ dienstplan.br.freigabe │ dp… │ 2b5a… │ ││ │ 19.04 12:01Z │ Sabine M. │ urlaub.genehmigt │ ua… │ 9f64… │ ││ │ 19.04 08:14Z │ Frau Müller │ datev.export.lodas │ ml… │ 8b1c… │ ││ └──────────────────────────────────────────────────────────────────────────┘ ││ ││ [Chain prüfen (Integrity-Check)] [VVT-Export] [Verfahrensdoku PDF] │└────────────────────────────────────────────────────────────────────────────────┘6.4 Integrity-Check-Report
Abschnitt betitelt „6.4 Integrity-Check-Report“┌────────────────────────────────────────────────────────────────────────────────┐│ Integrity-Check · Tenant shk-gebruder-schmidt [⤓ PDF] [⤓ JSON] │├────────────────────────────────────────────────────────────────────────────────┤│ Start: 20.04.2026 09:14:22 UTC ││ Ende: 20.04.2026 09:14:48 UTC ││ Dauer: 26 s ││ Events gesamt: 48.172 ││ Monats-Anker: 47 (seit 01.06.2022) ││ ││ 📊 Ergebnis ││ ✓ Hash-Chain vollständig (48.172 / 48.172) ││ ✓ Alle 47 Monats-Anker gültig (ed25519 gegen Public Key 2026-01) ││ ✓ Kein DB-UPDATE auf audit_events festgestellt ││ ✓ Kein DB-DELETE auf audit_events festgestellt ││ ✓ S3 Object Lock aktiv für alle Monats-Anker-Objekte ││ ││ Ergebnis-Signatur (ed25519): f3a8…9b12 (signiert mit Tenant-Private-Key) ││ PDF-Hash: c4e2…70df (im Audit: compliance.integrity.ok) ││ ││ Empfehlung: Report quartalsweise archivieren (S3 bucket 'integrity-reports'). │└────────────────────────────────────────────────────────────────────────────────┘6.5 Retention-Policy-Editor (Web)
Abschnitt betitelt „6.5 Retention-Policy-Editor (Web)“┌────────────────────────────────────────────────────────────────────────────────┐│ Aufbewahrungs-Richtlinien │├────────────────────────────────────────────────────────────────────────────────┤│ ┌──────────────────────────────────────────────────────────────────────────┐ ││ │ Tabelle │ Frist │ Rechtsgr. │ Bei Ablauf │ DPO-OK │ ││ │ zeitbuchungen │ 2 J. │ §41a EStG │ Pseudonymisie. │ ✓ │ ││ │ lohnjournal │ 10 J. │ §147 AO │ Pseudonymisie. │ ✓ │ ││ │ rechnungen │ 10 J. │ §147 AO │ nichts │ ✓ │ ││ │ bautagebuch │ 5 J. │ VOB/B §14 │ Löschung │ ✓ │ ││ │ schulungsnachweise │ 10 J. │ DGUV V1 §4 │ Pseudonymisie. │ ✓ │ ││ │ audit_events │ 10 J.+ │ §147 AO │ NIE Löschung │ ⛔ │ ││ │ dsgvo_antraege │ 3 J. │ §79 BDSG │ Löschung │ ✓ │ ││ │ passkey_credentials │ bei Ausscheiden │ Art. 17 │ Löschung │ ✓ │ ││ └──────────────────────────────────────────────────────────────────────────┘ ││ [+ Tabelle hinzufügen] [Defaults wiederherstellen] [Speichern (DPO-Review)] │└────────────────────────────────────────────────────────────────────────────────┘6.6 Art. 17 Pseudonymisierungs-Dialog
Abschnitt betitelt „6.6 Art. 17 Pseudonymisierungs-Dialog“┌────────────────────────────────────────────────────────────────────────────────┐│ Pseudonymisierung ausgeschiedener Mitarbeiter [Abbrechen] [OK] │├────────────────────────────────────────────────────────────────────────────────┤│ Mitarbeiter: Klaus Bernhart (ausgeschieden 31.03.2015) ││ Ausscheiden: 31.03.2015 ││ Aufbew.-Frist: 10 J. §147 AO → abgelaufen 01.04.2025 ││ ││ 🔴 Folgende Felder werden ersetzt: ││ - Name → SHA256-Hash "a1b2c3d4…" (Salt pro Tenant) ││ - E-Mail → gelöscht ││ - Anschrift → gelöscht ││ - SV-Nr. → gelöscht ││ - Geburtsdatum → gelöscht ││ ││ 🟢 Folgende Felder bleiben erhalten (statistische Zwecke): ││ - Stunden-Summen pro Monat ││ - Lohn-Summen pro Monat ││ - Projekt-Zuordnungen ││ ││ Begründung (Pflicht): ││ ┌──────────────────────────────────────────────────────────────────────────┐ ││ │ Aufbewahrungsfrist §147 AO nach Ausscheiden 31.03.2015 abgelaufen; │ ││ │ Anspruchsverjährung §195 BGB geprüft; keine laufenden Verfahren. │ ││ └──────────────────────────────────────────────────────────────────────────┘ ││ ││ [Pseudonymisieren] (wird als dsgvo.pseudonymisiert geloggt) │└────────────────────────────────────────────────────────────────────────────────┘6.7 BR-Freigabe für Aggregations-View (Web)
Abschnitt betitelt „6.7 BR-Freigabe für Aggregations-View (Web)“┌────────────────────────────────────────────────────────────────────────────────┐│ BetrVG §87(1)6 · Freigabe Aggregations-View │├────────────────────────────────────────────────────────────────────────────────┤│ Antrag vom: Markus (Admin) am 18.04.2026 ││ View: "Durchschnittliche Überstunden je MA pro Monat" ││ Zweck: Planungs-Grundlage Budget 2026-H2 ││ Betroffene: 78 Monteure ││ Zugriff: Bauleitung + Geschäftsleitung, read-only ││ ││ BR-Stellungnahme: ││ ┌──────────────────────────────────────────────────────────────────────────┐ ││ │ Freigegeben unter folgenden Bedingungen (BetrVG §87 Abs. 1 Nr. 6): │ ││ │ - Nur Monats-Durchschnitte, keine Tages-Werte. │ ││ │ - Mindest-Gruppengröße 5 MA, sonst Aggregation verweigert. │ ││ │ - Automatische Löschung nach 12 Monaten. │ ││ │ - Widerruf jederzeit per schriftlicher Mitteilung möglich. │ ││ └──────────────────────────────────────────────────────────────────────────┘ ││ ││ BR-Beschluss-Dokument: [⤓ BR_Beschluss_2026-04-15.pdf] ││ Gültig bis: 15.04.2027 ││ ││ [Freigeben] [Verwerfen (mit Begründung)] [Zurückstellen] │└────────────────────────────────────────────────────────────────────────────────┘Symbol-Konvention. 🛡 Compliance-Banner, ✍️ Manuell-Event, 🔑 Auth-Event, 📍 Geo/Stempel, 🌴 Urlaub, ⛔ nicht löschbar.
7. Datenmodell-Skizze
Abschnitt betitelt „7. Datenmodell-Skizze“// Zentrale, tenant-übergreifende Spine-Tabelle — aber RLS schneidet auf tenant_idexport const auditEventsTable = pgTable('audit_events', { id: uuid('id').primaryKey().defaultRandom(), // UUID v7 tenantId: uuid('tenant_id').notNull().references(() => tenantsTable.id), blockNumber: bigint('block_number', { mode: 'bigint' }).notNull(), // monoton steigend je Tenant occurredAt: timestamp('occurred_at', { withTimezone: true }).notNull(), actorUserId: uuid('actor_user_id').references(() => usersTable.id), // nullable für System-Events actorKind: varchar('actor_kind', { length: 16 }).notNull(), // 'user' | 'system' | 'api-client' action: varchar('action', { length: 64 }).notNull(), // 'zeit.stempel.start', 'datev.export.lodas' resourceType: varchar('resource_type', { length: 32 }).notNull(), // 'zeitbuchung','dienstplan', ... resourceId: uuid('resource_id'), diff: jsonb('diff'), // Before/After, kanonisiert ipHash: bytea('ip_hash'), // SHA-256 auf salted IP userAgent: text('user_agent'), // --- Hash-Chain --- hashPrev: bytea('hash_prev').notNull(), // SHA-256 des Vorgängers hashSelf: bytea('hash_self').notNull(), // SHA-256 dieser Zeile (kanonisiert)}, (t) => ({ tenantBlockUq: uniqueIndex('audit_ev_tenant_block_uq').on(t.tenantId, t.blockNumber), occurredIdx: index('audit_ev_occurred_idx').on(t.tenantId, t.occurredAt.desc()), actorIdx: index('audit_ev_actor_idx').on(t.tenantId, t.actorUserId, t.occurredAt.desc()), resourceIdx: index('audit_ev_resource_idx').on(t.tenantId, t.resourceType, t.resourceId),}));
// Monats-Anker: am 1. jedes Monats um 00:10 UTC läuft Cronjob, signiert Chain-Standexport const auditAnchorsTable = pgTable('audit_anchors', { id: uuid('id').primaryKey().defaultRandom(), tenantId: uuid('tenant_id').notNull().references(() => tenantsTable.id), periodYear: integer('period_year').notNull(), periodMonth: integer('period_month').notNull(), fromBlock: bigint('from_block', { mode: 'bigint' }).notNull(), toBlock: bigint('to_block', { mode: 'bigint' }).notNull(), merkleRoot: bytea('merkle_root').notNull(), // Merkle-Tree über alle hash_self ed25519Signature: bytea('ed25519_signature').notNull(), // KMS-Sign keyVersion: varchar('key_version', { length: 16 }).notNull(), // 'v2026-01' rfc3161Token: bytea('rfc3161_token'), // Optional Notariats-Zeitstempel createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(),}, (t) => ({ tenantPeriodUq: uniqueIndex('audit_anchor_tenant_period_uq').on(t.tenantId, t.periodYear, t.periodMonth),}));
// DSGVO-Anträgeexport const dsgvoAntraegeTable = pgTable('dsgvo_antraege', { id: uuid('id').primaryKey().defaultRandom(), tenantId: uuid('tenant_id').notNull().references(() => tenantsTable.id), antragstellerId: uuid('antragsteller_id').notNull().references(() => usersTable.id), artikel: varchar('artikel', { length: 8 }).notNull(), // '15','17','20' status: varchar('status', { length: 24 }).notNull(), // 'offen','in_bearbeitung','abgeschlossen','abgelehnt' slaDeadline: timestamp('sla_deadline', { withTimezone: true }).notNull(), assigneeId: uuid('assignee_id').references(() => usersTable.id), exportUrl: text('export_url'), // presigned S3 ablehnungsGrund: text('ablehnungs_grund'), createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(), resolvedAt: timestamp('resolved_at', { withTimezone: true }), hashPrev: bytea('hash_prev'), hashSelf: bytea('hash_self'),});
// Retention-Policiesexport const retentionPoliciesTable = pgTable('retention_policies', { id: uuid('id').primaryKey().defaultRandom(), tenantId: uuid('tenant_id').notNull().references(() => tenantsTable.id), tableName: varchar('table_name', { length: 64 }).notNull(), retentionYears: integer('retention_years').notNull(), onExpire: varchar('on_expire', { length: 24 }).notNull(), // 'loeschung','pseudonymisierung','nichts' rechtsgrundlage: text('rechtsgrundlage').notNull(), approvedByDpo: uuid('approved_by_dpo').references(() => usersTable.id), approvedAt: timestamp('approved_at', { withTimezone: true }),}, (t) => ({ tenantTableUq: uniqueIndex('retention_tenant_table_uq').on(t.tenantId, t.tableName),}));
// VVTexport const vvtEintraegeTable = pgTable('vvt_eintraege', { id: uuid('id').primaryKey().defaultRandom(), tenantId: uuid('tenant_id').notNull().references(() => tenantsTable.id), bezeichnung: varchar('bezeichnung', { length: 120 }).notNull(), verantwortlicher: varchar('verantwortlicher', { length: 120 }).notNull(), zweck: text('zweck').notNull(), betroffeneKategorien: text('betroffene_kategorien').notNull(), datenkategorien: text('datenkategorien').notNull(), empfaenger: text('empfaenger'), drittlandUebermittlung: text('drittland_uebermittlung'), loeschfristen: text('loeschfristen').notNull(), tomMasnahmen: text('tom_massnahmen').notNull(), rechtsgrundlage: varchar('rechtsgrundlage', { length: 64 }).notNull(), einwilligungsRef: text('einwilligungs_ref'),});RLS-Policy-Sketch.
ALTER TABLE audit_events ENABLE ROW LEVEL SECURITY;
CREATE POLICY audit_events_tenant_iso ON audit_events USING (tenant_id = current_setting('app.tenant_id')::uuid);
CREATE POLICY audit_events_own_or_admin ON audit_events FOR SELECT USING ( tenant_id = current_setting('app.tenant_id')::uuid AND ( current_setting('app.roles') LIKE '%admin%' OR current_setting('app.roles') LIKE '%dpo%' OR (current_setting('app.scope') = 'own' AND actor_user_id = current_setting('app.user_id')::uuid) OR (current_setting('app.scope') = 'team' AND resource_type = current_setting('app.resource_context')) ) );
-- KRITISCH: keine UPDATE/DELETE-Policies — Tabelle ist DB-technisch append-onlyREVOKE UPDATE, DELETE ON audit_events FROM PUBLIC;-- Nur der Superuser (Schema-Migrationen) darf, normale Apps niemals.ER-Bezug. audit_events wird von jedem mutierenden Write-Endpoint geschrieben — zeitbuchungen, urlaubsantraege, dienstplaene, datev_monatslaufe, users, passkey_credentials. Das Schreiben passiert im selben Transaction-Block wie die fachliche Mutation (atomar), so dass Konsistenz garantiert ist.
8. API-Endpunkte
Abschnitt betitelt „8. API-Endpunkte“Pfad-Konvention: /v1/kern/compliance/… und /v1/kern/dsgvo/….
| Methode | Pfad | Auth-Scope | Rate-Limit | Idempotenz | Beschreibung |
|---|---|---|---|---|---|
GET |
/v1/kern/compliance/audit |
audit:read |
Standard | — | Audit-Log-Liste (Cursor-Pagination) |
GET |
/v1/kern/compliance/audit/{id} |
audit:read |
Standard | — | Event-Detail mit Hash |
POST |
/v1/kern/compliance/audit/integrity-check |
audit:admin |
Privileged | Idempotency-Key | Startet Chain-Verifikation |
GET |
/v1/kern/compliance/audit/integrity-check/{id} |
audit:admin |
Standard | — | Report-Status + Download-URLs |
POST |
/v1/kern/compliance/anchor/{year}/{month} |
system |
System | Idempotency-Key | Monats-Anker erzeugen (Cronjob) |
GET |
/v1/kern/compliance/verfahrensdoku |
audit:admin |
Standard | — | PDF generieren und Download |
GET |
/v1/kern/compliance/vvt |
dpo |
Standard | — | VVT als Excel/JSON |
PUT |
/v1/kern/compliance/vvt/{id} |
dpo |
Standard | Idempotency-Key | VVT-Eintrag bearbeiten |
GET |
/v1/kern/compliance/retention |
audit:admin |
Standard | — | Retention-Policies-Liste |
PUT |
/v1/kern/compliance/retention/{id} |
audit:admin + DPO-Co-Sign |
Privileged | Idempotency-Key | Policy ändern |
POST |
/v1/kern/compliance/br/aggregation-request |
audit:admin |
Standard | Idempotency-Key | BR-Freigabe anfragen |
POST |
/v1/kern/compliance/br/aggregation-request/{id}/freigeben |
betriebsrat |
Privileged | Idempotency-Key | BR-Entscheidung |
POST |
/v1/kern/dsgvo/antrag |
own |
Privileged | Idempotency-Key | Art. 15/17/20 einreichen |
GET |
/v1/kern/dsgvo/antrag/{id} |
own/admin/dpo |
Standard | — | Status |
POST |
/v1/kern/dsgvo/antrag/{id}/export-generieren |
admin/dpo |
Privileged | Idempotency-Key | Art. 15/20 Paket |
POST |
/v1/kern/dsgvo/antrag/{id}/pseudonymisieren |
admin/dpo |
Privileged | Idempotency-Key | Art. 17 Flow |
OpenAPI-Schema-Skizze (gekürzt):
paths: /v1/kern/compliance/audit/integrity-check: post: operationId: startIntegrityCheck x-werkszeit-scope: audit:admin x-werkszeit-rate-limit: privileged responses: '202': content: application/json: schema: type: object properties: jobId: { type: string, format: uuid } status: { type: string, enum: [queued] } estimateSeconds: { type: integer }Webhook-Events.
compliance.integrity.ok/compliance.integrity.brokencompliance.anchor.createddsgvo.antrag.erstellt/dsgvo.antrag.abgeschlossenbetrvg.aggregation.freigegeben/betrvg.aggregation.widerrufen
9. Offline-Profil
Abschnitt betitelt „9. Offline-Profil“| Profil | Begründung | Mechanik |
|---|---|---|
| Online-only für Admin-Funktionen (Integrity-Check, DSGVO-Bearbeitung, Verfahrensdoku) | Kryptographische Operationen laufen in KMS; Integrity-Check braucht vollständigen DB-Zugriff. | UI-Block bei connectivity == none. |
| Read-only offline für Mobile-Audit-Trail | Mitarbeiter möchte seine letzten Events auch im Keller sehen können. | SQLite-Cache letzte 90 Tage, keine Mutation offline. |
| Online-only für DSGVO-Antragseinreichung | Identitäts-Bestätigung per Passkey zwingend online. | Button disabled bei keiner Verbindung, Hinweistext „Bitte online stellen“. |
Konflikt-Strategie. Entfällt für Audit — Events sind append-only, keine Konflikte. Für DSGVO-Anträge: Duplikat-Detection via (antragsteller_id, artikel, status IN ('offen','in_bearbeitung'))-Constraint — zweiter Antrag gleichen Typs geht nicht, UI zeigt bestehenden Status.
10. Compliance-Mapping
Abschnitt betitelt „10. Compliance-Mapping“10.1 GoBD
Abschnitt betitelt „10.1 GoBD“- Append-only:
audit_eventsohneUPDATE/DELETE-Berechtigungen für App-User. PostgreSQLREVOKEauf Tabellenebene + keineupdated_at-Spalte + RLS ohne Write-Policy außerINSERT. - Hash-Chain: Jeder Eintrag hat
hash_prev = hash_self(vorheriger_block_gleichen_tenants). Kanonisierung überJCS(JSON Canonicalization Scheme, RFC 8785) vor SHA-256. - Monats-Anker: Cronjob am 1. jedes Monats 00:10 UTC erzeugt Merkle-Tree über alle
hash_selfdes Vormonats, signiert Root mited25519(Key in AWS KMS). Signatur + Key-Version + Block-Range inaudit_anchorsabgelegt. - Notariats-Zeitstempel (V1.5): Jährlich zum 31.12. wird der Merkle-Root aller 12 Monats-Anker extern qualifiziert zeitgestempelt (RFC 3161 bei D-Trust oder Swisscom Trust). Token in
rfc3161_tokenabgelegt. - Verfahrensdokumentation: Generator liest Tenant-Config, Retention-Policies, Schlüssel-Versionen, Personen-Verantwortliche; baut Markdown → PDF (Stand-Datum im Footer, SHA-256 des PDF wird Audit-Event
compliance.verfahrensdoku.erzeugt). - Aufbewahrung 10 Jahre:
audit_events+audit_anchors+ signierte PDFs in S3 (werkszeit-audit-eu-central-1) mit Object Lock Compliance Mode, Retention 10 Jahre. - Integrity-Check: Verifiziert für alle Events:
hash_self == SHA256(canonicalize(row_without_hashes) + hash_prev). Verifiziert für alle Anker:ed25519_verify(public_key, merkle_root, signature). Bei Abweichung:compliance.integrity.broken-Event (ironischerweise ein Audit-Eintrag) + Admin-Alert.
10.2 ArbZG
Abschnitt betitelt „10.2 ArbZG“— nicht zutreffend; ArbZG-Compliance wird in §3.1/§3.8 umgesetzt, nicht hier.
10.3 VOB/B
Abschnitt betitelt „10.3 VOB/B“— nicht zutreffend.
10.4 DSGVO
Abschnitt betitelt „10.4 DSGVO“- Art. 5 Datenminimierung: Audit-Log speichert kein IP im Klartext, nur
SHA-256(salt||ip)(Salt pro Tenant, rotierend). Keine User-Agents länger als 512 Zeichen. - Art. 6 Rechtsgrundlage: Art. 6 Abs. 1 c (Rechtspflicht) + Art. 6 Abs. 1 f (berechtigtes Interesse an Nachvollziehbarkeit) — dokumentiert in VVT-Eintrag „Audit-Log“.
- Art. 9: keine besonderen Kategorien im Audit. Krank-Diagnose wird als Abwesenheits-Typ geloggt, nicht als ICD-Code.
- Art. 15 Auskunft: Zentral-Service sammelt aus
audit_events(gefiltert aufactor_user_id = XODERresource_id IN (X owns)), aus Stammdaten, aus Zeit/Urlaub/Lohn. Export als ZIP (<15 min SLA, 30 Tage Pflicht-SLA Art. 12 Abs. 3). - Art. 17 Löschung mit GoBD-Kollision: Zwei-Pfad-Strategie:
- Pfad A (Tabellen ohne Aufbewahrungspflicht, z. B.
passkey_credentials): physische Löschung. - Pfad B (GoBD-pflichtige Tabellen, z. B.
zeitbuchungen): Pseudonymisierung nach Ablauf (Name → SHA-256(salt||name), SV-Nr. → gelöscht). Geschehnis, Stunden, Lohn bleiben, nur die Person wird unidentifizierbar.
- Pfad A (Tabellen ohne Aufbewahrungspflicht, z. B.
- Art. 20 Portabilität: JSON-Schema
personendaten-v1.schema.jsondefiniert Struktur; Export enthält alle Felder, nichts was auf andere Personen verweist (Lohn-Summen statt LODAS-Datei). - Art. 30 VVT: Liste aller Verarbeitungen als eigene Tabelle; Excel-Export mit 10 Pflichtspalten.
- Art. 32 Sicherheit: ed25519, AES-256-GCM für at-rest, TLS 1.3 für in-transit, KMS für Schlüsselverwaltung, HSM-gesicherte Private Keys, Incident-Response-Prozess (Datenpannen-Workflow V2).
- DSFA: Pflicht (Art. 35 Abs. 3 b — umfangreiche Verarbeitung besonderer Kategorien, hier: Gesundheitsbezug bei Krank-Tagen, BetrVG-Bezug). DSFA-Dokument wird in der Verfahrensdoku als Anhang generiert, regelmäßig reviewed.
10.5 BFSG / WCAG 2.2 AA
Abschnitt betitelt „10.5 BFSG / WCAG 2.2 AA“- Mobile-DSGVO-Wizard ist ESS-Flow → voller BFSG-Anwendungsbereich.
- Screenreader-Labels auf allen Buttons, Live-Regions bei Status-Wechsel („Antrag eingereicht“).
- Kontrast: Anthrazit
#1A1F2Bauf Beige#F5F1EA≥ 12:1 (weit über AA). - Tastatur-Navigation: Wizard durchgehend per Tab, Skip-Links zwischen Schritten.
10.6 BetrVG §87(1)6
Abschnitt betitelt „10.6 BetrVG §87(1)6“- Aktive Pflicht-Erkenntnis: Audit-Log ist Leistungs-/Verhaltenskontroll-geeignet. Wir stellen sicher, dass:
- Default-Manager-View zeigt nur den Audit zu einer konkret geöffneten Ressource (z. B. „Zeitbuchung #123 — wer hat sie wann geändert?“), nicht aggregiert über MA.
- Aggregations-Views (Anzahl Events pro MA, Häufigkeit Stempel-Korrekturen, Pausen-Durchschnitt) sind hinter
betrvg.aggregation.freigegeben-Flag. - Flag-Aktivierung nur durch BR-Freigabe-Workflow (F-W-08), nicht durch Admin-Alleinentscheidung.
- Jede Aggregations-Aktivierung bekommt einen Audit-Event
betrvg.aggregation.freigegebenmit Verweis auf hochgeladenes BR-Beschluss-PDF. - Widerruf jederzeit möglich, sofort wirksam, blendet Views aus.
- Textbaustein „Betriebsvereinbarung Audit-Log“ (Beispiel) wird in der Verfahrensdoku mitgeliefert als Hilfe für den Betrieb.
10.7 Weitere Spezial-Compliance
Abschnitt betitelt „10.7 Weitere Spezial-Compliance“- eIDAS Art. 42 (qualifizierter Zeitstempel): RFC 3161-Anker beim qualifizierten VDA ist der einzige Weg zu einem gerichtsfesten externen Anker. Alternativ: Blockchain-Anker (z. B. Bitcoin-Commit via OpenTimestamps) — wir bauen diesen nicht, weil nicht rechtlich anerkannt.
- BDSG §26 (Beschäftigtendaten): Audit-Zugriff durch Manager zweckgebunden, keine Mitarbeiter-Profilbildung ohne BR-Freigabe.
- §257 HGB (Handelsbücher): deckungsgleich mit §147 AO behandelt.
11. Edge-Cases
Abschnitt betitelt „11. Edge-Cases“| # | Szenario | Erwartetes Verhalten |
|---|---|---|
| EC-01 | Direkter DB-Eingriff (Ops-User ändert via Raw-SQL eine audit_events-Zeile) |
Integrity-Check erkennt hash_self != recompute(row), meldet exakte Zeile + Block-Nr. compliance.integrity.broken-Event wird erzeugt. Admin-Alert via E-Mail + SRE-Pager. |
| EC-02 | Mitarbeiter scheidet aus, fordert 6 Monate später Art. 17 | System prüft Aufbewahrungsfristen: Lohn-bezogene Tabellen → Pseudonymisierung frühestens 10 Jahre nach Ausscheiden; Zeitbuchungen → 2 Jahre; passkey_credentials → sofort. Antragsteller erhält Bescheid mit den maßgeblichen Fristen. |
| EC-03 | Multi-Tenant-Cross-Read im Audit | RLS erzwingt tenant_id-Filter; Versuch, per ID-Guessing fremden Event zu lesen → 404 (nicht 403), kein Audit im fremden Tenant. |
| EC-04 | Tenant-Deletion (Firma gibt Werkszeit auf, will alle Daten gelöscht) | Zwei-Stufen-Prozess: Export aller Daten (Art. 20), dann Anonymisierung tenant_id → fixer Hash und Blockade aller Log-ins. Vollständige DB-Löschung erst nach 10 Jahren bei Lohn-Daten möglich; Kunde wird darüber vertraglich aufgeklärt. |
| EC-05 | KMS-Key-Rotation während laufendem Anker | Monats-Anker wird mit dem zum Anker-Zeitpunkt gültigen Key signiert. key_version im Anker festgehalten. Verifikation nutzt exakte Version. Alte Public Keys bleiben permanent archiviert. |
| EC-06 | BR-Widerruf einer Aggregations-Freigabe mitten in laufendem Report | Reports werden sofort ausgeblendet; bereits erzeugte PDF-Exporte bleiben lokal, werden aber serverseitig entwertet (Download-Links invalidiert). Audit: betrvg.aggregation.widerrufen. |
| EC-07 | 100.000+ Events/Tag bei Peak | Audit-Writer ist async (Queue), Event-Schreibe-Latenz P95 < 50 ms. Block-Nummer-Sequenz per PostgreSQL Sequence (atomarer nextval), Hash-Berechnung nach Commit in eigener kleiner Transaktion. |
| EC-08 | Clock-Skew (Server-Uhr 5 min falsch) | NTP-erzwungen via Chrony; bei Abweichung > 30 s: Alert + Event-Schreibe-Pause bis Sync. Entfernt das Risiko falscher occurred_at. |
| EC-09 | Datenpannen-Erstmeldung außerhalb Werkszeit (Admin meldet per E-Mail statt Flow) | Workflow dokumentiert Pflicht-Weg; nachträgliche Nachtragung möglich. |
| EC-10 | DPO wechselt | Admin-Rollen-Migration. Retention-Policy-Approvals bleiben mit ursprünglichem DPO im Audit. Neuer DPO muss alle aktiven Policies re-approve innerhalb 30 Tage. |
| EC-11 | Verfahrensdoku-PDF > 20 MB | Stream-Rendering als Chunked Upload in S3, Download via presigned URL. Nie in DB. |
| EC-12 | Mitarbeiter stellt Art. 15-Antrag, System ist überlastet | Antrag queued, Mitarbeiter erhält Bestätigung mit Fertigstellungs-SLA (max. 30 Tage). Bei Überlast eskaliert Monitoring; Art. 12 Abs. 3 erlaubt einmalige Verlängerung um 2 Monate mit Begründung. |
| EC-13 | Integrity-Check findet historischen Bruch (jemand hat 2023 etwas verändert) | Report markiert genau den fraglichen Block, Zeit-Bereich, User. Incident-Response-Playbook: forensische Analyse, ggf. Meldung an Behörden (Art. 33 DSGVO 72 h). |
12. Akzeptanzkriterien (Gherkin)
Abschnitt betitelt „12. Akzeptanzkriterien (Gherkin)“Funktionalität: Compliance & Audit
Hintergrund: Angenommen ein Tenant "shk-gebruder-schmidt" mit aktivem Modul-Gate "module.kern.compliance-audit" Und ein Nutzer "Hannes" (Mitarbeiter) Und ein Nutzer "Markus" (Admin) Und ein Nutzer "Frau Bengescu" (DPO, extern) Und der Audit-Log enthält 48.172 Events, 47 Monats-Anker
Szenario: Happy Path — Art. 15 Datenauskunft durch Mitarbeiter Wenn Hannes in der Mobile-App "Meine Daten (Art. 15)" öffnet Und den Antrag per Passkey bestätigt Und die vorausgewählten Kategorien bestätigt Dann wird ein DSGVO-Antrag mit artikel="15", status="offen" erstellt Und der Antragsteller erhält eine Bestätigung mit SLA-Datum (30 Tage) Und ein Audit-Event "dsgvo.antrag.erstellt" wird geschrieben Wenn Markus "Export generieren" klickt Dann wird innerhalb 15 min ein ZIP mit personendaten.json, auskunft.pdf und anhaenge/ erzeugt Und Hannes erhält eine Push-Notification mit Download-Link (presigned URL, 7 Tage) Und ein Audit-Event "dsgvo.antrag.abgeschlossen" wird geschrieben
Szenario: Grenzfall — Integrity-Check erkennt DB-Manipulation Angenommen ein Ops-User hat direkt per SQL eine audit_events-Zeile verändert Wenn Markus "Chain prüfen" klickt Dann erkennt der Integrity-Check Block 42.118 als korrupt Und der Report zeigt den exakten Zeitstempel, User und Diff der Manipulation Und ein Audit-Event "compliance.integrity.broken" wird erzeugt Und Markus erhält sofort eine E-Mail + SRE-Pager-Alert Und der Integrity-Check-Report wird als PDF + signiertes JSON gespeichert
Szenario: Grenzfall — GoBD-Kollision mit Art. 17-Löschungsanfrage Angenommen Hannes (noch im Betrieb) stellt einen Art. 17-Antrag auf komplette Löschung Wenn Markus den Antrag prüft Dann zeigt die UI die maßgeblichen Aufbewahrungsfristen pro Tabelle Und der Antrag wird abgelehnt mit Begründung "§147 AO 10 Jahre, Art. 17 Abs. 3 b DSGVO" Und Hannes erhält diesen Bescheid als PDF Und ein Audit-Event "dsgvo.antrag.abgelehnt" mit dieser Begründung wird geschrieben
Szenario: Grenzfall — BR-Widerruf einer Aggregations-View Angenommen eine Aggregations-View "Durchschnittliche Überstunden je MA" ist seit 2 Monaten aktiv Wenn Herr Gärtner (BR-Vorsitzender) "Freigabe widerrufen" klickt Und eine Begründung eingibt Dann wird die View in allen Dashboards sofort ausgeblendet Und bereits erzeugte PDF-Exporte werden serverseitig entwertet (Download-Links 403) Und ein Audit-Event "betrvg.aggregation.widerrufen" wird geschrieben Und der Admin wird benachrichtigt
Szenario: Grenzfall — Multi-Tenant-Isolation im Audit-Browser Angenommen ein zweiter Tenant "musterbetrieb-maler" mit eigenen Audit-Events Wenn Markus (shk-gebruder-schmidt) versucht, per API GET /audit/{id} mit einer fremden Event-ID aufzurufen Dann antwortet die API mit 404 Und es entsteht KEIN Cross-Tenant-Eintrag Und der Zugriffsversuch selbst wird in Tenant shk-gebruder-schmidt als audit.read.forbidden geloggt
Szenario: Grenzfall — Monats-Anker-Cronjob nach KMS-Key-Rotation Angenommen der ed25519-Schlüssel wurde am 01.05.2026 von Version v2025-01 auf v2026-05 rotiert Wenn der Cronjob am 01.06.2026 00:10 UTC den Mai-Anker erstellt Dann wird der Anker mit key_version="v2026-05" signiert Und der April-Anker bleibt mit key_version="v2025-01" verifizierbar Und der Integrity-Check kann beide Versionen validieren13. Test-Cases
Abschnitt betitelt „13. Test-Cases“13.1 Unit-Tests (TypeScript + Dart)
Abschnitt betitelt „13.1 Unit-Tests (TypeScript + Dart)“- U-01 — JCS-Kanonisierung (RFC 8785) auf 1.000 Zufalls-Objekten, Re-Roundtrip muss identisches Byte-Output liefern.
- U-02 — SHA-256-Chain: Genesis-Block + 1.000 Blöcke, Chain-Break-Detection an Block 500 durch Mutation.
- U-03 — ed25519-Sign/Verify mit KMS-Mock, 100 Samples.
- U-04 — Merkle-Tree-Bau auf 10.000 Hashes, Root-Stabilität.
- U-05 — Retention-Policy-Resolver: Gegeben ein MA mit Austritts-Datum und Tabellen-Policies, berechne Löschungs-/Pseudonymisierungs-Datum korrekt.
- U-06 — SLA-Counter DSGVO: Gegeben Antrags-Datum, Feiertage, Wochenenden → korrekte Deadline nach Art. 12 Abs. 3.
- U-07 — Pseudonymisierungs-Hash mit Tenant-Salt: identische Namen in verschiedenen Tenants → unterschiedliche Hashes.
- U-08 — Mobile-DSGVO-Wizard Dart-Widget: Passkey-Re-Auth erzwungen, Back-Button-Verhalten.
13.2 Widget- / Component-Tests
Abschnitt betitelt „13.2 Widget- / Component-Tests“- W-01 — Mobile Audit-Trail-List Golden-Test (de-DE + en-US), Dark + Light Theme.
- W-02 — DSGVO-Wizard Schritt-Navigation, Fokus-Reihenfolge.
- W-03 — Admin Audit-Browser Table-Sort, Cursor-Pagination.
13.3 Integrations-Tests (Drizzle In-Memory)
Abschnitt betitelt „13.3 Integrations-Tests (Drizzle In-Memory)“- I-01 — Multi-Tenant-Isolation für alle 17 Compliance-Endpunkte (DOD §2.2).
- I-02 — RLS: Mitarbeiter sieht nur eigene Audit-Events.
- I-03 — Trigger-Test: UPDATE auf audit_events schlägt fehl (Permission denied).
- I-04 — Monats-Anker-Cronjob: schreibt atomar Anker + Audit-Event; bei Fehler Rollback beides.
- I-05 — DSGVO-Antrag-Dedup: Zweiter offener Antrag gleichen Typs → 409.
- I-06 — Retention-Policy-Änderung ohne DPO-Co-Sign → 403.
13.4 E2E-Tests (Playwright + Patrol)
Abschnitt betitelt „13.4 E2E-Tests (Playwright + Patrol)“- E-01 — Happy Path Art. 15 aus §12 (Mobile + Web).
- E-02 — Integrity-Check mit 100k Events in < 30 s (Last-Szenario).
- E-03 — Visuelle Regression: Verfahrensdoku-PDF-Rendering Golden-Test.
- E-04 — Accessibility: axe-core auf allen Compliance-Screens + Flutter-Semantics-Test für Mobile-DSGVO-Flow.
- E-05 — BR-Freigabe End-to-End: Admin-Antrag → BR-Genehmigung → View sichtbar → Widerruf → View weg.
13.5 Compliance-Tests (Suite apps/api/test/compliance/audit/)
Abschnitt betitelt „13.5 Compliance-Tests (Suite apps/api/test/compliance/audit/)“- C-01 — Hash-Chain-Bruch-Detection: gezielt eine Zeile manipulieren, Integrity-Check muss in < 1 s Bruch erkennen (DOD §2.2 Pflicht-Test).
- C-02 — ed25519-Verifikation: Monats-Anker mit absichtlich falscher Signatur → Detection.
- C-03 — GoBD-Verfahrensdoku-Template-Abdeckung: Jedes GoBD-Pflichtkapitel (Verantwortliche, Datenerfassung, Datenaufbewahrung, Internal Control, …) erscheint im Generator-Output.
- C-04 — DSGVO-Exporteinheit: Art. 15-Paket enthält alle Pflichtfelder, keine Daten Dritter.
- C-05 — Art. 17-GoBD-Kollisions-Test: Löschungs-Antrag auf Lohn-pflichtige Daten → korrekte Ablehnung + Maskierungs-Hinweis.
- C-06 — Retention-Engine-Test: 5-Jahres-alter Datensatz mit 2-Jahres-Frist wird als „zur Pseudonymisierung fällig“ markiert.
- C-07 — S3 Object Lock: Attempt zu DELETE auf Anker-Objekt → AWS-SDK-Fehler.
13.6 Flakiness-Schutz
Abschnitt betitelt „13.6 Flakiness-Schutz“- 20× Re-Run der Cronjob-Tests (Zeitbezug) grün.
- 20× Re-Run der Integrity-Check-Tests mit variierender Event-Anzahl.
14. Nicht-Ziele
Abschnitt betitelt „14. Nicht-Ziele“| Nicht-Ziel | Begründung |
|---|---|
| Automatische Meldung an Landesdatenschutzbehörde (Datenpannen-Workflow Art. 33) | V2. In MVP wird nur intern dokumentiert; Meldung an Behörde manuell. |
| Blockchain-Anker (Bitcoin, Ethereum) | Rechtlich nicht als qualifizierter Zeitstempel anerkannt. RFC 3161 bei VDA ist die richtige Lösung. |
| Vollständige Pentest-Dokumentation | Liegt im CISO-Bereich, nicht im Produkt. Verfahrensdoku verlinkt auf Pentest-Reports. |
| Zero-Knowledge-Proofs für Audit-Verifikation | Overengineering für B2B-Handwerk. Standard-ed25519 + Merkle-Tree reicht. |
| Multi-Region-Replikation für Hash-Chain | MVP: single-region eu-central-1. V2 bei Bedarf Cross-Region-Read-Replica. |
| Automatisierte DSFA-Erstellung | DSFA bleibt manuelle Arbeit des DPO; wir liefern nur die Datengrundlage. |
| Benutzerdefinierte Audit-Events über Plugin-API | V2; MVP nur festes Event-Katalog. |
| Real-time Audit-Stream für SIEM (Splunk, QRadar) | V1.5 via Webhook-Events + Webhook-Receiver. MVP: Events nur in Werkszeit-DB. |
15. Risiken & offene Annahmen
Abschnitt betitelt „15. Risiken & offene Annahmen“| Risiko / Annahme | Impact | Wahrscheinlichkeit | Gegenmaßnahme |
|---|---|---|---|
| Hash-Chain-Performance bei Peak (> 500 Events/s) | hoch | mittel | Queue-based Audit-Writer (SQS), Benchmark mit Seed-Tenant-Load vor Release |
| RFC 3161-VDA hat Service-Downtime zum 31.12. | mittel | niedrig | Fallback auf zweiten VDA; monatlicher Smoke-Test; Notariats-Anker ist V1.5, MVP reicht interner Anker |
| KMS-Key-Verlust (Region-Ausfall) | sehr hoch | sehr niedrig | Multi-Region-Key-Replikation, Backup-KMS in eu-west-1 |
| Rechtliche Neuinterpretation Art. 17 (BGH-Urteil, das GoBD-Vorrang kippt) | hoch | niedrig | Jährlicher Rechts-Review durch Fachkanzlei; Architektur erlaubt Policy-Wechsel ohne Code-Release |
| Betriebsrat verweigert jegliche Aggregations-View | niedrig | mittel | Features bleiben funktionsfähig ohne Aggregations-Views; nur statistische Berichte entfallen |
| Mitarbeiter-Masse-DSGVO-Anträge als Störungs-Taktik (100 Anträge in einer Woche) | mittel | niedrig | Rate-Limit pro Antragsteller (1 pro 90 Tage, Art. 12 Abs. 5 erlaubt bei „offensichtlich unbegründet“ Ablehnung), Queue |
| Jahres-Audit-Volumen überschreitet S3 Object Lock Limits | niedrig | sehr niedrig | S3 skaliert praktisch unbegrenzt; Kosten-Monitoring |
16. Abhängigkeiten
Abschnitt betitelt „16. Abhängigkeiten“- Vorbedingung:
kern/09-auth-self-serviceliefert Rollen-Model + Passkey-Re-Auth für DSGVO-Bestätigung. - Schnittstelle zu: AWS KMS (ed25519-Keys), AWS S3 Object Lock (
werkszeit-audit-eu-central-1-Bucket), Webhook-Bus (§3.12), RFC 3161-VDA (V1.5). - Wird konsumiert von: allen Werkszeit-Features, weil jedes mutierende Endpoint
audit_eventsschreibt. DATEV (kern/10) nutzt den Monatsschluss-Lock aus diesem Feinkonzept. Reporting (kern/07) nutztaudit_eventsals Quelle für Änderungs-Reports.
17. Referenzkunde-Slot
Abschnitt betitelt „17. Referenzkunde-Slot“Status: TBD — zu klären mit Sales / Product-Owner.
DOR §1.1.1 verlangt: „Mindestens ein zahlender Design-Partner ist namentlich dokumentiert, der das Feature konkret fordert.“
Kandidaten-Profile:
- Handwerksbetrieb 50–150 MA mit externem Datenschutzbeauftragten + aktivem Betriebsrat
- Betrieb, der kürzlich eine Betriebsprüfung durchlaufen hat und die Schmerzpunkte aus erster Hand kennt
- Ggf. Steuerkanzlei mit GoBD-Beratungsgeschäft, die Compliance als USP will
Validierungs-Fragen:
- Wie viele Stunden kostet Sie ein Art. 15-Auskunftsantrag heute?
- Haben Sie eine aktuelle Verfahrensdokumentation (Stand < 12 Monate)?
- Gab es schon einmal Diskussionen mit dem BR über Software, die „zu viel weiß“?
- Wären Sie bereit, das Feature als erster Kunde 60 Tage im Beta zu testen, inklusive Penetrationstest durch Ihren IT-Prüfer?
18. Senior-Berater-Empfehlung
Abschnitt betitelt „18. Senior-Berater-Empfehlung“Build-Sequenz:
- Datenmodell (
audit_events,audit_anchors,dsgvo_antraege,retention_policies,vvt_eintraege) + RLS + UPDATE/DELETE-Revoke. - Audit-Writer-Bibliothek (
@werkszeit/audit) — jede mutierende Operation ruft sie auf. Alle Feature-Teams integrieren sie vor allem anderen. - Hash-Chain-Berechnung + Test gegen DB-Trigger-Manipulation.
- Monats-Anker-Cronjob + KMS-ed25519-Integration.
- Integrity-Check-Endpoint + PDF-Report-Generator.
- DSGVO-Antrags-Flow (Mobile Wizard + Web Dashboard + Export-Generator).
- Retention-Policy-Editor + DPO-Co-Sign-Workflow.
- Verfahrensdoku-Generator.
- VVT-Export.
- BR-Freigabe-Workflow (V1) + Notariats-Anker (V1.5) + Datenpannen-Workflow (V2).
Risiko-Reihenfolge:
- Hash-Chain-Integrität ist die Essenz. Wenn die kaputt ist, ist das gesamte Compliance-Versprechen kaputt.
- DSGVO-Art. 17 mit GoBD-Kollision — falsche Reihenfolge wäre ein Rechtsrisiko.
- Audit-Writer-Latenz — wenn der Writer Mutations blockiert, wird die ganze App langsam.
Streich-Kandidaten bei Zeitnot:
- BR-Freigabe-Workflow → V1.
- Notariats-Anker → V1.5.
- VVT-Excel-Export → V1 (JSON reicht MVP).
- Mobile-Audit-Trail offline-Cache → V1.
Stop-the-Bus-Triggers:
- Integrity-Check-Test schlägt fehl → Merge blockiert, SRE-Pager.
- Multi-Tenant-Bleed-Test im Audit schlägt fehl → Deploy blockiert.
- Art. 17-Löschung ohne DPO-Approval möglich → Sofort-Patch.
- ed25519-Sign-Aufruf findet Private Key außerhalb KMS → Security-Incident.
Was uns 2027 dankbar macht:
- Das zentrale
@werkszeit/audit-Modul wird zum Differenzierungs-Merkmal gegenüber SaaS-Konkurrenten. Wer jemals eine Betriebsprüfung mit Werkszeit durchlaufen hat, bleibt — weil der Wechsel die Verfahrensdoku und den externen Anker neu aufsetzen würde. - Der DSGVO-Self-Service senkt Support-Tickets dauerhaft um einen Faktor ~5 gegenüber manueller Bearbeitung.
- Die Retention-Engine ist die Grundlage, um später Multi-Jurisdiction-Compliance (Österreich, Schweiz) anzubauen, ohne den Audit-Log neu zu denken.
Feinkonzept-Version 1.0 · Stand 2026-04-20 · Autor: Senior Consultant · Review: Tech-Lead + CISO + DPO
Für Entwickler — API-Endpoints16
| Methode | Pfad | Auth | Zweck |
|---|---|---|---|
| POST | /v1/kern/compliance/anchor/{year}/{month} | bearerAuth | Create or fetch the monthly audit anchor (system scope) |
| GET | /v1/kern/compliance/audit | bearerAuth | List audit events (cursor-paginated) |
| GET | /v1/kern/compliance/audit/{id} | bearerAuth | Fetch a single audit event (incl. hash fields) |
| POST | /v1/kern/compliance/audit/integrity-check | bearerAuth | Start an async hash-chain integrity check |
| GET | /v1/kern/compliance/audit/integrity-check/{id} | bearerAuth | Fetch integrity-check job status and report |
| POST | /v1/kern/compliance/br/aggregation-request | bearerAuth | Request Betriebsrat approval for a new aggregation view |
| POST | /v1/kern/compliance/br/aggregation-request/{id}/freigeben | bearerAuth | Record the Betriebsrat's decision on an aggregation request |
| GET | /v1/kern/compliance/retention | bearerAuth | List retention policies |
| PUT | /v1/kern/compliance/retention/{id} | bearerAuth | Update a retention policy (requires DPO co-sign) |
| GET | /v1/kern/compliance/verfahrensdoku | bearerAuth | Generate and download the Verfahrensdokumentation PDF |
| GET | /v1/kern/compliance/vvt | bearerAuth | List the Verzeichnis von Verarbeitungstätigkeiten (Art. 30) |
| PUT | /v1/kern/compliance/vvt/{id} | bearerAuth | Update a VVT entry |
| POST | /v1/kern/dsgvo/antrag | bearerAuth | File a DSGVO Art. 15/17/20 request (self-service) |
| GET | /v1/kern/dsgvo/antrag/{id} | bearerAuth | Fetch DSGVO request status |
| POST | /v1/kern/dsgvo/antrag/{id}/export-generieren | bearerAuth | Generate the Art. 15/20 export bundle (admin/DPO) |
| POST | /v1/kern/dsgvo/antrag/{id}/pseudonymisieren | bearerAuth | Execute the Art. 17 pseudonymisation flow |