Zum Inhalt springen

DATEV-Integration — LODAS-ASCII, EXTF, Monatsabschluss, Korrekturlauf

Live in Produktion

Feinkonzept · §3.10 DATEV-Integration — LODAS-ASCII, EXTF, Monatsabschluss, Korrekturlauf

Abschnitt betitelt „Feinkonzept · §3.10 DATEV-Integration — LODAS-ASCII, EXTF, Monatsabschluss, Korrekturlauf“

Einordnung. Dieses Feinkonzept setzt FUNKTIONSUMFANG §3.10 um. DATEV ist in Deutschland nicht „ein“ Lohn-Abrechnungssystem unter vielen — es ist in rund 40 % der mittelständischen Handwerksbetriebe der de-facto-Standard, verzahnt mit dem Steuerberater. Wer Zeiterfassung baut, baut Lohn-Vorbereitung; wer Lohn-Vorbereitung baut und DATEV nicht sauber bedient, liefert ein halbes Produkt. Frau Müller in der Buchhaltung tippt heute Überstunden, Krankheit, Urlaub und Spesen in drei Systeme ab; jedes Zahlenspiel ist Handarbeit. Wir setzen auf zwei parallele Wege, nicht einen: LODAS-ASCII für Lohnbuchhalter, die in DATEV LODAS mandantenseitig arbeiten, und EXTF für die Kanzlei, die in DATEV Lohn und Gehalt klassisch bucht. LESSONS-LEARNED §8 mahnt uns: niemals einen proprietären CSV-Export als „DATEV-Export“ verkaufen — das hat die Alt-App so gemacht, und es hat Frau Müller eine Stunde pro Monat gekostet, die Mapping-Fehler händisch zu korrigieren.


feature_id: kern/10-datev-integration
title: DATEV-Integration — LODAS-ASCII, EXTF, Monatsabschluss, Korrekturlauf
funktionsumfang_ref: §3.10
roadmap_horizont: MVP # Ohne DATEV kein Markt — Pflicht ab Tag 1
plattformen:
mobile: aus # Lohn-Export ist Back-Office-Arbeit
web: vollständig # Export, Status, Korrektur, Mandanten-Setup
desktop: aus
owner_rolle: Buchhaltung # Frau Müller; Admin macht Mandanten-Setup
modul_gate_flag: module.kern.datev
compliance_flags:
gobd: true # Lohn-Export ist handelsrechtlich relevant
arbzg: false
vob: false
dsgvo: true # Sozialversicherungsnummer, Bankdaten — Art. 9/Art. 88
bfsg: false # Back-Office-Funktion, kein ESS
betrvg: false # §87(1)6 greift nicht bei Lohn-Export
stvg: false
weitere:
- "§147 AO (10-Jahres-Aufbewahrung der Lohnunterlagen)"
- "§41 EStG (Lohnsteuerabzug, Aufzeichnungspflicht)"
- "§28f SGB IV (Sozialversicherungs-Beitragsnachweise)"
- "DATEV-Schnittstellenbeschreibung Lohnvorerfassung (LODAS-ASCII, Stand Jg. 2026)"
- "DATEV EXTF-Format v9.0 (Kassenbuch / Finanzbuchhaltung / Lohn)"
- "DATEV Unternehmen online API v1.4 (optional ab V1)"
referenzkunde:
status: TBD
name: "zu klären — Zielprofil: Handwerksbetrieb 40–80 MA mit externer Steuerkanzlei, DATEV-Mandat bestätigt"
quelle: "Sales-Discovery + Steuerberater-Netzwerk ZDH/HWK"
estimate_eng_tage: 38 # LODAS-Writer (10), EXTF-Writer (6), Mapping-UI (8),
# Monatsabschluss (6), Korrekturlauf (4), DUO-API (4)
abhängigkeiten:
- kern/01-zeiterfassung # Ist-Stunden sind die Quelle
- kern/02-arbeitszeit-compliance # Überstunden-/Nachtzuschlag-Kategorisierung
- kern/03-abwesenheiten # Krank/Urlaub-Tage gehen als AAG/EFZG
- kern/06-spesen-reisemanagement # Verpflegungsmehraufwand, Km-Geld
- kern/11-compliance-audit # Export ist ein auditierter Vorgang

Marktrealität (DE-Handwerk). In der typischen Gebrüder-Schmidt-GmbH (SHK, 80 MA) übernimmt die Buchhaltung — Frau Müller, 56, seit 22 Jahren im Betrieb — die Lohn-Vorbereitung. Sie zieht am 25. jedes Monats den „Lohnjournal“-Bericht aus der Alt-App (das war in der Alt-App: eine CSV-Datei mit 18 Spalten, datum;name;stunden;zuschlag;projekt;…), öffnet Excel, schiebt Spalten, löscht Kopfzeile, gleicht Überstunden-Konten händisch ab, tippt Zuschläge in einen DATEV-Erfassungsbogen und schickt ihn per DATEV-Unternehmen-Online an den Steuerberater. Das Ganze kostet sie 3–4 Arbeitsstunden pro Monat, produziert reihenweise Fehler (Komma statt Punkt, falsche Lohnart, vergessene Schlüsselzahlen) und wird vom Steuerberater mit monatlichen Rückfragen quittiert. Beim Maler-Betrieb mit 25 MA macht das die Steuerkanzlei direkt aus dem übergebenen Ordner — kein Export, keine Datenhaltung im Betrieb. Beide Fälle sind legitim, beide wollen wir bedienen.

Rechtlicher Rahmen. Lohnunterlagen unterliegen §147 AO (10 Jahre Aufbewahrung), §41 EStG (Lohnkonten-Pflichtfelder) und §28f SGB IV (Beitragsnachweis). Die DATEV-Schnittstelle ist nicht gesetzlich normiert, aber faktisch Pflichtstandard: Wer als Betrieb „DATEV-Export“ bewirbt, muss das offizielle LODAS-ASCII-Format der aktuellen Jahrgangsversion oder EXTF liefern, sonst stößt er bei der Steuerkanzlei auf eine verschlossene Tür. LODAS-ASCII ist ein CP1252-codiertes Festlängen-ASCII-Format mit Satzarten (100 Stammsatz, 110 Bewegungssatz, 120 Zuschlags-/Zulagensatz), strengem Spaltenraster und DATEV-spezifischen Schlüsselzahlen (Lohnart 1=Grundlohn, 5=Überstunden, 9=Sonntagszuschlag…). EXTF (externe Datei) ist ein CSV-Format mit 730+ Feldern in der Finanzbuchhaltung und einem separaten Lohn-Layout (v9.0), UTF-8 mit BOM, Semikolon-separiert, Buchungsperiode hart auf Monat normiert. DATEV Unternehmen online ist die Web-API-Brücke, die den Dateiversand automatisieren kann — optional, nicht MVP-kritisch.

Schmerzpunkt der Alt-App. LESSONS-LEARNED §8 hält fest: Die Alt-App exportierte in einem selbstgestrickten CSV-Format, das die Betriebe als „DATEV-Export“ verkauft bekamen — mit freier Spaltenfolge, deutschem Datumsformat, UTF-8 ohne BOM. Kein Steuerberater konnte das direkt importieren. Es entstand eine Zwischenschicht („Frau Müller’s Excel-Makro“), die Mapping-Fehler produzierte. Die DATEV-Validator-Suite wurde nie angewandt, Jahrgangs-Schlüsselzahlen veralteten. Wir machen das anders: Der Export ist byte-genau DATEV-konform ab dem ersten Release, durchläuft pre-release die DATEV-Validator-Toolchain, und wird als Write-Contract behandelt — was wir schreiben, muss DATEV lesen, keine Ausnahme.

Erwarteter Outcome (SMART).

  • Spezifisch: Monatsabschluss-Klick erzeugt LODAS-ASCII + EXTF, parallel zur Wahl, mit Versand-Status und Audit-Trail.
  • Messbar: Lohn-Vorbereitungszeit Frau Müller von 240 min/Monat auf ≤ 20 min/Monat (91 % Reduktion).
  • Achievable: 38 Engineering-Tage für MVP (Writer + Mapping-UI + Korrekturlauf).
  • Relevant: DATEV-Mapping-Fehlerquote < 0,5 % (Steuerberater-Rückfragen).
  • Terminiert: Ab MVP-Release (ohne DATEV ist die App im deutschen Handwerk unverkäuflich — DOR §1.2.1).

