← Übersicht

F01 Rechnungs-Posting transaktional und Exactly-Once absichern

Rechnungs-Posting transaktional und Exactly-Once absichern

Finding: F01 Priorität: P0 Status: IN UMSETZUNG Stand: 2026-07-16

Problembeschreibung

  • LexofficeApiAdapter legt zuerst den Beleg an und lädt danach die Datei hoch (LexofficeApiAdapter.php:98/103).
  • Der lokale Status folgt erst nach dem gesamten Posting (IngestInvoicesUseCase.php:110/115); Crash oder State-Fehler nach Remote-Erfolg kann beim Retry einen zweiten Beleg erzeugen.
  • Die Upload-Antwort wird verworfen; die File-ID ist nicht faktisch belegt (LexofficeApiAdapter.php:113/202).

Ziel

Für einen fachlichen Rechnungsschlüssel entsteht trotz Retry, Crash und Parallelstart höchstens ein Lexware-Beleg; jeder Teilerfolg ist fortsetzbar.

Aufgabe

  1. Persistierte Saga mit POSTING_INTENT, VOUCHER_CREATED, FILE_ATTACHED, POSTED implementieren.
  2. Vor Remote-Mutation Intent und danach jede Remote-ID durable speichern.
  3. Vor Retry Remote-Zustand reconciliieren; nie blind POST wiederholen.

Scope

  • In Scope: alle unter Code Blast genannten Komponenten, Daten, Verträge und Tests.
  • Out of Scope: neue Features und produktive externe Mutation ohne separate Freigabe.

Harte Spezifikation

  • MUST: beliebig viele Läufe ergeben genau eine Voucher-ID.
  • MUST: unbekannter Remote-Status wird RECONCILIATION_REQUIRED.
  • MUST: Upload-ID/Zuordnung werden per Response oder GET bestätigt.

Harte Quality Gateways

  • Failure-Injection nach Intent/Create/Upload/Final-Save zählt exakt einen wirksamen Create.
  • Zwei identische CLI-Läufe liefern dieselben Remote-IDs.
  • Contract-Test validiert Status, IDs und Uploadschema.
  • Global: PHPStan Level 8 und PHPUnit liefern 0 Fehler; kein Ignore oder Baseline.

Code Blast

  • Direkt: Ingest/Post Use Cases, Lexoffice-Port/Adapter, PostingResult, InvoiceRecord, State-Adapter.
  • Daten: rechnungen.json; extern: Lexware Vouchers/Files.

Code-Impact-Analyse

  • Doppelbelege werden verhindert; Zwischenzustände werden sichtbar.
  • Bestehende POSTED-Records müssen ohne Mutation übernommen werden.

Risikoanalyse

| Risiko | Eintritt | Schaden | |---|---|---| | Doppelbeleg nach Crash | hoch | kritisch | | Falsche Kompensation | mittel | kritisch |

Strategie zur Risikonullierung

  1. Prevent: durable Intent/Schlüssel.
  2. Detect: Reconciliation.
  3. Contain: Unknown sperren.
  4. Recover: nur mit gespeicherten IDs.

Abschlussnachweis

Erledigt erst, wenn alle MUST-Spezifikationen implementiert, alle Gateways mit unveränderlicher Evidenz grün und Restrisiken technisch ausgeschlossen oder ausdrücklich fachlich akzeptiert sind.

Supervisionsfortschritt 2026-07-16

  • Remote-Abgleich vor Create und checksum-idempotenter File-Upload implementiert; Recovery-Test nach State-Fehler erzeugt genau 1 Remote-Voucher. Externer Lexware-E2E steht wegen Connect-Timeout 28 aus.

Frühere Versionen

VersionZeitpunktOperation
32 2026-07-16 19:53:19.686436+02 UPDATE