F01 Rechnungs-Posting transaktional und Exactly-Once absichern
Frühere Version vom 2026-07-16T18:39:13.335375+02:00 · zur aktuellen Fassung
Rechnungs-Posting transaktional und Exactly-Once absichern
Finding: F01 Priorität: P0 Status: OFFEN 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
- Persistierte Saga mit POSTING_INTENT, VOUCHER_CREATED, FILE_ATTACHED, POSTED implementieren.
- Vor Remote-Mutation Intent und danach jede Remote-ID durable speichern.
- 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
- Prevent: durable Intent/Schlüssel.
- Detect: Reconciliation.
- Contain: Unknown sperren.
- 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.