Rolle Aktion Scope Plattform
Buchhaltung Monatslauf anstoßen, Mapping pflegen, Export herunterladen all 🌐
Admin Mandantenstamm (Beraternummer, Mandantennummer, Lohnkonten-Zuordnung) pflegen all 🌐
Steuerberater (extern) Optional: liest Export via DATEV Unternehmen online API
Manager Monatslauf-Freigabe (fachliche Prüfung: Überstunden-Konten korrekt?) team 🌐
Mitarbeiter Keine direkte Interaktion; sieht nur „Lohn-Beleg Januar versandt“ im ESS own 📱 (nur Info)

Persona-Skizzen:

  • Frau Müller (Buchhaltung, 56, SHK-Betrieb Gebr. Schmidt) — Tastatur-User, kennt DATEV LODAS seit 2005. Erwartet Jahres-Versionswechsel automatisch, will keine Excel-Brücke mehr. Verzichtet gern auf Schönheit, besteht auf Präzision.
  • Herr Schuster (Steuerberater extern, Kanzlei Schuster & Partner, betreut 80 Mandanten) — bekommt EXTF-Dateien per DATEV Unternehmen online direkt ins Rechnungswesen. Rückfrage-Typ: „Wo ist die Schlüsselzahl 9 bei Hannes’ Sonntagsstunden?“ — wenn das passiert, ist unser Mapping kaputt.
  • Markus (Admin, 34, IT-affiner Meister) — setzt einmalig die Mandantennummer, Beraternummer, Lohnart-Mapping auf. Will klare Defaults für die Branchen-Tarifverträge (TV Maler, SOKA-Bau, TV SHK).

US-01 [MVP] Als Buchhaltung möchte ich am Monatsende einen Klick "DATEV-Export"
drücken und eine valide LODAS-ASCII-Datei + EXTF-Datei erhalten,
um den Lauf in <=5 Minuten an die Kanzlei zu übergeben.
US-02 [MVP] Als Buchhaltung möchte ich das Mapping "Werkszeit-Zeitart → DATEV-
Lohnart" einmal pflegen, um es nicht jeden Monat neu zu tippen.
US-03 [MVP] Als Buchhaltung möchte ich bei Korrekturen einen Nachlauf erzeugen
können (Storno + Neu), ohne die Original-Datei manuell zu editieren.
US-04 [MVP] Als Admin möchte ich Beraternummer + Mandantennummer validiert
eingeben (Check-Digit), um Fehlläufe zum Steuerberater zu vermeiden.
US-05 [MVP] Als Manager möchte ich den Monatsabschluss fachlich freigeben,
bevor die Buchhaltung exportiert — keine Export-Datei ohne 4-Augen.
US-06 [V1] Als Buchhaltung möchte ich den Versand via DATEV Unternehmen online
direkt aus Werkszeit anstoßen, um die manuelle Upload-Strecke
zu sparen.
US-07 [V1] Als Steuerberater möchte ich Rückläufer (Import-Fehler) in Werkszeit
sehen, um sie dort zu korrigieren statt per E-Mail.
US-08 [V1.5] Als Admin möchte ich den Jahrgangs-Wechsel (2026→2027) per
automatischem Update der DATEV-Schlüsselzahlen einspielen.
US-09 [V2] Als Referenzkunde möchte ich auch SAP HCM / Sage-Personal anbinden
können, über denselben Lohnart-Mapping-Layer.

— nicht zutreffend, weil DATEV-Export eine Back-Office-Funktion ist. Mitarbeiter sehen im ESS höchstens den Info-Stand „Lohn April 2026 versandt“ — das liegt im Feinkonzept §3.9 Self-Service, nicht hier.

  • F-W-01 — Monatsabschluss-Dashboard: Liste der letzten 13 Monate mit Status-Pill (Entwurf / BR-Freigabe / Buchhaltung-Freigabe / Versandt / Korrekturlauf). Kennzahlen pro Monat: Stunden gesamt, Überstunden, Krank-Tage, Urlaubstage, DATEV-Export-Zeitpunkt, letzter Download. Filter: Jahr, Status, Sortierung chronologisch absteigend.
  • F-W-02 — Export-Wizard (3 Schritte): Schritt 1 „Zeitraum + Mandant wählen“ (Jahr/Monat/Mandantennummer-Auswahl bei Multi-Tenant-Steuerkanzlei), Schritt 2 „Vorschau“ (Tabelle mit Mitarbeiter × Lohnart × Stunden/Betrag, Validierungs-Rot-Markierung fehlender Zuordnungen), Schritt 3 „Format wählen“ (LODAS-ASCII / EXTF / beide) + Download-Trigger.
  • F-W-03 — Mapping-Editor: Tabelle „Werkszeit-Zeitart → DATEV-Lohnart“ mit Autocomplete auf DATEV-Schlüsselzahl-Liste (aktueller Jahrgang). Beispiele: arbeitszeit.regulaer → 1 (Grundlohn), zuschlag.nacht → 13 (Nachtzuschlag), zuschlag.sonntag → 9 (Sonntagszuschlag 50%), abwesenheit.krank → 58 (Entgeltfortzahlung). Validierung: keine ungespeicherten Werte, keine Duplikate.
  • F-W-04 — Korrekturlauf: Jeder bereits versandte Monat bekommt Button „Korrekturlauf erstellen“. Erzeugt Storno-Satz (identische Sätze mit negativen Stunden/Beträgen) + neue korrigierte Sätze. Korrekturlauf referenziert per ref_export_id auf Ursprungs-Export. Audit-Begründung Pflicht (min. 20 Zeichen).
  • F-W-05 — Mandantenstamm-Verwaltung: Eingabemaske für Beraternummer (7-stellig), Mandantennummer (1–5-stellig), Wirtschaftsjahr-Beginn, Kontenrahmen (SKR03/SKR04), DATEV-E-Mail für Rückläufer. Check-Digit-Validierung: offizielle DATEV-Prüfziffer auf Beraternummer-Eingabe.
  • F-W-06 — Monats-Freigabe-Workflow: Manager sieht „zu prüfen“-Queue, gibt per Klick frei (oder verwirft mit Begründung). Erst nach Manager-Freigabe wird der Export-Button für Buchhaltung aktiv.
  • F-W-07 — Versand-Status-Pill: Für jeden Monat: Versandt 15.04.2026 15:32 · Frau Müller · Download-Log 2×. Klick auf Pill öffnet Audit-Detail.
  • F-W-08 — DATEV Unternehmen online API (V1): Zusätzlicher Button „An DATEV senden“ neben Download. OAuth 2.0-Flow beim Mandanten-Setup, API-Call POST /uo/v1/belege.
  • F-W-09 — Dry-Run-Validator: Vor dem echten Export kann Buchhaltung einen „Trockenlauf“ starten — erzeugt Datei, lässt sie durch den internen DATEV-Validator laufen, zeigt Befunde, schreibt nichts in den Audit-Log. Nur finaler Export ist dokumentationspflichtig.
  • F-X-01 — Zeiteinheit konsistent: Stunden werden firmeneinheitlich als Industrie-Stunden (Dezimal, 2 Nachkommastellen) geführt — so wie es die Zeiterfassung §3.1 speichert. DATEV erwartet ebenfalls Industrie-Stunden; wir konvertieren nicht, wir passieren nur durch.
  • F-X-02 — Monatsgrenze hart: Eine Zeitbuchung gehört zu dem Monat, in dem sie angefangen hat. Schichten über Mitternacht am 31.→1. werden beim Tag-Anfang abgeschnitten; die Stunden nach Mitternacht zählen in den Folgemonat (das ist DATEV-Standardverhalten, nicht unsere Wahl).
  • F-X-03 — Nachträgliche Änderung gesperrt: Sobald ein Monat Status Versandt hat, werden die zugrunde liegenden Zeitbuchungen read-only. Änderungen sind nur über Korrekturlauf möglich (siehe F-W-04). Siehe auch Feinkonzept kern/11-compliance-audit §3 „Monatsschluss-Lock“.
  • F-A-01 — Lohnart-Defaults je Branche: Bei Tenant-Anlage kommt ein Wizard, der die Branche abfragt (SHK, Maler, Elektro, Dachdecker, Trockenbau) und die passenden DATEV-Lohnarten inklusive SOKA-Bau-Zuschläge vorbelegt. Admin kann einzelne Mappings überschreiben.
  • F-A-02 — Kontenrahmen-Wahl: SKR03 oder SKR04 (Default SKR03). Betrifft Sachkonten-Zuordnung im EXTF-Export.
  • F-A-03 — Jahrgangs-Pflege: Admin-Oberfläche zeigt, welche DATEV-Schlüsselzahlen-Version aktuell geladen ist (z. B. „Jahrgang 2026, geladen 2026-01-08“). Update-Button lädt aktuelle Version aus datev-schluessel-NPM-Paket (eigenes Repository, gegen DATEV-Schnittstellenbeschreibung validiert).
  • F-A-04 — Feature-Flag-Abschaltung: Wenn Betrieb kein DATEV nutzt (z. B. ADDISON, lexoffice), blendet der Admin module.kern.datev komplett aus. Die Zeiterfassung bleibt erhalten.
