Zum Inhalt springen

Nachforderungsauftrag / Nachtrag (VOB §2 Abs. 5/6)

Live in Produktion

Feinkonzept · Nachforderungsauftrag / Nachtrag — Mobile First (§4.2)

Abschnitt betitelt „Feinkonzept · Nachforderungsauftrag / Nachtrag — Mobile First (§4.2)“

Feature-ID: handwerk/02-nachtrag · Stand: 2026-04-19 · Autor: Senior-Berater-Rolle Handwerks-/Bau-SaaS Verwandte Feinkonzepte: 01-bautagebuch (Nachtrag entsteht in 7 von 10 Fällen aus einem Bautagebuch-Eintrag — entweder aus einer Behinderungsanzeige §6 oder einem nicht-vom-LV-gedeckten Regiebericht), handwerk/04-rechnung-vob (V1, noch nicht finalisiert).


feature_id: handwerk/02-nachtrag
title: Nachforderungsauftrag / Nachtrag (VOB §2 Abs. 5/6)
funktionsumfang_ref: §4.2
roadmap_horizont: MVP # Basis-Nachtrag ohne GAEB/LV-Bezug ist MVP (FU §6)
plattformen:
mobile: vollständig # Mobile-First — Nachtrag entsteht auf der Baustelle
web: mit-Bulk # Freigabe, Abrechnung, Versionierung, Status-Dashboard
desktop: aus
owner_rolle: Bauleitung # Eigentümer; erstellt wird vom Polier/Monteur
modul_gate_flag: module.handwerk.nachtrag
compliance_flags:
gobd: true # Nachtrag ist abrechnungsrelevant → §147 AO, 10 Jahre
arbzg: false
vob: true # §2 Abs. 5 (geänderte Leistung), §2 Abs. 6 (zusätzliche Leistung), §14 (Abrechnung)
dsgvo: true # Bauherr-Daten, Signatur-Metadaten
bfsg: false
betrvg: false # Keine Leistungs-/Verhaltenskontrolle
stvg: false
weitere: [KI-VO (EU AI Act) Art. 50 Transparenzpflicht, §14 UStG (bei Direkt-Abrechnung)]
referenzkunde:
status: TBD
name: "zu klären mit Sales — Kandidat: SHK-Gebrüder-Schmidt (NRW, 80 MA), aktueller Prozess: E-Mail + Word + nachträgliche Unterschrift"
quelle: Sales-Call 2026-03
estimate_eng_tage: 32 # 12 Mobile + 8 Backend + 6 Web + 4 KI-Integration + 2 Test/Compliance
abhängigkeiten:
- kern/03-projekte-baustellen
- kern/08-audit-log
- handwerk/01-bautagebuch # Deep-Link vom Bautagebuch-Eintrag
- kern/05-rechnung-basis # Nachtrag wird Rechnungs-Position (MVP: PDF-Basis)
- kern/12-ki-gateway # KI-Textvorschlag hinter Hono-AI-Gateway (opt-in pro Tenant)

Marktrealität (DE-Handwerk). Der Nachtrag ist der häufigste und härteste Streitpunkt zwischen Handwerker und Bauherrn. VOB/B §2 Abs. 5 regelt, dass bei einer Änderung des Bauentwurfs oder anderer Anordnungen des Auftraggebers der Auftragnehmer vor der Ausführung eine Preisankündigung machen muss. §2 Abs. 6 regelt zusätzliche Leistungen, die nicht im Vertrag vorgesehen sind — hier ist die Ankündigung ebenfalls vor Beginn Pflicht. Wer erst mit der Rechnung kommt, bekommt oft nichts (BGH VII ZR 164/20: Nachträge ohne vorherige Anzeige gelten als Kulanz).

Heute läuft das in der Zielbranche so: Monteur merkt auf der Baustelle, dass der Bauherr etwas anders haben will. Er ruft die Bauleitung an („Chef, der will jetzt noch die Fußbodenheizung“), die Bauleitung ruft den Bauherrn an, schickt abends eine Word-Datei mit geschätzten Mehrkosten, der Bauherr unterschreibt (oder nicht), die Mehrarbeit läuft parallel. Ergebnis: 30–40 % der Nachträge werden nachträglich bestritten, 15–20 % landen im Streit beim Anwalt. Bauherren kennen §2 Abs. 5 VOB/B besser als Handwerker und schieben die Nicht-Ankündigung vor.

Der rechtliche Rahmen verlangt Schriftform (Textform genügt nach §126b BGB) + Vor-Beginn-Anzeige + Preisermittlung auf Basis der Grundlagen der Preisvermittlung. Ein Vor-Ort-Workflow mit Unterschrift des Bauherrn bevor die Mehrarbeit startet ist der rechtssicherste und schnellste Weg — und genau die Stelle, an der Handwerker ohne App täglich Geld verlieren.

KI als Effizienz-Hebel — mit Haftungs-Zähnen. Nachtragstexte sind formelhaft. „Wegen geänderter Anordnung des Auftraggebers gemäß §2 Abs. 5 VOB/B erlaubt sich der Auftragnehmer hiermit, vor Ausführung eine Mehrvergütung von …“ — das kann ein LLM aus Stichworten zuverlässig formulieren. Der Haken: Der KI-Output ist keine Rechtsberatung, und der EU AI Act Art. 50 verlangt ab 2026 Transparenzpflicht bei KI-generiertem Text. Wir liefern einen KI-Vorschlag mit deutlich sichtbarem Disclaimer, Pflicht-Review durch den Nutzer, Audit-Eintrag pro Anzeige. Kein Auto-Submit.

Schmerzpunkt der Alt-App. Die Alt-App hatte einen quotes.js-Flow, der Angebote neben dem LV baute (LESSONS-LEARNED §5, §11). Das ist für Nachträge strukturell falsch — ein Nachtrag ist eine Variante eines Hauptauftrags und muss auf dessen LV-Struktur (GAEB) aufsetzen. MVP-Werkszeit hat noch kein GAEB (kommt V1), also bauen wir den Nachtrag als freie Position mit Referenz auf Hauptauftrag, nicht als eigenen Angebots-Zweig. Das V1-Refactor zur GAEB-Bindung ist im Datenmodell vorgesehen (Spalte lv_position_ref bleibt NULL im MVP, wird V1 gefüllt).

Erwarteter Outcome. Messbar am Design-Partner: Rechtssicher unterschriebene Nachträge von heute ~60 % auf >90 % (vor Ausführung signiert). Durchschnittliche Nachtrag-Abwicklungszeit von heute 4–7 Tagen auf <1 h (Erfassung vor Ort, Bauherr-Signatur innerhalb 15 min, Rechnungs-Position automatisch). VOB-§2-Abs.-5-Streit-Quote von heute ~25 % auf <5 % (Bauherr hat vor Ausführung signiert, Beweisfrage entfällt).


Rolle Aktion Scope Plattform
Monteur Nachtrag erfassen (eigene Baustelle), Foto-Beleg, Sprach-zu-Text own 📱
Polier / Vorarbeiter Nachtrag erfassen, Bauherr-Signatur einholen team 📱
Bauleitung Nachtrag prüfen, Preisansatz verfeinern, freigeben, E-Mail-Versand team 📱🌐
Kalkulator Preis-Anpassung, EP-Kalkulation (V1 mit GAEB) team 🌐
Manager Nachtrag-Übersicht über alle Baustellen, Bulk-Freigabe all 🌐
Bauherr (externer Gast) Nachtrag lesen, signieren (Link-Token ohne Login), PIN-Alternative extern 📱🌐
Admin Nachtrag-Vorlagen, KI-Aktivierung, Tenant-Einstellungen all 🌐

Persona-Skizzen:

  • Mehmet Yılmaz (Monteur, 32, SHK) — findet beim Heizungstausch einen zusätzlichen Asbestbefall an der Kesseldämmung. Muss Mehrarbeit melden, bevor er weitermacht. Ruft heute den Chef an — morgen will er das selbst erfassen können.
  • Thomas Schmidt (Bauleitung, 45) — sieht Mehmets Nachtrag 15 min später auf seinem Tablet, prüft den Preisansatz (Asbest-Entsorgung ist nicht im Hauptauftrag), gibt frei, E-Mail-Link geht an den Bauherrn.
  • Hr. Müller-Bgm. (Bauherr-Vertreter Schulträger) — bekommt E-Mail mit Link. Liest 3 Sätze, sieht Foto, sieht Preis, signiert per Touch oder PIN. Dauer: 90 Sekunden.
  • Sabine Maier (Manager musterbetrieb-maler) — nutzt die Nachtrag-Funktion typischerweise bei Renovierungsaufträgen („Kunde will dann doch die Decke mit“, „Tapete lässt sich nicht entfernen, muss geschliffen werden“). Schnelle Vor-Ort-Abwicklung ist ihr Top-Kaufargument.

