Skip to Content
ArchitekturBestandssynchronisation

Bestandssynchronisation

Wie Flowkom Bestandsänderungen zu Shopify und Amazon pusht — und wie der Sync gegen Silent-Failures abgesichert ist.

Diese Seite ist für Admins und Power-User, die Sync-Drift analysieren oder Logs interpretieren wollen. Für reguläre Nutzung ist sie nicht relevant.

Überblick

Flowkom ist die Source-of-Truth für Bestände. Drei Dinge ändern den verfügbaren Bestand:

  1. Physischer Stock-Change — Wareneingang, Versand, Umlagerung, manuelle Buchung
  2. Reservierung — Eine Bestellung im Status offen, in Bearbeitung oder gepickt reserviert ihre Positionen
  3. Bundle-Cascade — Wenn ein Bundle-Bestand sich ändert, ändert sich auch der seiner Komponenten (und umgekehrt)

Jede dieser Änderungen muss zu allen verbundenen Plattformen propagiert werden — sonst überverkauft Shopify oder Amazon Bestand, der eigentlich anderswo reserviert ist.

Architektur

Reservierungs-Modell

Eine Bestellposition zählt als reserviert, solange ihr übergeordneter Auftrag in einem dieser Status ist:

StatusReserviert?Bedeutung
openAuftrag importiert, noch nicht in Bearbeitung
in_progressIn Pickliste eingeplant
pickedGepickt, wartet auf Versand
shippedVersendet — Bestand wurde abgebucht
completedAbgeschlossen
cancelledStorniert — Bestand ist wieder frei

Beim Push zu Shopify rechnet Flowkom: available = physischer_stock − reserviert. Amazon erhält den gleichen Wert pro FBM-Listing.

Was triggert einen Sync?

Es gibt zwei parallele Mechanismen, die das Produkt in die Sync-Queue schreiben:

1. DB-Trigger (primär)

Direkt in der PostgreSQL-Transaktion. Kann nicht silent failen — wenn der Trigger fehlschlägt, schlägt auch der Order-Insert/-Update fehl.

TriggerWannWas wird enqueued
trg_inventory_queue_on_line_itemINSERT/DELETE/UPDATE OF (product_id, quantity) auf order_line_itemsbetroffenes Produkt, sofern Order in Reservierungs-Status
trg_inventory_queue_on_order_statusUPDATE OF status auf orders, Übergang in/aus Reservierungs-Setalle Line-Items der Order
trg_inventory_queue_on_order_deleteBEFORE DELETE auf orders mit Reservierungs-Statusalle Line-Items vor CASCADE

Schreibt source = 'reservation' in inventory_sync_queue.

Trigger gibt es nur für die Shopify-Queue. Die Amazon-Queue (amazon_inventory_dirty_queue) wird vom App-Layer befüllt, weil sie pro Eintrag über amazon_listings, bundle_items und amazon_fba_inventory filtern muss — zu komplex für reinen SQL-Trigger.

2. App-Layer-Hooks (Defense-in-Depth)

In allen Order-Lifecycle-Routen wird zusätzlich ein Helper aufgerufen, der beide Queues füllt: Shopify (über markProductsDirty) und Amazon (über enqueueAmazonDirtyBatch). Beide haben einen internen Retry mit 500 ms Backoff.

Wenn der DB-Trigger und der App-Hook beide feuern, fängt das ON CONFLICT (workspace_id, product_id)-Constraint die doppelte Schreibung auf — idempotent.

Reconciliation: Safety-Sync

Selbst wenn beide oben genannten Mechanismen versagen, fängt ein Voll-Abgleich alle Drift ein:

  • Shopify: inventory-safety-sync läuft pro Integration alle 60 Minuten und pusht alle gemappten Produkte komplett neu. Reservierungen werden frisch aus order_line_items berechnet und abgezogen.
  • Amazon: amazon-inventory-safety-sync (Status: separate Baustelle) macht Analoges.

Das Intervall ist pro Integration konfigurierbar via integrations.settings.safety_sync_interval_minutes.

Drift-Diagnose

Wenn Shopify einen falschen Bestand zeigt:

  1. Queue-Eintrag prüfenselect * from inventory_sync_queue where product_id = '...'. Wenn leer: Trigger und App-Hook haben nicht gegriffen.
  2. Letzten Push prüfenselect * from integration_sync_logs where sync_type='inventory_push' order by created_at desc limit 5.
  3. Reservierungen prüfenselect oli.product_id, oli.quantity, o.status from order_line_items oli join orders o on o.id=oli.order_id where oli.product_id='...' and o.status in ('open','in_progress','picked').
  4. Logs nach [PROJ-265]-Marker filtern — alle Hook-Failures sind damit getaggt.
  5. Backup-Trigger — manuell select mark_product_dirty(workspace_id, product_id, 'manual') aufrufen, dann den Sync abwarten.

Quellen

  • Spec: features/PROJ-265-inventory-queue-db-triggers.md (DB-Trigger + Härtung)
  • Spec: features/PROJ-235-inventory-sync-reliability.md (App-Hook-Verdrahtung)
  • Spec: features/PROJ-55-bestandssync-wms-to-shop.md (Shopify-Sync-Engine)
  • Spec: features/PROJ-64-amazon-fbm-bestandssync.md (Amazon-FBM-Sync-Engine)