Anforderung-ID MVP V1 V1.5 V2
F-W-01 Monatsabschluss-Dashboard
F-W-02 Export-Wizard
F-W-03 Mapping-Editor
F-W-04 Korrekturlauf
F-W-05 Mandantenstamm
F-W-06 Monats-Freigabe
F-W-07 Versand-Status
F-W-08 DUO-API
F-W-09 Dry-Run-Validator
F-A-03 Jahrgangs-Pflege automatisch
SAP HCM / Sage-Writer

HTML-Hero-Mockup: 10-datev-integration.html — Web-primäres Layout mit Monatsabschluss-Dashboard + Export-Wizard.

┌────────────────────────────────────────────────────────────────────────────────┐
│ Werkszeit · shk-gebruder-schmidt Frau Müller · Buchhaltung [▾] │
├────────────────────────────────────────────────────────────────────────────────┤
│ Sidebar │ Lohn-Vorbereitung DATEV │
│ ─────── │ ┌──────────────────────────────────────────────────────────────┐ │
│ Zeit │ │ Monat │ Stunden │ Überst. │ Krank │ Status │ Aktion │ │
│ Urlaub │ │ Apr 2026 │ 13.184 │ 412 │ 54 │ Entwurf │ prüfen │ │
│ Plan │ │ Mrz 2026 │ 14.012 │ 398 │ 38 │ Versandt │ view │ │
│ Projekte │ │ Feb 2026 │ 12.876 │ 302 │ 47 │ Versandt │ view │ │
│ Rechnung │ │ Jan 2026 │ 13.501 │ 421 │ 61 │ Korrektur 1 │ view │ │
│ ▶ DATEV │ │ Dez 2025 │ 11.984 │ 287 │ 89 │ Versandt │ view │ │
│ Audit │ └──────────────────────────────────────────────────────────────┘ │
│ │ Mandant: 12345 · Berater: 1234567 (Kanzlei Schuster) │
│ │ Jahrgang DATEV 2026, Kontenrahmen SKR03 │
│ │ [Monatslauf April starten] [Mapping pflegen] [DUO verbinden] │
└────────────────────────────────────────────────────────────────────────────────┘
┌────────────────────────────────────────────────────────────────────────────────┐
│ Export April 2026 · Vorschau (2/3) [Abbrechen] [Weiter]│
├────────────────────────────────────────────────────────────────────────────────┤
│ 🛡 Compliance: §147 AO · §41 EStG · §28f SGB IV · DSGVO Art. 88 │
│ │
│ Summen pro Lohnart: │
│ ┌──────────────────────────────────────────────────────────────────────────┐ │
│ │ Lohnart │ DATEV-Schl. │ Stunden │ MA │ Mapping │ │
│ │ Grundlohn │ 1 │ 12.140 │ 78 │ ✓ Standard │ │
│ │ Überstunden 25% │ 5 │ 302 │ 42 │ ✓ Standard │ │
│ │ Nachtzuschlag │ 13 │ 81 │ 11 │ ✓ Standard │ │
│ │ Sonntag 50% │ 9 │ 24 │ 6 │ ✓ Standard │ │
│ │ Feiertag 125% │ 10 │ — │ — │ ✓ Standard │ │
│ │ Ruf-Bereitschaft │ —— │ — │ — │ 🔴 NICHT GEMAPPT │ │
│ │ EFZG Krank │ 58 │ 378 │ 12 │ ✓ Standard │ │
│ │ Urlaub │ 65 │ 216 │ 9 │ ✓ Standard │ │
│ │ SOKA-Bau-Zuschlag │ 142 │ — │ — │ ✓ Custom │ │
│ └──────────────────────────────────────────────────────────────────────────┘ │
│ │
│ 🔴 1 Mapping-Lücke: "Ruf-Bereitschaft" hat keine DATEV-Schlüsselzahl. │
│ Ohne Mapping läuft die Datei in LODAS auf Fehler. [Jetzt mappen →] │
└────────────────────────────────────────────────────────────────────────────────┘
┌────────────────────────────────────────────────────────────────────────────────┐
│ Export April 2026 · Format wählen (3/3) [Zurück] [Exportieren]│
├────────────────────────────────────────────────────────────────────────────────┤
│ │
│ Zu welchem DATEV-Format? │
│ ( ) LODAS-ASCII (für DATEV LODAS, CP1252, Festlänge) │
│ (•) EXTF v9.0 (für DATEV Lohn und Gehalt, UTF-8 BOM, CSV) │
│ ( ) Beide parallel (ZIP mit beiden Dateien) │
│ │
│ [ ] Zusätzlich via DATEV Unternehmen online direkt versenden (DUO-API) │
│ │
│ Dry-Run: Datei wurde intern mit dem DATEV-Validator geprüft — alle Regeln │
│ eingehalten (0 Fehler, 0 Warnungen). ✓ │
│ │
│ [Export erstellen] │
│ │
│ Nach dem Export wird dieser Monat schreibgeschützt. Änderungen nur per │
│ Korrekturlauf. │
└────────────────────────────────────────────────────────────────────────────────┘
┌────────────────────────────────────────────────────────────────────────────────┐
│ Lohnart-Mapping · Tenant shk-gebruder-schmidt · Branche SHK │
├────────────────────────────────────────────────────────────────────────────────┤
│ ┌──────────────────────────────────────────────────────────────────────────┐ │
│ │ Werkszeit-Zeitart │ DATEV-Lohnart │ Konto (SKR03) │ │
│ │ arbeitszeit.regulaer │ 1 Grundlohn │ 6200 │ │
│ │ arbeitszeit.ueberstunde_25 │ 5 Überstunden 25% │ 6200 │ │
│ │ arbeitszeit.ueberstunde_50 │ 6 Überstunden 50% │ 6200 │ │
│ │ zuschlag.nacht │ 13 Nachtzuschlag │ 6206 │ │
│ │ zuschlag.sonntag │ 9 Sonntag 50% │ 6206 │ │
│ │ zuschlag.feiertag │ 10 Feiertag 125% │ 6206 │ │
│ │ bereitschaft.ruf │ ▼ Bitte wählen … │ 🔴 │ │
│ │ abwesenheit.krank │ 58 EFZG │ 6210 │ │
│ │ abwesenheit.urlaub │ 65 Urlaub │ 6220 │ │
│ │ spesen.verpflegung_12h │ 300 Verpflegungsmehr. │ 4674 │ │
│ │ soka.bau.zuschlag │ 142 SOKA-Bau │ 6100 │ │
│ └──────────────────────────────────────────────────────────────────────────┘ │
│ [+ Zeile] [Branchen-Defaults wiederherstellen] [Speichern] │
└────────────────────────────────────────────────────────────────────────────────┘
┌────────────────────────────────────────────────────────────────────────────────┐
│ Korrekturlauf für Januar 2026 [Abbrechen] [OK]│
├────────────────────────────────────────────────────────────────────────────────┤
│ │
│ Originallauf: 15.02.2026 14:08 · Export-ID export_2026-01_v1 │
│ │
│ Welche Änderung? │
│ ( ) Einzelne Buchung korrigieren │
│ (•) Komplett-Storno + Neulauf │
│ │
│ Begründung (Pflicht, min. 20 Zeichen): │
│ ┌──────────────────────────────────────────────────────────────────────────┐ │
│ │ Mehmet Yılmaz: Nachträgliche Genehmigung 4 h Samstagsarbeit KW2, │ │
│ │ Freigabe durch Thomas Schmidt 2026-02-28, DGUV-Meldung Nr. 2026-014. │ │
│ └──────────────────────────────────────────────────────────────────────────┘ │
│ │
│ Die erzeugte Datei enthält: │
│ • Storno aller Originalsätze (negative Stunden) │
│ • Neue korrigierte Sätze │
│ • Referenz export_ref = export_2026-01_v1 │
│ │
│ [Korrekturlauf erstellen] │
└────────────────────────────────────────────────────────────────────────────────┘
┌────────────────────────────────────────────────────────────────────────────────┐
│ Audit-Trail · Monat März 2026 │
├────────────────────────────────────────────────────────────────────────────────┤
│ 📅 2026-04-15 09:12 datev.monatslauf.erstellt Frau Müller │
│ 📅 2026-04-15 10:24 datev.monatslauf.freigegeben Thomas Schmidt (Bauleiter) │
│ 📅 2026-04-15 15:32 datev.export.lodas-ascii Frau Müller │
│ └─ Datei SHA256: 4a8f…c9b2 │
│ └─ 412 Sätze, 17 KB CP1252, Validator ✓ │
│ 📅 2026-04-15 15:33 datev.export.extf Frau Müller │
│ └─ Datei SHA256: 8b1c…92e7 │
│ 📅 2026-04-15 15:45 datev.duo.versandt System (DUO-API v1.4) │
│ └─ DUO-Beleg-ID bel_9af82b3c · Empfang bestätigt │
│ 📅 2026-04-22 11:08 datev.download Frau Müller (Re-Download) │
│ │
│ Aufbewahrung: Datei + Audit bis 31.12.2036 (§147 AO, 10 Jahre) │
└────────────────────────────────────────────────────────────────────────────────┘