US-01 [MVP] Als Polier möchte ich einen Nachtrag in der App erfassen, bevor
ich die Mehrarbeit beginne, damit ich §2 Abs. 5 VOB/B einhalte.
US-02 [MVP] Als Polier möchte ich per Sprach-Aufnahme die Situation
diktieren können (Handschuhe, Baustellen-Lärm), damit die
Tipp-Hürde fällt.
US-03 [MVP] Als Bauleitung möchte ich einen KI-Textvorschlag bekommen, der
die Formulierung nach VOB §2 Abs. 5 oder 6 vorschlägt, aber ich
muss den Text reviewen und freigeben, bevor er an den Bauherrn
geht.
US-04 [MVP] Als Bauherr möchte ich per E-Mail-Link auf meinem Smartphone
den Nachtrag lesen, das Foto sehen, den Preis sehen und mit
einer Touch-Unterschrift oder einer PIN bestätigen können,
ohne eine App installieren zu müssen.
US-05 [MVP] Als Bauleitung möchte ich den Nachtrag-Status live sehen
(Erfasst / Versendet / Gelesen / Signiert / Abgerechnet).
US-06 [V1] Als Kalkulator möchte ich den Nachtrag auf eine GAEB-LV-Position
beziehen (wenn vorhanden) und die EP aus der Hauptkalkulation
übernehmen, damit der Preisansatz konsistent ist.
US-07 [V1] Als Bauleitung möchte ich einen abgelehnten Nachtrag in eine
Behinderungsanzeige §6 VOB/B überführen können, damit die
Bauzeitverlängerung dokumentiert ist.
US-08 [V1.5] Als Manager möchte ich Nachtrag-Varianten verwalten (Nachtrag 1,
Nachtrag 2, Änderungs-Nachtrag), mit Versionierung.

  • F-M-01 Nachtrag anlegen — Eingangspunkt. Drei Wege: (1) aus Baustellen-Detail („+ Nachtrag“), (2) aus Bautagebuch-Eintrag (Deep-Link „Als Nachtrag übernehmen“), (3) aus Home-Screen Quick-Action (letzte Baustelle, GPS-Vorschlag).
  • F-M-02 Baustellen- und Hauptauftrags-Auswahl. Standard: GPS-nächstgelegene aktive Baustelle. Hauptauftrag wird automatisch gewählt, wenn nur einer auf der Baustelle läuft, sonst Auswahl-Sheet.
  • F-M-03 Grund-Klassifikation (Pflichtfeld). Radio-Auswahl: §2 Abs. 5 VOB/B — geänderte Anordnung / §2 Abs. 6 VOB/B — zusätzliche Leistung / freie Vereinbarung (außer VOB). Die Auswahl steuert den KI-Textvorschlag und das Pflichtfeld-Profil.
  • F-M-04 Leistungsbeschreibung. Freitext bis 2000 Zeichen. Alternative: Voice-Dictation (on-device STT, iOS Speech / Android SpeechRecognizer). Voice-Transkript wird als ergänzender Eintrag mit voice_transcript=true gespeichert (Audit-Zweck).
  • F-M-05 Foto-Beleg. Bis 8 Fotos, gleicher Geo-Stempel-Mechanismus wie Bautagebuch (siehe 01-bautagebuch.md F-M-04). Mindestens 1 Foto empfohlen, nicht Pflicht (manche Nachträge sind reine Textänderung).
  • F-M-06 Preisansatz vor Ort. Drei Eingabe-Modi:
    • (a) Summe (Pauschalpreis) — ein Feld, EUR netto.
    • (b) Stunden + Material — Stundensätze aus Kalkulation (V1: aus LV-Umlage, MVP: aus Tenant-Standard-Stundensatz), Material aus Autolager-Stammsatz oder freitext.
    • (c) Nach Aufwand — kein fixer Preis, Text „nach Aufwand gemäß VOB §15“, Regiebericht-Referenz (siehe §4.1).
  • F-M-07 KI-Textvorschlag (opt-in, Tenant-Ebene). Button „✨ KI-Vorschlag generieren“ triggert Hono-AI-Gateway → AWS Bedrock Frankfurt (Claude Sonnet 4.6). Input: {grund, leistung, preisansatz, bauherr_name, baustelle}. Output wird erst als Vorschlag im Editor angezeigt, mit dauerhaft sichtbarem Disclaimer-Banner: „⚠ Vorschlag — bitte prüfen. Keine Rechtsberatung.“ Audit-Eintrag nachtrag.ai.suggestion_shown mit Modell-ID (claude-sonnet-4.6), Prompt-Hash, Token-Verbrauch. Der Nutzer kann den Text akzeptieren (Edit-bar), ablehnen, oder manuell weiterschreiben. Submit ohne Review-Klick ist gesperrt.
  • F-M-08 Bauherr-Signatur vor Ort (Pflicht für Status „Beauftragt“). Gleiche Signatur-Mechanik wie 01-bautagebuch.md F-M-11: Touch (primary) oder PIN per Mail (Fallback). Ohne Signatur bleibt der Nachtrag im Status versendet, wird aber nicht zur Ausführung freigegeben. Eine Ausführung trotz fehlender Signatur ist explizit risikoreich und wird im UI mit rotem Warn-Banner „Rechtsrisiko §2 Abs. 5 VOB/B — nicht signiert“ ausgewiesen.
  • F-M-09 E-Mail-Versand an Bauherr (wenn Bauherr nicht vor Ort). Bauleiter-Freigabe per Swipe → E-Mail mit Link zum Signatur-Portal (siehe F-M-14). Textbaustein aus Admin-Vorlage. Link ist 14 Tage gültig, signaturpflichtig, mit Rate-Limit auf den Token (10 Aufrufe).
  • F-M-10 Offline-Erfassung. Voll-offline: Outbox + Idempotency-Key. KI-Vorschlag und E-Mail-Versand benötigen Netz und sind im Offline-Modus disabled mit Hinweis „KI- und Mail-Funktionen bei Netz“.
  • F-M-11 Status-Tracking im Detail-Screen. Zeitleiste mit fünf Knoten: Erfasst → Versendet → Gelesen → Signiert → Abgerechnet. „Gelesen“ = Link wurde geöffnet (1×1-Tracking-Pixel im E-Mail-HTML, DSGVO-transparent dokumentiert).
  • F-M-12 Verknüpfung zum Bautagebuch. Wenn Nachtrag aus Bautagebuch-Eintrag entstanden: Deep-Link sichtbar als „Quelle: Eintrag vom 19.04.2026 · Schulstr. 12“. Click öffnet Bautagebuch-Detail.
  • F-M-13 Schnell-Änderung Preisansatz nach Bauleiter-Review. Solange Status erfasst: Monteur kann Preisansatz ändern ohne Zweit-Signatur-Pflicht. Status versendet: Änderung erfordert neue Version (Versionierung, siehe F-W-03).
  • F-M-14 Externes Signatur-Portal (nicht primär Mobile-App, sondern Web-Link). Bauherr öffnet Link auf beliebigem Gerät. Zeigt: Nachtrag-Text, Fotos, Preis, Pflicht-Review-Checkbox „Ich habe den Text gelesen und verstanden“, dann Touch-Signatur oder PIN. Mobile-Web-optimiert. Keine Werkszeit-Registrierung nötig.
  • F-W-01 Nachtrag-Dashboard. Liste aller Nachträge pro Baustelle, Filter nach Status, Grund-Klassifikation, Betrag-Range, Zeitraum. Bulk-Aktion „An Bauherr versenden“ für mehrere gleichzeitig.
  • F-W-02 Nachtrag-Detail mit vollständigem Audit-Trail. Alle Zustandsübergänge, KI-Vorschlag-Versionen (Vorschlag → akzeptierter Text → edits), Signatur-Metadaten.
  • F-W-03 Versionierung. Wenn ein Nachtrag nach versendet geändert wird (z. B. Preis angepasst nach Bauherr-Feedback), entsteht Nachtrag-Version 2 mit Verweis auf v1. Bauherr-Link wird pro Version neu generiert. Alte Version bleibt für Audit erhalten.
  • F-W-04 Preisansatz-Verknüpfung mit Kalkulation (V1 mit GAEB). LV-Position auswählen, EP übernehmen, Aufschlag/Abschlag konfigurieren, Ergebnis als Nachtrag-Preis.
  • F-W-05 Rechnungs-Übernahme. Signierter Nachtrag erscheint als Position im Rechnungs-Entwurf (V1 als XRechnung-Position, MVP als freier Text in PDF-Rechnung).
  • F-W-06 Nachtrag-Vorlagen. Admin kann Textbausteine je Gewerk/Leistungsart anlegen (ohne KI). KI-Vorschläge können als Vorlage gespeichert werden (mit Anonymisierung).
  • F-W-07 KI-Nutzungsstatistik. Pro Tenant: Anzahl KI-Calls, Token-Verbrauch, Akzeptanz-Quote (User hat Text übernommen vs. verworfen). Kosten-Transparenz (3 €/User/Monat inkludiert X Calls, Overage-Info).
  • F-X-01 Append-only mit Version-Chain. Ähnlich Bautagebuch, aber zusätzlich: Versionen eines Nachtrags bilden eine eigene Chain. hash_prev verweist auf Vorgänger-Version desselben Nachtrags, nicht auf vorherigen Nachtrag der Baustelle.
  • F-X-02 Signatur-Portal-Link. JWT-basiert, HS256 mit Tenant-Secret, Payload {tenantId, nachtragId, version, exp: +14d, maxUses: 10}. Kein Server-Session, zustandslos.
  • F-X-03 PDF-Export. Typst-Template mit Werkszeit-Branding + Tenant-Logo. Enthält: Hauptauftrag-Bezug, Grund-Klassifikation, Text, Fotos (eingebettet), Preisansatz, Signatur-Bild, Hash-Signatur im Footer, Audit-QR-Code (führt auf Read-Only-Portal-View).
  • F-A-01 KI-Aktivierung pro Tenant. Tenant-Admin aktiviert KI-Addon (+3 €/User/Monat). Ohne Aktivierung ist F-M-07 unsichtbar. BR-Zustimmung nicht nötig (KI bei Textvorschlag ist keine Leistungskontrolle).
  • F-A-02 E-Mail-Vorlage für Bauherr-Versand. Anrede, Einleitung, Signatur-Link-Platzhalter, Footer. Tenant-spezifisch editierbar.
  • F-A-03 Signatur-Link-Gültigkeit. Default 14 Tage, konfigurierbar 1–30 Tage.
  • F-A-04 Nachtrag-Nummern-Kreis. Format {Baustelle-Kurz}/NT-{jjjj}-{nnn}, z. B. SCHULE-KOELN/NT-2026-007. Gap-frei, Tenant-intern.
