Vissza a Journal-hoz
logisticshu

Tobb raktar, egy stock view

Negy raktar, 18.400 SKU, stock view 280ms alatt. Miert hagytuk az available mezot szandekosan optimistanak.

Negy raktar, 18.400 SKU, es egy ertekesito, aki azt kerdezi: "van keszleten?". Ez a Netorigo Logistics legszemelyesebb teljesitmenyteszttje, es az elmult fel evben sokat tanultunk arrol, hogy miert nem trivialis egy multi-warehouse stock view.

A naiv megoldas miert nem mukodik

Az elso verzionk minden lekerdezeskor osszeszedte a stock_movements tablabol a futo egyenleget per SKU per warehouse, hozzaadta a reservations tablabol a fuggo foglalasokat, kivonta a in_transit tetelket, es 4 masodperc alatt visszaadta a valaszt. Negy masodperc egy ertekesito beszelgetes kozben az orokkevalosag. A megoldas: materialized view, ami SKU+warehouse szintu aggregalt sorokat tart, es minden stock_movement insert utan async job triggerezi a refresh-t (PostgreSQL pg_notify + worker). A stock view ma 280ms alatt tolt, raktartol fuggetlenul.

A fogalmi modell, ami szamit

Minden SKU-nak harom szinten van keszlete:

  • at_warehouse: fizikailag a polcon, nem foglalt.
  • in_transit: ket raktar kozott utazik (cross-stock vagy replenishment).
  • reserved: aktiv cart, ajanlat vagy rendeles tartja vissza.
  • available: at_warehouse mainusz reserved.

Ez a negy oszlop minden drill-down nezeten ott van. A logisztikai vezeto a at_warehouse + in_transit osszeget nezi ("mennyi van a halozaton osszesen"), az ertekesito az available-t ("mennyit igerhetek meg ma"), a beszerzes a available - safety_stock kuszob alatti SKU-kat ('mit kell rendelni').

Miert hagytuk az available-t szandekosan optimistanak

A legforradalmibb dontesunk: az available mezo nem dekremental cart-add-kor. Csak akkor csokken, amikor a pick-list legeneralodik (rendeles + warehouse-allocator dontes utan). Igy ket cart parhuzamosan tudja foglalni ugyanazt az utolso darabot, es csak az nyer, akinek a pick-list-je elobb generalodik. Az indok: a B2B kereskedelmi cart-elhagyasi arany 67%. Ha minden cart-add azonnal foglal, a keszlet artificialisan elfogy, es a kovetkezo latogatonak hibaisan azt jelezzuk, hogy nincs raktaron. Igy 30 percenkent rebooting-olnank a keszlet-feedbacket egy idle cart-cleanup job-bal, ami sajat magaban race condition forras.

A reservation lifecycle

A reservations tabla allapotai:

  1. cart - vasarloi kosaron van, soft hold, 24 oran utan TTL alapjan torlodik.
  2. quote - ajanlatban szerepel, 30 nap TTL, kemenyebb hold.
  3. order - megrendelve, varjuk a pick-listet.
  4. picking - aktiv pick-list-en, a pick-warehouse-bol nem mozdithato.
  5. shipped - kuldve, mar nem a Logistics modul problemaja.

Minden allapotvaltas audit-traillel kerul be a reservation_events tablaba. Volt egy bug 2026 marciusban, hogy a quote -> order atmenet nem indexelte a reservation-t a warehouse-allokatorra, igy a pick-list a rossz raktarrol generalodott (cross-stock-szal kerult kezbesitesre, +18 ora SLA-csuszas). Az auit-trail meg az este meglatatta a hibat.

A drill-down

A stock view alapertelmezett nezete osszevont (4 raktar, egy szam per SKU). Egy kattintas a SKU-ra megnyitja a per-warehouse breakdown-t: melyik raktarban mennyi van, melyikbol mennyi utazik, melyik raktar reservation-jei tartjak vissza. Egy kattintas a reservation szamra megnyitja a reservation-listat: melyik cart-/quote-/order-ID, mikor jart le.

A managerek 80%-a az osszevont view-on dolgozik. A 20% specializalt raktarmenedzser hasznalja a drill-down-t, foleg amikor egy cross-stock dontest hoz: "a 18-as raktarban van 4, a 33-asban 12, kuldjunk 6-ot at a 18-ra a holnapi pick-wave-hez". A cross-stock muvelet direkt a drill-down-bol triggerezheto, es a stock view 280ms-on belul reflektalja.

Amit a kovetkezo iteracioban csinalnank maskepp

A materialized view megoldas mukodik 18.000 SKU-ra es 4 raktarra. 100.000 SKU es 12 raktar felett valoszinuleg event-sourced megoldasra valtanank (Kafka + KSQL), es a stock view-t streaming-bol epitenenk. Egyelore nincs ilyen meretu partnerunk, igy a materialized view a kovetkezo 12 honapra elegendo.