Symbol-Konvention. 🔴 Pflichtfeld / Error, Validierung ok, 📅 Audit-Zeitstempel, Download, Upload, Select.


Pseudo-Drizzle-Schema.

apps/api/src/db/schema/datev.ts
export const datevMandantenTable = pgTable('datev_mandanten', {
id: uuid('id').primaryKey().defaultRandom(),
tenantId: uuid('tenant_id').notNull().references(() => tenantsTable.id),
beraternummer: varchar('beraternummer', { length: 7 }).notNull(), // DATEV-Beraternr
mandantennummer: varchar('mandantennummer', { length: 5 }).notNull(), // innerhalb Berater
kontenrahmen: varchar('kontenrahmen', { length: 5 }).notNull(), // SKR03 | SKR04
wjBeginnMonat: integer('wj_beginn_monat').notNull().default(1), // Jan=1
jahrgang: varchar('jahrgang', { length: 4 }).notNull(), // "2026"
duoClientId: text('duo_client_id'), // OAuth bei DUO
duoRefreshToken: text('duo_refresh_token_encrypted'), // KMS-verschlüsselt
createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(),
}, (t) => ({
tenantIdx: uniqueIndex('datev_mandanten_tenant_idx').on(t.tenantId),
berMandCheck: check('datev_ber_digit', sql`length(${t.beraternummer})=7`),
}));
export const datevLohnartMappingTable = pgTable('datev_lohnart_mapping', {
id: uuid('id').primaryKey().defaultRandom(),
tenantId: uuid('tenant_id').notNull().references(() => tenantsTable.id),
zeitart: varchar('zeitart', { length: 64 }).notNull(), // 'arbeitszeit.regulaer'
datevSchluessel: integer('datev_schluessel').notNull(), // 1, 5, 9, 13, 58 …
sachkonto: varchar('sachkonto', { length: 8 }).notNull(), // '6200'
bezeichnung: varchar('bezeichnung', { length: 80 }).notNull(), // 'Grundlohn'
createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(),
createdBy: uuid('created_by').notNull().references(() => usersTable.id),
}, (t) => ({
tenantZeitUq: uniqueIndex('datev_lohnart_tenant_zeit_uq').on(t.tenantId, t.zeitart),
}));
export const datevMonatslaufTable = pgTable('datev_monatslaufe', {
id: uuid('id').primaryKey().defaultRandom(), // UUID v7 (Idempotenz)
tenantId: uuid('tenant_id').notNull().references(() => tenantsTable.id),
jahr: integer('jahr').notNull(),
monat: integer('monat').notNull(),
status: varchar('status', { length: 24 }).notNull(), // entwurf | freigabe | versandt | korrektur
refMonatslaufId: uuid('ref_monatslauf_id').references(() => datevMonatslaufTable.id), // bei Korrektur
freigegebenVon: uuid('freigegeben_von').references(() => usersTable.id),
freigegebenAt: timestamp('freigegeben_at', { withTimezone: true }),
versandtAt: timestamp('versandt_at', { withTimezone: true }),
exportFormate: jsonb('export_formate').$type<{ lodas?: FileRef; extf?: FileRef }>(),
validatorReport: jsonb('validator_report'),
korrekturGrund: text('korrektur_grund'), // Pflicht bei status=korrektur
createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(),
createdBy: uuid('created_by').notNull().references(() => usersTable.id),
// GoBD-Felder
hashPrev: bytea('hash_prev'),
hashSelf: bytea('hash_self'),
}, (t) => ({
tenantYearMonthUq: uniqueIndex('datev_monatslauf_t_y_m_uq')
.on(t.tenantId, t.jahr, t.monat)
.where(sql`status != 'korrektur'`), // nur 1 Hauptlauf je Monat
statusIdx: index('datev_monatslauf_status_idx').on(t.tenantId, t.status),
}));

RLS-Policy-Sketch.

ALTER TABLE datev_monatslaufe ENABLE ROW LEVEL SECURITY;
CREATE POLICY datev_mon_tenant_iso ON datev_monatslaufe
USING (tenant_id = current_setting('app.tenant_id')::uuid);
CREATE POLICY datev_mon_read ON datev_monatslaufe FOR SELECT
USING (
tenant_id = current_setting('app.tenant_id')::uuid
AND current_setting('app.scope') IN ('all','team') -- kein 'own'-Zugriff
AND current_setting('app.roles') LIKE '%buchhaltung%'
OR current_setting('app.roles') LIKE '%admin%'
OR current_setting('app.roles') LIKE '%manager%'
);
CREATE POLICY datev_mon_write ON datev_monatslaufe FOR INSERT
WITH CHECK (
tenant_id = current_setting('app.tenant_id')::uuid
AND current_setting('app.roles') LIKE '%buchhaltung%'
);
-- Append-only: keine UPDATE/DELETE durch normale Rollen
CREATE POLICY datev_mon_no_update ON datev_monatslaufe FOR UPDATE
USING (false);

ER-Bezug. Referenziert tenantsTable, usersTable, zeitbuchungenTable (Feinkonzept §3.1), abwesenheitenTable (§3.3), spesenTable (§3.6). Schreibt in auditLogTable (§3.11).


Pfad-Konvention: /v1/kern/datev/….