Anforderung-ID MVP V1 V1.5 V2
F-M-01–03 Basis-Erfassung
F-M-04 Voice-Dictation
F-M-06 Preisansatz (a)+(c)
F-M-06 (b) Stunden+Material mit Auto-Satz
F-M-07 KI-Textvorschlag
F-M-08 Signatur vor Ort
F-M-14 Externes Signatur-Portal
F-W-03 Versionierung
F-W-04 GAEB-LV-Bezug
F-W-05 XRechnung-Position
KI-Vorschlag Nachtrag → Vorlage
Sub-Beauftragung aus Nachtrag

HTML-Hero-Mockup: 02-nachtrag.html — Mobile (Vor-Ort-Erfassung mit KI-Vorschlag) + Web (Bauleitung-Freigabe) + Signatur-Pad prominent.

┌────────────────────────────────┐
│ ← Neuer Nachtrag ⚠ │
├────────────────────────────────┤
│ 🛡 GoBD · VOB §2 · DSGVO │
├────────────────────────────────┤
│ Baustelle 🔴 │
│ ┌──────────────────────────┐ │
│ │ Schulstraße 12, Köln ▼ │ │
│ │ 🟢 GPS (12 m) · 1 Auftr. │ │
│ └──────────────────────────┘ │
│ │
│ Hauptauftrag │
│ Sanierung Heizungsanlage │
│ Bgm.-Müller-Schule (#HZ-2036) │
│ │
│ GRUND DER NACHFORDERUNG 🔴 │
│ (•) §2 Abs. 5 VOB/B │
│ Geänderte Anordnung │
│ (Auftraggeber will anders) │
│ │
│ ( ) §2 Abs. 6 VOB/B │
│ Zusätzliche Leistung │
│ (nicht im Vertrag) │
│ │
│ ( ) Freie Vereinbarung │
│ (außerhalb VOB) │
│ │
│ ┌────────────────────────────┐ │
│ │ WEITER │ │
│ └────────────────────────────┘ │
└────────────────────────────────┘
┌────────────────────────────────┐
│ ← Nachtrag NT-2026-007 ⋯ │
├────────────────────────────────┤
│ 🛡 GoBD · VOB §2 Abs. 5 │
├────────────────────────────────┤
│ LEISTUNG IN STICHWORTEN 🔴 │
│ ┌──────────────────────────┐ │
│ │ Asbest Decke Kesselraum, │ │
│ │ Entsorgung, nicht im │ │
│ │ LV vorgesehen. Schutz │ │
│ │ Stufe 2. 🎤 │ │
│ └──────────────────────────┘ │
│ │
│ ┌────────────────────────────┐ │
│ │ ✨ KI-Textvorschlag erzeugen│ │
│ └────────────────────────────┘ │
│ │
│ ┌───── VORSCHLAG ────────────┐ │
│ │ ⚠ VORSCHLAG — BITTE PRÜFEN │ │
│ │ Keine Rechtsberatung. │ │
│ │ Modell: Claude Sonnet 4.6│ │
│ ├────────────────────────────┤ │
│ │ "Wegen geänderter │ │
│ │ Anordnung des │ │
│ │ Auftraggebers gemäß §2 │ │
│ │ Abs. 5 VOB/B erlaubt sich │ │
│ │ der Auftragnehmer hiermit │ │
│ │ vor Ausführung eine │ │
│ │ Mehrvergütung für die │ │
│ │ Entsorgung von Asbest- │ │
│ │ haltigem Dämmmaterial im │ │
│ │ Kesselraum anzuzeigen. │ │
│ │ Arbeitsschutz nach TRGS │ │
│ │ 519… │ │
│ │ [bearbeiten]│ │
│ │ [ übernehm.]│ │
│ │ [ verwerfen]│ │
│ └────────────────────────────┘ │
│ │
│ FOTOS (2/8) │
│ ┌──┐┌──┐┌──┐ │
│ │📷││📷││ +│ │
│ └──┘└──┘└──┘ │
│ │
│ ┌────────────────────────────┐ │
│ │ WEITER ZUM PREIS │ │
│ └────────────────────────────┘ │
└────────────────────────────────┘
┌────────────────────────────────┐
│ ← NT-2026-007 · Preis ⋯ │
├────────────────────────────────┤
│ PREIS-MODUS 🔴 │
│ ( ) Pauschal-Summe │
│ (•) Stunden + Material │
│ ( ) Nach Aufwand (§15 VOB) │
│ │
│ STUNDEN │
│ ┌─────────────────────────┐ │
│ │ Facharbeiter · 4 h │ │
│ │ à 58,00 € = 232,00 € │ │
│ └─────────────────────────┘ │
│ [ + Zeile ] │
│ │
│ MATERIAL │
│ ┌─────────────────────────┐ │
│ │ Big-Bag Asbest · 2 Stk. │ │
│ │ à 120,00 € = 240,00 € │ │
│ ├─────────────────────────┤ │
│ │ PSA Stufe 2 · 2 Stk. │ │
│ │ à 45,00 € = 90,00 € │ │
│ └─────────────────────────┘ │
│ │
│ ZUSCHLAG │
│ Wagnis+Gewinn 15 % = 84,30 € │
│ ─────────────────────── │
│ SUMME NETTO 646,30 € │
│ + MwSt 19 % 122,80 € │
│ ═══════════════════════ │
│ BRUTTO 769,10 € │
│ │
│ BAUHERR vor Ort? │
│ (•) Ja — jetzt signieren │
│ ( ) Nein — per E-Mail senden │
│ │
│ ┌── BAUHERR-SIGNATUR ─────────┐│
│ │ Name: Hr. Müller-Bgm. ││
│ │ ╭──────────────────────╮ ✍ ││
│ │ │ │ ││
│ │ │ Hier unterschreiben │ ││
│ │ │ │ ││
│ │ ╰──────────────────────╯ ││
│ │ ☑ Ich habe den Text ││
│ │ gelesen und verstanden. ││
│ └────────────────────────────┘│
│ │
│ ┌────────────────────────────┐ │
│ │ NACHTRAG BEAUFTRAGEN │ │ ← nur bei Signatur aktiv
│ └────────────────────────────┘ │
└────────────────────────────────┘

6.4 Mobile — Signatur-Alternative: PIN per E-Mail

Abschnitt betitelt „6.4 Mobile — Signatur-Alternative: PIN per E-Mail“
┌────────────────────────────────┐
│ ← Bauherr-Signatur ⋯ │
├────────────────────────────────┤
│ Bauherr ist nicht vor Ort. │
│ Wie möchtest du signieren │
│ lassen? │
│ │
│ 1. 📧 E-Mail-Link (empfohlen) │
│ • Touch-Signatur auf Gerät │
│ • 14 Tage gültig │
│ • Link pro Version neu │
│ │
│ 2. 🔢 PIN-Signatur (Textform) │
│ • 6-stellige PIN per SMS/ │
│ E-Mail │
│ • Schwächere Beweiskraft │
│ (§126b BGB Textform) │
│ • Für Nachträge <500 € ok │
│ │
│ Hr. Müller-Bgm. │
│ │
│ [ + SMS hinzufügen ] │
│ │
│ ┌────────────────────────────┐ │
│ │ E-MAIL-LINK VERSENDEN │ │
│ └────────────────────────────┘ │
│ ┌────────────────────────────┐ │
│ │ PIN PER E-MAIL + SMS │ │
│ └────────────────────────────┘ │
└────────────────────────────────┘
┌────────────────────────────────────────────────────────────────────────────────┐
│ Werkszeit · shk-gebruder-schmidt Thomas Schmidt · Bauleitung [▾] │
├────────────────────────────────────────────────────────────────────────────────┤
│ Sidebar │ Nachträge · Alle Baustellen · [Filter: ▼] [+ Neu] │
│ ───────── │ ───────────────────────────────────────────────────────────── │
│ Zeit │ KPI: 12 offen · 4 signiert · 847,50 € neu heute │
│ Plan │ │
│ Bautage │ ┌──────┬──────────┬────────┬────────┬───────────┬──────┬────┐ │
│ ▶ Nachtrg │ │ Nr │ Baustelle│ Grund │ Preis │ Status │ KI ? │ V │ │
│ Aufmaß │ ├──────┼──────────┼────────┼────────┼───────────┼──────┼────┤ │
│ │ │NT007 │ Schulstr.│ §2(5) │ 769,10 │🟢 signiert│ ✨ ja│ v1 │ │
│ │ │NT006 │ Schulstr.│ §2(6) │ 1240,— │🟡 wartet │ ✨ ja│ v2 │ │
│ │ │NT005 │ Lehrer A.│ §2(5) │ 480,50 │🟡 versandt│ — │ v1 │ │
│ │ │NT004 │ Lehrer A.│ frei │ 95,— │🔴 abgeleh.│ — │ v1 │ │
│ │ │NT003 │ Schulstr.│ §2(6) │ 3280,— │🟢 abgerech│ ✨ ja│ v3 │ │
│ │ └──────┴──────────┴────────┴────────┴───────────┴──────┴────┘ │
│ │ │
│ │ ┌─ Detail NT-2026-007 ──────────────────────────────────────┐ │
│ │ │ Bezug: Hauptauftrag #HZ-2036 Sanierung Heizung │ │
│ │ │ Grund: §2 Abs. 5 VOB/B (geänderte Anordnung) │ │
│ │ │ │ │
│ │ │ ✨ KI-Vorschlag wurde akzeptiert und editiert (Diff: 3 Zn) │ │
│ │ │ Modell: claude-sonnet-4.6 · Tokens: 420 in, 180 out │ │
│ │ │ Vorschlag-Hash: a3f8…9d21 │ │
│ │ │ │ │
│ │ │ Signatur: 🟢 Hr. Müller-Bgm. · 19.04.2026 · 17:03 │ │
│ │ │ Touch-Vector · Geräte-Fingerprint XY │ │
│ │ │ │ │
│ │ │ [⤓ PDF] [→ Rechnung] [⟲ Neue Version] [🗑 stornieren] │ │
│ │ └───────────────────────────────────────────────────────────┘ │
└────────────────────────────────────────────────────────────────────────────────┘

6.6 Externes Signatur-Portal (Bauherr-Perspektive, Mobile-Web)

Abschnitt betitelt „6.6 Externes Signatur-Portal (Bauherr-Perspektive, Mobile-Web)“
┌──────────────────────────────┐
│ Werkszeit · Nachtrag │
│ SHK Gebrüder Schmidt GmbH │
├──────────────────────────────┤
│ NT-2026-007 · Schulstr. 12 │
│ Sanierung Heizung │
│ │
│ Sehr geehrte/r │
│ Hr. Müller-Bgm., │
│ │
│ bitte bestätigen Sie den │
│ folgenden Nachtrag vor │
│ Beginn der Mehrarbeiten │
│ gemäß §2 Abs. 5 VOB/B. │
│ │
│ ┌──────────────────────┐ │
│ │ "Wegen geänderter │ │
│ │ Anordnung ... Asbest │ │
│ │ ... TRGS 519 ..." │ │
│ │ [mehr ▼] │ │
│ └──────────────────────┘ │
│ │
│ [ Foto 1 ] [ Foto 2 ] │
│ │
│ Preis: 769,10 € │
│ inkl. MwSt 19 % │
│ │
│ ☑ Ich habe Text und │
│ Preis gelesen und │
│ verstanden. │
│ │
│ ╭────────────────────────╮ │
│ │ │ │
│ │ Hier unterschreiben │ │
│ │ │ │
│ ╰────────────────────────╯ │
│ │
│ [ NACHTRAG BEAUFTRAGEN ] │
│ │
│ [ alternativ PIN anfordern] │
│ │
│ Link gültig bis 03.05.2026 │
└──────────────────────────────┘

apps/api/src/db/schema/nachtrag.ts
export const nachtraegeTable = pgTable('nachtraege', {
id: uuid('id').primaryKey().defaultRandom(),
tenantId: uuid('tenant_id').notNull().references(() => tenantsTable.id),
baustelleId: uuid('baustelle_id').notNull().references(() => baustellenTable.id),
hauptauftragId: uuid('hauptauftrag_id').references(() => auftraegeTable.id),
nachtragNummer: text('nachtrag_nummer').notNull(), // z. B. "SCHULE-KOELN/NT-2026-007"
version: integer('version').notNull().default(1),
// Klassifikation
grund: nachtragGrund('grund').notNull(),
// 'vob_2_5' | 'vob_2_6' | 'freie_vereinbarung'
// Inhalt
stichworte: text('stichworte').notNull(), // Monteur-Eingabe, Voice-Transkript oder Tastatur
leistungstext: text('leistungstext').notNull(), // Finaler Text (evtl. KI-basiert, User-reviewed)
voiceTranscript:boolean('voice_transcript').notNull().default(false),
// KI-Metadaten
aiSuggested: boolean('ai_suggested').notNull().default(false),
aiModelId: text('ai_model_id'), // z. B. "claude-sonnet-4.6"
aiPromptHash: bytea('ai_prompt_hash'), // SHA-256 über kanonisierten Prompt
aiTokensIn: integer('ai_tokens_in'),
aiTokensOut: integer('ai_tokens_out'),
aiAcceptedRaw: boolean('ai_accepted_raw'), // true = unverändert übernommen
aiEditDistance: integer('ai_edit_distance'), // Levenshtein vom Vorschlag zum finalen Text
// Preisansatz
priceMode: priceMode('price_mode').notNull(),
// 'pauschal' | 'stunden_material' | 'nach_aufwand'
sumNet: decimal('sum_net', { precision: 12, scale: 2 }).notNull(),
sumGross: decimal('sum_gross', { precision: 12, scale: 2 }).notNull(),
vatRate: decimal('vat_rate', { precision: 4, scale: 2 }).notNull().default('19.00'),
lvPositionRef: text('lv_position_ref'), // V1 mit GAEB; MVP NULL
// Signatur (Bauherr)
signedByName: text('signed_by_name'),
signedAt: timestamp('signed_at', { withTimezone: true }),
signatureBlobId:uuid('signature_blob_id').references(() => blobsTable.id),
signatureKind: signatureKind('signature_kind'), // 'touch_vector' | 'pin_token'
signaturePortalTokenHash: bytea('signature_portal_token_hash'), // SHA-256 des JWT (Rotation)
reviewCheckboxConfirmed: boolean('review_checkbox_confirmed').notNull().default(false),
// Status-Maschine
status: nachtragStatus('status').notNull().default('erfasst'),
// 'erfasst' | 'versendet' | 'gelesen' | 'signiert' | 'abgelehnt'
// | 'beauftragt' | 'in_ausfuehrung' | 'abgerechnet' | 'storniert'
rejectionReason: text('rejection_reason'), // wenn 'abgelehnt'
// Version-Chain
previousVersionId: uuid('previous_version_id').references(() => nachtraegeTable.id),
versionReason: text('version_reason'), // Pflicht, wenn previousVersionId != NULL
// Bautagebuch-Bezug
bautagebuchEntryId: uuid('bautagebuch_entry_id').references(() => bautagebuchEntriesTable.id),
// GoBD
hashPrev: bytea('hash_prev'),
hashSelf: bytea('hash_self').notNull(),
// Audit
createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(),
createdBy: uuid('created_by').notNull().references(() => usersTable.id),
approvedBy: uuid('approved_by').references(() => usersTable.id),
approvedAt: timestamp('approved_at', { withTimezone: true }),
idempotencyKey: uuid('idempotency_key').notNull().unique(),
}, (t) => ({
tenantNrIdx: uniqueIndex('nachtraege_tenant_nr_version_uq')
.on(t.tenantId, t.nachtragNummer, t.version),
tenantBaustelleIdx: index('nachtraege_tenant_baustelle_idx')
.on(t.tenantId, t.baustelleId, t.createdAt.desc()),
statusIdx: index('nachtraege_status_idx').on(t.tenantId, t.status),
}));
export const nachtragPositionenTable = pgTable('nachtrag_positionen', {
id: uuid('id').primaryKey().defaultRandom(),
nachtragId: uuid('nachtrag_id').notNull().references(() => nachtraegeTable.id),
tenantId: uuid('tenant_id').notNull(),
positionTyp: positionTyp('position_typ').notNull(), // 'stunde' | 'material' | 'zuschlag'
bezeichnung: text('bezeichnung').notNull(),
menge: decimal('menge', { precision: 12, scale: 3 }).notNull(),
einheit: text('einheit').notNull(),
einzelpreis: decimal('einzelpreis', { precision: 10, scale: 2 }).notNull(),
gesamtpreis: decimal('gesamtpreis', { precision: 12, scale: 2 }).notNull(),
sortIdx: integer('sort_idx').notNull().default(0),
});
export const nachtragPhotosTable = pgTable('nachtrag_photos', {
id: uuid('id').primaryKey().defaultRandom(),
nachtragId: uuid('nachtrag_id').notNull().references(() => nachtraegeTable.id),
tenantId: uuid('tenant_id').notNull(),
s3Key: text('s3_key').notNull(),
contentSha256: bytea('content_sha256').notNull(),
geoStampSha256: bytea('geo_stamp_sha256'), // optional, gleiche Mechanik wie §4.1
capturedAtUtc: timestamp('captured_at_utc', { withTimezone: true }).notNull(),
});
export const nachtragSignaturEventsTable = pgTable('nachtrag_signatur_events', {
id: uuid('id').primaryKey().defaultRandom(),
nachtragId: uuid('nachtrag_id').notNull().references(() => nachtraegeTable.id),
tenantId: uuid('tenant_id').notNull(),
eventType: sigEvent('event_type').notNull(),
// 'link_versendet' | 'link_geoeffnet' | 'review_checked'
// | 'signatur_eingabe' | 'pin_angefordert' | 'pin_verifiziert' | 'abgelehnt'
eventAt: timestamp('event_at', { withTimezone: true }).notNull().defaultNow(),
ipHash: bytea('ip_hash'), // SHA-256(ip || tenantSalt) — DSGVO-freundlich
userAgent: text('user_agent'),
payload: jsonb('payload'),
});

RLS-Policy-Sketch:

ALTER TABLE nachtraege ENABLE ROW LEVEL SECURITY;
CREATE POLICY nachtraege_tenant_isolation ON nachtraege
USING (tenant_id = current_setting('app.tenant_id')::uuid);
-- Monteur (scope=own) sieht nur eigene Nachträge
CREATE POLICY nachtraege_scope ON nachtraege 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)
)
);
-- Status 'signiert' ist ein harter Gate: nachfolgende Änderungen erzeugen Neue Version
CREATE POLICY nachtraege_no_content_update_after_sign ON nachtraege FOR UPDATE
USING (tenant_id = current_setting('app.tenant_id')::uuid)
WITH CHECK (
status IN ('erfasst', 'versendet')
OR (leistungstext = (SELECT leistungstext FROM nachtraege WHERE id = nachtraege.id)
AND sum_net = (SELECT sum_net FROM nachtraege WHERE id = nachtraege.id))
);

