feat(import): ERP-Sync in DB dokumentieren + Startup-Catch-up

Jeder ERPframe-Import (Scheduler, Startup, manuell) wird in der neuen Tabelle
erp_sync_runs protokolliert (target_date, trigger, success, Zaehler, Fehler).
Beim Serverstart synct das Backend das Zieldatum (heute + offset, i.d.R. morgen)
nach, falls dafuer noch kein erfolgreicher Lauf dokumentiert ist — deckt
Erststart UND laengere Unterbrechungen ab, bei denen der Cron-Zeitpunkt verpasst
wurde. Gated ueber [import] enabled.

- Migration 0030_erp_sync_runs
- Port SyncRunRepository (+ SyncRunRecord, SyncTrigger)
- Adapter PgSyncRunRepository
- ImportErpToursUseCase dokumentiert jeden Lauf; neues execute_with(date, trigger)
- main.rs: Repo verdrahtet, Scheduler-Trigger, Startup-Catch-up (tokio::spawn)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Dennis Nemec
2026-06-08 16:23:12 +02:00
parent c65e13485d
commit 2f4368ec52
7 changed files with 272 additions and 3 deletions

View File

@ -0,0 +1,40 @@
-- 0030_erp_sync_runs.sql
--
-- Dokumentation der ERP-Import-Läufe (Sync mit ERPframe). Jeder Lauf — egal ob
-- vom täglichen Scheduler, vom Startup-Catch-up oder manuell über den
-- Admin-Endpunkt (`POST /admin/import-erp`) — hinterlässt hier eine Zeile.
-- Zweck: Audit/Nachvollziehbarkeit ("wann wurde für welches Tourdatum gesynct,
-- mit welchem Ergebnis").
--
-- Zusätzlich Grundlage für den Startup-Catch-up: beim Serverstart (Erststart
-- ODER nach längerer Unterbrechung, wenn der Cron-Zeitpunkt verpasst wurde)
-- prüft das Backend, ob für das Zieldatum (morgen) bereits ein ERFOLGREICHER
-- Lauf dokumentiert ist — wenn nicht, synct es nach.
CREATE TABLE erp_sync_runs (
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
-- Tourdatum, für das gesynct wurde (NICHT der Zeitpunkt des Laufs).
target_date date NOT NULL,
-- Auslöser: 'scheduler' | 'startup' | 'manual'.
trigger text NOT NULL,
-- true = Lauf lief durch (ERP gelesen + verarbeitet); ein einzelner
-- fehlerhafter Beleg (tours_failed > 0) zählt weiterhin als erfolgreicher
-- Lauf. false = Lauf komplett gescheitert (z. B. ERP nicht erreichbar),
-- dann ist `error` gesetzt.
success boolean NOT NULL,
tours_total integer NOT NULL DEFAULT 0,
tours_ok integer NOT NULL DEFAULT 0,
tours_failed integer NOT NULL DEFAULT 0,
drivers_provisioned integer NOT NULL DEFAULT 0,
error text,
created_at timestamptz NOT NULL DEFAULT now()
);
-- Schnelle Abfrage „gibt es einen ERFOLGREICHEN Sync für Datum X?" (Catch-up).
CREATE INDEX erp_sync_runs_date_success
ON erp_sync_runs (target_date)
WHERE success;
-- Chronologische Sicht fürs Audit (neueste zuerst).
CREATE INDEX erp_sync_runs_created_at
ON erp_sync_runs (created_at DESC);