Methode Pfad Auth-Scope Rate-Limit Idempotenz Beschreibung
GET /v1/kern/datev/mandant datev:read Standard Mandantenstamm lesen
PUT /v1/kern/datev/mandant datev:admin Privileged Idempotency-Key Beraternr/Mandantennr setzen
GET /v1/kern/datev/mapping datev:read Standard Lohnart-Mapping-Liste
PUT /v1/kern/datev/mapping datev:admin Privileged Idempotency-Key Mapping anlegen/ändern
GET /v1/kern/datev/monatslauf datev:read Standard Monatsliste 13 Monate
POST /v1/kern/datev/monatslauf datev:write Privileged Idempotency-Key Monatslauf erstellen (Entwurf)
POST /v1/kern/datev/monatslauf/{id}/preview datev:read Privileged Vorschau-Tabelle (Schritt 2)
POST /v1/kern/datev/monatslauf/{id}/dry-run datev:write Privileged Validator-Trockenlauf, kein Audit
POST /v1/kern/datev/monatslauf/{id}/freigeben datev:approve Privileged Idempotency-Key Manager-Freigabe
POST /v1/kern/datev/monatslauf/{id}/export datev:export Privileged Idempotency-Key Export mit format=lodas|extf|beide
GET /v1/kern/datev/monatslauf/{id}/download/{format} datev:export Privileged Datei-Download (presigned)
POST /v1/kern/datev/monatslauf/{id}/korrektur datev:write Privileged Idempotency-Key Korrekturlauf-Start
POST /v1/kern/datev/monatslauf/{id}/duo-send datev:export Privileged Idempotency-Key Versand via DATEV Unternehmen online

OpenAPI-Schema-Skizze.

paths:
/v1/kern/datev/monatslauf/{id}/export:
post:
operationId: exportMonatslauf
x-werkszeit-scope: datev:export
x-werkszeit-rate-limit: privileged
parameters:
- name: id
in: path
required: true
schema: { type: string, format: uuid }
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [format]
properties:
format: { type: string, enum: [lodas, extf, beide] }
duoSend: { type: boolean, default: false }
responses:
'200':
content:
application/json:
schema:
type: object
properties:
status: { type: string, enum: [versandt] }
lodasUrl: { type: string, format: uri }
extfUrl: { type: string, format: uri }
validator: { $ref: '#/components/schemas/ValidatorReport' }
auditEventId: { type: string, format: uuid }
'409': { description: 'Monatslauf bereits exportiert — Korrekturlauf nötig' }
'422': { description: 'Mapping-Lücken oder Validator-Fehler' }

Webhook-Events.

  • datev.monatslauf.erstellt
  • datev.monatslauf.freigegeben
  • datev.monatslauf.versandt
  • datev.monatslauf.korrektur
  • datev.duo.rueckmeldung (V1)

Profil Begründung Mechanik
Online-only DATEV-Export ist ein Back-Office-Vorgang an einem Arbeitsplatz mit Festnetz. Offline-Export wäre gefährlich (veraltete Schlüsselzahlen, keine Validator-Prüfung, keine DUO-Quittung). UI-Block bei connectivity == none; Hinweis „DATEV-Export nur online verfügbar“.

Konflikt-Strategie. Entfällt — keine Mobile-Interaktion, keine Offline-Mutation.

Datei-Handling. Erzeugte LODAS-/EXTF-Dateien werden in S3 (eu-central-1, Object Lock Compliance Mode, 10 Jahre) abgelegt. Download erfolgt über presigned URL (15 min Gültigkeit). Die Datei selbst wird NICHT in der DB gespeichert, nur die SHA-256-Hash-Referenz im datev_monatslaufe-Eintrag.


  • Append-only: datev_monatslaufe hat hashPrev/hashSelf (SHA-256 kanonisiert). Keine UPDATE-Policy (siehe §7).
  • Korrekturlauf statt Änderung: Original bleibt unverändert, Korrektur als eigener Datensatz mit ref_monatslauf_id. Begründung Pflicht (min. 20 Zeichen).
  • Aufbewahrung: LODAS-/EXTF-Dateien + datev_monatslaufe-Zeilen + zugehörige Audit-Events bleiben 10 Jahre + laufendes Jahr gem. §147 AO. S3 Object Lock Compliance Mode verhindert technisch das Löschen.
  • Verfahrensdokumentation: Auto-generiert aus diesem Feinkonzept + tatsächlicher Systemparameter (Jahrgang, Validator-Version) in gobd-verfahrensdoku.md (siehe kern/11-compliance-audit).
  • Nachvollziehbarkeit: Jeder Export erzeugt Audit-Event mit User, Zeit, Datei-Hash, Validator-Report-Hash. Hash-Chain unveränderlich.
  • Unveränderlichkeit nach Monatsschluss: Sobald status=versandt, werden referenzierte Zeitbuchungen im DB-Trigger read-only (Zuordnungs-ID statt „Monatsschluss-Flag“).

— nicht zutreffend, weil DATEV-Export nur Lohn-Daten transportiert, keine Arbeitszeit-Regel durchsetzt. ArbZG-Compliance passiert beim Stempeln (§3.1) und Planen (§3.8).

— nicht zutreffend, DATEV ist Lohn, nicht Bauleistung.

  • Art. 5 Datenminimierung: Exportiert werden nur die zur Lohnabrechnung gesetzlich notwendigen Felder (Name, SV-Nummer, Steuerklasse, Stunden, Lohnart, Konto). Keine Fotos, keine Geo-Daten, keine Bautagebuch-Einträge.
  • Art. 6 Rechtsgrundlage: Vertrag (Art. 6 Abs. 1 b) — Arbeitsvertrag verpflichtet zur Lohnabrechnung. SV-Nummer & Steuer-ID: gesetzliche Pflicht (Art. 6 Abs. 1 c) + §41 EStG / §28a SGB IV.
  • Art. 9 Besondere Kategorien: Krankheitstage erscheinen als EFZG-Zeilen — aber ohne Diagnose. Nur Anzahl-Tage, was nach AAG/EFZG zulässig ist.
  • Art. 17 Löschung: Scheidet ein Mitarbeiter aus, bleiben Lohn-Daten 10 Jahre (§147 AO > Art. 17 DSGVO, konkurrierende Pflicht). Nach Ablauf Frist wird der Datensatz in datev_monatslaufe pseudonymisiert (Name → Hash), die Datei selbst wird gelöscht.
  • Art. 20 Datenexport: Mitarbeiter erhält auf Anfrage seine persönlichen Lohn-Daten als JSON (Name, Monate, Stunden, Zuschläge, Zusatzbeträge). Nicht die gesamte LODAS-Datei (die enthält Daten anderer Mitarbeiter).
  • Art. 30 Verarbeitungsverzeichnis: Eintrag „DATEV-Export Lohnvorerfassung“ — Zweck: Lohnabrechnung, Empfänger: Steuerkanzlei X, Aufbewahrung: 10 Jahre §147 AO, Rechtsgrundlage: Art. 6 Abs. 1 b/c.
  • DSFA: Keine Pflicht. Es handelt sich um eine gesetzlich geforderte, standardisierte Datenverarbeitung ohne automatisierte Einzelentscheidung, ohne Profiling, ohne Art. 35 Abs. 3 Fallgruppe.
  • Art. 88 (Beschäftigten-Datenschutz): SV-Nummer, Bankdaten, Steuermerkmale werden verschlüsselt at-rest (PostgreSQL pgcrypto + KMS-verwaltete Keys) gespeichert und nur bei Export in die DATEV-Datei geschrieben. Audit-Events protokollieren jeden Zugriff auf das Feld.

— nicht zutreffend, weil Back-Office-Funktion ohne ESS-Bezug. Intern gilt trotzdem WCAG 2.1 AA für die Web-UI (Tastatur-Navigation, Kontrast, Screenreader-Labels), weil es Teil des Werkszeit-Design-Systems ist.