ER-Bezug. Referenziert: tenants, users, baustellen, auftraege (Hauptauftrag), bautagebuch_entries (Quelle), blobs (Signatur, Fotos), audit_log.


Methode Pfad Auth-Scope Rate-Limit Idempotenz Beschreibung
POST /v1/handwerk/nachtraege nachtrag:write Standard Pflicht Neuer Nachtrag (Status erfasst)
GET /v1/handwerk/nachtraege nachtrag:read:<scope> Standard Liste, Filter nach Status, Baustelle, Zeitraum
GET /v1/handwerk/nachtraege/{id} nachtrag:read:<scope> Standard Detail inkl. Signatur-Events
POST /v1/handwerk/nachtraege/{id}/ai-suggest nachtrag:write + ai:use AI (10/min) Pflicht KI-Vorschlag, liefert {suggestion, modelId, promptHash, tokens}
POST /v1/handwerk/nachtraege/{id}/send nachtrag:approve Privileged Pflicht E-Mail-Versand + Portal-Token generieren
POST /v1/handwerk/nachtraege/{id}/versions nachtrag:write Standard Pflicht Neue Version mit versionReason
POST /v1/handwerk/nachtraege/{id}/cancel nachtrag:approve Privileged Pflicht Stornieren mit Begründung
GET /v1/handwerk/nachtraege/{id}/pdf nachtrag:read:<scope> Heavy Typst-PDF
GET /v1/public/nachtrag/{token} öffentlich (JWT) Standard Bauherr-Portal-View
POST /v1/public/nachtrag/{token}/sign öffentlich (JWT) Standard Pflicht Signatur-Event, Status → signiert
POST /v1/public/nachtrag/{token}/pin/request öffentlich (JWT) Privileged Pflicht PIN-Code per E-Mail/SMS
POST /v1/public/nachtrag/{token}/pin/verify öffentlich (JWT) Privileged Pflicht PIN verifizieren → Signatur-Kind pin_token

