Bautagebuch & Vor-Ort-Dokumentation
Feinkonzept · Bautagebuch & Vor-Ort-Dokumentation (§4.1)
Abschnitt betitelt „Feinkonzept · Bautagebuch & Vor-Ort-Dokumentation (§4.1)“Feature-ID:
handwerk/01-bautagebuch· Stand: 2026-04-19 · Autor: Senior-Berater-Rolle Handwerks-/Bau-SaaS Verwandte Feinkonzepte:02-nachtrag(ein Bautagebuch-Eintrag ist fast immer der Auslöser eines Nachtrags),10-arbeitssicherheit(PSA-Check und Erst-Unterweisung sind eigene Eintrags-Typen im Bautagebuch).
1. Header & Metadaten
Abschnitt betitelt „1. Header & Metadaten“feature_id: handwerk/01-bautagebuchtitle: Bautagebuch & Vor-Ort-Dokumentationfunktionsumfang_ref: §4.1roadmap_horizont: MVP # Basis-Bautagebuch ist MVP (FU §6); Werkzeug-QR & DWD-Cache V1plattformen: mobile: vollständig # Primär — der Eintrag entsteht immer auf der Baustelle web: mit-Bulk # Wochenberichte, PDF-Export, Stammdaten, ERP-Integration desktop: aus # V1.5 nur auf Nachfrage (FU §6)owner_rolle: Bauleitung # Eigentümer des Eintragsmodul_gate_flag: module.handwerk.bautagebuchcompliance_flags: gobd: true # Bautagebuch ist rechnungs- und streitrelevant → §147 AO, 10 Jahre arbzg: false # Zeit wird in §3.1 erfasst, nicht hier vob: true # §3 Abs. 3, §6 (Behinderungsanzeige), §15 (Regiebericht) dsgvo: true # Fotos enthalten ggf. Personen, Geo-EXIF ist personenbezogen bfsg: false # Kein ESS-Pflichtflow betrvg: true # Geo-EXIF an Fotos = mittelbare Ortsdatenerfassung → BR-Freigabe stvg: false weitere: [DWD-Nutzungsbedingungen, KI-VO Art. 50 (nur bei KI-Zusammenfassung)]referenzkunde: status: TBD name: "zu klären mit Sales — Kandidat: SHK-Gebrüder-Schmidt (NRW, 80 MA), aktueller Prozess: Excel + WhatsApp + Foto-Galerie" quelle: Sales-Call 2026-03estimate_eng_tage: 38 # 14 Mobile + 10 Backend + 6 Web + 4 DWD-Adapter + 4 Test/Complianceabhängigkeiten: - kern/03-projekte-baustellen # Baustellen-Stammdaten müssen existieren - kern/08-audit-log # Jeder Eintrag schreibt ins Audit-Log - kern/09-foto-upload-pipeline # S3-Multipart mit presigned URL - handwerk/10-arbeitssicherheit # PSA-Check-Eintrag als Bautagebuch-Typ2. Kontext & Problem
Abschnitt betitelt „2. Kontext & Problem“Marktrealität (DE-Handwerk). Das Bautagebuch ist im Bauvertrag nach VOB/B keine freie Fleißarbeit, sondern die Beweisgrundlage. Bei Behinderung (§6 Abs. 1 VOB/B) muss der Auftragnehmer die Ursache und ihre Wirkung unverzüglich und schriftlich anzeigen — wer drei Tage wartet, verliert seinen Anspruch auf Bauzeitverlängerung. Bei Regiearbeiten schreibt §15 Abs. 3 VOB/B vor, dass der Stundenlohn-Zettel werktäglich, spätestens am übernächsten Werktag zur Bestätigung vorzulegen ist. Ohne Unterschrift des Bauherren gilt die Leistung als nicht erbracht — der Handwerker trägt die Beweislast (BGH VII ZR 314/13).
Heute läuft das in der Zielbranche typischerweise so: Der Polier schreibt abends im Auto ein paar Zeilen in ein liniertes A4-Bautagebuch, klebt drei Polaroids oder Smartphone-Ausdrucke ein, holt dem Bauleiter morgens auf dem Hof die Unterschrift (oder eben nicht), scannt das Ganze irgendwann im Büro ein. Das Wetter wird geschätzt („trocken, ca. 12°C“), nicht gemessen. Werkzeug-Übergaben laufen über einen Zettel im Werkzeug-Container, der nach sechs Monaten aussieht wie ein Biotop. WhatsApp-Fotos haben kein Geo-Tag, keinen verlässlichen Zeitstempel (iOS strippt EXIF beim Teilen) und lassen sich vor Gericht nur mit Aufwand zuordnen.
Der rechtliche Rahmen erzwingt die digitale Lösung: GoBD (§147 AO) verlangt 10 Jahre Aufbewahrung unveränderlich, DSGVO Art. 5 Datenminimierung verbietet „Foto-Dumping auf Gruppen-Chats“, und §15 Abs. 3 VOB/B setzt eine Unterschrift auf dem Regiebericht als Anspruchsvoraussetzung. Ein PDF mit eingebettetem Foto und Touch-Signatur ist heute die rechtssicherste und gleichzeitig schnellste Form.
Schmerzpunkt der Alt-App. Die Alt-App (zeitapp) hatte bereits einen BautagebuchScreen. Er war aber (a) sichtbar für jeden Tenant unabhängig von der Branche (Feature-Wildwuchs, LESSONS-LEARNED §2), (b) ohne Wetter-API angebunden (der Nutzer musste die Temperatur tippen), (c) mit PWA-Foto-Upload gelöst, der auf iOS bei längerer Baustellen-Abwesenheit regelmäßig Daten verloren hat (Safari-Storage-Cleanup, LESSONS-LEARNED §4). Der Regiebericht war nicht vom „freien Eintrag“ getrennt — also gab es auch keine Signatur-Pflicht.
Was wir explizit anders machen:
- DWD-Open-Data-Wetter automatisch aus Baustellen-Geo → Temperatur, Niederschlag, Windgeschwindigkeit, Frost-Flag. Kein Tippen. Offline-Fallback mit Cache der letzten 48 h.
- Foto-EXIF mit kryptografischem Geo-Zeitstempel (SHA-256 über Foto-Bytes + GPS + UTC) — beweisfest, nicht nur hübsch.
- Werkzeug-Ausgabe über QR/NFC statt Klemmbrett, mit DGUV-Prüfdaten-Anzeige direkt im Scan-Flow.
- Regiebericht als eigener, signaturpflichtiger Eintragstyp — ohne Bauherr-Unterschrift lässt sich der Eintrag nicht als „Regieleistung“ markieren.
- Append-only + Hash-Chain statt „Edit-Button für den Polier“ — Einträge sind nach Submit eingefroren, Korrektur = neuer Eintrag mit Verweis auf Vorgänger.
Erwarteter Outcome. Messbar am Design-Partner (SHK-Gebrüder-Schmidt): Erstellung eines vollständigen Tageseintrags von heute 18 min (Excel + Foto-Galerie + Signatur nachträglich) auf 3 min auf der Baustelle. Quote signierter Regieberichte am selben Tag von ~40 % auf >85 % (BGH-relevante Beweis-Quote). Dauer eines VOB-§6-Behinderungs-Streits von „14 Tage E-Mail-Ping-Pong“ auf „30 Minuten, alle Belege in einem PDF“.
3. Personas & Rollen
Abschnitt betitelt „3. Personas & Rollen“| Rolle | Aktion | Scope | Plattform |
|---|---|---|---|
| Monteur | Eintrag erfassen (eigene Arbeit), Werkzeug ausbuchen, Foto hochladen | own | 📱 |
| Vorarbeiter / Polier | Regiebericht führen, Bauherr-Signatur einholen, Behinderungsanzeige | team | 📱 |
| Bauleitung | Wochenbericht prüfen, Eintrag korrigieren (append-only), PDF-Export | team | 📱🌐 |
| Manager | Tenant-übergreifender Überblick, Bulk-PDF-Export | all | 🌐 |
| Admin | Werkzeug-Stammdaten, DGUV-Prüfdaten, ERP-Integration | all | 🌐 |
| Bauherr (externer Gast) | Regiebericht signieren (Link-Token, ohne Login) | extern | 📱🌐 |
Persona-Skizzen:
- Mehmet Yılmaz (Monteur, 32, SHK, Tenant
shk-gebruder-schmidt) — arbeitet auf der „Sanierung Heizungsanlage Bgm.-Müller-Schule, Schulstraße 12, 50667 Köln“. Kein LTE im Kellergeschoss. Trägt Handschuhe. Tippt ungern. Spricht deutsch und türkisch — die App ist deutsch, aber Voice-Notiz auf Türkisch soll transkribiert werden können (V1.5). - Thomas Schmidt (Bauleitung, 45, Tenant
shk-gebruder-schmidt) — koordiniert 4 parallele Baustellen, fährt zwischen Köln und Bonn, dokumentiert abends am Tablet im Auto. Will Wochenbericht auf Knopfdruck. - Hr. Müller-Bgm. (Bauherr-Vertreter Schulträger, nicht in Werkszeit-System) — bekommt E-Mail mit Link, unterschreibt per Touch auf dem Smartphone. Kein App-Download, keine Registrierung.
- Sabine Maier (Manager Tenant
musterbetrieb-maler, 25-MA-Maler Bayern) — nutzt das Bautagebuch für Malerarbeiten, braucht den DWD-Wetter-Nachweis für den Winterausfallgeld-Antrag (siehe §4.9 SOKA-Bau, V2).
4. User-Stories
Abschnitt betitelt „4. User-Stories“US-01 [MVP] Als Monteur möchte ich vor Ort in 90 Sekunden einen Tageseintrag anlegen können (Foto, 2 Sätze Tätigkeit, Wetter automatisch), auch wenn mein LTE gerade nicht stabil ist.
US-02 [MVP] Als Polier möchte ich einen Regiebericht mit Bauherr-Unterschrift abschließen, bevor der Bauherr die Baustelle verlässt, damit ich §15 Abs. 3 VOB/B einhalte.
US-03 [MVP] Als Bauleitung möchte ich den Tagesbericht aller Baustellen am Abend in einer Liste sehen (Anwesende, Wetter, Besonderheiten) und per Swipe zwischen den Tagen blättern.
US-04 [V1] Als Polier möchte ich eine Werkzeug-Ausgabe per QR-Scan oder NFC-Siegel dokumentieren, ohne die DGUV-Prüfplakette zu suchen.
US-05 [V1] Als Bauleitung möchte ich einen Wochenbericht als PDF mit Hash-Signatur erzeugen, der vor Gericht als Anscheinsbeweis taugt (§371 ZPO Augenscheinsbeweis).
US-06 [V1] Als Polier möchte ich eine VOB-§6-Behinderungsanzeige in der App erfassen, die automatisch mit DWD-Wetterdaten, Foto und Zeitstempel versehen per E-Mail an den Bauherrn rausgeht.
US-07 [V1.5] Als Manager möchte ich das Bautagebuch in RIB iTWO / Nevaris / pds einspielen können (XML-Export nach deren Schema).
US-08 [V1.5] Als Monteur möchte ich eine Voice-Notiz aufnehmen, die on-device zu Text transkribiert und an den Eintrag geheftet wird.5. Funktionale Anforderungen
Abschnitt betitelt „5. Funktionale Anforderungen“5.1 Mobile App (📱) — iOS + Android
Abschnitt betitelt „5.1 Mobile App (📱) — iOS + Android“- F-M-01 Eintragstyp wählen. Fünf Typen: Tageseintrag, Regiebericht, Behinderungsanzeige (VOB §6), Werkzeug-Übergabe, PSA-Check (aus
handwerk/10-arbeitssicherheit). Standard beim Öffnen ist Tageseintrag. Jeder Typ ist eine eigene RLS-isolierte Variante mit eigenen Pflichtfeldern. - F-M-02 Baustelle auswählen. Default: nächstgelegene aktive Baustelle per GPS (Haversine-Distanz <300 m → auto-ausgewählt mit grünem Badge „GPS-Treffer“). Manuelle Auswahl immer möglich. Kein GPS → letzte verwendete Baustelle.
- F-M-03 Wetter automatisch. DWD-Open-Data (
opendata.dwd.de/weather/weather_reports/poi/) wird auf Basis der Baustellen-Koordinaten im nächstgelegenen DWD-MOSMIX-Punkt angefragt. Ergebnis: Temperatur (°C), Niederschlag (mm/h), Windgeschwindigkeit (km/h), Frost-Flag (T<0°C). Offline: Cache der letzten 48 h pro Baustelle, Fallback auf manuelle Eingabe mit Banner „Wetter manuell — DWD nicht erreichbar“. - F-M-04 Foto-Upload mit Geo-EXIF. Bis 12 Fotos pro Eintrag. Pro Foto wird beim Shot lokal ein Geo-Stempel-Artefakt erzeugt: JSON mit
{foto_sha256, lat, lon, utc_iso, device_id, heading_deg?}, anschließend SHA-256 über diesen JSON + Foto-Hash. Beides bleibt dauerhaft als Nachweis-Blob gespeichert. Komprimierung auf Longest-Edge 2048 px, JPEG q=82, wenn Original >10 MB (LESSONS-LEARNED §4: Offline-Fotos bis 500 MB lokal cachen, dann Sync). - F-M-05 Tätigkeits-Freitext. Bis 2000 Zeichen. Voice-Dictation per iOS Speech / Android SpeechRecognizer als Alternative zur Tastatur (Handschuh-Tauglichkeit).
- F-M-06 Anwesende Gewerke. Multi-Select aus Baustellen-Konfiguration (Subunternehmer-Liste). Neues Gewerk: Quick-Create mit Mindestfeldern (Name, Kontakt-Telefon).
- F-M-07 Fortschritt-Schätzer. Drei Varianten:
Im Plan/Vorsprung ~X Tage/Verzug ~X Tage, Grund: <Auswahl>. Bei Verzug mit Ursache „Witterung“ wird automatisch DWD-Wetter des betroffenen Zeitraums angeheftet (unterstützt spätere Behinderungsanzeige). - F-M-08 Werkzeug-Ausgabe per Scan.
mobile_scannerfür QR/Code-128 odernfc_managerfür NFC-Siegel (ISO 14443). Scan → Werkzeug-Stammsatz geladen → DGUV-Prüfdatum sichtbar, bei abgelaufener Prüfung Warn-Banner „DGUV-Prüfung fällig seit X Tagen — Werkzeug darf nicht übergeben werden“ mit Hart-Block fürhandwerk/10-arbeitssicherheit. - F-M-09 Regiebericht — Pflichtfelder. Stunden (aus Zeiterfassung vorausgefüllt, editierbar mit Begründungszwang), Material (freitext + optional aus Autolager-Stammsatz), Bauherr-Name, Touch-Signatur Pflicht. Ohne Signatur kein Status „Bestätigt“ — bleibt als „Entwurf“ liegen, Push-Erinnerung an Polier und Bauleitung.
- F-M-10 Offline-Erfassung. Voll-offline. Outbox-Einträge mit Idempotency-Key (UUID v7). Fotos landen zuerst in lokaler SQLite als Thumbnail-Referenz, Originale in App-Sandbox-Storage. Bei Netz: S3-Multipart-Upload über presigned URL, danach Eintrag-POST. Sync-Priorität: Regieberichte > Behinderungsanzeigen > Tageseinträge > Fotos.
- F-M-11 Signature-Pad für Bauherr.
signatureFlutter-Package, Canvas 340×180 px, Vector-Strokes gespeichert (kein Raster). Signatur-Metadaten: Name (Pflicht), Funktion (Bauherr / Bauleiter / Vertreter), Datum/Uhrzeit (System), Geräte-Fingerprint. Alternative bei ablehnendem Bauherr: PIN-Code-Signatur (optional, 6-stellig, aus separatem E-Mail-Link) — niedrigere Beweiskraft, explizit als solche gekennzeichnet (EES statt eigene Schrift-Signatur). - F-M-12 Bauleiter-Mit-Signatur (optional). Zweiter Signatur-Slot für Bauleitung. Wenn Bauleiter abwesend: Regiebericht bleibt trotzdem wirksam bei Bauherr-Signatur (§15 VOB/B — Bauherr-Bestätigung genügt).
5.2 Web-App (🌐)
Abschnitt betitelt „5.2 Web-App (🌐)“- F-W-01 Wochenbericht-Liste. Tabelle mit Filter nach Baustelle / Woche / Gewerk. Sortierung nach Datum absteigend. Bulk-Export: bis 50 Einträge als kombiniertes PDF.
- F-W-02 Eintrag-Detail mit Foto-Lightbox und Audit-Trail. Alle Mutationen des Eintrags werden als versionierte Hash-Chain dargestellt (Zeit, User, Diff-Feldliste).
- F-W-03 Werkzeug-Stammdaten. CRUD für Werkzeuge mit DGUV-Prüfintervall, Letzter-Prüfer, Zuweisungs-Status, Fahrzeug-Bindung. Massen-Import aus CSV (EAN, DGUV-Prüfdatum).
- F-W-04 DWD-Cache-Verwaltung. Admin sieht Cache-Zustand pro Baustelle (letzter Abruf, Cache-Hits vs. Misses). Manueller Refresh-Trigger.
- F-W-05 ERP-Export (V1.5). XML-Export nach Schema von RIB iTWO (
.x83-ähnlich), Nevaris (.XML), pds Baulogbuch. Konfiguration pro Kunden-Integration. - F-W-06 Regiebericht-Freigabe / Abrechnung. Freigegebene Regieberichte landen als Positionen im Rechnungs-Entwurf (siehe
kern/05-rechnung).
5.3 Cross-Plattform (🔄)
Abschnitt betitelt „5.3 Cross-Plattform (🔄)“- F-X-01 Append-only mit Hash-Chain. Jeder Eintrag hat
hash_prev(SHA-256 des Vorgängers in derselben Baustelle) undhash_self(SHA-256 über kanonisierte Zeilen-Repräsentation incl. aller Anhänge-Hashes). Korrektur = neuer Eintrag mitcorrects_entry_id+ Pflicht-Begründung ≥ 20 Zeichen. - F-X-02 Status-Maschine.
entwurf → offen → bestätigt(bei Regiebericht mit Signatur),→ exportiert → archiviert. Kein Rückwärts-Übergang — nur neue Version. - F-X-03 DSGVO Art. 20 Export. User kann eigene Einträge als ZIP (JSON + Original-Fotos) herunterladen.
5.4 Admin-Konfiguration
Abschnitt betitelt „5.4 Admin-Konfiguration“- F-A-01 Bautagebuch-Pflichtfeld-Profil. Pro Tenant konfigurierbar: welche Felder sind bei Tageseintrag Pflicht (z. B. „Gewerke anwesend“ Pflicht in Tenant A, optional in Tenant B).
- F-A-02 Regiebericht-Vorlage. Logo, Anrede-Textbaustein, Mini-Verzicht-auf-Einwendungen-Klausel (juristisch vom Kunden selbst zu stellen — Werkszeit liefert einen leeren Slot mit Hinweis-Link auf DE-Anwaltsportal).
- F-A-03 BR-Freigabe Geo-EXIF. Geo-Stempel ist BetrVG §87(1)6-relevant. Default: aus. Aktivierung nur mit dokumentierter BR-Zustimmung, Datum und BR-Beschluss-ID sind Pflichtfelder (siehe §10.6).
5.5 Roadmap-Schichtung
Abschnitt betitelt „5.5 Roadmap-Schichtung“| Anforderung-ID | MVP | V1 | V1.5 | V2 |
|---|---|---|---|---|
| F-M-01 Tageseintrag | ✅ | |||
| F-M-02 GPS-Auswahl | ✅ | |||
| F-M-03 DWD-Wetter | ✅ | |||
| F-M-03 DWD-Cache 48h | ✅ | |||
| F-M-04 Foto + Geo-EXIF | ✅ | |||
| F-M-08 Werkzeug-Scan | ✅ | |||
| F-M-09 Regiebericht | ✅ | |||
| F-M-11 PIN-Signatur | ✅ | |||
| F-W-05 ERP-Export | ✅ | |||
| Voice-Transkription | ✅ | |||
| Drohnen-Orthofoto | ❔ (nur auf Referenzkunde) |
6. Mockups & Flows
Abschnitt betitelt „6. Mockups & Flows“HTML-Hero-Mockup: 01-bautagebuch.html — Mobile + Web Side-by-Side. Mobile-Persona: Mehmet Yılmaz (Monteur) auf Baustelle Schulstraße 12. Web-Persona: Thomas Schmidt (Bauleitung) im Büro shk-gebruder-schmidt.
6.1 Mobile — Eintragstyp wählen (Entry-Screen)
Abschnitt betitelt „6.1 Mobile — Eintragstyp wählen (Entry-Screen)“┌────────────────────────────────┐│ ← Bautagebuch 📍 GPS│├────────────────────────────────┤│ 🛡 GoBD · VOB · DSGVO │ ← Compliance-Banner├────────────────────────────────┤│ Schulstr. 12, 50667 Köln ││ Mo 19.04.2026 · KW 16 ││ 🌧 6°C · 1,2 mm/h · Wind 18 │ ← DWD auto│ ││ Welcher Eintrag? ││ ┌──────────────────────────┐ ││ │ 📋 Tageseintrag │ ││ │ Foto + 2 Sätze │ ││ └──────────────────────────┘ ││ ┌──────────────────────────┐ ││ │ ✍ Regiebericht 🔴 │ │ ← Signatur-Pflicht│ │ Unterschrift Bauherr │ ││ └──────────────────────────┘ ││ ┌──────────────────────────┐ ││ │ ⚠ Behinderung (VOB §6) │ ││ └──────────────────────────┘ ││ ┌──────────────────────────┐ ││ │ 🔧 Werkzeug-Übergabe │ ││ └──────────────────────────┘ ││ ┌──────────────────────────┐ ││ │ 🦺 PSA-Check (→ §4.10) │ ││ └──────────────────────────┘ ││ │├────────────────────────────────┤│ [Zeit] [Plan] [Doku] [Mehr] │└────────────────────────────────┘6.2 Mobile — Tageseintrag-Formular
Abschnitt betitelt „6.2 Mobile — Tageseintrag-Formular“┌────────────────────────────────┐│ ← Neuer Tageseintrag ✓ │├────────────────────────────────┤│ 🛡 GoBD · VOB · DSGVO │├────────────────────────────────┤│ BAUSTELLE 🔴 ││ ┌─────────────────────────┐ ││ │ Schulstraße 12, Köln ▼ │ ││ │ 🟢 GPS-Treffer (12 m) │ ││ └─────────────────────────┘ ││ ││ WETTER (DWD 09:42) ││ 🌧 6°C · 1,2 mm/h · W 18km/h ││ [bearbeiten] ││ ││ TÄTIGKEIT 🔴 ││ ┌─────────────────────────┐ ││ │ Heizungsdemontage │ ││ │ Keller, Altkessel aus. │ ││ │ Asbest-Prüfung negativ. │ ││ │ 🎤 │ │ ← Voice-Dictation│ └─────────────────────────┘ ││ ││ FOTOS (3/12) ││ ┌──┐┌──┐┌──┐┌──┐ ││ │📷││📷││📷││ +│ ││ └──┘└──┘└──┘└──┘ ││ 🟢 Geo-Stempel aktiv ││ ││ ANWESENDE GEWERKE ││ [ ✓ SHK-Schmidt ] [ ✓ Elektro] ││ [ + Gewerk hinzufügen ] ││ ││ FORTSCHRITT ││ ( ) Im Plan ││ (•) Verzug ~1 Tag ││ Grund: ▼ Witterung ││ ││ ┌────────────────────────────┐ ││ │ EINTRAG SPEICHERN │ │ ← Primary (orange)│ └────────────────────────────┘ │└────────────────────────────────┘6.3 Mobile — Regiebericht mit Signatur-Pad
Abschnitt betitelt „6.3 Mobile — Regiebericht mit Signatur-Pad“┌────────────────────────────────┐│ ← Regiebericht ⋯ │├────────────────────────────────┤│ 🛡 GoBD · VOB §15 · DSGVO │├────────────────────────────────┤│ Schulstr. 12 · 19.04.2026 ││ ││ LEISTUNG 🔴 ││ ┌─────────────────────────┐ ││ │ Mehr-Stunden Keller │ ││ │ Asbest-Sanierung Decke │ ││ └─────────────────────────┘ ││ ││ STUNDEN ││ ┌─────────────────────────┐ ││ │ Yılmaz, M. 4:15 h │ ││ │ Demir, F. 4:15 h │ ││ │ ────────────────────── │ ││ │ Summe: 8:30 h │ ││ └─────────────────────────┘ ││ ││ MATERIAL (optional) ││ PE-Folie 4m² 12,40 € ││ Entsorgungs-Big-Bag 48,00 € ││ [ + aus Lager ] [ + frei ] ││ ││ BAUHERR-UNTERSCHRIFT 🔴 ││ Name: Müller-Bgm. ││ Funktion: ▼ Bauherr ││ ╭───────────────────────────╮ ││ │ │ ││ │ ⎯⎯⎯ Hier unterschreiben │ ││ │ │ ││ ╰───────────────────────────╯ ││ ✕ leeren ││ Alternative: [ 📧 PIN per Mail]││ ││ ┌────────────────────────────┐ ││ │ REGIEBERICHT BESTÄTIGEN │ │ ← nur aktiv bei Signatur│ └────────────────────────────┘ │└────────────────────────────────┘6.4 Mobile — Werkzeug-Ausgabe per Scan
Abschnitt betitelt „6.4 Mobile — Werkzeug-Ausgabe per Scan“┌────────────────────────────────┐│ ← Werkzeug-Übergabe 📡 │├────────────────────────────────┤│ Scan bereit ││ ││ ╭──────────────╮ ││ │ ▓▓▓ ▓▓ ▓▓▓ │ ││ │ ▓▓▓▓▓▓▓▓▓▓▓▓ │ ││ │ ▓▓ ▓▓▓▓▓ ▓▓ │ ││ │ ▓▓▓▓ ▓▓ ▓▓▓▓ │ ││ ╰──────────────╯ ││ ││ [ QR / Code-128 ] [ NFC 📡 ]││ ││ Ausgabe an: ││ Mehmet Yılmaz ▼ ││ │├────────────────────────────────┤│ Zuletzt gescannt: ││ HILTI TE 30-AVR WZ-00142 ││ DGUV-Prüfung: 14.01.2026 ✅ ││ [ Ausbuchen ] │└────────────────────────────────┘6.5 Web — Wochenbericht Bauleitung
Abschnitt betitelt „6.5 Web — Wochenbericht Bauleitung“┌────────────────────────────────────────────────────────────────────────────────┐│ Werkszeit · shk-gebruder-schmidt Thomas Schmidt · Bauleitung [▾] │├────────────────────────────────────────────────────────────────────────────────┤│ Sidebar │ Bautagebuch · KW 16 · 12.–18.04.2026 [⤓ Wochen-PDF] ││ ───────── │ Baustelle: Schulstraße 12, Köln ▼ ││ Zeit │ ───────────────────────────────────────────────────────────── ││ Plan │ KPI: 5 Tage · 18 Fotos · 2 Regieberichte · 1 Behinderung ││ ▶ Bautage │ ││ Aufmaß │ ┌──────┬──────────────┬────────┬──────────┬─────────┬─────────┐ ││ Mängel │ │ Tag │ Wetter DWD │ Typ │ Ersteller│ Status │ Signatur│ ││ Projekte │ ├──────┼──────────────┼────────┼──────────┼─────────┼─────────┤ ││ Rechng. │ │ Mo19 │ 🌧 6°, 1,2mm │ Tag │ Yılmaz │ Offen │ — │ ││ Audit │ │ Mo19 │ 🌧 6° │ Regie │ Schmidt │ 🟡 war- │ ✍ 1/2 │ ││ │ │ │ │ │ │ tend │ │ ││ │ │ Fr16 │ ☁ 12° │ VOB §6 │ Schmidt │ 🟢 GS │ ✍ 1/1 │ ││ │ │ Do15 │ ☀ 14° │ Regie │ Yılmaz │ 🟢 GS │ ✍ 2/2 │ ││ │ │ Mi14 │ ☀ 13° │ Werkz. │ Yılmaz │ 🟢 │ — │ ││ │ └──────┴──────────────┴────────┴──────────┴─────────┴─────────┘ ││ │ ││ │ Geo-Karte aller Fotos: ││ │ ┌────────────────────────────────────────────────────────────┐ ││ │ │ Köln · Schulstraße 12 │ ││ │ │ 📍 📍 📍 │ ││ │ │ 📍 📍 📍 📍 │ ││ │ │ 📍 │ ││ │ └────────────────────────────────────────────────────────────┘ │└────────────────────────────────────────────────────────────────────────────────┘6.6 Mobile — Offline-State (Sync-Queue)
Abschnitt betitelt „6.6 Mobile — Offline-State (Sync-Queue)“┌────────────────────────────────┐│ ← Bautagebuch 🚫LTE │├────────────────────────────────┤│ 🟡 Offline · 3 Einträge + ││ 14 Fotos warten auf Sync ││ ││ Sync-Queue ││ ┌────────────────────────────┐ ││ │ 📋 Mo 19.04. · Tageseintr. │ ││ │ ⏳ wartet (2 Fotos) │ ││ ├────────────────────────────┤ ││ │ ✍ Mo 19.04. · Regie │ ││ │ 🟢 bereit (signiert) │ ││ ├────────────────────────────┤ ││ │ 📷 Mo 19.04. · 9 Fotos │ ││ │ ⏳ 4,2 MB (wird kompr.) │ ││ └────────────────────────────┘ ││ ││ DWD-Cache: letzter Abruf ││ Mo 19.04. 09:42 · Köln ││ 🟢 Gültig bis Di 21.04. 09:42 ││ ││ [ Jetzt synchronisieren ] │└────────────────────────────────┘7. Datenmodell-Skizze
Abschnitt betitelt „7. Datenmodell-Skizze“Pseudo-Drizzle-Schema (Postgres 17 + RLS + pgvector).
export const bautagebuchEntriesTable = pgTable('bautagebuch_entries', { id: uuid('id').primaryKey().defaultRandom(), // UUID v7 tenantId: uuid('tenant_id').notNull().references(() => tenantsTable.id), baustelleId: uuid('baustelle_id').notNull().references(() => baustellenTable.id),
entryType: bautagebuchEntryType('entry_type').notNull(), // 'tageseintrag' | 'regiebericht' | 'behinderung_vob6' // | 'werkzeug_uebergabe' | 'psa_check' entryDate: date('entry_date').notNull(), // Tag auf der Baustelle (nicht createdAt)
// Wetter (DWD) weatherSource: wetterSource('weather_source').notNull().default('dwd_mosmix'), // 'dwd_mosmix' | 'dwd_cache' | 'manual_fallback' weatherTempC: real('weather_temp_c'), weatherPrecMm: real('weather_precipitation_mm_h'), weatherWindKmh: real('weather_wind_kmh'), weatherFrost: boolean('weather_frost').notNull().default(false), weatherFetchedAt: timestamp('weather_fetched_at', { withTimezone: true }),
// Inhaltliche Felder description: text('description').notNull(), // Pflicht bei tageseintrag progressEnum: progressEnum('progress'), // 'on_track' | 'ahead' | 'delayed' progressDelayDays: integer('progress_delay_days'), progressReason: delayReasonEnum('progress_reason'), // 'weather' | 'material' | 'sub' | 'other'
// Signatur (bei regiebericht pflicht) signedByName: text('signed_by_name'), signedByRole: signedByRole('signed_by_role'), // 'bauherr' | 'bauleiter' | 'vertreter' signedAt: timestamp('signed_at', { withTimezone: true }), signatureBlobId:uuid('signature_blob_id').references(() => blobsTable.id), signatureKind: signatureKind('signature_kind'), // 'touch_vector' | 'pin_token'
// Status-Maschine status: entryStatus('status').notNull().default('entwurf'), // 'entwurf' | 'offen' | 'bestaetigt' | 'exportiert' | 'archiviert' correctsEntryId:uuid('corrects_entry_id').references(() => bautagebuchEntriesTable.id), correctionReason: text('correction_reason'), // Pflicht wenn correctsEntryId
// GoBD (Flag: true) hashPrev: bytea('hash_prev'), // 32 Byte, NULL nur für ersten Eintrag je Baustelle hashSelf: bytea('hash_self').notNull(), // 32 Byte geoExifEnabled: boolean('geo_exif_enabled').notNull(), // aus Tenant-Config, Snapshot zum Entry
// Audit createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(), createdBy: uuid('created_by').notNull().references(() => usersTable.id), idempotencyKey: uuid('idempotency_key').notNull().unique(),
}, (t) => ({ tenantBaustelleIdx: index('bautagebuch_tenant_baustelle_idx') .on(t.tenantId, t.baustelleId, t.entryDate.desc()), statusIdx: index('bautagebuch_status_idx').on(t.tenantId, t.status), hashChainIdx: uniqueIndex('bautagebuch_hash_self_uq').on(t.tenantId, t.hashSelf),}));
export const bautagebuchPhotosTable = pgTable('bautagebuch_photos', { id: uuid('id').primaryKey().defaultRandom(), tenantId: uuid('tenant_id').notNull().references(() => tenantsTable.id), entryId: uuid('entry_id').notNull().references(() => bautagebuchEntriesTable.id), s3Key: text('s3_key').notNull(), // S3 Object Lock Compliance-Mode contentSha256: bytea('content_sha256').notNull(), widthPx: integer('width_px').notNull(), heightPx: integer('height_px').notNull(), bytesOriginal: bigint('bytes_original', { mode: 'number' }).notNull(), bytesStored: bigint('bytes_stored', { mode: 'number' }).notNull(), gpsLat: decimal('gps_lat', { precision: 9, scale: 6 }), gpsLon: decimal('gps_lon', { precision: 9, scale: 6 }), capturedAtUtc: timestamp('captured_at_utc', { withTimezone: true }).notNull(), headingDeg: real('heading_deg'), geoStampSha256: bytea('geo_stamp_sha256').notNull(), // SHA-256 über {foto_sha, lat, lon, utc, device} createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(),});
export const bautagebuchGewerkeTable = pgTable('bautagebuch_gewerke', { entryId: uuid('entry_id').notNull().references(() => bautagebuchEntriesTable.id), subunternehmerId: uuid('subunternehmer_id').references(() => subunternehmerTable.id), freitextName: text('freitext_name'), // wenn kein Stammsatz existiert}, (t) => ({ pk: primaryKey({ columns: [t.entryId, t.subunternehmerId, t.freitextName] }) }));
export const werkzeugeTable = pgTable('werkzeuge', { id: uuid('id').primaryKey().defaultRandom(), tenantId: uuid('tenant_id').notNull().references(() => tenantsTable.id), inventarNr: text('inventar_nr').notNull(), // z. B. "WZ-00142" bezeichnung: text('bezeichnung').notNull(), // "HILTI TE 30-AVR Bohrhammer" qrCode: text('qr_code'), // EAN-13 / Code-128 / QR-Payload nfcUid: text('nfc_uid'), // ISO 14443 UID hex dguvPruefDatum: date('dguv_pruef_datum'), dguvPruefIntervallMonate: integer('dguv_pruef_intervall_monate').notNull().default(12), dguvLetzterPruefer: text('dguv_letzter_pruefer'), fahrzeugId: uuid('fahrzeug_id').references(() => fahrzeugeTable.id), ausgegebenAnUserId: uuid('ausgegeben_an_user_id').references(() => usersTable.id), ausgegebenSeit: timestamp('ausgegeben_seit', { withTimezone: true }),}, (t) => ({ tenantQrIdx: uniqueIndex('werkzeuge_tenant_qr_uq').on(t.tenantId, t.qrCode), tenantNfcIdx: uniqueIndex('werkzeuge_tenant_nfc_uq').on(t.tenantId, t.nfcUid),}));
export const werkzeugUebergabenTable = pgTable('werkzeug_uebergaben', { id: uuid('id').primaryKey().defaultRandom(), tenantId: uuid('tenant_id').notNull().references(() => tenantsTable.id), werkzeugId: uuid('werkzeug_id').notNull().references(() => werkzeugeTable.id), entryId: uuid('entry_id').notNull().references(() => bautagebuchEntriesTable.id), richtung: uebergabeRichtung('richtung').notNull(), // 'ausgabe' | 'ruecknahme' vonUserId: uuid('von_user_id').references(() => usersTable.id), anUserId: uuid('an_user_id').references(() => usersTable.id), scanMethod: scanMethod('scan_method').notNull(), // 'qr' | 'nfc' | 'manual' scannedAt: timestamp('scanned_at', { withTimezone: true }).notNull().defaultNow(), dguvValidAtScan:boolean('dguv_valid_at_scan').notNull(), // Snapshot — blockt Übergabe in 10.x});
export const dwdCacheTable = pgTable('dwd_cache', { cacheKey: text('cache_key').primaryKey(), // "{baustelleId}:{dateIso}" baustelleId: uuid('baustelle_id').notNull().references(() => baustellenTable.id), dateIso: date('date_iso').notNull(), mosmixStation: text('mosmix_station').notNull(), // DWD-MOSMIX-Kennung payload: jsonb('payload').notNull(), // Vollständige DWD-Antwort fetchedAt: timestamp('fetched_at', { withTimezone: true }).notNull(), validUntil: timestamp('valid_until', { withTimezone: true }).notNull(),});RLS-Policy-Sketch:
ALTER TABLE bautagebuch_entries ENABLE ROW LEVEL SECURITY;
CREATE POLICY btb_entries_tenant_isolation ON bautagebuch_entries USING (tenant_id = current_setting('app.tenant_id')::uuid);
CREATE POLICY btb_entries_scope_own ON bautagebuch_entries FOR SELECT USING ( tenant_id = current_setting('app.tenant_id')::uuid AND ( current_setting('app.scope') = 'all' OR (current_setting('app.scope') = 'team' AND baustelle_id IN (SELECT bs_id FROM user_baustellen_membership WHERE user_id = current_setting('app.user_id')::uuid)) OR (current_setting('app.scope') = 'own' AND created_by = current_setting('app.user_id')::uuid) ) );
-- Append-only: UPDATE nur auf status, signature, korrektur-Felder. Inhaltliche Felder eingefroren.CREATE POLICY btb_entries_no_content_update ON bautagebuch_entries FOR UPDATE USING (tenant_id = current_setting('app.tenant_id')::uuid) WITH CHECK ( -- Inhaltliche Felder dürfen nach INSERT nicht geändert werden description = (SELECT description FROM bautagebuch_entries WHERE id = bautagebuch_entries.id) AND entry_date = (SELECT entry_date FROM bautagebuch_entries WHERE id = bautagebuch_entries.id) -- Weather-Snapshot ebenfalls eingefroren AND weather_temp_c IS NOT DISTINCT FROM (SELECT weather_temp_c FROM bautagebuch_entries WHERE id = bautagebuch_entries.id) );
-- DELETE strikt verboten (GoBD):REVOKE DELETE ON bautagebuch_entries FROM PUBLIC;ER-Bezug. Referenzierte Tabellen: tenants, users, baustellen (Kern), subunternehmer (Kern), fahrzeuge (V2-Lager), blobs (zentraler Signatur-/Asset-Store), audit_log (Append-only Zentraltabelle).
8. API-Endpunkte
Abschnitt betitelt „8. API-Endpunkte“Pfad-Konvention: /v1/handwerk/bautagebuch/.... Alle hinter Hono-Modul-Gate module.handwerk.bautagebuch.
| Methode | Pfad | Auth-Scope | Rate-Limit | Idempotenz | Beschreibung |
|---|---|---|---|---|---|
POST |
/v1/handwerk/bautagebuch/entries |
bautagebuch:write |
Standard | Idempotency-Key Pflicht |
Eintrag anlegen |
GET |
/v1/handwerk/bautagebuch/entries |
bautagebuch:read:<scope> |
Standard | — | Liste, Filter baustelleId, from, to, type |
GET |
/v1/handwerk/bautagebuch/entries/{id} |
bautagebuch:read:<scope> |
Standard | — | Detail |
POST |
/v1/handwerk/bautagebuch/entries/{id}/signature |
bautagebuch:write |
Privileged | Pflicht | Signatur anhängen, Status → bestaetigt |
POST |
/v1/handwerk/bautagebuch/entries/{id}/correction |
bautagebuch:write |
Standard | Pflicht | Korrektur-Eintrag (neuer Datensatz mit correctsEntryId) |
GET |
/v1/handwerk/bautagebuch/entries/{id}/pdf |
bautagebuch:read:<scope> |
Heavy | — | Typst-PDF, Hash-Signatur im Footer |
POST |
/v1/handwerk/bautagebuch/photos/presign |
bautagebuch:write |
Standard | Pflicht | Pre-Signed URL für S3-Multipart |
POST |
/v1/handwerk/bautagebuch/photos |
bautagebuch:write |
Standard | Pflicht | Metadaten-Post nach S3-Upload, inkl. Geo-Stempel-Hash |
GET |
/v1/handwerk/bautagebuch/weather |
bautagebuch:read:own |
Heavy (DWD-Rate-Limit) | — | DWD-Proxy mit Cache, Query baustelleId, date |
POST |
/v1/handwerk/werkzeuge/{id}/uebergabe |
werkzeug:write |
Standard | Pflicht | Ausgabe/Rücknahme per Scan |
GET |
/v1/handwerk/werkzeuge |
werkzeug:read:<scope> |
Standard | — | Stammdaten-Liste, Filter nach DGUV-Fälligkeit |
POST |
/v1/handwerk/bautagebuch/weekly-pdf |
bautagebuch:read:team |
Heavy | Pflicht | Wochenbericht-PDF-Bulk |
OpenAPI-Schema-Skizze:
paths: /v1/handwerk/bautagebuch/entries: post: operationId: createBautagebuchEntry x-werkszeit-scope: bautagebuch:write x-werkszeit-module-gate: module.handwerk.bautagebuch x-werkszeit-rate-limit: standard requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/BautagebuchEntryCreateInput' responses: '201': { description: 'Created', content: { application/json: { schema: { $ref: '#/components/schemas/BautagebuchEntry' } } } } '409': { description: 'Idempotency conflict' } '422': { description: 'Validation error (Valibot)' }components: schemas: BautagebuchEntryCreateInput: type: object required: [idempotencyKey, baustelleId, entryType, entryDate, description] properties: idempotencyKey: { type: string, format: uuid } baustelleId: { type: string, format: uuid } entryType: { type: string, enum: [tageseintrag, regiebericht, behinderung_vob6, werkzeug_uebergabe, psa_check] } entryDate: { type: string, format: date } description: { type: string, maxLength: 2000 } weatherOverride: type: object properties: tempC: { type: number } precMm: { type: number } windKmh: { type: number } progress: { type: string, enum: [on_track, ahead, delayed] } progressDelayDays: { type: integer, minimum: 0, maximum: 90 }Webhook-Events (AsyncAPI 3.0, via BullMQ an registrierte Partner-Endpoints):
bautagebuch.entry.createdbautagebuch.entry.signed(Regiebericht — Trigger für Rechnungs-Vorgang)bautagebuch.entry.correctedbautagebuch.behinderung.declared(VOB §6 — Trigger für Fristüberwachung)werkzeug.uebergebenwerkzeug.dguv_abgelaufen(täglicher Scheduler, Push an Bauleitung)
9. Offline-Profil
Abschnitt betitelt „9. Offline-Profil“| Profil | Begründung | Mechanik |
|---|---|---|
| Voll-offline | Monteur-Alltag im Heizungskeller, SHK-Schacht, Stahlbetonbau — oft stundenlang kein LTE. Regiebericht muss trotzdem signierbar sein, bevor der Bauherr die Baustelle verlässt. | Outbox-Pattern mit UUID-v7-Idempotency-Key. Drift-Tabelle bautagebuch_outbox mit entry_json, photo_refs[], status (pending / uploading / failed). Foto-Originale im App-Sandbox-Filesystem, nur Thumbnail in SQLite. Bei Netz: Photos zuerst (S3 presigned Multipart), dann Entry-POST mit Photo-IDs. |
Konflikt-Strategie. Keine — Einträge sind append-only. „Konflikt“ heißt hier nicht „gleicher Datensatz wurde von zwei Seiten geändert“, sondern „der Idempotency-Key wurde zweimal zugestellt“ → Server antwortet 409 + bestehender Eintrag, Client entfernt aus Outbox.
Wetter-Cache. DWD-Antworten werden pro Baustelle für 48 h gecacht. Bei Offline-Submit wird der letzte gültige Cache-Eintrag angeheftet und als weather_source='dwd_cache' markiert. Beweis-Wert reicht für §6-VOB-Nachweis; Nachtrag-Berechnung von Winterausfallgeld (§4.9 SOKA-Bau, V2) fordert zusätzlich Server-seitigen DWD-Nachabgleich.
Foto-Sync. S3-Multipart mit presigned URL. Bei Foto >10 MB (Originale iPhone 16 Pro Apple ProRAW) wird clientseitig auf 2048 px longest edge + JPEG q=82 komprimiert; Original wird optional als _orig.heic mitgeschickt, wenn der Tenant das aktiviert hat (Default: aus — spart S3-Kosten). Geo-EXIF-Hash wird vor der Komprimierung gerechnet, damit er den Original-Zustand beweist.
10. Compliance-Mapping
Abschnitt betitelt „10. Compliance-Mapping“10.1 GoBD
Abschnitt betitelt „10.1 GoBD“- Append-only-Tabelle.
bautagebuch_entriesmithash_prev/hash_self. Hash ist SHA-256 über kanonisierte Feld-Reihenfolge(id, tenantId, baustelleId, entryType, entryDate, description, weatherTempC, weatherPrecMm, signedByName, signedAt, hashPrev)— stabile Ordnung, keine Insertion-Order-Abhängigkeit. - Aufbewahrung. Fotos in S3 mit Object Lock (Compliance-Mode, 10 Jahre) — Lifecycle
transition to Glacier Instant Retrieval after 1 year. Entry-Daten in Postgres mit PITR (7 Tage) + täglichem pgBackRest-Snapshot + Hot-Standby in eu-central-1b. - Nachvollziehbarkeit. Jede Mutation erzeugt einen
audit_log-Eintrag (bautagebuch.entry.created,...signed,...corrected). Audit-Log ist selbst Hash-verkettet (siehekern/08-audit-log). - Verfahrensdokumentation. Textbaustein in
gobd-verfahrensdoku.mdmit Modul-Abschnitt „Bautagebuch — Erfassung, Unveränderbarkeit, Archivierung“.
10.2 ArbZG
Abschnitt betitelt „10.2 ArbZG“— nicht zutreffend, weil Arbeitszeit-Erfassung in kern/01-zeiterfassung läuft. Ein Bautagebuch-Eintrag ist kein Stempel-Ereignis. Regiebericht kann aber auf existierende Zeit-Einträge verweisen (Foreign Key zeit_eintraege[], read-only).
10.3 VOB/B
Abschnitt betitelt „10.3 VOB/B“- §3 Abs. 3 (Ausführungsunterlagen): Bautagebuch als „gleichwertiger Nachweis“ der Ausführung nach übergebener Unterlage.
- §6 (Behinderung): Separater Eintragstyp
behinderung_vob6mit Pflichtfeldern Ursache, Zeitraum, erwarteter Einfluss auf Bauzeit. Nach Signatur wird automatisch ein E-Mail-Versand an den bei der Baustelle hinterlegten Bauherr-Kontakt ausgelöst (bautagebuch.behinderung.declared→ Mailer-Worker). Zeitstempel des E-Mail-Versands wird als „Unverzüglichkeits-Nachweis“ mitprotokolliert. - §14 (Abrechnung): Regiebericht wird als Position in Teil-/Schlussrechnung übernommen (siehe
handwerk/04-rechnung-vob, V1). - §15 Abs. 3 (Stundenlohnarbeiten): Regiebericht = Stundenlohn-Zettel. Pflicht-Signatur des Auftraggebers im Status-Übergang
offen → bestaetigt. Ohne Signatur bleibt Eintragentwurf— keine Abrechnung möglich. Push-Reminder um 17:00 an Polier + um 18:00 an Bauleitung bei ungesigniertem Regiebericht vom selben Tag.
10.4 DSGVO
Abschnitt betitelt „10.4 DSGVO“- Art. 5 Datenminimierung. Fotos werden standardmäßig ohne Geo-EXIF abgelegt — der Geo-Stempel ist ein separater Nachweis-Hash, nicht EXIF. Geo-EXIF im Foto selbst bleibt nur, wenn der Tenant
geoExifInExifexplizit aktiviert (BR-Workflow, siehe §10.6). Gesichter auf Fotos werden nicht automatisch verpixelt (kein KI-Feature-Zwang), der Kunde trägt die DSFA-Verantwortung für Baustellen-Fotos. - Art. 6 Rechtsgrundlage. Vertrag (Art. 6 Abs. 1 lit. b DSGVO) für Bauherr-Daten und Sub-Vertreter-Daten, berechtigtes Interesse (Art. 6 Abs. 1 lit. f) für Werkzeug-Übergabe-Logs an eigene Mitarbeiter (BetrVG-konform, siehe §10.6).
- Art. 17 Löschung. Eintrags-Inhalt in Postgres kann nach Ablauf der GoBD-10-Jahres-Frist gelöscht werden. Vorher: logische Maskierung (personenbezogene Namen →
[geloescht_2028-03], Fotos → schwarze Kachel mit Hash-Nachweis). Keine physische Löschung vor Ablauf — DSGVO-vs-GoBD-Konflikt wird zugunsten GoBD entschieden, wie in Art. 17 Abs. 3 lit. b vorgesehen. - Art. 20 Datenexport. User bekommt ZIP mit eigenen Einträgen (JSON + Foto-Originale + Signatur-Bytes), nicht die komplette Baustelle.
- Art. 30 Verarbeitungsverzeichnis. Eintrag „Bautagebuch“ mit Zweck: Dokumentationspflicht VOB/B, Rechtsgrundlage: Vertrag, Empfänger: keine (Bauherr ist Vertragspartner), Drittland: keines (AWS Frankfurt).
- DSFA. Nicht pflichtig im Regelfall (kein systematisches Monitoring, keine sensiblen Kategorien nach Art. 9). Pflicht wird Pflicht, wenn der Tenant zusätzlich Gesichts-/Nummernschild-KI-Schwärzung aktiviert — dann DSFA-Template aus
kern/11-dsgvo-toolkit.
10.5 BFSG / WCAG 2.2 AA
Abschnitt betitelt „10.5 BFSG / WCAG 2.2 AA“— nicht zutreffend, weil das Bautagebuch kein ESS-Flow ist. Trotzdem gilt: Web-Oberfläche erfüllt WCAG 2.2 AA (Screenreader-Labels, Tastatur-Navigation, Kontrast ≥4.5:1) als Haus-Standard aus kern/11-bfsg-baseline.
10.6 BetrVG §87(1)6
Abschnitt betitelt „10.6 BetrVG §87(1)6“- Geo-EXIF / Geo-Stempel als Ortsdatenerfassung. Der Geo-Stempel (Baustellen-Position pro Foto) ist mittelbare Leistungs-/Verhaltenskontrolle nach BetrVG §87(1)6. Default: deaktiviert auf Tenant-Ebene. Aktivierung nur über Admin-UI → Einstellungen → Betriebsrat-Freischaltungen mit Pflichtfeldern: BR-Beschluss-Datum, Protokoll-ID (Freitext), Uploaded-Beschluss-PDF.
- Werkzeug-Übergabe-Log. Das Log speichert
von_user_id,an_user_id→ potenziell Leistungsdaten. Rechtsgrundlage: berechtigtes Interesse (Haftung §823 BGB, DGUV-Prüfpflicht). Kein BR-Gate erforderlich, aber Transparenz-Pflicht: Mitarbeiter sieht im eigenen Profil alle eigenen Übergaben. - Audit-Eintrag bei Aktivierung Geo-EXIF mit
betrvg.feature.activatedundbriefErstattDatum→ Compliance-Suite.
10.7 Weitere Spezial-Compliance
Abschnitt betitelt „10.7 Weitere Spezial-Compliance“- DWD-Nutzungsbedingungen. Open-Data-Lizenz DL-DE→BY-2.0 mit Quellenangabe „Datenbasis: Deutscher Wetterdienst, eigene Darstellung“ im PDF-Footer.
- KI-VO Art. 50 (EU AI Act) — Transparenzpflicht. Relevant nur, wenn der Kunde die Voice-Transkription (V1.5) oder eine spätere Tages-Zusammenfassung per LLM aktiviert. Dann: sichtbares Label „Vorschlag — bitte prüfen“ und Audit-Eintrag
ai.summary.shownmit Modell-ID, Version, Provider (AWS Bedrock Frankfurt / Mistral Paris). Kein KI-Output wird unkommentiert als verbindlicher Text übernommen.
11. Edge-Cases
Abschnitt betitelt „11. Edge-Cases“| # | Szenario | Erwartetes Verhalten |
|---|---|---|
| EC-01 | DWD-API offline (DWD-Wartung, nachts zwischen 02:00 und 04:00, regulär) | Client fällt auf Cache zurück (weather_source = 'dwd_cache'), angezeigt mit gelbem Badge „Wetter aus Cache (Mo 19.04. 09:42)“. Bei Cache älter 48 h: manuelle Eingabe mit explizitem weather_source = 'manual_fallback' und Audit-Eintrag. Eintrag wird trotzdem gespeichert. |
| EC-02 | Foto >10 MB (iPhone 16 Pro Apple ProRAW DNG, ~28 MB) | Client komprimiert vor S3-Upload auf Longest-Edge 2048 px + JPEG q=82. Geo-Stempel-Hash wird über Original-Bytes berechnet, nicht über komprimierte Version. Ergebnis: beweisfeste Kette vom Original-Hash zum gespeicherten Foto (Komprimierungs-Metadaten als Sidecar-JSON). |
| EC-03 | Bauleiter lehnt Signatur ab | Regiebericht-Status bleibt entwurf, kein Rechts-/Abrechnungseffekt. Polier kann den Eintrag mit entryType='behinderung_vob6' kopieren und als Behinderungsanzeige umwidmen („Verweigerung Regie-Bestätigung trotz angeordneter Leistung“). Bauleitung bekommt Push, Abrechnung pausiert. |
| EC-04 | Zwei Monteure erfassen gleichen Tag offline | Beide dürfen separate Tageseinträge anlegen (entryType='tageseintrag' ist kein Singleton je Tag/Baustelle). Die Aggregation im Wochenbericht zeigt beide mit Creator-Zuordnung. Nur regiebericht ist pro Tag/Baustelle/Gewerk unique (DB-Constraint). |
| EC-05 | Baustelle wird während Eintrag-Erfassung deaktiviert (Admin deaktiviert im Web) | Client-seitige Cache der Baustelle bleibt bis Sync gültig. Server-Reaktion auf Eintrag-POST: 201 Created mit Warn-Header X-Werkszeit-Baustelle-Inactive: true. Eintrag wird in Web mit Pill „Baustelle inaktiv seit …“ markiert, ist aber voll gültig. |
| EC-06 | Werkzeug-DGUV-Prüfung abgelaufen | Scan zeigt rote Warnung. Übergabe ist trotzdem möglich, aber der Eintrag bekommt dguv_valid_at_scan = false, Audit-Eintrag werkzeug.ausgegeben_trotz_abgelaufen, E-Mail an HSSE-Rolle und Bauleitung. Für handwerk/10-arbeitssicherheit ist dies ein Hart-Block (Schicht startet nicht), siehe dort. Hier im Bautagebuch nur Warnung. |
| EC-07 | Bauherr-Unterschrift per PIN statt Touch | Signatur-Kind pin_token. E-Mail an Bauherr mit 6-stelliger PIN, Eintrag im Bautagebuch-PDF als „EES-Textform-Signatur (PIN)“ gekennzeichnet — schwächere Beweiskraft als eigene Schrift, aber rechtsgültig nach §126b BGB. Im Web-Audit-Trail mit anderer Farbe. |
| EC-08 | Tenant wechselt zwischen musterbetrieb-maler und shk-gebruder-schmidt (Berater mit zwei Tenants) |
Aktiver Tenant ist pro Session festgelegt (Header X-Werkszeit-Tenant-Id). RLS blockt Query auf fremden Tenant, API antwortet 404 (nicht 403, um Existenz nicht zu offenbaren). Outbox wird pro Tenant getrennt gehalten (Composite-Key {tenantId, idempotencyKey}). |
| EC-09 | Eintrag-Korrektur: Monteur will Tippfehler fixen nach Submit | POST /entries/{id}/correction mit Begründung ≥ 20 Zeichen. Neuer Eintrag mit correctsEntryId=<original>, Status offen, originaler Eintrag bekommt Flag superseded_by (non-destructive, nur View-Layer). PDF-Export zeigt beide, Original ausgegraut mit Stempel „Korrigiert am …“ |
| EC-10 | S3-Multipart-Upload schlägt bei 6. von 8 Fotos fehl (Netz-Abbruch) | Outbox-Worker retried die einzelnen Multipart-Parts (exponential backoff, max 5 Versuche). Bei dauerhaftem Fehler: Foto bleibt in Outbox mit Status failed, Eintrag wird trotzdem committet (Fotos nachträglich anhängbar). Nutzer sieht Banner „2 Fotos warten noch auf Upload“. |
12. Akzeptanzkriterien (Gherkin)
Abschnitt betitelt „12. Akzeptanzkriterien (Gherkin)“Funktionalität: Bautagebuch-Eintrag auf Baustelle Schulstraße 12, Köln
Hintergrund: Angenommen ein Tenant "shk-gebruder-schmidt" mit aktivem Modul-Gate "module.handwerk.bautagebuch" Und die Baustelle "Sanierung Heizungsanlage Bgm.-Müller-Schule, Schulstraße 12, 50667 Köln" Und der Monteur "Mehmet Yılmaz" mit Rolle "Mitarbeiter" und Scope "own" Und der Bauleiter "Thomas Schmidt" mit Rolle "Bauleitung" und Scope "team"
Szenario: Happy Path — Tageseintrag mit DWD-Wetter und Foto Wenn Mehmet am 19.04.2026 um 16:42 Uhr die App auf der Baustelle öffnet Und auf "Neuer Eintrag" tippt Und "Tageseintrag" auswählt Dann zeigt die App die Baustelle "Schulstraße 12" als GPS-Treffer (12 m Distanz) Und das Wetter "6°C, 1,2 mm/h, 18 km/h" mit Quelle "DWD MOSMIX K5701" ist automatisch befüllt Wenn Mehmet 3 Fotos mit Kamera aufnimmt Und "Heizungsdemontage Keller, Altkessel ausgebaut" als Tätigkeit tippt Und auf "Eintrag speichern" tippt Dann wird der Eintrag mit Status "offen" erstellt Und der hash_self ist berechnet und chainet an den letzten Eintrag der Baustelle Und ein Audit-Log-Eintrag "bautagebuch.entry.created" mit hashSelf ist vorhanden Und die 3 Fotos liegen in S3 mit Object Lock (Compliance-Mode, 10 Jahre) Und jedes Foto hat einen Geo-Stempel-SHA256 mit {lat, lon, utc, device_id}
Szenario: Grenzfall — DWD-API offline, Cache-Fallback Angenommen die DWD-API "opendata.dwd.de" ist nicht erreichbar (Timeout nach 3 s) Und der letzte Cache für die Baustelle ist 12 h alt Wenn Mehmet einen Tageseintrag anlegen will Dann zeigt die App ein gelbes Banner "Wetter aus Cache (19.04.2026 03:00 Uhr)" Und das Wetter-Feld ist mit den Cache-Werten vorbelegt Und `weather_source` wird als "dwd_cache" gespeichert Und der Eintrag wird normal erstellt Und im Audit-Log steht "bautagebuch.weather.cache_fallback" mit Cache-Alter
Szenario: Grenzfall — Foto >10 MB wird komprimiert, Original-Hash bleibt beweisfest Angenommen Mehmet nimmt ein Foto im Apple ProRAW-Format mit 28,4 MB auf Wenn das Foto in die Outbox gelegt wird Dann wird der Geo-Stempel-SHA256 über die Original-Bytes berechnet Und das Foto wird auf Longest-Edge 2048 px, JPEG q=82 komprimiert (Ergebnis ~1,8 MB) Und die Sidecar-JSON speichert {original_sha256, compressed_sha256, compression_params} Und der S3-Upload erfolgt mit dem komprimierten Foto Und im PDF-Export ist die Kette "Original-SHA256 → Komprimierungs-Params → Stored-SHA256" sichtbar
Szenario: Grenzfall — Bauleiter lehnt Regiebericht-Signatur ab Angenommen Mehmet hat einen Regiebericht über 8:30 h und 60,40 € Material erfasst Wenn der Bauleiter "Hr. Müller-Bgm." die Unterschrift verweigert Und Mehmet "Signatur verweigert" im Signatur-Pad-Menü auswählt und die Situation beschreibt Dann bleibt der Regiebericht im Status "entwurf" Und es entsteht keine Rechnungs-Position Und Mehmet kann den Eintrag mit einem Tipp als "Behinderungsanzeige (VOB §6)" umwidmen Und die Bauleitung Thomas Schmidt bekommt eine Push-Nachricht "Regie-Bestätigung verweigert: Schulstraße 12, 19.04.2026"
Szenario: Grenzfall — Multi-Tenant-Isolation beim Eintrags-Detail Angenommen ein zweiter Tenant "musterbetrieb-maler" mit einem eigenen Eintrag E_MM Wenn Mehmet (Tenant shk-gebruder-schmidt) versucht, E_MM per ID abzurufen Dann antwortet die API mit HTTP 404 Und es entsteht KEIN Audit-Log-Eintrag in "musterbetrieb-maler" Und die RLS-Policy protokolliert den Zugriffsversuch im Security-Log (anonymisiert)13. Test-Cases
Abschnitt betitelt „13. Test-Cases“13.1 Unit-Tests (Dart + TypeScript)
Abschnitt betitelt „13.1 Unit-Tests (Dart + TypeScript)“- U-01 DWD-Response-Parser: Mock-Payload →
{tempC, precMm, windKmh, frost}korrekt - U-02 Geo-Stempel-Hash: gleicher Input → gleicher Hash (deterministisch); Byte-Änderung am Foto → anderer Hash
- U-03 Hash-Chain-Canonicalization: Feld-Reihenfolge invariant gegenüber JSON-Key-Order
- U-04 Property-based: für 10.000 zufällige Eintrags-Payloads ist
hashSelfkollisionsfrei - U-05 Signatur-Vector → SVG-Serialisierung → Re-Parse ist identisch (Roundtrip)
13.2 Widget-/Component-Tests (Flutter)
Abschnitt betitelt „13.2 Widget-/Component-Tests (Flutter)“- W-01 Stempel-Button-State:
connectivity == none→ Upload-Button disabled, Outbox-Counter sichtbar - W-02 Golden-Test für
de-DE+ Dark Theme auf Regiebericht-Screen - W-03 Signature-Pad: Canvas empty → “Bestätigen” disabled; ≥ 5 Punkte → enabled
- W-04 DWD-Widget: Offline + Cache-Alter 12 h → gelbes Banner sichtbar
13.3 Integrations-Tests (Backend, Drizzle In-Memory)
Abschnitt betitelt „13.3 Integrations-Tests (Backend, Drizzle In-Memory)“- I-01 Multi-Tenant-Isolation: Tenant A legt Eintrag an, Tenant B liest Liste → leer. Tenant B fragt Eintrags-UUID direkt ab → 404. (DOD §2.2 Pflicht)
- I-02 RLS
own-Scope: User U1 legt Eintrag an, User U2 (gleicher Tenant, gleiche Baustelle, Scopeown) sieht ihn nicht inGET /entries - I-03 Outbox-Idempotenz: doppelter POST mit gleichem
Idempotency-Key→ 409 + bestehender Entry, kein zweiter DB-Row - I-04 Hash-Chain: Mutation eines Eintrags über direkten DB-Update (Test-Bypass) → Chain-Verify-Job meldet Bruch
- I-05 Append-only RLS:
UPDATE descriptionwird von RLS-Policy abgelehnt (kein SQL-Error, stattdessen 0 Rows affected) - I-06 DWD-Cache-Hit: zweiter Weather-Call innerhalb 48 h triggert keinen Upstream-DWD-Request (Mock-Counter = 1)
13.4 E2E-Tests
Abschnitt betitelt „13.4 E2E-Tests“- E-01 Happy Path aus §12: Patrol iOS + Android; Playwright Chromium/Firefox/WebKit für Web
- E-02 Offline-Erfassung: Patrol simuliert
network off, Nutzer legt 3 Einträge + 9 Fotos an,network on→ Sync komplett, Golden-Image aller 3 Detail-Views - E-03 Visuelle Regression: Golden pro Plattform × (Light/Dark) ×
de-DE; Abweichung >0.1 % blockt Merge - E-04 axe-core ohne Critical/Serious-Findings auf Web-Wochenbericht
- E-05 DWD-Mock-Offline-Szenario: Chaos-Test mit 3-s-Timeout auf
opendata.dwd.de→ Banner erscheint in <4 s
13.5 Compliance-Tests (apps/api/test/compliance/)
Abschnitt betitelt „13.5 Compliance-Tests (apps/api/test/compliance/)“- C-01 Hash-Chain-Integrität: Simulierter Tamper auf
descriptionvia direktem UPDATE →verifyBautagebuchChain(tenantId, baustelleId)liefert erste gebrochene Position korrekt - C-02 DWD-Lizenz: jeder PDF-Export enthält im Footer „Datenbasis: Deutscher Wetterdienst, eigene Darstellung“ (Regex-Test auf generiertem Typst-Output)
- C-03 DSGVO Art. 20: Export-ZIP enthält alle Einträge des Users, alle Foto-Originale, Signatur-Blobs; keine fremden User-Daten
- C-04 DSGVO Art. 17 + GoBD-Konflikt:
DELETE /v1/me/dataauf User mit 18-monatigen Einträgen → logische Maskierung statt Delete; erneuter Export zeigt[geloescht_2026-10] - C-05 VOB §6-Pflicht-Felder Property-Test: 100 zufällige
behinderung_vob6-Payloads — Ursache + Zeitraum + Einfluss sind Pflicht, Valibot failt korrekt - C-06 BetrVG-Gate: Aktivierung
geoExifInExifohne hinterlegten BR-Beschluss → 422 „BR-Beschluss-Nachweis fehlt“
13.6 Flakiness-Schutz
Abschnitt betitelt „13.6 Flakiness-Schutz“Lokaler 20× Re-Run der neuen E2E-Tests (Offline-Sync ist Flakiness-Kandidat Nummer 1) grün in CI, kein Test landet in der Quarantäne-Liste. Auto-Retry in Patrol auf max. 1 (nicht 3 — wir wollen das echte Signal, siehe TECH-STACK §8.2).
14. Nicht-Ziele
Abschnitt betitelt „14. Nicht-Ziele“| Nicht-Ziel | Begründung |
|---|---|
| Drohnen-Orthofoto-Integration | Kein Phase-1-Kunde. Spezialtool (Pix4D, DroneDeploy) bleibt bei Kunde. V2+ nur mit zahlendem Design-Partner. |
| Automatische Gesichts-/Nummernschild-Verpixelung | DSFA-Overhead + KI-Modell-Haftung. Kunde regelt DSGVO im Baustellen-Vertrag mit Bauherrn; wir bieten Foto-Lösch-Tool im Nachgang. |
| 3D-Scan-Integration (LiDAR, Matterport) | Nische, kein KMU-Bedarf im Zielsegment. Liegt bei Spezialtools. |
| BIM-Modell-Verknüpfung (IFC, BCF) | Liegt bei RIB iTWO, Solibri. Wir exportieren Bautagebuch zu denen, nicht umgekehrt. |
| KI-Fortschritts-Erkennung aus Foto | Technisch reizvoll, rechtlich heikel (Leistungskontrolle §87(1)6), ROI unklar. Frühestens V3. |
| Wetterdaten anderer Provider (OpenWeatherMap etc.) | DWD ist amtlich und kostenlos. Kein zweiter Provider, solange kein Kunde „DWD-Ausfall >1×/Monat“ reklamiert. |
| Unterschrift nach QES-Niveau | EES (Touch) + PIN reicht für §15 VOB/B. QES-Massensignatur ist V3+, nur wenn Enterprise-Kunde es fordert (FU §5). |
| Live-Video-Stream von Baustelle | Datenschutz-Alarm (BR + DSGVO), operativ wenig Nutzen gegenüber Foto + Zeitstempel. Nein. |
15. Risiken & offene Annahmen
Abschnitt betitelt „15. Risiken & offene Annahmen“| Risiko / Annahme | Impact | Wahrscheinlichkeit | Gegenmaßnahme |
|---|---|---|---|
| DWD-MOSMIX-Station bis 30 km von Baustelle entfernt → Wetter ungenau | mittel | mittel | MOSMIX ist Deutschland-flächendeckend auf ~5–10 km Raster, Einzelfall-Abweichung dokumentiert im Feld mosmix_distance_km. Fallback auf Nowcast bei Bedarf. |
| DWD-API-Rate-Limit bei Bulk-Wochenbericht (viele Baustellen) | mittel | hoch | Batched Request pro Station; Server-seitiger Redis-Cache 1 h für Same-Station-Same-Hour. |
| Geo-Stempel wird als DSGVO-Leistungskontrolle-Fall ausgelegt | hoch | niedrig | BR-Freischaltungs-Workflow als Default-aus, dokumentierter BR-Beschluss-Slot in Admin-UI; Rechtsanwalt-Konsultation eingeplant vor GA. |
| Foto-Volumen sprengt S3-Budget (80-MA-Betrieb → ~800 Fotos/Tag) | mittel | mittel | Komprimierung ist Default, Kosten-Check in DOD §2.7. Lifecycle auf Glacier nach 1 Jahr. Monatliches Review. |
| Bauherren verweigern Signatur auf Smartphone-Display (Generation 60+) | niedrig | hoch | PIN-per-E-Mail als Fallback, Papier-Signatur-Scan als zweite Fallback-Option (V1.5, Foto der Unterschrift + OCR). |
| VOB-§6-Mail geht nicht raus (SES-Fehler) → „Unverzüglich“ verpasst | hoch | niedrig | BullMQ mit Retry + Dead-Letter-Queue, Push an Polier bei Nicht-Zustellung, zweiter Fallback-Mailer (Mailjet). |
| Append-only UPDATE-Policy blockt legitime Signatur-Nachtrag-Operation | mittel | niedrig | Separate Spalte signature_* ist explizit aus der Append-only-Check-Constraint ausgeklammert; getestet in I-05. |
16. Abhängigkeiten
Abschnitt betitelt „16. Abhängigkeiten“- Vorbedingung:
kern/03-projekte-baustellen— Baustellen-Stammdaten mit GPS-Koordinaten (für DWD-Lookup)kern/08-audit-log— Zentrale Audit-Log-Tabelle mit Hash-Chainkern/09-foto-upload-pipeline— S3-Multipart mit presigned URL, Object Lock
- Schnittstelle zu:
kern/01-zeiterfassung— Regiebericht referenziert Zeit-Einträge (read-only)handwerk/02-nachtrag— Behinderungsanzeige und nicht-signierter Regiebericht sind typische Auslöser; Deep-Link von Bautagebuch-Eintrag zum Nachtrags-Entwurfhandwerk/10-arbeitssicherheit— PSA-Check ist eigener Eintragstyp; Werkzeug-DGUV-Abgelaufen-Event triggert Schicht-Block dort
- Wird konsumiert von:
handwerk/04-rechnung-vob(V1) — Regiebericht wird Rechnungs-Positionhandwerk/09-soka-bau(V2) — DWD-Frost-Tage aggregiert als Winterausfallgeld-Nachweis (§101 SGB III)kern/07-reporting— Bautagebuch-KPIs im Management-Dashboard
17. Referenzkunde-Slot
Abschnitt betitelt „17. Referenzkunde-Slot“Status: TBD — zu klären mit Sales vor Sprint-Start.
DOR §1.1.1 verlangt mindestens einen zahlenden Design-Partner.
Kandidaten-Profile (für Sales-Recherche):
- SHK-Betrieb NRW, 50–100 MA, 2–5 parallele Baustellen, nutzt heute Excel + WhatsApp; bereits DATEV-Kunde (simplifiziert Onboarding). Primär-Kandidat: SHK-Gebrüder-Schmidt (aus Interview 2026-03).
- Maler-/Stuck-Betrieb Bayern, 20–40 MA, häufig öffentliche Aufträge (→ VOB-Pflicht), kennt Sander & Doll / Streit-Wettbewerb. Sekundär: musterbetrieb-maler (Seed-Tenant).
- Tiefbau 30–80 MA, hoher Witterungs-Streit-Anteil (§6-Behinderungen häufig), DWD-Wetter-Automatisierung ist der Kauf-Argument Nr. 1.
Validierungs-Fragen für das Erst-Gespräch:
- Wie viele Regieberichte schreiben Sie pro Monat? Wie viele davon werden nach 48 h noch ohne Unterschrift zurückgewiesen?
- Welche VOB-§6-Behinderungsanzeigen haben Sie letztes Jahr tatsächlich geschrieben? Wie hoch war Ihre Erfolgsquote bei Bauzeitverlängerung?
- Welches Wetter-Datum steht heute in Ihrem Bautagebuch — geschätzt oder gemessen? Mit welcher Quelle würde Ihr Anwalt vor Gericht besser arbeiten können?
- Wären Sie bereit, das Feature im Beta-Status für 30 Tage zu testen, gegen Starter→Business-Preis-Lock-In bis V1?
18. Senior-Berater-Empfehlung
Abschnitt betitelt „18. Senior-Berater-Empfehlung“Build-Sequenz (innerhalb des Features):
- Datenmodell + RLS + Multi-Tenant-Test zuerst.
bautagebuch_entries,bautagebuch_photos,werkzeuge,werkzeug_uebergaben,dwd_cache+ alle RLS-Policies + I-01 grün. Alles andere ist auf Sand. - DWD-Adapter-Lambda als eigenständiger Service mit Redis-Cache. Unabhängig testbar, trägt das höchste externe Ausfall-Risiko.
- Backend-API (Hono) + OpenAPI-Spec + Dart-Client-Regenerierung → Build grün.
- Mobile-MVP-Flow: Tageseintrag offline-fähig, Foto-Upload mit Outbox, DWD-Integration mit Cache.
- Regiebericht-Signatur-Flow mit Signature-Pad + PIN-Fallback + PDF-Export (Typst-Template).
- Web-Wochenbericht mit Bulk-PDF und Karten-Ansicht.
- Compliance-Test-Suite erweitern: Hash-Chain-Verify, Append-only-RLS, DSGVO-Export-Struktur.
- E2E-Suite vervollständigen (Patrol + Playwright), Flakiness-20×-Check.
- Werkzeug-Scan-Flow als eigener Sub-Epic (Scope V1 laut Roadmap).
- Doku-PR unter
docs/features/handwerk/bautagebuch.mdmit auto-generierten Screenshots aus E2E.
Risiko-Reihenfolge (was zuerst absichern, falls Zeitnot):
- Multi-Tenant-Isolation (I-01), Append-only (I-05), Hash-Chain (C-01) sind nicht verhandelbar.
- Werkzeug-Scan, ERP-Export, Voice-Transkription sind die ersten Streich-Kandidaten.
- Bei harter Zeitnot: Regiebericht ohne PIN-Fallback ausliefern (nur Touch-Signatur), PIN in V1 nachziehen.
Stop-the-Bus-Triggers (Build sofort anhalten, Eskalation an Tech-Lead + PO):
- Multi-Tenant-Bleed in I-01.
- Hash-Chain-Bruch in C-01.
- DSGVO-Löschung überschreibt GoBD-relevante Felder (C-04 fail).
- DWD-Adapter-Latenz p95 > 3 s (Mobile-UX kippt bei Offline-Warte-Zeit).
- Foto-Upload-Pipeline verliert Original-Hash-Kette bei Komprimierung.
Was uns 2027 dankbar macht:
- Hash-Chain ab Tag 1 — wenn wir später einen Tamper-Audit machen müssen (BGH-relevanter Baustreit, Staatsanwaltschaft), haben wir die Nachweiskette für 10 Jahre.
- Append-only-RLS statt „Soft Delete + Update-API“ — spart uns die GoBD-Retrofit-Baustelle, die wir in der Alt-App hatten.
- DWD-Adapter sauber isoliert — wenn DWD die API ändert (passiert alle paar Jahre), ist es eine Service-Deployment, keine Mobile-Release.
- Geo-Stempel statt EXIF-Geo — BetrVG-Diskussion wird niemals über Foto-Metadaten geführt, sondern über einen expliziten, abschaltbaren Feature-Flag. Saubere Trennung spart 2027 eine DSGVO-Diskussion mit dem Betriebsrat.
Letzte Aktualisierung: 2026-04-19. Änderungen an diesem Feinkonzept erfordern PR-Review durch Tech-Lead + Product-Owner und Refactor der abhängigen Feinkonzepte (02-nachtrag, 10-arbeitssicherheit).
Für Entwickler — API-Endpoints4
| Methode | Pfad | Auth | Zweck |
|---|---|---|---|
| GET | /v1/handwerk/bautagebuch/entries | bearerAuth | Einträge einer Baustelle im Zeitraum auflisten. |
| POST | /v1/handwerk/bautagebuch/entries | bearerAuth | Bautagebuch-Eintrag anlegen. |
| GET | /v1/handwerk/bautagebuch/entries/{id} | bearerAuth | Eintrags-Detail. |
| POST | /v1/handwerk/bautagebuch/entries/{id}/correction | bearerAuth | Korrektur-Eintrag anlegen (neuer Row, Original bleibt stehen). |