— nicht zutreffend, DATEV-Export ist keine Leistungs-/Verhaltenskontrolle. Der Export zeigt Stunden und Lohnarten, die aus bereits genehmigten Zeitbuchungen stammen; keine neue Überwachungsdimension entsteht.

  • §147 AO (10 Jahre): S3 Object Lock Compliance Mode, bucketseitig konfiguriert, Löschversuche werden von S3 selbst zurückgewiesen.
  • §41 EStG (Lohnkonto-Pflichtfelder): Sozialversicherungsnummer, Steuer-ID, Geburtsdatum, Steuerklasse, Konfession müssen im LODAS-Stammsatz (Satzart 100) geführt werden. Werkszeit liest sie aus dem HR-Stamm; fehlen Felder, blockiert der Validator den Export.
  • §28f SGB IV (Beitragsnachweis): SV-Nummer zwingend. Validator prüft Modulo-11-Prüfziffer der SV-Nr.
  • DATEV-Schnittstellenbeschreibung LODAS-ASCII (Jg. 2026): Jede Satzart (100 Stamm, 110 Bewegung, 120 Zuschlag) hat festgelegte Feldbreiten, CP1252-Encoding, CRLF-Zeilenenden. Unser Writer-Modul folgt dem Kapitel „Satzaufbau LODAS-ASCII“ der aktuellen Jahrgangs-Doku byte-genau; Generator-Konstruktor bekommt das Jahrgangs-Objekt injiziert, so dass beim Jahreswechsel 2026→2027 nur das Jahrgangs-Paket getauscht wird.
  • DATEV EXTF v9.0: UTF-8 BOM, Semikolon-separiert, Header-Zeile 1 ist Metadaten-Zeile (EXTF;700;21;Buchungsstapel;9;…), Header-Zeile 2 ist Spaltennamen. Wir schreiben Lohn-Bewegungen auf „Buchungsstapel“-Schema.
  • DATEV Unternehmen online API v1.4 (V1): OAuth 2.0 Authorization Code + Refresh Token, POST /uo/v1/belege mit kategorie=lohn, Datei als Multipart-Body. Refresh-Token KMS-verschlüsselt in DB.
  • DATEV-Validator: Eigenes Team-internes Npm-Paket @werkszeit/datev-validator, das die offiziellen Regelwerke der DATEV-Schnittstellenbeschreibung abbildet. CI läuft Musterdateien durch Validator; Abweichung blockt Merge.

# Szenario Erwartetes Verhalten
EC-01 Monatsübergreifende Schicht (Schicht 31.03. 22:00 – 01.04. 06:00) Split bei 24:00; Stunden vor Mitternacht → März, nach Mitternacht → April. Entsprechend zwei Zeilen im Export, Mitarbeiter merkt nichts.
EC-02 Mapping-Lücke zum Export-Zeitpunkt (neue Zeitart bereitschaft.ruf erstmals erfasst) Vorschau Schritt 2 markiert 🔴, „Jetzt mappen“ führt zum Mapping-Editor, dort Schlüsselzahl eingeben, zurück zum Wizard. Export blockiert bis Mapping vollständig.
EC-03 Multi-Tenant-Bleed-Versuch (Buchhaltung einer Kanzlei bedient 10 Mandanten) current_setting('app.tenant_id') erzwingt Isolation. Download einer fremden Export-URL via ID-Guessing liefert 404 (nicht 403). Kein Audit in fremdem Tenant.
EC-04 Korrekturlauf auf Korrekturlauf (Mehrfach-Korrektur Januar 2026) Kette v1 → v1.k1 → v1.k2, jede Version referenziert Vorgänger. UI zeigt Version-Tree. Validator prüft Gesamt-Saldo Original − Storno + Neu == aktueller Soll-Stand.
EC-05 Großmenge (250 MA × 31 Tage = 7.750 Stundeneinträge) LODAS-Writer streamt als node:stream.Writable direkt in S3-Multipart-Upload. P95 < 15 s für 10.000 Sätze (Last-Test-Ziel).
EC-06 Abgelaufene DATEV-Jahrgangs-Version (Betrieb hat Jahrgang 2025, Export wird im April 2026 versucht) Validator wirft UnsupportedYearFault, UI zeigt „Jahrgang 2026 laden“ → Admin klickt → NPM-Paket wird aktualisiert → Retry.
EC-07 SV-Nummer fehlt (neuer Mitarbeiter, noch nicht eingetragen) Vorschau zeigt 🔴 neben Name, Link zu HR-Stamm-Edit. Export ohne SV-Nr. wird nicht erzeugt.
EC-08 DUO-API down (DATEV-Server 503 bei Versand) Status bleibt versandt_lokal, Retry-Queue läuft Backoff (1 min, 5 min, 30 min, 2 h). Nach 3 Fehlversuchen: Buchhaltung wird benachrichtigt, manueller Upload-Pfad (Datei-Download) als Fallback.
EC-09 Buchhaltungs-Nutzerin wechselt den Arbeitgeber mitten im Monatslauf RBAC entfernt bei Austritt sofort den Scope datev:export. Laufender Lauf bleibt in Status Entwurf, Admin muss neuen Nutzer zuweisen. Kein Datenverlust.
EC-10 Double-Submit (Buchhaltung klickt „Export“ zweimal schnell) Idempotency-Key auf POST /monatslauf/{id}/export erkennt Duplikat → 200 mit identischer Antwort, kein zweiter Audit-Eintrag, keine zweite S3-Datei.
EC-11 Zeitzonen-Chaos (Buchhaltung im Urlaub in Thailand, klickt Export um 22:00 Bangkok = 16:00 CET) Export-Zeitstempel = UTC, UI-Anzeige = Europe/Berlin. In LODAS-Datei steht der CET-Monat, niemals Bangkok-Zeit.
EC-12 Kanzlei-Wechsel zum Jahreswechsel (Beraternummer 1234567 → 7654321) Admin ändert Mandantenstamm per neuem Datensatz mit gueltig_ab=2027-01-01; alte Zeilen bleiben für Altläufe referenziert (Append-only-Pattern).