OpenAPI-Schema-Skizze:

paths:
/v1/handwerk/nachtraege/{id}/ai-suggest:
post:
operationId: nachtragAiSuggest
x-werkszeit-scope: nachtrag:write
x-werkszeit-ai-feature: true # UI zeigt "Vorschlag — bitte prüfen"-Disclaimer
x-werkszeit-rate-limit: ai
responses:
'200':
content:
application/json:
schema:
type: object
properties:
suggestion: { type: string }
modelId: { type: string, enum: [claude-sonnet-4.6, mistral-large-2] }
promptHash: { type: string, format: hex }
tokensIn: { type: integer }
tokensOut: { type: integer }
disclaimer: { type: string, enum: [vorschlag_bitte_pruefen] }
'402': { description: 'KI-Feature nicht aktiv (Tenant-Plan)' }
'429': { description: 'KI-Rate-Limit erreicht' }

Webhook-Events:

  • nachtrag.erfasst
  • nachtrag.versendet
  • nachtrag.gelesen (Link erstmals geöffnet)
  • nachtrag.signiert → Trigger für Rechnungs-Position
  • nachtrag.abgelehnt → Trigger für VOB-§6-Behinderungsanzeige-Workflow
  • nachtrag.version.created

8.1 LV-Merge-Konflikt-Resolver + Versionsdrift (Patch 2026-04-23)

Abschnitt betitelt „8.1 LV-Merge-Konflikt-Resolver + Versionsdrift (Patch 2026-04-23)“

Der MVP-Stand der Alt-App hat LV-Positionen ohne optimistic-lock gepflegt. Sobald ein Nachtrag eine bestehende LV-Position überlagern oder eine neue in den LV einbauen soll (Szenario: Bauleitung kalkuliert den Nachtrag auf dem Tablet, während die Kalkulation im Büro parallel an Positionen 42–58 feilt), entsteht eine Merge-Konflikt-Klasse, die wir bisher nicht erkannt haben. Dieser Patch schließt die Lücke mit einem 3-Way-Diff (base = LV-Zustand bei Nachtrag-Erstellung, left = aktueller LV, right = Nachtrag-Vorschlag) und einer append-only Konflikt-Audit-Tabelle mit Hash-Chain (GoBD §147 AO).

Neue Endpoints:

Methode Pfad Scope Idempotenz Beschreibung
POST /v1/handwerk/nachtraege/{id}/lv-merge-dry-run nachtrag:write Pflicht Klassifiziert jede Position (3-Way-Diff), liefert conflicts[] ohne DB-Write.
POST /v1/handwerk/nachtraege/{id}/lv-merge-apply nachtrag:approve Pflicht Atomarer Merge mit optimistic-lock WHERE version = live.version. Mismatch → 409 version-mismatch.
GET /v1/handwerk/nachtraege/{id}/konfliktbericht nachtrag:read:<scope> Append-only Audit, dedupliziert auf jüngste Resolution pro Position.
GET /v1/handwerk/nachtraege/{id}/drift-report nachtrag:read:<scope> Feld-für-Feld-Diff base ↔ live (kein Nachtrag-Vergleich).
POST /v1/handwerk/nachtraege/{id}/drift-resolve/{positionId} nachtrag:write Pflicht Strategien: rebase (basis_lv_snapshot auf live setzen), force (Nachtrag-Wert überschreibt LV), abort (nur Audit).

3-Way-Diff-Algorithmus (Pseudocode):

threeWayDiff(base, left, right):
b_l = equal(base, left) # LV seit Nachtrag-Erstellung unverändert?
b_r = equal(base, right) # Nachtrag lässt Position unverändert?
l_r = equal(left, right) # LV und Nachtrag zufällig gleich?
if b_l and b_r -> 'unchanged' # no-op
if b_l and not b_r -> 'right_only' # Nachtrag gewinnt, kein Konflikt
if not b_l and b_r -> 'left_only' # LV hat gedriftet, Nachtrag ignoriert diese Position
if not b_l and not b_r:
if l_r -> 'both_same' # beide Seiten gleich geändert, no-op
else -> 'both_diff' # CONFLICT, resolution pending

Konflikt-Resolution-Matrix (3x3):

lv_state ↓ / nachtrag_state unverändert geändert == LV geändert ≠ LV
unverändert seit base no-op Nachtrag-write Nachtrag-write
gedriftet == Nachtrag LV bleibt both_same → no-op unmöglich (widerspricht Zeilen-Label)
gedriftet ≠ Nachtrag LV bleibt (drift allein) unmöglich (widerspricht Zeilen-Label) CONFLICTpending Audit, Resolver-UI

Resolution-Strategien: nachtrag_wins schreibt den Nachtrag-Wert, lv_wins verwirft den Nachtrag-Wert für diese Position, manual erlaubt einen Third-Way-Wert (mit manualValue im Body), aborted schreibt nur den Audit-Eintrag.

Optimistic Lock (lv_positionen.version). Neue Spalte integer NOT NULL DEFAULT 1, BEFORE-UPDATE-Trigger bumpt um +1. Der Client kann die Versionsnummer nicht freezen — der Trigger überschreibt jeden clientseitig gesetzten Wert. lv-merge-apply vergleicht die Version der Dry-Run-Phase mit der live-Version im Apply-Tx; bei Divergenz → Rollback + 409 version-mismatch.

Audit-Kette (nachtrag_merge_konflikte). Append-only (RLS no_update + no_delete), SHA-256 Hash-Chain per (tenant_id, nachtrag_id). Resolution-Updates sind keine UPDATEs, sondern neue INSERTs, die über hash_prev auf den pending-Eintrag zeigen — jede Revision der Entscheidung ist nachvollziehbar. Canonical Hash-String ist in Migration 0029_handwerk_02_nachtrag_merge.sql und in merge-service.ts::lvVersionHash identisch definiert.

Snapshot (nachtraege.basis_lv_snapshot_json). Unveränderlicher LV-Zustand bei Nachtrag-Erstellung (JSONB). Dient als base im 3-Way-Diff. Nur durch drift-resolve mit Strategie rebase änderbar.

Abgrenzung zur Bestands-Logik. Die Nachtrag-Versionierung (Feld version auf nachtraege, FU §6) bleibt unverändert und betrifft das Dokument als Ganzes. Das neue lv_positionen.version ist ein separater optimistic-lock-Counter je LV-Position. Kein Namespace-Clash, da unterschiedliche Tabellen.


Profil Begründung Mechanik
Best-effort-offline für Erfassung Baustelle oft ohne LTE — Erfassung muss gelingen. Versand und KI-Vorschlag brauchen aber Netz. Outbox-Pattern für Nachtrag-Anlage. KI-Button und Mail-Send sind disabled im Offline-Mode mit Hinweis „Benötigt Internet“. Nachtrag kann offline angelegt, Signatur offline eingeholt werden (wenn Bauherr vor Ort), Versand erfolgt beim nächsten Sync.
Online-only für KI-Vorschlag, E-Mail-Versand, Portal-View KI-Gateway und SMTP/SES nicht offline mockbar. UI zeigt Offline-State, Nutzer kann manuell Text schreiben (volle Erfassung möglich ohne KI).

Konflikt-Strategie. Nachtrag ist versioniert. Zwei Offline-Geräte, die denselben Nachtrag ändern: Gerät A syncted zuerst → wird Version 1. Gerät B syncted später → Server erkennt previousVersionId Kollision, antwortet mit 409 + Hinweis „Eine neuere Version existiert“ — Gerät B kann sich die Server-Version holen und als Version 2 erneut committen.

