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
open✅Auftrag importiert, noch nicht in Bearbeitung
in_progress✅In Pickliste eingeplant
picked✅Gepickt, wartet auf Versand
shipped❌Versendet — Bestand wurde abgebucht
completed❌Abgeschlossen
cancelled❌Storniert — 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ĂŒfen — select * from inventory_sync_queue where product_id = '...'. Wenn leer: Trigger und App-Hook haben nicht gegriffen.
  2. Letzten Push prĂŒfen — select * from integration_sync_logs where sync_type='inventory_push' order by created_at desc limit 5.
  3. Reservierungen prĂŒfen — select 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)