Funktionalität: DATEV-Monatsabschluss und Export
Hintergrund:
Angenommen ein Tenant "shk-gebruder-schmidt" mit Modul-Gate "module.kern.datev"
Und ein Mandantenstamm mit Beraternummer "1234567" und Mandantennummer "12345"
Und ein Nutzer "Frau Müller" mit Rolle "Buchhaltung"
Und ein Nutzer "Thomas Schmidt" mit Rolle "Manager"
Und gepflegtes Lohnart-Mapping für alle im April 2026 benutzten Zeitarten
Szenario: Happy Path — Monatsabschluss April 2026, LODAS + EXTF exportieren
Wenn Frau Müller "Monatslauf April starten" klickt
Dann wird ein Monatslauf mit Status "Entwurf" angelegt
Und Frau Müller sieht die Vorschau-Tabelle mit allen Lohnarten, 0 Mapping-Lücken
Wenn Thomas Schmidt den Lauf freigibt
Und Frau Müller einen Dry-Run klickt
Dann meldet der DATEV-Validator 0 Fehler, 0 Warnungen
Wenn Frau Müller "Export erstellen" mit Format "beide" klickt
Dann werden zwei Dateien erzeugt (LODAS-ASCII, EXTF)
Und der Status wechselt auf "Versandt"
Und die referenzierten April-Zeitbuchungen sind read-only
Und ein Audit-Log-Eintrag "datev.export.lodas-ascii" existiert
Und ein Audit-Log-Eintrag "datev.export.extf" existiert
Szenario: Grenzfall — Mapping-Lücke blockiert Export
Angenommen ein Mitarbeiter hat erstmals eine Zeitbuchung mit Zeitart "bereitschaft.ruf"
Und diese Zeitart ist nicht gemappt
Wenn Frau Müller den Monatslauf-Export-Wizard öffnet
Dann zeigt die Vorschau (Schritt 2) die Zeitart mit rotem Marker "NICHT GEMAPPT"
Und der "Weiter"-Button zu Schritt 3 ist deaktiviert
Wenn Frau Müller im Mapping-Editor "bereitschaft.ruf → 62 Bereitschaftszuschlag" hinzufügt
Und zurück zum Wizard geht
Dann ist die Vorschau grün, der "Weiter"-Button aktiv
Szenario: Grenzfall — Korrekturlauf nach nachträglicher Samstagsgenehmigung
Angenommen Januar 2026 ist bereits versandt (Export-ID "export_2026-01_v1")
Und eine nachträgliche Samstagsarbeit 4 h für "Mehmet Yılmaz" wurde genehmigt
Wenn Frau Müller "Korrekturlauf erstellen" für Januar klickt
Und als Begründung "Nachträgliche Samstagsgenehmigung KW2, Freigabe 28.02.2026" eingibt
Und "Komplett-Storno + Neulauf" wählt und bestätigt
Dann wird ein neuer Monatslauf mit status="korrektur" und ref_monatslauf_id=Ursprung erzeugt
Und die Export-Datei enthält einen Stornoblock (negative Stunden) plus den neuen Monatsstand
Und das Audit-Log zeigt drei Events: "korrektur.erstellt", "korrektur.validiert", "korrektur.versandt"
Szenario: Grenzfall — Multi-Tenant-Isolation beim Direkt-Download
Angenommen ein zweiter Tenant "musterbetrieb-maler"
Und ein dort existierender Monatslauf mit ID "mon_ABC"
Wenn Frau Müller (Tenant shk-gebruder-schmidt) GET /monatslauf/mon_ABC/download/lodas aufruft
Dann antwortet die API mit 404
Und es entsteht KEIN Audit-Log-Eintrag im Tenant musterbetrieb-maler
Szenario: Grenzfall — GoBD-Unveränderlichkeit blockiert Zeitbuchungs-Korrektur
Angenommen April 2026 ist "Versandt"
Wenn Thomas Schmidt versucht, eine April-Zeitbuchung direkt zu ändern
Dann antwortet die API mit 409 "Monat ist abgeschlossen — Korrekturlauf nutzen"
Und es entsteht KEIN DB-UPDATE
Und das Audit-Log zeigt "zeitbuchung.korrektur.blockiert"
Szenario: Grenzfall — DATEV Unternehmen online API 503
Wenn Frau Müller "Export + DUO senden" klickt
Und die DUO-API 503 antwortet
Dann wechselt der Status auf "versandt_lokal"
Und eine Retry-Queue startet mit Backoff 1 min → 5 min → 30 min → 2 h
Und nach 3 Fehlversuchen erhält Frau Müller eine UI-Benachrichtigung
Und sie hat weiterhin Zugriff auf den lokalen Datei-Download als Fallback

  • U-01 — Beraternummer-Prüfziffer (Modulo-Check) gegen offizielle DATEV-Beispiele.
  • U-02 — SV-Nummer-Modulo-11 (§28a SGB IV) als Property-based Test (10 000 Seed-Werte).
  • U-03 — LODAS-Satzart-100-Layout: Festlängen, Padding, CP1252-Encoding bei Umlauten („Müller“ → 4D 75 EC 6C 6C 65 72).
  • U-04 — EXTF-Header-Zeile: Version, Buchungsart, Mandantennummer an korrekten Positionen.
  • U-05 — Monats-Split bei Schichten über Mitternacht (Property-based auf 1 000 Zufalls-Schichten).
  • U-06 — Korrekturlauf-Saldo-Formel: sum(storno) + sum(neu) == delta_stand.
  • U-07 — Rundung Stunden auf 2 Nachkommastellen (Banker’s Rounding, IEEE 754 half-even) — Property-based.
  • U-08 — Idempotency-Key-Dedup-Logik: doppelter Key in 60 s → 200 mit Cache-Antwort, kein zweiter DB-Insert.

— entfällt (keine Mobile-Komponenten). Web-Component-Tests in §13.4.

13.3 Integrations-Tests (Backend, Drizzle In-Memory)

Abschnitt betitelt „13.3 Integrations-Tests (Backend, Drizzle In-Memory)“
  • I-01 — Multi-Tenant-Isolation für alle 13 DATEV-Endpunkte (Pflicht DOD §2.2).
  • I-02 — RLS: Buchhaltung Tenant A sieht keine Monatsläufe Tenant B.
  • I-03 — Outbox-Idempotenz bei POST export: doppelter Idempotency-Key → 409 oder identische Antwort.
  • I-04 — Hash-Chain-Bruch-Detection: direkte DB-Mutation eines datev_monatslaufe-Eintrags → Integrity-Check meldet Chain-Bruch.
  • I-05 — Zeitbuchungs-Read-Only-Lock nach versandt: UPDATE auf Buchung blockiert per Trigger.
  • I-06 — Mapping-Uniqueness: zweiter Mapping-Eintrag für identische Zeitart → 409.
  • E-01 — Happy-Path April 2026 auf Seed-Tenant shk-gebruder-schmidt (80 MA, 12 000 Stunden): Wizard-Strecke + Download + SHA-256-Verifikation der Datei gegen Fixture-Hash.
  • E-02 — Mapping-Lücke-Flow: Zeitart „bereitschaft.ruf“ erstmalig erfasst, Wizard blockt, Admin pflegt Mapping, Wizard geht weiter.
  • E-03 — Korrekturlauf-Flow mit Begründungs-Validierung (<20 Zeichen abgewiesen).
  • E-04 — Accessibility: axe-core auf allen 3 Wizard-Schritten + Mapping-Editor, 0 Critical/Serious.
  • E-05 — Visuelle Regression: Golden-Image Dashboard + Wizard-Steps für Chromium + Firefox + WebKit.

13.5 Compliance-Tests (Suite apps/api/test/compliance/datev/)

Abschnitt betitelt „13.5 Compliance-Tests (Suite apps/api/test/compliance/datev/)“
  • C-01 — Hash-Chain-Integrität auf 1 000 zufälligen Monatsläufen.
  • C-02DATEV-Validator offiziell: Test-Fixtures fixtures/lodas/happy-path-april-2026.csv + fixtures/extf/happy-path-april-2026.csv durchlaufen den offiziellen DATEV-Prüfservice (eingerichtet als eigener CI-Job mit DATEV-Test-Mandant).
  • C-03 — Jahrgangs-Wechsel-Test: Fixture mit Jahrgang 2025 wird mit Jahrgang-2026-Writer geladen → erwarteter Fehler UnsupportedYearFault.
  • C-04 — CP1252-Byte-Treue: LODAS-Datei vom Writer wird byte-genau mit Referenz-Dump (von DATEV Beispiel-Kunde) verglichen.
  • C-05 — SV-Nr.-Modulo-Validierung als Property-based Test (10 000 Samples).
  • C-06 — GoBD-Aufbewahrungs-Test: Attempt zu DELETE auf S3 Object Lock → AWS-SDK wirft InvalidWriteOffset, Test erwartet diesen Fehler.
  • Lokaler 20×-Re-Run der E2E-Tests grün (DOD §2.2).
  • CI-Job datev-validator-smoke läuft nightly gegen offiziellen Service.

Nicht-Ziel Begründung
Integration mit ADDISON, Sage Payroll, lexoffice-Lohn Phase 1: nur DATEV. Markt-Realität: 40 % Handwerksbetriebe auf DATEV, alle anderen zusammen < 20 %. Kein Referenzkunde aus diesen Ökosystemen fragt es an. V2 auf Request.
Direkte Lohnabrechnung (Netto-Berechnung, Steuer/SV-Beiträge) Werkszeit ist Lohn-Vorerfassung, nicht Lohnabrechnung. Die Kanzlei macht die eigentliche Abrechnung. Ein Netto-Rechner wäre rechtlich riskant (ständige Steuer- und SV-Updates) und außerhalb unseres Fokus.
DMS-Funktionalität (Lohnzettel-Archiv, elektronische Lohnsteuerbescheinigung) DATEV macht das selbst via DUO. Wir leiten nur die Vorerfassung durch.
Abrechnung von Minijobs auf Minijob-Zentrale V1.5+, benötigt separates Feinkonzept und Anbindung.
SOKA-Bau-Meldungen direkt aus Werkszeit Eigenes Feinkonzept handwerk/12-soka-bau. DATEV-Export enthält SOKA-Zuschlag-Sätze, aber die Meldung an SOKA läuft separat.
Export historischer Monate vor Werkszeit-Go-Live Einmalige Migration kein Produkt-Feature. Wird als Professional Service umgesetzt.
Custom-CSV-Export-Designer („Wenn-Sie-nicht-DATEV-nutzen“) Nein. LESSONS-LEARNED §8 erklärt die Bananenschale. Wenn DATEV nicht passt: module.kern.datev abschalten, Rohdaten via Reporting §3.7 exportieren.