Foto-Sync. Gleiche Pipeline wie §4.1.


  • Append-only mit Version-Chain. Nachtrag-Status nach signiert blockt inhaltliche Änderungen (siehe RLS-Policy). Für Korrekturen nach Signatur: neue Version mit Verweis auf Vorgänger und Pflicht-Begründung.
  • Aufbewahrung. 10 Jahre in S3 Object Lock (Compliance-Mode). PDF jedes Zustands wird bei Statusübergang neu erzeugt und archiviert (nachtrag_{id}_v{n}_{status}.pdf).
  • Hash-Chain. Pro Nachtrag eine eigene Chain über die Versionen. hash_self umfasst auch Positionen-Tabelle (Rollup-Hash über Positionen).

— nicht zutreffend.

  • §2 Abs. 5 (geänderte Anordnung). Eingegeben als grund = 'vob_2_5'. Pflicht-Prozessschritt: Signatur des Bauherrn vor Ausführung. UI zeigt „Rechtsrisiko“ bei Ausführungs-Start ohne Signatur. PDF-Footer enthält Zitat „Anzeige vor Ausführung gemäß §2 Abs. 5 VOB/B“.
  • §2 Abs. 6 (zusätzliche Leistung). grund = 'vob_2_6'. Gleicher Workflow, anderer KI-Prompt-Template (unterscheidet Ankündigungs-Wortlaut).
  • §14 (Abrechnung). Signierter Nachtrag wird automatisch zum Kandidaten für Teil-/Schlussrechnung. Im MVP als manuelle Übernahme im Web-Modul kern/05-rechnung-basis, V1 automatisch in XRechnung.
  • §15 (Stundenlohn). Bei priceMode = 'nach_aufwand' gilt §15 — UI verweist auf Regiebericht-Workflow im Bautagebuch (01-bautagebuch F-M-09).
  • VOB-Klauseln-Inkonsistenz — automatische Prüfung. Backend-Validator prüft: grund = vob_2_5 aber leistungstext enthält „zusätzliche Leistung außerhalb des Vertrags“ → Warnung „VOB-Klauseln-Inkonsistenz? §2 Abs. 5 = Änderung einer bestehenden Position. §2 Abs. 6 = neue Position außerhalb LV. Bitte prüfen.“ Nicht blockend, aber sichtbarer Hinweis mit 1-Click-Grund-Tausch.
  • Art. 5 Datenminimierung. Bauherr-Daten: Name + E-Mail-Adresse, keine Telefonnummer ohne Bedarf. IP-Adresse im Signatur-Event wird nur als SHA-256(ip || tenantSalt) gespeichert.
  • Art. 6 Rechtsgrundlage. Vertrag (Art. 6 Abs. 1 lit. b). Signatur-Portal-Nutzung ist Vertragserfüllung, keine Einwilligung nötig.
  • Art. 13 Information. Portal-View zeigt Transparenz-Banner: „Diese Seite protokolliert Aufruf-Zeitpunkt (pseudonym) und Signatur-Metadaten. Zweck: VOB-§2-Nachweis. Speicherdauer: 10 Jahre (§147 AO). Kontakt Datenschutz: .“
  • Art. 17 Löschung. Gleiche Regel wie Bautagebuch: Nach 10 Jahren logische Maskierung statt Delete.
  • Art. 20 Datenexport. Bauherr kann per Kontakt zum Tenant-Admin eigene Signatur-Events exportieren. Kein Self-Service (Bauherr hat keinen Werkszeit-Account).

— teilweise zutreffend: Das externe Signatur-Portal ist öffentlich zugänglich und damit BFSG-pflichtig ab 28.06.2025. Anforderungen:

  • Screenreader-Labels für Signatur-Pad (VoiceOver / TalkBack / NVDA).
  • Tastatur-Navigation durch Portal inkl. PIN-Eingabe.
  • Kontrast ≥4.5:1.
  • axe-core ohne Critical/Serious-Findings im E2E-Test.
  • Alternative zu Touch-Signatur vorhanden (PIN-Eingabe).

— nicht zutreffend. Nachtrag betrifft Bauherr (externen Dritten), keine eigene Belegschaft. KI-Textvorschlag ist keine Leistungskontrolle der Mitarbeiter.

10.7 KI-VO / EU AI Act Art. 50 (Transparenzpflicht)

Abschnitt betitelt „10.7 KI-VO / EU AI Act Art. 50 (Transparenzpflicht)“
  • Obligatorisches Disclaimer-UI. Jeder KI-Vorschlag erscheint mit permanentem Banner „⚠ Vorschlag — bitte prüfen. Keine Rechtsberatung.“ Banner ist nicht wegklickbar.
  • Modell-Offenlegung. Im PDF-Footer: „Text unter Verwendung von KI-Vorschlag erstellt (Modell: claude-sonnet-4.6, Anbieter: AWS Bedrock Frankfurt). Text wurde vom Auftragnehmer geprüft.“
  • Audit-Log pro KI-Call. ai.suggestion.shown mit {promptHash, modelId, tokens, userId, tenantId}. Retention: 3 Jahre für KI-VO-Nachweis.
  • Opt-in pro Tenant. Ohne Tenant-Aktivierung keine KI, keine Opt-out-Pflicht für einzelne Nutzer nötig (Tenant-Admin entscheidet).
  • Rechtsunsichere Vorschläge — automatischer Block. Bei Erkennungs-Heuristik (Prompt-Inhalt enthält „gewährleistung“, „mängelrüge“, „klage“, „anwalt“) triggert Server eine Zusatz-Warn-Meldung im UI: „Dieser Vorschlag berührt anwaltlich beratungswürdige Themen. Bitte Rücksprache mit Rechtsanwalt — Werkszeit kann keine Rechtsberatung liefern.“ Text wird trotzdem erzeugt, aber mit doppeltem Disclaimer.

# Szenario Erwartetes Verhalten
EC-01 VOB-Klauseln-Inkonsistenz — Nutzer wählt §2 Abs. 5, schreibt aber über zusätzliche Leistung Heuristik-Validator (Server) erkennt: „Das klingt nach §2 Abs. 6. Wollten Sie §2 Abs. 5 = Änderung, oder §2 Abs. 6 = neu?“ Soft-Warn, nicht blockend. 1-Click-Wechsel. Audit-Eintrag.
EC-02 KI-Vorschlag ist rechtlich heikel (enthält „Gewährleistung“, „Mängelrüge“) Zusatz-Warnung „Bitte Anwalt konsultieren“. Text wird erzeugt, aber mit doppeltem Disclaimer-Banner. Audit-Flag ai.suggestion.sensitive.
EC-03 Bauherr signiert per PIN statt Hand Signatur-Kind pin_token. PIN wird 6-stellig, numerisch, über SES (E-Mail) oder SNS (SMS) zugestellt. Gültigkeit: 15 min. 3 Fehlversuche → Token gesperrt, neuer Link nötig. Beweiskraft: §126b BGB Textform. Im PDF als „EES-Textform (PIN-Code)“ gekennzeichnet.
EC-04 Portal-Link verfällt (14 Tage überschritten) Öffnen zeigt Fehler-Seite „Link abgelaufen. Bitte neuen Link beim Auftragnehmer anfordern.“ Tenant-Admin bekommt E-Mail mit Re-Send-Button im Web-Dashboard.
EC-05 Bauherr lehnt Nachtrag ab (im Portal „Ablehnen“-Button) Portal-Event abgelehnt, Begründungsfeld Pflicht. Status wechselt auf abgelehnt. Bauleitung bekommt Push mit 1-Click „In Behinderungsanzeige überführen“ (Deep-Link zu §4.1 F-M-01 → Typ behinderung_vob6).
EC-06 Bauleiter versendet Nachtrag versehentlich an falsche E-Mail Revoke-Button im Web-Detail → Token wird serverseitig invalidiert (Signatur-Blacklist in Redis). Neue Version mit korrigierter E-Mail erzeugt neuen Link. Altes Portal zeigt „Link widerrufen“.
EC-07 Multi-Tenant-Bleed-Versuch — Angreifer mit gültigem JWT probiert andere Nachtrag-IDs JWT-Payload ist an {tenantId, nachtragId, version} gebunden. Versuch mit anderer ID → 404 (nicht 403), RLS-Enforcement. Audit-Eintrag im Security-Log.
EC-08 KI-Feature deaktiviert mid-flow (Admin deaktiviert KI-Addon während Nutzer im Vorschlag-Screen) Backend antwortet 402 Payment Required. Client zeigt „KI-Feature nicht mehr aktiv. Bitte Text manuell schreiben oder Admin kontaktieren.“ Bereits erzeugte Vorschläge bleiben verfügbar (wurden an Nachtrag gebunden).
EC-09 Nachtrag wird nach Signatur geändert (Polier tippt neuen Preis ein) RLS-Policy blockt UPDATE. Client zeigt Dialog „Nachtrag ist signiert. Änderungen erfordern neue Version. Fortfahren?“ → POST /versions mit versionReason, Portal-Link wird neu versendet.
EC-10 Offline-Erfassung + Bauherr signiert offline auf selbem Gerät Vollständig offline möglich: Nachtrag-Anlage, Signatur-Pad, alles in Outbox. Beim Sync: Ein einziger POST mit eingebettetem Signatur-Blob, Status springt direkt auf signiert. KEIN Portal-Token nötig, weil Bauherr physisch anwesend war.
EC-11 Signatur-Portal läuft in inkompatiblem Browser (IE11, Android WebView 4.x) Portal zeigt Fallback „Ihr Browser unterstützt die Signatur nicht. Bitte öffnen Sie den Link auf einem aktuellen Smartphone/Tablet oder nutzen Sie die PIN-Alternative.“ PIN bleibt immer zugänglich.

