Abwesenheiten — Urlaub, eAU, Sonderurlaub, Freistellung, Genehmigungs-Workflow
Feinkonzept — Abwesenheiten (Urlaub · eAU · Sonderurlaub · Freistellung)
Abschnitt betitelt „Feinkonzept — Abwesenheiten (Urlaub · eAU · Sonderurlaub · Freistellung)“Kern-Modul. Dieses Feinkonzept regelt alle Nicht-Anwesenheiten: bezahlter Erholungsurlaub (BUrlG), Arbeitsunfähigkeitsbescheinigung (eAU via GKV-Schnittstelle § 109 SGB IV), Sonderurlaub (§ 616 BGB, TV Bau § 6), Bildungsurlaub (Ländergesetze), unbezahlte Freistellung, Mutterschutz/Elternzeit (nur Stamm-Erfassung, keine Lohnabrechnung). Struktur nach Pflichtvorlage
../TEMPLATE.md, alle 18 Sektionen.
1. Header & Metadaten
Abschnitt betitelt „1. Header & Metadaten“feature_id: kern/03-abwesenheitentitle: Abwesenheiten — Urlaub, eAU, Sonderurlaub, Freistellung, Genehmigungs-Workflowfunktionsumfang_ref: §3.3roadmap_horizont: MVP # Urlaub + eAU-Import MVP; Bildungsurlaub V1plattformen: mobile: vollständig # Antrag + Status + Familienkalender-View web: vollständig # Genehmigung, Bulk, Urlaubsplanung desktop: aus # nichts Desktop-spezifischesowner_rolle: HR # Regeln; Manager genehmigt, MA beantragtmodul_gate_flag: module.kern.abwesenheitencompliance_flags: gobd: true # Urlaubskonten append-only, Genehmigungshistorie arbzg: true # Urlaub reduziert Soll, eAU = 0 Ist vob: false dsgvo: true # Gesundheitsdaten Art. 9 — besondere Kategorie bfsg: true betrvg: true # §87(1)5 Urlaubsgrundsätze, §87(1)1 Ordnung stvg: false weitere: [BUrlG, EntgFG §3, §5, SGB V §109 (eAU), TV Bau §6, MuSchG (Stamm), BEEG (Stamm), JArbSchG §19]referenzkunde: status: TBD name: "zu klären mit Sales — Kandidaten-Profil: 20–80 MA, Bauwirtschaft mit Saison" quelle: Sales-Call "Urlaubsplanung auf Papier"estimate_eng_tage: 36abhängigkeiten: - kern/01-zeiterfassung # Abwesenheit blockiert Stempel-Einträge am Tag - kern/02-arbeitszeit-compliance # Urlaub zählt auf Soll an, reduziert ÜS-Konto - kern/08-dienstplanung # Genehmigung nur bei Schicht-Freigabe2. Kontext & Problem
Abschnitt betitelt „2. Kontext & Problem“Marktrealität (DE-Handwerk). Urlaubsplanung im Handwerk ist saison-getrieben (Winterpause Bau, Sommer-Peak SHK-Heizungswartung). In 80 % der KMU geschieht das auf Papier-Kalender im Büro, per WhatsApp oder in einer Excel-Tabelle mit farbigen Zellen. Folge: Überschneidungen werden erst gemerkt, wenn die Baustelle leer ist. Krankmeldung (seit 2023 eAU-Pflicht: Arbeitgeber ruft elektronisch bei der GKV ab, §109 SGB IV) wird regelmäßig vergessen, weil niemand im Büro das TI-Portal kennt. Sonderurlaub (Hochzeit, Umzug, Todesfall naher Angehöriger) wird „großzügig gewährt“, aber nie im System erfasst — Nachweis bei Lohnsteuer-Prüfung fehlt.
Schmerzpunkt der Alt-App. LESSONS-LEARNED §7 erwähnt: Urlaubsanträge waren als requestType = 'URL' im timeEntries-Baum gemischt, kein separates Modell. Ergebnis: Ein Urlaubstag, den ein Mitarbeiter zusätzlich noch abstempelte, erzeugte ein Ghost-Ist von 8 h. eAU existierte gar nicht — Arbeitsunfähigkeit wurde per hand als Null-Stempel eingetragen. Genehmigungslogik war eine Bool-Spalte approved ohne Workflow-State, ohne Ablehnungsgrund, ohne BR-Zustimmungsprotokoll.
Erwarteter Outcome.
- Antrag zu Genehmigung < 24 h (heute: 3–10 Tage, weil Papier im Büro liegt).
- eAU-Abruf automatisch, mit Fallback bei GKV-Timeout (manuelle Erfassung + Auditpunkt).
- Urlaubskonten transparent mit Verfallslogik nach BUrlG § 7(3) + BAG-Urteil 31.01.2023 (9 AZR 244/20 „Aufforderungs- und Hinweisobliegenheit“).
- DSGVO Art. 9: Krankheitsdaten strikt getrennt, Zugriff protokolliert, nie in Statistiken nicht-anonymisiert.
- Familien-Kalender-View für Monteure: „kann ich nächste Woche frei nehmen?“ ohne Manager-Call.
3. Personas & Rollen
Abschnitt betitelt „3. Personas & Rollen“| Rolle | Aktion | Scope | Plattform |
|---|---|---|---|
| Mitarbeiter | Antrag stellen, Status verfolgen, Restanspruch sehen, eAU nachreichen (Foto als Fallback) | own |
📱🌐 |
| Manager | Genehmigen/ablehnen, Team-Urlaubskalender, Engpass-Warnung | team |
📱🌐 |
| HR | Sonderurlaub-Kategorien pflegen, Sperrzeiten setzen, eAU-Abruf prüfen, Korrekturen | all |
🌐 |
| Admin | Tarifliche Anspruchsregeln, BR-Zustimmung dokumentieren | all |
🌐 |
| Buchhaltung | Lese-Zugriff für Lohnabrechnung (DATEV-Export Feinkonzept §3.7) | all |
🌐 |
Persona-Skizzen.
- Hannes Krüger (Monteur, 38, Maler-Geselle, Musterbetrieb-Maler) — plant Familienurlaub Pfingsten 2026, will Montag mittag per Handy einen Antrag stellen, hat keine Lust, das Büro anzurufen. Stammdaten: 30 Urlaubstage/Jahr (TV Bau, 5-Tage-Woche), Rest 19, davon 4 aus Vorjahr mit Verfall 31.03.
- Sabine Maier (Managerin, 45) — muss in KW 27 entscheiden, ob sie Hannes freigibt oder nicht, weil am 08.06. ein großes Fassadenobjekt startet und sie zwei Geselle braucht. Arbeitet am Tablet, will Ampel-Kalender.
- Frau Müller (Buchhaltung, 56) — generiert Krankenquote für DATEV-LODAS-Export, braucht zuverlässige Abwesenheitsarten-Mapping zu DATEV-Lohnarten (100 = Gehalt, 200 = Krank, 300 = Urlaub, 400 = Sonderurlaub), hat heute 3 verschiedene Excel-Tabellen.
- Thomas Schmidt (Bauleiter, 52) — meldet selten Krank, aber 19.04. war er beim Zahnarzt. System muss seine eAU automatisch in 24 h haben.
4. User-Stories
Abschnitt betitelt „4. User-Stories“US-01 [MVP] Als Mitarbeiter möchte ich einen Urlaubsantrag vom Handy stellen und sofort sehen, wie viele Resttage nach Genehmigung übrig bleiben, um vor dem Absenden keine Überraschung zu erleben.
US-02 [MVP] Als Manager möchte ich in einer Team-Kalender-Ansicht sehen, wer im Antragszeitraum bereits frei ist, bevor ich genehmige — damit ich keine Baustelle lahmlege.
US-03 [MVP] Als Mitarbeiter möchte ich meine Krankmeldung per eAU-Pull automatisch gemeldet bekommen, damit ich beim Arztbesuch nichts weiteres tun muss als dem Arzt zu sagen „elektronisch".
US-04 [MVP] Als HR möchte ich gesetzeskonform den Verfall von Urlaub vermerken und Mitarbeiter auf den drohenden Verfall hinweisen (BAG 9 AZR 244/20), damit der Arbeitgeber nicht haftet.
US-05 [V1] Als Manager möchte ich Sperrzeiten für Teams definieren können (z. B. „Hochphase Fassaden KW 23–27 — max. 1 Person in Urlaub"), damit das System Anträge vorfiltert.
US-06 [V1] Als Mitarbeiter möchte ich Sonderurlaub (Hochzeit, Umzug, Tod) mit korrekter TV-Bau-Kategorie beantragen können, ohne das Regelwerk auswendig zu kennen.
US-07 [V1.5] Als Admin möchte ich Bildungsurlaub nach Landes-Bildungsurlaubs- gesetz konfigurierbar gewähren (5 Tage NRW, 5 Tage Bayern eingeführt 01/2025).5. Funktionale Anforderungen
Abschnitt betitelt „5. Funktionale Anforderungen“5.1 Mobile (📱)
Abschnitt betitelt „5.1 Mobile (📱)“- F-M-01 Urlaubsantrag: Zeitraum (von/bis inkl. halber Tage), Kategorie (Urlaub / Sonderurlaub / unbezahlt), Vertretung wählen (optional), Notiz (optional). Vor Absenden: Vorschau „nach Genehmigung verbleiben X Tage“.
- F-M-02 eAU-Meldung: „Ich bin krank“ → sendet Trigger an Backend → Backend pollt GKV-Schnittstelle alle 30 min für 72 h. Fallback: Foto der AU hochladen (Zwischenschritt, verschlüsselt abgelegt, Löschung nach eAU-Eingang).
- F-M-03 Kalender-Strip der nächsten 60 Tage mit Status-Pins (genehmigt, offen, abgelehnt, eAU). Tap → Detail.
- F-M-04 Restanspruch-Kachel „Ich habe noch: 19 Tage, davon 4 bis 31.03.2027“ inkl. Hinweis bei drohendem Verfall < 45 Tage.
- F-M-05 Push bei Status-Wechsel (genehmigt / abgelehnt mit Grund / eAU erfolgreich abgerufen).
5.2 Web (🌐)
Abschnitt betitelt „5.2 Web (🌐)“- F-W-01 Team-Urlaubskalender: Heatmap 12-Monate-Grid, Filter Team/Qualifikation, Engpass-Warnung (rot, wenn < 60 % Team anwesend).
- F-W-02 Genehmigungs-Inbox für Manager: Liste offener Anträge, Bulk-Genehmigung (bis 10), Ablehnung mit Pflichtfeld „Begründung“.
- F-W-03 HR-Ansicht Urlaubskonten-Matrix: alle MA, Soll/Ist/Rest/Verfallsdatum, Bulk-Import CSV (Migration Alt-System).
- F-W-04 eAU-Cockpit: offene Pulls, TI-Timeouts, manueller Nachforder-Button.
- F-W-05 Sperrzeiten-Editor: Baustein-Formular (Team, Zeitraum, max. gleichzeitig, Override-Regel).
- F-W-06 Report „Fehlzeitenquote“ monatlich (Krankenquote DSGVO-konform aggregiert, keine Einzel-Identifikation bei < 5 MA pro Team).
5.3 Cross-Plattform (🔄)
Abschnitt betitelt „5.3 Cross-Plattform (🔄)“- F-X-01 Antrag-Statusmodell:
draft → submitted → approved|rejected|withdrawn(append-only Historie). - F-X-02 Familien-Kalender-Export: iCal-Feed je Mitarbeiter (signed URL, pro Device revokable).
- F-X-03 Genehmigte Abwesenheit blockiert Stempeln (kern/01) am betreffenden Tag, außer HR überschreibt mit Audit-Pflicht.
5.4 Admin
Abschnitt betitelt „5.4 Admin“- F-A-01 Tariflicher Urlaubsanspruch pro Lohngruppe (TV Bau: 30 Tage gewerblich ab 2. Jahr) mit Jahres-Rollover-Regel.
- F-A-02 Kategorien-Mapping zu DATEV-Lohnarten (§3.7) — Vorlage für „Musterbetrieb-Maler“ und „SHK-Gebrüder-Schmidt“ mitgeliefert.
- F-A-03 GKV-Abruf-Konfiguration (Betriebsnummer, TI-Zertifikat-Upload, Timeouts).
5.5 Roadmap-Schichtung
Abschnitt betitelt „5.5 Roadmap-Schichtung“| Anforderung | MVP | V1 | V1.5 | V2 |
|---|---|---|---|---|
| F-M-01 Antrag | ✅ | |||
| F-M-02 eAU-Trigger | ✅ | |||
| F-M-03 Kalender-Strip | ✅ | |||
| F-M-04 Restanspruch | ✅ | |||
| F-W-01 Team-Kalender | ✅ | |||
| F-W-02 Genehmigungs-Inbox | ✅ | |||
| F-W-03 HR-Matrix | ✅ | |||
| F-W-04 eAU-Cockpit | ✅ | |||
| F-W-05 Sperrzeiten | ✅ | |||
| F-A-03 GKV-Konfig | ✅ | |||
| Bildungsurlaub Länder | ✅ | |||
| Mutterschutz/Elternzeit | ✅ |
6. Mockups & Flows
Abschnitt betitelt „6. Mockups & Flows“HTML-Hero-Mockup: 03-abwesenheiten.html — Mobile (Antrag Pfingst-Urlaub Hannes) und Web (Genehmigungs-Inbox + Team-Kalender Sabine) Side-by-Side.
6.1 Mobile — Urlaubsantrag (Schritt 1)
Abschnitt betitelt „6.1 Mobile — Urlaubsantrag (Schritt 1)“┌────────────────────────────────┐│ ← Urlaubsantrag ⓘ ││ 🛡 DSGVO · BUrlG · TV Bau ││────────────────────────────────││ Restanspruch ││ ┌──────────────────────────┐ ││ │ 19 / 30 Tage │ ││ │ davon 4 verfallen 31.03 │ ││ └──────────────────────────┘ ││ ││ Zeitraum ││ ┌─────────────┐ ┌───────────┐ ││ │ Mo 25.05.26 │ │Do 04.06.26│ ││ └─────────────┘ └───────────┘ ││ = 8 Werktage ││ ││ Kategorie ││ (•) Erholungsurlaub ││ ( ) Sonderurlaub ││ ( ) Unbezahlt ││ ││ Vertretung (optional) ││ [ Frank Demir ▼ ] ││ ││ Notiz ││ [ Familienurlaub Ostsee ] ││ ││ ▼ Nach Genehmigung: 11 Tage ││ ⚠ KW 22 sind bereits 2 MA auf ││ Urlaub · Manager entscheidet││ ││ [ Abbrechen ] [ ✓ ANTRAG ] │└────────────────────────────────┘6.2 Mobile — Restanspruch-Kachel mit Verfallshinweis
Abschnitt betitelt „6.2 Mobile — Restanspruch-Kachel mit Verfallshinweis“┌────────────────────────────────┐│ Urlaub ││────────────────────────────────││ ││ 19 ││ ───────── ││ Tage frei ││ ││ von 30 Jahres-Anspruch ││ bereits 8 genommen, 3 geplant ││ ││ ⚠ Achtung Verfall ││ ┌──────────────────────────┐ ││ │ 4 Tage aus 2025 verfallen│ ││ │ am Di 31.03.2026 (§7(3) │ ││ │ BUrlG, BAG 9 AZR 244/20) │ ││ │ │ ││ │ [ Antrag jetzt stellen ] │ ││ └──────────────────────────┘ ││ ││ eAU-Status: kein Eintrag ││ (letzte AU 03.02.2026, 2 Tage)│└────────────────────────────────┘6.3 Web — Genehmigungs-Inbox Manager
Abschnitt betitelt „6.3 Web — Genehmigungs-Inbox Manager“┌──────────────────────────────────────────────────────────────────────────────┐│ musterbetrieb-maler › Abwesenheiten › Genehmigungs-Inbox Sabine Maier ││ 🛡 DSGVO Art. 9 · BUrlG · BetrVG §87(1)5 · BR-Zustimmung 02/2026 ││──────────────────────────────────────────────────────────────────────────────││ Offen [ 4 ] Genehmigt [ 12 ] Abgelehnt [ 1 ] eAU-Pulls [ 2 offen ] ││ ││ [✓] MA Zeitraum Tage Art Engpass Aktion ││ [ ] Hannes Krüger Mo 25.05–04.06 8 Urlaub ⚠ KW 22 [Detail][✓][✗]││ [ ] Mehmet Yılmaz Mi 06.05–08.05 3 Urlaub ok [Detail][✓][✗]││ [ ] Frank Demir Fr 22.05 0,5 Sonder. ok [Detail][✓][✗]││ [ ] Jonas Brehm Mo 01.06–05.06 5 Bildung — [Detail][✓][✗]││ ││ [ Bulk genehmigen (0) ] [ CSV ] ││──────────────────────────────────────────────────────────────────────────────││ Team-Kalender KW 21–27 (2026) ││ Name M D M D F | M D M D F | M D M D F | M D M D F | M D M D F ││ Hannes · · · · · | U U U U U | U U U · · | · · · · · | · · · · · ││ Mehmet · · · · · | · · · · · | · U U U · | · · · · · | · · · · · ││ Frank · · · · · | · · · · · | · · · · S | · · · · · | · · · · · ││ Thomas · · · · · | · · · · · | · · · · · | · · · · · | · · · · · ││ Andreas · · · · · | · · · · · | · · · · · | · · · · · | · · · · · ││ … ││ Legende: U=Urlaub S=Sonder K=Krank (eAU) B=Bildung ▲=Anwesend=<60% (rot) │└──────────────────────────────────────────────────────────────────────────────┘6.4 Web — HR-Urlaubskonten-Matrix
Abschnitt betitelt „6.4 Web — HR-Urlaubskonten-Matrix“┌──────────────────────────────────────────────────────────────────────────────┐│ HR › Urlaubskonten 2026 Frau Müller ││──────────────────────────────────────────────────────────────────────────────││ MA Soll Rest-VJ Neu26 Genommen Offen Rest Verfall ││ Hannes Krüger 30 4 30 8 8 19 31.03.26 → 4T ││ Mehmet Yılmaz 30 2 30 4 3 25 — ││ Frank Demir 30 0 30 2 0 28 — ││ Thomas Schmidt 30 6 30 0 0 36 ⚠ 31.03.26 → 6T ││ Jonas Brehm 28 0 28 0 5 23 — (JArbSchG §19)││ Σ 18 MA … ││ ││ [ CSV-Export ] [ BUrlG-Hinweis verschicken (3 MA mit Verfall) ] │└──────────────────────────────────────────────────────────────────────────────┘6.5 Web — eAU-Cockpit
Abschnitt betitelt „6.5 Web — eAU-Cockpit“┌──────────────────────────────────────────────────────────────────────────────┐│ HR › eAU-Cockpit GKV-Schnittstelle · letzte 15 min││──────────────────────────────────────────────────────────────────────────────││ Pending Pulls ││ MA Trigger Kasse Status Seit Aktion ││ Thomas Schmidt Mo 19.04 08:15 TK ⏳ retry 3 5:12 h [Nachpol.] ││ Andreas Wirth Fr 16.04 11:04 AOK-Bay ✓ empfangen — [Anzeigen] ││ Frank Demir Do 15.04 06:48 Barmer ✗ not_found 98 h [Manuell ↑] ││ ││ [ Manuelle Erfassung starten ] [ Log GKV-TI ansehen ] │└──────────────────────────────────────────────────────────────────────────────┘6.6 Mobile — Krankmeldung (eAU-Trigger)
Abschnitt betitelt „6.6 Mobile — Krankmeldung (eAU-Trigger)“┌────────────────────────────────┐│ ← Ich bin krank ││────────────────────────────────││ ││ Krankmeldung starten ││ ││ Arzt war ││ (•) Heute ││ ( ) Gestern ││ ( ) Anderes Datum ▼ ││ ││ Gehe ich zum Arzt? ││ [ Ja, elektronisch (eAU) ] ││ [ Ich reiche AU als Foto ] ││ ││ ▼ Was passiert danach? ││ • Werkszeit fragt deine Kasse ││ in den nächsten 72 h ab ││ • Du siehst den Status hier ││ • Kein Stempeln für heute ││ ││ [ Abbrechen ] [ KRANK MELDEN ]│└────────────────────────────────┘7. Datenmodell
Abschnitt betitelt „7. Datenmodell“Drift (Flutter-lokal) + Drizzle (Server). Abwesenheiten sind ein eigenständiges Aggregat, nie in time_entries gemischt (Lesson Alt-App).
class AbsencesTable extends Table { TextColumn get id => text()(); // UUID v7 TextColumn get tenantId => text()(); TextColumn get employeeId => text()(); TextColumn get category => text()(); // vacation | sick | special | unpaid | education | maternity | parental DateTimeColumn get startDate => dateTime()(); // inklusive, lokale TZ DateTimeColumn get endDate => dateTime()(); // inklusive RealColumn get days => real()(); // berechnet, inkl. halber Tage TextColumn get status => text()(); // draft | submitted | approved | rejected | withdrawn TextColumn get substituteId => text().nullable()(); // Vertretung TextColumn get note => text().nullable()(); TextColumn get createdBy => text()(); DateTimeColumn get createdAt => dateTime()(); TextColumn get approvedBy => text().nullable()(); DateTimeColumn get approvedAt => dateTime().nullable()(); TextColumn get rejectionReason => text().nullable()(); TextColumn get eauSource => text().nullable()(); // gkv_ti | photo | manual DateTimeColumn get eauReceivedAt => dateTime().nullable()(); TextColumn get hashPrev => text().nullable()(); TextColumn get hashSelf => text()(); // SHA-256}
class AbsenceBalancesTable extends Table { // Jahresanspruch-Konto TextColumn get id => text()(); TextColumn get tenantId => text()(); TextColumn get employeeId => text()(); IntColumn get year => integer()(); RealColumn get entitlement => real()(); // 30 Tage TV Bau RealColumn get carryOverPrevYear => real()(); // § 7(3) BUrlG DateTimeColumn get carryOverExpiresAt => dateTime().nullable()(); RealColumn get taken => real()(); RealColumn get scheduled => real()();}
class AbsenceLockPeriodsTable extends Table { // Sperrzeiten TextColumn get id => text()(); TextColumn get tenantId => text()(); TextColumn get teamId => text().nullable()(); DateTimeColumn get startDate => dateTime()(); DateTimeColumn get endDate => dateTime()(); IntColumn get maxConcurrent => integer()(); // max. gleichzeitig auf Urlaub TextColumn get reason => text()();}Server-seitig zusätzlich:
eau_pulls(Triggered-Pulls an GKV TI, retry-Counter, Response-Log verschlüsselt)absence_audit_log(jeder Statuswechsel mit Hash-Chainhash_prev/hash_self, GoBD)- RLS:
tenant_id = current_setting('app.tenant')::uuid. Zusätzlich fürcategory='sick'eine separate Policy: nur HR und Mitarbeiter selbst, nicht Manager (DSGVO Art. 9: besondere Kategorie).
Retention. Urlaubsanträge 10 Jahre (GoBD, Lohnsteuer-Belege). eAU-Rohdaten: 6 Monate in primären DB, danach verschlüsselt archiviert, Schlüssel-Escrow bei HR. Foto-AUs löschen binnen 30 Tage nach eAU-TI-Eingang (DSGVO-Datenminimierung).
8. Geschäftslogik & Regelwerk
Abschnitt betitelt „8. Geschäftslogik & Regelwerk“Anspruchsberechnung. Neues Jahr = Entitlement (Tarifvertrag) + Carry-over aus Vorjahr, capped an tarifliches Maximum. Verfallsdatum der Carry-over-Tage = 31.03. des Folgejahres, außer der Arbeitgeber hat nicht nachweislich aufgefordert und hingewiesen (BAG 9 AZR 244/20) — dann Verfall ausgesetzt. Das System erzwingt Aufforderung: Automatischer E-Mail/In-App-Hinweis an MA, Empfangsnachweis gespeichert, HR-Checkbox „Alle aufgefordert“ vor Jahreswechsel.
Antrag-Workflow.
- MA erstellt Antrag (Status
draftlokal, bis Submit). - Submit →
submitted. Validierung server-seitig: Restanspruch ausreichend? Zeitraum nicht in Sperrzeit (außer Override)? Nicht überlappend mit genehmigter Abwesenheit? - Manager-Notification via Push/E-Mail. Manager entscheidet →
approved|rejected. - Approval setzt in
kern/01-zeiterfassungeinen Day-Block (keine Stempelung möglich, außer HR-Override mit Begründung). - Withdraw (durch MA) nur in Status
submittedoderapprovedbis Start-Datum, wird als neuer Log-Eintrag geschrieben, nicht gelöscht.
eAU-Pull. Trigger = „Ich bin krank“ Event. Backend-Queue startet einen 30-min-Pull gegen GKV-TI pro MA, bis max. 72 h. Bei Treffer: eau_received_at gesetzt, Abwesenheit automatisch auf approved. Bei Kein-Treffer nach 72 h: HR-Eskalation („Mitarbeiter nach AU fragen / Abmahnung prüfen“). Fallback Foto-AU: MA lädt AU-Scan hoch, HR muss in 5 Werktagen manuell prüfen, Datei wird nach eAU-Eingang gelöscht.
Sperrzeiten. Manager/HR definieren {team, start, end, maxConcurrent}. Neuer Antrag in Sperrzeit: zuerst prüfen ob count(approved) < maxConcurrent, sonst Antrag mit Status submitted aber Kennzeichnung „Engpass“ — Manager sieht rotes Icon und muss explizit overriden.
DSGVO Art. 9. Krankheitsdaten: Zugriff nur HR + MA selbst. Manager sieht Kategorie „Abwesenheit“ aber nicht „Krank“ vs. „Urlaub“ in Team-Listen — außer Manager gehört zu Rolle HR ebenfalls. Report-Aggregation: Bei Team < 5 MA wird Krankenquote geblurred (< 5 MA, keine %-Zahl).
DATEV-Mapping. Kategorien →
vacation → Lohnart 300 (bezahlter Urlaub)sick → Lohnart 200 (bezahlt §3 EntgFG 6 Wochen)sick > 42 Tage → Lohnart 210 (Krankengeld-Zuschuss / unbezahlt)special → Lohnart 400 (bezahlter Sonderurlaub TV Bau §6)unpaid → Lohnart 500 (unbezahlte Freistellung)education → Lohnart 410 (Bildungsurlaub, bezahlt nach LBG)9. Akzeptanzkriterien (Gherkin)
Abschnitt betitelt „9. Akzeptanzkriterien (Gherkin)“Happy Path — Urlaubsantrag Hannes
Abschnitt betitelt „Happy Path — Urlaubsantrag Hannes“Feature: Urlaubsantrag stellen, Restanspruch prüfen, Manager genehmigt
Scenario: Hannes stellt am 19.04.2026 Antrag für Pfingsten Given Hannes hat Restanspruch 19 Tage (davon 4 Verfall 31.03.2027) And Sperrzeit "Fassaden KW 23–27 max 1 MA" ist aktiv When Hannes Antrag "25.05.–04.06.2026, Erholungsurlaub" sendet Then im Team-Kalender erscheint der Antrag als "Engpass" gelb And Manager Sabine erhält eine Push-Benachrichtigung When Sabine den Antrag öffnet Then sie sieht: 2 MA sind in KW 22 bereits genehmigt → Konflikt markiert When Sabine mit Begründung "Baustelle pausiert in KW 22" genehmigt Then der Antrag wird auf "approved" gesetzt (append-only) And Hannes erhält Push "Urlaub genehmigt, Rest 11 Tage" And in kern/01 (Zeiterfassung) sind die Tage 25.05.–04.06. blockiert And im audit_log steht `approval` mit hash_self SHA-256Grenzfall 1 — eAU-Timeout & Fallback
Abschnitt betitelt „Grenzfall 1 — eAU-Timeout & Fallback“Scenario: GKV antwortet nicht binnen 72 h, Hannes reicht Foto nach Given Hannes meldet "Ich bin krank" am Mo 19.04.2026 07:30 And Backend startet GKV-Pull alle 30 min When 72 h vergangen sind ohne Treffer Then HR-Cockpit zeigt "Frank Demir: not_found" in Rot And Mitarbeiter bekommt Hinweis "Bitte AU als Foto einreichen" When Hannes lädt AU-Foto hoch Then Datei wird verschlüsselt (AES-256, Schlüssel Schlüsselverwaltung HR) And Status "photo" wird gesetzt And HR prüft manuell, genehmigt, `eau_received_at` gesetzt And Foto wird 30 Tage nach Einlesung automatisch gelöschtGrenzfall 2 — BUrlG-Verfall ohne Aufforderung
Abschnitt betitelt „Grenzfall 2 — BUrlG-Verfall ohne Aufforderung“Scenario: Arbeitgeber hat nicht aufgefordert, Verfall ausgesetzt (BAG 9 AZR 244/20) Given Thomas Schmidt hat 6 Tage Resturlaub aus 2025 And Das System hat bis 15.02.2026 keinen Aufforderungs-Log gesendet When die Jahres-Rollover-Task am 31.03.2026 läuft Then die 6 Tage werden NICHT verfallen gesetzt And ein HR-Eintrag "Verfall ausgesetzt — §7(3) BUrlG BAG 9 AZR 244/20" wird erzeugt And Thomas' Konto zeigt "6 Tage, kein Verfallsdatum (Aufforderung fehlt)"Grenzfall 3 — DSGVO Art. 9 Scope-Isolation
Abschnitt betitelt „Grenzfall 3 — DSGVO Art. 9 Scope-Isolation“Scenario: Manager sieht Krankheit nur als "Abwesenheit", nicht als "Krank" Given Frank Demir ist am 15.04.2026 krank gemeldet (eAU) And Manager Sabine (keine HR-Rolle) öffnet Team-Kalender When sie 15.04.2026 anschaut Then sieht sie "Abwesend" grau And NICHT das Wort "Krank" oder "AU" When Frau Müller (HR) denselben Tag öffnet Then sieht sie "Krank eAU, TK" And ein Zugriffs-Log wird geschrieben (DSGVO Art. 30)Grenzfall 4 — Multi-Tenant Isolation 404
Abschnitt betitelt „Grenzfall 4 — Multi-Tenant Isolation 404“Scenario: Antrag aus anderem Tenant Given Tenant musterbetrieb-maler und shk-gebruder-schmidt And Hannes hat einen Antrag in musterbetrieb-maler When ein Request mit Hannes' Antrag-ID gegen shk-gebruder-schmidt gestellt wird Then antwortet Server mit 404 (nicht 403, um Existenz nicht zu bestätigen) And RLS-Policy blockt auf DB-Ebene, nicht nur Application-SchichtGrenzfall 5 — Month-Lock nach GoBD
Abschnitt betitelt „Grenzfall 5 — Month-Lock nach GoBD“Scenario: Ein vergangener Monat ist gesperrt Given Der März 2026 wurde am 15.04. GoBD-festgeschrieben (§3.7 Rechnungsstellung) When HR versucht, einen Urlaubstag 20.03. rückwirkend zu setzen Then Server antwortet mit 423 "Monat gesperrt" And HR bekommt Option "Korrektur-Lauf anfordern" (Supersedes-Eintrag, nicht Update) And der neue Eintrag referenziert die Original-ID via `supersedes_id`10. Nicht-funktionale Anforderungen
Abschnitt betitelt „10. Nicht-funktionale Anforderungen“- P95 Antrag-Submit < 350 ms (reine DB-Write, GKV-Pull asynchron).
- P95 Team-Kalender < 600 ms für 12-Monate / 50 MA.
- eAU-Pull Worst-Case 72 h bis Fallback — SLA gegen GKV-TI ist extern, wir SLA gegen unser Retry.
- Push-Delivery < 30 s bei Statuswechsel (App Badge Update).
- Offline-Fähigkeit: Antrag auf iPhone im Keller erstellbar (Draft lokal, Submit beim Reconnect, idempotent via UUID v7).
- BFSG/WCAG 2.2 AA: Kalender-Heatmap mit Textmuster-Alternative (nicht nur Farbe), Screen-Reader liest „Mo 25.05. genehmigter Urlaub Hannes Krüger“.
- Sprach-Barrierefreiheit: Deutsch Pflicht, Türkisch und Polnisch als Anzeige-Sprache ab V1 (Monteure DE-Handwerk).
11. Compliance-Mapping
Abschnitt betitelt „11. Compliance-Mapping“| Regelwerk | Pflicht | Umsetzung |
|---|---|---|
| BUrlG §7(3) | Verfall Urlaub | Auto-Aufforderung 45 d vor Jahreswechsel, Empfangs-Log |
| BAG 9 AZR 244/20 | Hinweisobliegenheit | Verfallsdatum nur aktiv, wenn Aufforderungs-Log vollständig |
| EntgFG §3 | Lohnfortzahlung 6 W bei Krank | Status-Wechsel auf Tag 43 → Lohnart 210 im DATEV-Export |
| SGB V §109 | eAU elektronisch | GKV-TI-Pull, Betriebsnummer pro Tenant, TI-Zertifikat-Rotation |
| DSGVO Art. 9 | Gesundheitsdaten | Separate RLS-Policy category='sick' → nur HR + Selbst |
| DSGVO Art. 30 | Verarbeitungsverzeichnis | Auto-Log jedes Zugriffs auf eAU-Daten |
| TV Bau §6 | Sonderurlaub-Tatbestände | Katalog vorkonfiguriert, editierbar per Admin |
| BetrVG §87(1)5 | Urlaubsgrundsätze | BR-Zustimmungsdatum pro Tenant, Policy-Versionierung |
| BetrVG §87(1)1 | Ordnung des Betriebs | Genehmigungsregeln sind Policy, BR-approved |
| MuSchG / BEEG | Stamm-Erfassung | Eigene Kategorie, kein Lohnlauf aus Werkszeit |
| GoBD §147 AO | 10 Jahre Aufbewahrung | append-only Tabelle, S3 Object Lock Compliance |
| JArbSchG §19 | 25–30 Tage Azubi-Urlaub | Alters-abhängige Entitlement-Berechnung |
12. API-Verträge (OpenAPI 3.1)
Abschnitt betitelt „12. API-Verträge (OpenAPI 3.1)“Auszug. Volle Spec siehe openapi/kern/abwesenheiten.yaml.
paths: /v1/kern/absences: get: parameters: - name: employee_id - name: year - name: status responses: "200": { content: { application/json: { schema: { $ref: '#/components/schemas/AbsenceList' } } } } post: requestBody: content: application/json: schema: { $ref: '#/components/schemas/AbsenceCreate' } responses: "201": { headers: { "Idempotency-Key": { required: true } } } "409": { description: "Konflikt Sperrzeit / Überschneidung" } "422": { description: "Restanspruch unzureichend" }
/v1/kern/absences/{id}/approve: post: responses: "200": {} "423": { description: "Monat gesperrt (GoBD)" }
/v1/kern/absences/{id}/reject: post: requestBody: content: application/json: schema: { type: object, required: [reason], properties: { reason: { type: string, minLength: 5 } } }
/v1/kern/eau/trigger: post: requestBody: content: application/json: schema: { $ref: '#/components/schemas/EauTrigger' }
/v1/kern/absences/balances: get: { ... }
components: schemas: AbsenceCreate: required: [employee_id, category, start_date, end_date] properties: id: { type: string, format: uuid } # UUID v7, client-generiert category: { enum: [vacation, sick, special, unpaid, education] }13. UI-Komponenten (Design System)
Abschnitt betitelt „13. UI-Komponenten (Design System)“Ausschließlich wz-*-Klassen aus ../assets/werkszeit-design-system.css + components.html:
wz-frame-mobile/wz-frame-webwz-compliance-bannermit Shields BUrlG/DSGVO/GoBDwz-cardmitwz-card__headerfür Restanspruch-Kachelwz-pill--ok|warn|dangerfür Statuswz-table+wz-row--warnfür Genehmigungs-Inboxwz-kpi-gridmit 4 KPIs (Offen, Krankenquote, Ø Resttage, Verfall-Risiko)- Neue Spezialkomponente:
wz-kalender-heatmap(aus cookbook, hier wiederverwendet),wz-restanspruch-dial,wz-eau-pull-row
Kein Selbstbau von Komponenten ohne DS-Eintrag. Erweiterungen gehen zuerst in components.html #cookbook.
14. Test-Strategie
Abschnitt betitelt „14. Test-Strategie“- Unit (Drift + Drizzle): Anspruchsberechnung, Carry-over-Verfall, Sperrzeit-Overlap, DSGVO-RLS-Policy.
- Property-based: Zufällige Abwesenheits-Zeiträume × Schaltjahr × DST — Tageszahl-Berechnung muss stimmen (kein 7-statt-8-Tage-Bug wegen 29.03.2026 DST).
- Integration: GKV-TI-Mock (recorded fixtures), Timeout-Path, not_found-Path, success-Path.
- Contract: OpenAPI-Dryrun für jede Response (200/409/422/423/404).
- E2E Patrol (iOS+Android): Hannes-Happy-Path Antrag → Genehmigung → Stempel-Block am 25.05.
- E2E Playwright (Web): Sabine-Bulk-Genehmigung (10 Anträge), Engpass-Warnung.
- Multi-Tenant-Invariant-Test: Ein Test ruft bewusst Tenant A-Antrag über Tenant-B-Context → muss 404.
- DSGVO-Test: Manager-Rolle darf in keinem Endpoint
category='sick'sehen (Snapshot-Test über alle Responses). - Load-Test (k6): 200 gleichzeitige Anträge, Team-Kalender 12 Monate bei 100 MA.
15. Migrations- & Rollout-Strategie
Abschnitt betitelt „15. Migrations- & Rollout-Strategie“- CSV-Import Alt-System. Template mit 12 Spalten (MA-ID, Kategorie, Von, Bis, Tage, Status, …). Bulk-Loader im HR-Cockpit, Dry-Run-Modus mit Konflikt-Report.
- Feature-Flag
module.kern.abwesenheitendefaultfalse. Aktivierung pro Tenant im Admin. - Pilot:
musterbetrieb-maler(25 MA) 2 Wochen mit Schattenbetrieb (Papier + App parallel). Fehler-Budget 1 falscher Antrag / 100. - Rollout: GKV-TI-Produktion erst nach Zertifikats-Validierung durch gematik (SLA: 3 Wochen).
- Rollback: Feature-Flag aus → Read-only, Lese-Zugriff bleibt. Keine Daten-Löschung.
KPIs zur Abnahme:
- 0 falsche Krankenquoten in Pilot
- eAU-Success-Rate > 90 %
- Ø Zeit Antrag → Genehmigung < 24 h
- 0 DSGVO-Zugriffs-Verstöße im Pen-Test
16. Risiken & Annahmen
Abschnitt betitelt „16. Risiken & Annahmen“| Risiko | Wahrsch. | Impact | Mitigation |
|---|---|---|---|
| GKV-TI-Zertifikat-Rotation kaputt | mittel | hoch | Rotation-Reminder 30 d vorher, Dual-Active-Zertifikate |
| Manager genehmigt flüchtig, Engpass übersehen | hoch | mittel | Engpass-Warnung muss explizit override-bestätigt werden |
| BAG-Urteil zu Verfall ändert sich | niedrig | hoch | Verfalls-Logik in separater Policy-Tabelle, nicht Code |
| Foto-AU wird nicht gelöscht | mittel | hoch (DSGVO) | Scheduled Job mit Prüfsumme, Monitoring-Alert bei Misslöschung |
| BR-Zustimmung fehlt, System läuft | niedrig | sehr hoch | BR-approved-Flag pro Tenant Pflicht vor Aktivierung |
Annahmen
- Alle Ziel-Kunden haben Betriebsnummer und können GKV-TI anbinden (true für alle > 5 MA).
- DATEV-Mapping Standard ist für 80 % ausreichend; individuelle Lohnarten pro Tenant im Admin editierbar.
- Azubi-Urlaub JArbSchG (max. 30 Tage bis 16 J., 25 bis 17, Standard ab 18) wird aus Geburtsdatum berechnet — Stammdaten-Pflege ist Verantwortung HR (kern/06).
17. Referenzkunde / Sales-Narrativ
Abschnitt betitelt „17. Referenzkunde / Sales-Narrativ“Profil: 20–80 MA Bauwirtschaft, TV-Bau-gebunden, Saison-Peak Mai–Oktober, heute Excel-Urlaubskalender und Papier-Krankmeldung. Kernfrage im Sales-Call: „Wie viele Resttage hat Monteur X im Juni?“ — Antwort muss heute in 5 s im System stehen, nicht in 30 min Excel-Blätter-Blättern.
Pitch-Mikro-Narrativ: „Mit Werkszeit stellt Ihr Monteur seinen Urlaubsantrag am Frühstückstisch per Handy. Ihr Manager sieht auf dem Tablet sofort, ob die Baustelle dadurch kippt. Ihre HR spart bei jedem Krankheitsfall 15 Minuten TI-Portal. Und bei der Lohnsteuerprüfung ist die Beweiskette lückenlos — 10 Jahre, append-only, BUrlG-konform.“
Referenz-Name: TBD nach Sales-Call „BAG-Deadline-Angst“ Q1/2026.
18. Nicht-Ziele (Non-Goals)
Abschnitt betitelt „18. Nicht-Ziele (Non-Goals)“- Keine Lohnabrechnung — wir berechnen keine Bezüge, exportieren nur nach DATEV (siehe kern/05 Rechnung / kern/07 Reporting).
- Keine Entgeltumwandlung — Elternzeit/Mutterschutz nur Stamm, keine ElterngeldPlus-Berechnung.
- Keine Schwerbehinderten-Zusatzurlaub-Automatik (SGB IX § 208) — wird als Sonderurlaub manuell gepflegt in Phase 1.
- Kein Abwesenheits-Vertretungs-Mechanismus mit Task-Umverteilung (das macht kern/08 Dienstplanung).
- Keine Urlaubs-Optimierer-KI („beste Urlaubstage 2026 für Brückentage“) — Spielerei, nicht Compliance.
- Kein Papier-Formular-PDF-Druck — das wäre Rückschritt, BAG verlangt elektronisch.
- Keine automatische Krankengeld-Abrechnung ab Tag 43 — Hinweis an HR, manuelle Weiterleitung an Krankenkasse, aber kein Krankengeld-Antrag.
- Keine eigene TI-Anbindung zu Arzt-Praxen — wir nutzen ausschließlich GKV-Schnittstelle § 109 SGB IV, der Arzt meldet weiter an die Kasse.
Ende Feinkonzept. Revision 0.1 — 19.04.2026 — Autor: Senior Consultant · Review offen: HR-Compliance + Betriebsrat-Muster + DATEV-Mapping-Abgleich.
Für Entwickler — API-Endpoints8
| Methode | Pfad | Auth | Zweck |
|---|---|---|---|
| GET | /v1/kern/absences | bearerAuth | Abwesenheiten auflisten |
| POST | /v1/kern/absences | bearerAuth | Abwesenheitsantrag anlegen |
| GET | /v1/kern/absences/{id} | bearerAuth | Einzelne Abwesenheit |
| POST | /v1/kern/absences/{id}/approve | bearerAuth | Antrag genehmigen |
| POST | /v1/kern/absences/{id}/reject | bearerAuth | Antrag ablehnen |
| POST | /v1/kern/absences/{id}/withdraw | bearerAuth | Antrag zurückziehen (MA selbst) |
| GET | /v1/kern/absences/balances | bearerAuth | Urlaubskonten auflisten |
| POST | /v1/kern/eau/trigger | bearerAuth | eAU-Abruf starten |