Risiko / Annahme Impact Wahrscheinlichkeit Gegenmaßnahme
DATEV-Schnittstellenbeschreibung Jg. 2026 ändert Spaltenlayout kurzfristig hoch niedrig Jahrgangs-Paket @werkszeit/datev-schluessel wird quartalsweise gegen offizielle Doku reviewed; Canary-Deploy bei Jahrgangswechsel
DUO-API v1.4 wird deprecated zugunsten v2 mittel mittel Schema-Abstraktion im API-Client, v1 + v2 parallel, Rollout per Feature-Flag
Referenzkunde hat Sonder-Lohnarten (z. B. Akkord, Werkverträge), die kein Standard-Mapping haben mittel hoch Mapping-Editor hat „Custom“-Flag, Admin kann freie Schlüsselzahlen eingeben + Kommentar; Steuerberater-Review vor Go-Live
Steuerkanzlei weigert sich, EXTF zu importieren, will nur LODAS niedrig mittel Beide Formate parallel ab MVP. Buchhaltung wählt am Wizard.
Mehrere Mandantennummern beim selben Betrieb (Holding-Struktur) mittel niedrig V1.5: Tenant-Hierarchie. MVP: 1:1 Tenant = 1 Mandantennummer.
Zeitzonen-Bug beim Monatsgrenze-Split (Sommer-/Winterzeit-Umstellung) hoch niedrig Property-based Test mit 1000 Samples aus DST-Übergängen. Konsequent UTC-storage + Europe/Berlin-Darstellung.

  • Vorbedingung: kern/01-zeiterfassung liefert die Stunden-Quelle; kern/03-abwesenheiten liefert Krank/Urlaub; kern/06-spesen-reisemanagement liefert Verpflegungsmehraufwand + Km-Geld; kern/09-auth-self-service liefert Rolle „Buchhaltung“.
  • Schnittstelle zu: S3 Object Lock (Aufbewahrung), KMS (SV-Nr-Verschlüsselung), Audit-Log-Service kern/11-compliance-audit.
  • Wird konsumiert von: Reporting kern/07-reporting-auswertung (Kennzahl „DATEV-Exporte YTD“), Compliance-Dashboard kern/11-compliance-audit.

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 40–80 MA, eigenständige Lohnbuchhaltung, DATEV LODAS
  • Steuerkanzlei mit 3–10 Handwerks-Mandanten auf DATEV Lohn und Gehalt (mandantenseitig)
  • Regional: Bayern, NRW, Baden-Württemberg (höchste DATEV-Dichte)

Validierungs-Fragen:

  1. Wie viele Stunden kostet Sie heute der Monats-Lohnabschluss (von Zeitstunden-Export bis Kanzlei-Bestätigung)?
  2. Welchen Anteil Ihrer monatlichen Kanzlei-Rückfragen betrifft falsche Lohnart-Zuordnungen?
  3. Nutzen Sie DATEV Unternehmen online für den Dateiversand, oder per E-Mail/USB-Stick?
  4. Wären Sie bereit, einen Bugfix-Release gegen 30 Tage Beta-Test zu tauschen?

Build-Sequenz:

  1. Datenmodell (datev_mandanten, datev_lohnart_mapping, datev_monatslaufe) + RLS + Multi-Tenant-Test.
  2. @werkszeit/datev-schluessel-NPM-Paket mit Jahrgang 2026 anlegen; LODAS-Schlüsselzahlen gegen offizielle Schnittstellenbeschreibung validieren.
  3. LODAS-ASCII-Writer als Stream (node:stream.Writable → S3-Multipart), Unit-Tests auf byte-genauem Layout.
  4. EXTF-Writer analog.
  5. Mapping-Editor-UI + Branchen-Defaults.
  6. Wizard (3 Schritte) + Dry-Run-Validator.
  7. Monats-Freigabe + Monatsschluss-Lock (DB-Trigger auf zeitbuchungen).
  8. Korrekturlauf-Logik.
  9. DATEV-Validator-CI-Job (offizieller Service + lokales Mock).
  10. DUO-API-Integration (V1).

Risiko-Reihenfolge (was zuerst absichern):

  • Byte-Treue des LODAS-Writers. Wenn der falsch ist, ist alles falsch.
  • Mandantennummer-Prüfziffer-Validierung (verhindert Fehlläufe zur Kanzlei).
  • Monatsschluss-Lock (GoBD nicht verhandelbar).

Streich-Kandidaten bei Zeitnot:

  • DUO-API → V1 statt MVP.
  • Jahrgangs-Auto-Update → V1.5.
  • Branchen-Defaults jenseits SHK + Maler → V1.

Stop-the-Bus-Triggers:

  • LODAS-Writer produziert ein Byte Abweichung zur Referenz-Dump → sofortiger Stop, kein Release.
  • DATEV-Validator meldet Fehler bei Fixture „happy-path“ → Merge blockiert, Tech-Lead eskaliert.
  • SV-Nummer-Leak im Audit-Log oder Fehlertext → Sofort-Patch.

Was uns 2027 dankbar macht:

  • @werkszeit/datev-schluessel als separates Paket mit Jahrgangs-Sequenz — Jahreswechsel wird ein 30-Minuten-Ticket, kein Release-Event. Die Jahrgangsabhängigkeit haben 90 % der Mitbewerber fest eingebaut; unsere Architektur macht daraus ein Update-Problem statt eines Produktproblems.
  • Korrekturlauf als First-Class-Konzept (nicht nachträglicher Bugfix) — künftige Compliance-Fragen wie „Kann man bei SOKA-Stornierung nachweisen, was ursprünglich gemeldet wurde?“ beantworten wir per Link in die Hash-Chain.
  • Der Mapping-Editor ist der Hebel für weitere Lohnsysteme: Sobald jemand eine Mapping-Engine zu SAP HCM fordert, ersetzen wir den DATEV-Writer durch einen SAP-Writer und behalten den gesamten Workflow (Vorschau, Korrektur, Audit).

Feinkonzept-Version 1.0 · Stand 2026-04-20 · Autor: Senior Consultant · Review: Tech-Lead + Buchhaltungs-PO

Für Entwickler — API-Endpoints14
MethodePfadAuthZweck
POST/v1/kern/datev/extf-export/lohnzeitenbearerAuthEXTF-Buchungsstapel Lohnzeiten (CSV-Download)
POST/v1/kern/datev/extf-export/rechnungenbearerAuthEXTF-Buchungsstapel Rechnungsausgang (CSV-Download)
GET/v1/kern/datev/kontenrahmen-mappingsbearerAuthKontenrahmen-Sachkonto-Mappings auflisten
PUT/v1/kern/datev/kontenrahmen-mappings/{id}bearerAuthKontenrahmen-Sachkonto-Mapping ändern
GET/v1/kern/datev/mandantbearerAuthDATEV-Mandantenstamm lesen
PUT/v1/kern/datev/mandantbearerAuthDATEV-Mandantenstamm anlegen oder ändern
GET/v1/kern/datev/mappingbearerAuthLohnart-/Zeitart-Mappings auflisten
PUT/v1/kern/datev/mappingbearerAuthLohnart-/Zeitart-Mapping anlegen oder ändern
DELETE/v1/kern/datev/mapping/{zeitart}bearerAuthLohnart-/Zeitart-Mapping löschen
GET/v1/kern/datev/monatslaufbearerAuthLohn-Monatsläufe auflisten
POST/v1/kern/datev/monatslaufbearerAuthMonatslauf-Entwurf anlegen
GET/v1/kern/datev/monatslauf/{id}bearerAuthMonatslauf-Einzelsatz lesen
POST/v1/kern/zeit/exports/datev-csvbearerAuthDATEV-CSV-Export (async, BullMQ-Job)
GET/v1/kern/zeit/exports/datev-csv/{jobId}bearerAuthDATEV-CSV-Export-Job-Status (Polling)