Funktionalität: Nachtrag mit VOB-§2-Ankündigung und KI-Vorschlag
Hintergrund:
Angenommen ein Tenant "shk-gebruder-schmidt" mit aktivem Modul-Gate "module.handwerk.nachtrag"
Und ein aktives KI-Addon (plan includes "ai_assist")
Und eine Baustelle "Sanierung Heizungsanlage Bgm.-Müller-Schule, Schulstraße 12, 50667 Köln"
Und ein Hauptauftrag "HZ-2036" darauf
Und der Polier "Mehmet Yılmaz" mit Rolle "Mitarbeiter" und Scope "own"
Und der Bauleiter "Thomas Schmidt" mit Rolle "Bauleitung" und Scope "team"
Szenario: Happy Path — Nachtrag §2 Abs. 5 VOB/B mit KI-Vorschlag und Vor-Ort-Signatur
Wenn Mehmet am 19.04.2026 einen Nachtrag anlegt
Und "§2 Abs. 5 VOB/B — geänderte Anordnung" auswählt
Und als Stichworte "Asbest Decke Kesselraum, Entsorgung, Schutz Stufe 2" eingibt
Und auf "KI-Textvorschlag generieren" tippt
Dann erhält er einen Textvorschlag vom Modell "claude-sonnet-4.6"
Und der Vorschlag wird mit dauerhaft sichtbarem Banner "Vorschlag — bitte prüfen. Keine Rechtsberatung." angezeigt
Und es entsteht ein Audit-Log-Eintrag "nachtrag.ai.suggestion_shown" mit Prompt-Hash und Token-Verbrauch
Wenn Mehmet den Vorschlag als Basis übernimmt und 3 Zeichen editiert
Und Stunden 4×58€ + Material 2×120€ + 2×45€ + 15% Zuschlag eingibt (Summe netto 646,30 €)
Und Bauherr Hr. Müller-Bgm. vor Ort anwesend ist
Und die Review-Checkbox "Text gelesen und verstanden" aktiviert
Und Hr. Müller-Bgm. auf dem Signatur-Pad unterschreibt
Und Mehmet auf "Nachtrag beauftragen" tippt
Dann wechselt der Status auf "signiert" und gleichzeitig "beauftragt"
Und ein Webhook "nachtrag.signiert" wird an registrierte Endpoints versandt
Und ein PDF mit KI-Disclaimer-Footer wird in S3 Object Lock archiviert
Und der Nachtrag erscheint als Rechnungs-Entwurfs-Position auf dem Hauptauftrag HZ-2036
Szenario: Grenzfall — VOB-Klauseln-Inkonsistenz
Angenommen Mehmet hat "§2 Abs. 5 VOB/B — geänderte Anordnung" gewählt
Wenn der Leistungstext die Phrase "zusätzliche Leistung außerhalb des ursprünglichen Vertrags" enthält
Dann zeigt die App eine Soft-Warnung "Wollten Sie §2 Abs. 5 oder §2 Abs. 6?"
Und bietet einen 1-Click-Wechsel auf §2 Abs. 6 an
Und der Nachtrag kann trotzdem mit der Original-Auswahl gespeichert werden
Und im Audit-Log erscheint "nachtrag.vob_klauseln.inconsistency_warning"
Szenario: Grenzfall — KI-Vorschlag rechtlich unsicher (Gewährleistungs-Thema)
Angenommen Mehmet schreibt Stichworte "Nachbesserung wegen Mängelrüge vom 12.04., Gewährleistung"
Wenn er auf "KI-Textvorschlag generieren" tippt
Dann erzeugt die KI einen Text-Vorschlag
Und zusätzlich zum Standard-Disclaimer erscheint eine rote Warnung
"Dieser Vorschlag berührt anwaltlich beratungswürdige Themen. Bitte Rücksprache mit Rechtsanwalt."
Und der Audit-Eintrag erhält das Flag "ai.suggestion.sensitive = true"
Und Mehmet kann den Text trotzdem übernehmen, aber im PDF erscheint der doppelte Disclaimer
Szenario: Grenzfall — Bauherr signiert per PIN statt Hand
Angenommen Mehmet hat den Nachtrag per E-Mail an Hr. Müller-Bgm. versandt
Und der Bauherr öffnet den Link am 20.04.2026 um 09:15 Uhr
Wenn der Bauherr auf "PIN anfordern" tippt
Dann versendet Werkszeit einen 6-stelligen PIN per E-Mail und SMS (Gültigkeit 15 min)
Wenn der Bauherr die PIN korrekt eingibt
Dann wird der Nachtrag signiert mit `signature_kind = 'pin_token'`
Und der PDF-Footer kennzeichnet dies als "EES-Textform-Signatur (PIN-Code) gemäß §126b BGB"
Und im Audit-Trail stehen: `pin_angefordert` · `pin_verifiziert` · `signatur_eingabe`
Und ein Webhook "nachtrag.signiert" wird ausgelöst wie beim Touch-Fall
Szenario: Grenzfall — Multi-Tenant-Isolation am Portal-Token
Angenommen ein Angreifer hat einen gültigen JWT für Nachtrag N_A (Tenant shk-gebruder-schmidt)
Wenn er im JWT die nachtragId auf N_B (Tenant musterbetrieb-maler) manipuliert und Signatur nachbildet
Dann schlägt die JWT-Verifikation fehl (andere Tenant-Secret)
Und die API antwortet 404 (nicht 403)
Und im Security-Log erscheint ein anonymisierter Eintrag "jwt.verify.failed"
Und es entsteht KEIN Datensatz in musterbetrieb-maler

  • U-01 Nachtrag-Nummer-Generator: gap-frei pro Tenant+Baustelle, kollisionsfrei bei parallelen Requests (Property-based)
  • U-02 VOB-Klauseln-Inkonsistenz-Heuristik: Testsätze mit richtiger/falscher Klassifikation, F1-Score ≥ 0.85 auf Testset
  • U-03 Levenshtein-Distanz für aiEditDistance korrekt
  • U-04 JWT-Portal-Token: Payload-Verifikation, Expiry, maxUses-Counter (Redis-Mock)
  • U-05 Preisansatz-Berechnung: Rundung auf 2 Nachkommastellen identisch in Dart und TypeScript
  • W-01 KI-Vorschlag-Card: Disclaimer-Banner ist nicht wegklickbar (keine Close-Button im DOM)
  • W-02 Signatur-Pad: leer → Submit-Button disabled
  • W-03 Preis-Modus-Radio: Wechsel zwischen Modi löscht vorherige Eingaben nicht (keine Datenverlust)
  • W-04 Golden-Test für deutsche Locale + Dark Theme auf Nachtrag-Detail
  • I-01 Multi-Tenant-Isolation (harte Invariante laut DOD §2.2)
  • I-02 RLS-Policy scope=own: Monteur sieht keine Nachträge von Kollegen
  • I-03 Status-Transitions: Vollständiger Pfad erfasst → versendet → gelesen → signiert → beauftragt → abgerechnet, illegale Übergänge liefern 422
  • I-04 Version-Chain: previousVersionId wird bei Sign + Edit gesetzt, alte Version bleibt Read-only
  • I-05 RLS UPDATE-Policy nach Signatur: direkte UPDATE liefert 0 Rows affected
  • I-06 Idempotency-Key: doppelter Request → 409
  • E-01 Happy Path Patrol iOS + Android + Playwright Chromium/Firefox/WebKit
  • E-02 Externes Signatur-Portal: Playwright öffnet Token-URL, klickt Review-Checkbox, signiert, sieht Erfolg — axe-core ohne Critical-Findings
  • E-03 Offline + KI deaktiviert: Patrol simuliert Offline, KI-Button disabled, manuelle Erfassung funktioniert
  • E-04 Visuelle Regression auf Portal-View (mobile-web) für de-DE
  • C-01 Hash-Chain-Integrität bei Version-Kette
  • C-02 VOB-§2-Abs.-5-Prüf-Text: PDF enthält Pflicht-Zitat
  • C-03 KI-VO Art. 50: jeder PDF hat Disclaimer-Footer mit Modell-ID; Property-Test über 100 generierte PDFs
  • C-04 DSGVO-Export: Bauherr-Signatur-Events können vom Tenant-Admin als ZIP exportiert werden
  • C-05 JWT-Token-Sicherheit: Fuzz-Test gegen malformed Tokens, Algorithmus-Confusion (alg=none), Tenant-Secret-Rotation

Portal-E2E ist der Kandidat Nr. 1 für Flakiness (externes SES-Mocking). 20×-Run grün, SES als In-Memory-Mock mit deterministischer PIN.


Nicht-Ziel Begründung
Automatische KI-Akzeptanz ohne User-Review KI-VO Art. 50 + Haftung. KI schreibt Vorschlag, Mensch übernimmt Verantwortung.
Vollautomatische Rechtsberatung Keine Anwälte ersetzen. Disclaimer ist Feature, nicht Workaround.
Offline-KI (on-device LLM) Mobile-Hardware nicht ausreichend für sinnvolle Textqualität, und die Modell-Versionierung wäre ein Doku-Drift-Alptraum. V3+ bei Bedarf.
QES für Bauherr-Signatur EES + PIN genügt nach KMU-Handwerk-Praxis. QES kostet, Onboarding komplex. V3 optional.
Eigene Nachtrag-ERP-Pipeline Integration mit RIB iTWO / Nevaris / pds läuft via GAEB-X-Export (V1), nicht als eigener Workflow.
Mehrsprachige Nachträge in Phase 1 Deutscher Markt, deutsche Baukultur, deutsche Rechtsgrundlagen. V3+.
Sub-Beauftragungs-Workflow im Nachtrag Sub-Vergabe ist eigenes Epic handwerk/08-sub-vergabe (V2).

