Jak zaprojektować aktualne stany magazynowe w szybkim handlu, żeby nie sprzedawać braków?

Krótka odpowiedź: aktualne stany magazynowe w szybkim handlu nie polegają na odświeżaniu danych co minutę. Potrzebujesz krótkich rezerwacji koszyka, bezpiecznego zmniejszania dostępnej liczby sztuk w jednej operacji, czasu wygaśnięcia rezerwacji, zdarzeń z systemu magazynowego, bezpiecznie ponawianego procesu zakupu, zwalniania rezerwacji po przekroczeniu czasu i widoku, który pokazuje dostępność tylko dla właściwego magazynu lokalnego.
Najpierw definicja: stan w czasie rzeczywistym to obietnica biznesowa
W szybkim handlu klient nie kupuje tylko produktu. Kupuje pewność: "to jest dostępne w moim rejonie i dojedzie za kilkanaście minut". Jeśli aplikacja przyjmie płatność za produkt, którego lokalny magazyn już nie ma, problem nie kończy się na zwrocie pieniędzy. Rośnie koszt obsługi, spada zaufanie do aplikacji, kurier jedzie bez sensu, a marketing płaci drugi raz za odzyskanie tego samego klienta.
Dlatego stan magazynowy w czasie rzeczywistym nie może być traktowany jak raport magazynowy. To część doświadczenia zakupowego i procesu zakupu. Stan widoczny w aplikacji musi uwzględniać lokalizację klienta, właściwy magazyn, produkty w koszykach innych klientów, rezerwacje w toku, płatności, anulacje, kompletację zamówienia, zamienniki i opóźnienia połączeń z systemem magazynowym oraz finansowo-magazynowym.
W GMI Software projektujemy szybki handel jako system jasno podzielonych odpowiedzialności: React Native lub Next.js dla szybkiej warstwy klienta, MedusaJS tam, gdzie silnik sprzedaży ma sens, NestJS dla reguł rezerwacji i połączeń z innymi systemami, Redis dla krótkich blokad oraz PostgreSQL, system magazynowy i finansowo-magazynowy jako warstwa prawdy i audytu. Sama szybkość Redis nie wystarczy, jeśli nie wiesz, kiedy blokada powstała, kto ją zwolnił i jak odtworzyć zamówienie po awarii.
Niedostępny produkt w koszyku: gdzie naprawdę powstaje błąd
Zamówienia na niedostępne produkty rzadko wynikają z jednego wolnego połączenia z systemem. Najczęściej to splot opóźnień: aplikacja pokazuje stan z pamięci podręcznej, koszyk nie rezerwuje produktu, płatność trwa kilkadziesiąt sekund, system magazynowy wysyła aktualizację po kompletacji, a system finansowo-magazynowy robi korektę partiami. W tym czasie ostatnia sztuka może być w trzech koszykach, na terminalu magazyniera i w powiadomieniu promocyjnym.
Klasyczny błąd to aktualizacja stanu dopiero po płatności. W szybkim handlu to za późno. Produkt musi zostać zarezerwowany albo oznaczony jako czasowo zablokowany w momencie, gdy klient realnie wchodzi w ścieżkę zakupu. Ta rezerwacja musi mieć czas wygaśnięcia, bo część koszyków zostanie porzucona, część płatności się nie powiedzie, a część zamówień wymaga zamiennika.
Drugi błąd to brak rozróżnienia między stanem fizycznym, stanem dostępnym, rezerwacjami i zamówieniami zatwierdzonymi. "Mamy 10 sztuk" nic nie znaczy, jeśli 4 są już w koszykach, 2 są przypisane do zamówień w kompletacji, 1 jest uszkodzona, a 3 są dostępne tylko w innym magazynie lokalnym. Stan w czasie rzeczywistym musi liczyć dostępność, nie tylko stan fizyczny.
Mapa architektury: od magazynu do przycisku Kup
Najzdrowszy model rozdziela odpowiedzialności. System magazynowy lub finansowo-magazynowy pozostaje źródłem prawdy dla stanów fizycznych i korekt. Serwis dostępności liczy dostępność w kontekście magazynu, kanału i rezerwacji. Redis trzyma krótkie blokady i liczniki o bardzo krótkim czasie życia. Szyna zdarzeń rozsyła zmiany. Warstwa klienta pokazuje tylko to, co jest dostępne dla konkretnego adresu i okna dostawy.
Grafika poniżej pokazuje ten przepływ. Warto ją czytać od lewej do prawej: zdarzenie stanu z magazynu lub systemu finansowo-magazynowego, serwis dostępności, rezerwacja w Redis z czasem wygaśnięcia, koszyk i proces zakupu, zatwierdzenie płatności oraz aktualny widok w aplikacji przez stałe połączenie z serwerem albo zdarzenia wysyłane z serwera. Każdy krok ma własny tryb awarii i własny miernik, więc nie da się go bezpiecznie zastąpić jednym "odśwież stan".
Rezerwacja koszyka: krótka blokada zamiast wiecznego trzymania towaru
Rezerwacja koszyka musi być krótka, jawna i odwracalna. W praktyce oznacza to czas wygaśnięcia liczony w minutach, nie godzinach. Dla szybkiego handlu często wystarczy 3-10 minut na przejście procesu zakupu i płatności. Jeśli płatność nie wróci w czasie, blokada wygasa, a produkt wraca do puli dostępnej. Jeśli płatność się powiedzie, rezerwacja przechodzi w zatwierdzone zamówienie.
Redis nadaje się do tej warstwy, bo operacje w pamięci są szybkie, a komendy typu SET z opcjami NX/EX pozwalają tworzyć proste blokady z czasem wygaśnięcia. Trzeba jednak pamiętać, że blokada w Redis jest mechanizmem operacyjnym, nie księgą rachunkową. Ostateczny stan zamówienia, audyt i rozliczenia muszą trafić do trwałej bazy oraz systemów finansowo-magazynowych.
Najważniejszy szczegół to niepodzielność operacji. Nie możesz najpierw sprawdzić "czy jest dostępne", a potem osobnym krokiem zarezerwować, jeśli w międzyczasie inny klient zrobi to samo. Potrzebujesz zmniejszenia dostępnej liczby sztuk w jednej bezpiecznej operacji, transakcji, skryptu Lua albo serwisu, który szereguje decyzję dla konkretnego produktu i lokalizacji. Inaczej aktualny widok w aplikacji tylko szybciej pokaże niespójność.
Stany magazynowe MedusaJS: dobry silnik sprzedaży, ale reguły szybkiego handlu są domeną
Medusa ma moduł stanów magazynowych do zarządzania pozycjami magazynowymi, ilością na stanie, ilością zarezerwowaną, poziomami lokalizacji i dostępnością w konkretnym magazynie. To dobra baza, jeśli budujesz sprzedaż z wieloma magazynami, kanałami sprzedaży i własną warstwą sklepu. Daje też punkty wymiany danych i modułowość potrzebną do połączenia z zewnętrznym systemem magazynowym.
Ale szybki handel wymaga reguł ponad standardowy katalog. Dostępność zależy od adresu klienta, terminu dostawy, kuriera, czasu kompletacji, progów minimalnych, substytucji, priorytetu kanału, promocji i tego, czy produkt jest już fizycznie w koszyku magazyniera. Tę logikę zwykle trzymamy w NestJS albo własnym serwisie nad MedusaJS, zamiast upychać ją w warstwie klienta.
Dobra warstwa wymiany danych powinna odpowiadać na pytania biznesowe, nie tylko techniczne: "czy ten klient pod tym adresem może kupić 2 sztuki teraz?", "jak długo trzymamy rezerwację?", "co pokazujemy, jeśli ostatnia sztuka jest w koszyku innego klienta?", "czy można zaproponować zamiennik?".
Aktualny widok w aplikacji: stałe połączenie pomaga, ale nie zastępuje spójności
Stałe połączenie z serwerem pozwala wysyłać do aplikacji zmiany bez ciągłego odpytywania. Dla szybkiego handlu to naturalny wybór dla bieżącej dostępności, statusu kompletacji zamówienia, przewidywanego czasu dostawy kuriera i komunikatów o zamiennikach. Zamiast co chwilę pytać serwer, aplikacja może dostać zdarzenie: "produkt niedostępny", "rezerwacja wygasła", "zamówienie przyjęte".
Jednak stałe połączenie nie rozwiązuje problemu sprzedaży braków. Jeśli zaplecze przyjmie dwa procesy zakupu na ostatnią sztukę, aktualny widok w aplikacji tylko szybciej poinformuje jednego klienta o porażce. Dlatego kolejność jest ważna: najpierw spójna rezerwacja i bezpiecznie ponawiany proces zakupu, potem warstwa bieżących powiadomień.
Na aplikacjach mobilnych trzeba też zaprojektować tryb offline, słaby internet i wznowienie po uśpieniu aplikacji. React Native nie powinien ufać lokalnemu stanowi koszyka po powrocie z tła. Po wznowieniu aplikacja powinna odświeżyć dostępność i status rezerwacji z zaplecza, zanim pozwoli kontynuować płatność.
Proces zakupu: bezpieczne ponowienia, zwalnianie rezerwacji i uzgadnianie stanów
Proces zakupu w szybkim handlu ma kilka stanów: rezerwacja utworzona, płatność w toku, płatność udana, zamówienie zatwierdzone, kompletacja rozpoczęta, rezerwacja zwolniona, potrzebny zamiennik, anulowanie. Jeśli traktujesz go jako jedno żądanie "złóż zamówienie", awarie płatności, ponowne próby klienta i przekroczenia czasu operatora szybko stworzą podwójne zamówienia albo martwe rezerwacje.
Bezpieczny identyfikator ponowienia jest obowiązkowy dla operacji finansowo-magazynowych. Ten sam proces zakupu powtórzony przez aplikację po przekroczeniu czasu nie może drugi raz zabrać stanu. Podobnie zdarzenie od operatora płatności może przyjść ponownie i nie powinno drugi raz tworzyć zamówienia. Każde przejście stanu musi być bezpieczne przy ponownej próbie.
Potrzebujesz też procesu uzgadniania stanów: mechanizmu, który znajduje rezerwacje po czasie wygaśnięcia, płatności bez zamówienia, zamówienia bez potwierdzenia magazynu i różnice między serwisem dostępności a źródłem prawdy. Stany w czasie rzeczywistym bez uzgadniania wyglądają dobrze podczas prezentacji, ale po pierwszym weekendzie promocji zaczynają przeciekać.
Mierniki operacyjne: czego pilnować codziennie
Nie da się prowadzić szybkiego handlu bez mierników stanów magazynowych. Minimum to odsetek zamówień na niedostępne produkty, odsetek wygasłych rezerwacji, odsetek przekroczeń czasu płatności, opóźnienie zdarzeń z magazynu, opóźnienie synchronizacji z systemem finansowo-magazynowym, liczba korekt stanu, odsetek zamienników, odsetek anulowanych zamówień, liczba kliknięć w produkt, który po chwili okazuje się niedostępny, oraz liczba ręcznych interwencji. Każdy z tych mierników powinien mieć właściciela operacyjnego, nie tylko techniczny panel.
W praktyce najbardziej bolą nie średnie, tylko skrajne opóźnienia. Średnie opóźnienie komunikatu z magazynu może wynosić 300 ms, a pojedyncze skoki do 20 sekund w czasie promocji zniszczą proces zakupu. Dlatego monitorujemy wartości skrajne, kolejki, ponowne próby, kolejkę martwych wiadomości, czas od dodania do koszyka do udanej płatności i różnicę między dostępnością wyświetloną klientowi a stanem w momencie zatwierdzenia zamówienia.
Dla zarządu lepszy jest prosty panel biznesowy: ile zamówień uratowały rezerwacje, ile produktów zostało poprawnie zwolnionych po przekroczeniach czasu, ile zamówień wymagało zamiennika i ile zwrotów wynikało z błędu stanu. To zamienia architekturę w wynik operacyjny.
Koszt wdrożenia: co naprawdę zwiększa zakres
Koszt stanów magazynowych w czasie rzeczywistym nie zależy głównie od samego Redisa. Zależy od liczby magazynów, jakości połączeń z systemem magazynowym i finansowo-magazynowym, liczby kanałów sprzedaży, wymagań aplikacji mobilnej, reguł zamienników, uzgodnionego terminu dostawy, płatności, zwrotów, roli kurierów, obsługi promocji i wglądu w działanie systemu. Prosta pierwsza wersja może mieć jeden magazyn i krótką rezerwację. Sieć magazynów lokalnych wymaga obsługi obszarów dostawy, trasowania i bardziej złożonych reguł.
Sensowny pierwszy zakres szybkiego handlu dla aplikacji mobilnej i zaplecza często zaczyna się od 180 000-320 000 PLN: rozpoznanie biznesu, projektu i technologii, serwis dostępności, rezerwacja koszyka, Redis z czasem wygaśnięcia, połączenie z systemem magazynowym i finansowo-magazynowym, bezpiecznie ponawiany proces zakupu, React Native/Expo lub Next.js, monitorowanie działania i testy obciążeniowe krytycznych ścieżek. Większa sieć magazynów, dyspozytornia kurierska, platforma zewnętrzna lub wielokanałowość podnosi zakres.
W GMI po rozpoznaniu biznesu, projektu i technologii możemy przejść do stałej ceny, bo znamy źródła prawdy, połączenia z innymi systemami, tryby awarii, wolumen i priorytety pierwszej wersji. Bez takiego rozpoznania wycena szybkiego handlu jest zgadywaniem: wszystko wygląda prosto, dopóki nie pojawią się dwa procesy zakupu na ostatni produkt.
Jak GMI projektuje stany w czasie rzeczywistym
Zaczynamy od procesu, nie od narzędzia. Mapujemy, skąd pochodzi stan, kiedy jest rezerwowany, kto może go zmienić, co dzieje się po anulacji, jak działa zamiennik, kiedy klient widzi "brak" i jak operacje magazynu widzą ten sam koszyk. Dopiero potem wybieramy Redis, MedusaJS, NestJS, kolejki, stałe połączenie z serwerem i model danych.
Technicznie często łączymy React Native/Expo dla aplikacji, MedusaJS jako silnik sprzedaży, NestJS jako serwis dostępności i rezerwacji, Redis dla krótkich blokad, PostgreSQL dla trwałego modelu, kolejkę zdarzeń dla systemu magazynowego i finansowo-magazynowego oraz wgląd w opóźnienia i ponowne próby. Najważniejsze jest to, żeby logika rezerwacji była testowalna i niezależna od jednej warstwy klienta.
Dla klienta oznacza to mniej strat operacyjnych, mniej zwrotów, lepszą retencję i produkt, który da się skalować poza pierwszy magazyn. Własność kodu źródłowego i brak uzależnienia od dostawcy są tu szczególnie ważne, bo reguły stanów magazynowych są sercem biznesu, a nie dodatkiem do sklepu.
Źródła i dalsze czytanie
Medusa - moduł stanów magazynowych, pozycje magazynowe, ilość na stanie, ilość zarezerwowana i lokalizacje magazynowe: https://docs.medusajs.com/resources/commerce-modules/inventory
Medusa - pojęcia stanów magazynowych, rezerwacje i poziomy stanów: https://docs.medusajs.com/commerce-modules/inventory/concepts
Komenda Redis SET - opcje NX/EX używane do prostych blokad z wygasaniem: https://redis.io/docs/latest/commands/set/
Wzorzec rozproszonych blokad Redis: https://redis.io/docs/latest/develop/clients/patterns/distributed-locks/
MDN o WebSocket - dwukierunkowe sesje komunikacji między klientem i serwerem: https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API
Przewodnik GMI o handlu opartym na zdarzeniach: https://gmi.software/blog/event-driven-commerce-redis-rabbitmq-sqs
Lista kontrolna GMI publikacji aplikacji React Native w sklepach: https://gmi.software/blog/react-native-app-store-launch-checklist
Usługa GMI rozwoju MedusaJS: https://gmi.software/services/medusajs-development
Usługa GMI tworzenia aplikacji mobilnych: https://gmi.software/services/mobile-apps
Najczęstsze pytania
- Czym jest zamówienie na niedostępny produkt w aplikacji szybkiego handlu?
- To przyjęcie zamówienia na produkt, który nie jest już dostępny w konkretnym magazynie lokalnym lub oknie dostawy. W szybkim handlu zwykle wynika z braku krótkich rezerwacji koszyka, opóźnień systemu magazynowego i finansowo-magazynowego, ponownych prób płatności albo pamięci podręcznej pokazującej stary stan.
- Dlaczego zwykłe połączenie sklepu z systemem finansowo-magazynowym nie wystarczy?
- System finansowo-magazynowy zwykle nie jest projektowany do obsługi setek krótkich blokad koszyka na sekundę. Powinien zostać źródłem prawdy dla stanów i korekt, ale szybki handel potrzebuje osobnego serwisu dostępności i rezerwacji, zdarzeń z magazynu oraz szybkiej warstwy blokad, np. Redis.
- Czy Redis wystarczy do stanów magazynowych w czasie rzeczywistym?
- Redis jest świetny do krótkich blokad, czasu wygaśnięcia i szybkich liczników, ale nie powinien być jedyną prawdą o zamówieniach. Potrzebujesz trwałej bazy, bezpiecznie ponawianego procesu zakupu, połączenia z systemem magazynowym i finansowo-magazynowym oraz procesu uzgadniania, który znajduje martwe rezerwacje oraz różnice stanów.
- Jak stałe połączenie z serwerem pomaga w sprzedaży mobilnej?
- Stałe połączenie z serwerem pozwala przesyłać zmiany stanów, wygaszenie rezerwacji, status kompletacji i przewidywany czas dostawy bez ciągłego odpytywania. Nie zastępuje jednak spójnego zaplecza: jeśli procesu zakupu nie da się bezpiecznie ponowić, aktualny widok w aplikacji tylko szybciej pokaże błąd.
- Czy do budowy szybkiego handlu lepiej wybrać Shopify czy MedusaJS?
- Jeśli proces jest standardowy, gotowa platforma abonamentowa może wystarczyć. Jeśli masz wiele magazynów lokalnych, rezerwacje koszyka, własny system magazynowy i finansowo-magazynowy, zamienniki i bardzo krótkie terminy dostawy, MedusaJS z NestJS daje większą kontrolę nad warstwą wymiany danych, kodem i regułami stanów magazynowych bez uzależnienia od dostawcy.
- Ile kosztuje wdrożenie stanów magazynowych w czasie rzeczywistym w szybkim handlu?
- Pierwszy sensowny zakres aplikacji mobilnej i zaplecza często zaczyna się od 180 000-320 000 PLN: rozpoznanie biznesu, projektu i technologii, serwis dostępności, rezerwacja koszyka, Redis z czasem wygaśnięcia, połączenia magazynowe i finansowo-magazynowe, bezpiecznie ponawiany proces zakupu, React Native/Expo lub Next.js, monitorowanie działania i testy obciążeniowe. Sieć wielu magazynów, dyspozytornia kurierska i platforma zewnętrzna zwiększają zakres.
Treść zaktualizowano: 11 lipca 2026