Risiko / Annahme Impact Wahrscheinlichkeit Gegenmaßnahme
KI-Vorschlag ist juristisch falsch, Nutzer übernimmt trotzdem hoch mittel Dreifach-Disclaimer (Banner + PDF-Footer + Audit); Heuristik für sensible Themen; Haftungs-Klausel in AGB
Bedrock-Latenz in Frankfurt >5 s → UX kippt mittel niedrig Prompt-Caching, Fallback auf Mistral Paris, Timeout 8 s mit Retry
SES-Mail landet im Spam, Bauherr sieht Link nicht hoch mittel Dedizierter IP-Pool, DKIM/SPF/DMARC, Fallback auf Mailjet; UI zeigt „Zustell-Check“ nach Versand (SES-Event)
JWT-Secret-Rotation sperrt aktive Portal-Links aus mittel niedrig Secret-Doppel-Lauf für 30 Tage nach Rotation; Dokumentierter Rotations-Prozess
Bauherr will Papier-Vorlage statt digitales Portal niedrig hoch Print-Button im Web (Typst-PDF mit Signatur-Feld-Rechteck) als Fallback; offline zurück-erfasst über Foto-Scan (V1.5)
§2-Abs.-5/6-Abgrenzung ist juristisch unscharf mittel mittel Heuristik + Soft-Warn, Disclaimer „Nicht-Abgrenzung ist Anwalts-Thema“
KI-Token-Verbrauch sprengt Addon-Budget niedrig mittel Rate-Limit pro User (10 Calls/Tag im Addon), Overage-Warning bei 80%

  • Vorbedingung:
    • kern/03-projekte-baustellen — Hauptauftrags-Stammdaten
    • kern/08-audit-log — Hash-verkettete Zentrale
    • kern/09-foto-upload-pipeline
    • kern/12-ki-gateway — Hono-AI-Gateway mit Bedrock/Mistral
    • kern/05-rechnung-basis — MVP: Nachtrag wird PDF-Rechnungs-Position
  • Schnittstelle zu:
    • handwerk/01-bautagebuch — Deep-Link-Eintrag; abgelehnter Nachtrag → §6-Behinderungsanzeige
    • handwerk/04-rechnung-vob (V1) — XRechnung-Position, Teil-/Schlussrechnung mit Kumulation
    • handwerk/03-gaeb-lv (V1) — LV-Position-Referenz für Preisansatz
  • Wird konsumiert von:
    • handwerk/04-rechnung-vob
    • handwerk/08-sub-vergabe (V2) — Nachtrag kann an Sub weitervergeben werden

Status: TBD.

Kandidaten-Profile:

  • SHK-/Heizungsbauer 50–100 MA mit 5+ parallelen öffentlichen Baustellen, hohe Nachtrag-Frequenz (schnelle Abwicklung = Cashflow). Primär-Kandidat: SHK-Gebrüder-Schmidt.
  • Elektro-/Gebäudetechnik 30–60 MA, viele §2-Abs.-5-Änderungen durch Bauherr-Wünsche. KI-Textvorschlag ist hier besonders wertvoll.
  • Maler-/Trockenbau 20–40 MA, häufig freie Vereinbarungen außer VOB (Private Bauherren).

Validierungs-Fragen:

  1. Wie viele Nachträge schreiben Sie pro Monat? Wie viele davon werden nachträglich bestritten?
  2. Wer formuliert den Nachtrag-Text heute — Chef, Sekretariat, Bauleiter? Wie lange dauert die Erstellung?
  3. Würde Ihnen ein KI-Vorschlag helfen oder misstrauen Sie KI-Output?
  4. Wären Sie bereit, 3 €/User/Monat extra für KI-Features zu zahlen, wenn wir 90% der Textformulierungen abnehmen?

Build-Sequenz:

  1. Datenmodell + RLS + Multi-Tenant-Test (I-01). Version-Chain-Logik von Anfang an modellieren, auch wenn MVP kaum Versionen sieht — Retrofit ist teuer.
  2. Portal-Token-System. JWT + Redis-Blacklist + Rate-Limit. Security-first, weil öffentlich erreichbar.
  3. Backend-API ohne KI + OpenAPI + Dart-Client. Muss grün sein, bevor KI kommt.
  4. Mobile-Erfassung ohne KI. Voll-Funktion manuell, inkl. Signatur-Pad offline.
  5. KI-Gateway-Anbindung mit Disclaimer-UI und Audit-Log. Als zweite Stufe, damit Nicht-KI-Pfad stabil steht.
  6. Externes Signatur-Portal. BFSG-Check + axe-core von Tag 1, nicht nachgerüstet.
  7. Web-Dashboard + Versionierung.
  8. Compliance-Tests (C-01–C-05).
  9. E2E-Suite mit Patrol + Playwright inkl. Portal-Flow.
  10. Doku-PR.

Risiko-Reihenfolge:

  • Nicht verhandelbar: Multi-Tenant-Isolation, JWT-Sicherheit, KI-Disclaimer-Pflicht.
  • Nicht verhandelbar: Status-nach-Signatur-Lock (Append-only).
  • Streich-Kandidaten bei Zeitnot: GAEB-LV-Bezug (V1 statt MVP), Versions-UI (kann textuell im MVP starten), KI-Heuristik für sensible Themen (kann V1).

Stop-the-Bus-Triggers:

  • Multi-Tenant-Bleed am Portal-Token (EC-07).
  • KI-Output wird ohne Disclaimer versendet (C-03 fail).
  • Status-Nach-Signatur-Lock umgehbar (I-05 fail).
  • Portal-View axe-core Critical-Finding (BFSG-Risiko).

Was uns 2027 dankbar macht:

  • Disclaimer-Pflicht-Banner hardcoded, nicht Tenant-konfigurierbar. Spart uns die Haftungs-Diskussion, wenn ein Tenant den Disclaimer „versehentlich“ abschaltet und Streit bekommt.
  • JWT-Portal statt eigenes Bauherr-Login. Zero-State-Lösung skaliert ohne User-Management-Aufwand; kein GDPR-Löschungs-Workflow für Nicht-Kunden.
  • Version-Chain ab Tag 1. Wir bekommen den „der Bauherr hat damals aber v1 unterschrieben“-Fall sauber abgebildet ohne Schema-Migration.
  • KI-Prompt-Hash statt Prompt-Cleartext gespeichert. Wenn Bedrock/Mistral-Prompts mal sensible Daten enthalten, haben wir sie nicht im Klartext 10 Jahre liegen.

Letzte Aktualisierung: 2026-04-19.

Für Entwickler — API-Endpoints21
MethodePfadAuthZweck
GET/v1/handwerk/nachtraegebearerAuthNachträge auflisten (Filter nach Status, Baustelle, Zeitraum).
POST/v1/handwerk/nachtraegebearerAuthNachtrag anlegen (Status `erfasst`).
DELETE/v1/handwerk/nachtraege/{id}bearerAuthNachtrag-Entwurf löschen (Hard-Delete, nur Status `erfasst`).
GET/v1/handwerk/nachtraege/{id}bearerAuthNachtrag-Detail inkl. Positionen und Signatur-Events.
POST/v1/handwerk/nachtraege/{id}/ai-suggestbearerAuthKI-Textvorschlag generieren — out-of-scope v1 (→ 501).
POST/v1/handwerk/nachtraege/{id}/cancelbearerAuthNachtrag stornieren.
GET/v1/handwerk/nachtraege/{id}/drift-reportbearerAuthDrift-Bericht (LV-Abweichungen seit Basis-Snapshot).
POST/v1/handwerk/nachtraege/{id}/drift-resolve/{positionId}bearerAuthDrift einer Position auflösen (rebase/force/abort).
GET/v1/handwerk/nachtraege/{id}/konfliktberichtbearerAuthKonflikt-Bericht (aufgelöste Merge-Konflikte mit Hash-Chain).
POST/v1/handwerk/nachtraege/{id}/lv-merge-applybearerAuthLV-Merge anwenden (Konflikt-Resolution).
POST/v1/handwerk/nachtraege/{id}/lv-merge-dry-runbearerAuthLV-Merge Vorschau (Dry-Run, keine Schreiboperation).
GET/v1/handwerk/nachtraege/{id}/pdfbearerAuthTypst-PDF-Export — out-of-scope v1 (→ 501).
POST/v1/handwerk/nachtraege/{id}/photosbearerAuthFoto-Metadaten festschreiben (nach Upload).
DELETE/v1/handwerk/nachtraege/{id}/photos/{photoId}bearerAuthFoto-Anhang löschen (nur Status `erfasst`).
POST/v1/handwerk/nachtraege/{id}/photos/presignbearerAuthPresigned-URL für Foto-Upload anfordern.
POST/v1/handwerk/nachtraege/{id}/sendbearerAuthNachtrag per E-Mail versenden + Portal-Token generieren.
POST/v1/handwerk/nachtraege/{id}/versionsbearerAuthNeue Version eines Nachtrags anlegen.
GET/v1/public/nachtrag/{token}publicBauherr-Portal-View (öffentlich, JWT-Token im Pfad).
POST/v1/public/nachtrag/{token}/pin/requestpublic6-stelligen PIN per E-Mail/SMS anfordern.
POST/v1/public/nachtrag/{token}/pin/verifypublicPIN verifizieren → signiert mit `pin_token` (§126b BGB Textform).
POST/v1/public/nachtrag/{token}/signpublicBauherr-Signatur einreichen (touch_vector oder pin_token).