Real-time w biznesie - dlaczego Twój konkurent wie o problemie 3 godziny przed Tobą
Piątek, 15:00. Generujesz raport tygodniowy. Czekasz 20 minut. Otwierasz. Widzisz, że we wtorek sprzedaż spadła o 40%. Dzwonisz do handlowca. "A, tak, klient X odwołał zamówienie, nie zdążyłem powiedzieć". Tracisz 3 dni na reakcję. 3 dni, w których mogłeś porozmawiać z klientem, zaproponować rabat, zrozumieć problem.
Twój konkurent ma dashboard real-time. We wtorek o 10:15, 15 minut po odwołaniu zamówienia, manager dostaje alert: "Klient X odwołał zamówienie na 45 000 PLN. Powód: brak potwierdzenia terminu dostawy." O 10:30 dzwoni do klienta. O 11:00 zamówienie jest przywrócone z potwierdzonym terminem.
Różnica? Nie technologia. Czas reakcji.
Czym jest real-time w kontekście biznesowym
Real-time to nie "dane odświeżają się co sekundę". To fundamentalna zmiana w sposobie, w jaki firma operuje:
System tradycyjny (raport): Coś się dzieje → dane są zbierane → ktoś generuje raport → ktoś go czyta → ktoś podejmuje decyzję → ktoś ją wykonuje. Cykl: godziny do dni.
System real-time: Coś się dzieje → system natychmiast informuje właściwą osobę → decyzja podejmowana jest w minutach → działanie natychmiast. Cykl: sekundy do minut.
To nie jest różnica stopnia. To różnica jakościowa. Firma z real-time nie jest "trochę lepsza" - gra w inną grę.
Gdzie real-time zmienia zasady
Sprzedaż: reakcja zamiast raportu
Bez real-time:
- Spadek sprzedaży widać w raporcie tygodniowym / miesięcznym
- Reakcja: spotkanie zespołu, analiza, plan działania, wdrożenie
- Czas od problemu do reakcji: 1-4 tygodnie
- Klienci odchodzą w tym czasie do konkurencji
Z real-time:
- Dashboard pokazuje sprzedaż na żywo z porównaniem do analogicznego dnia / tygodnia / roku
- Alert, gdy sprzedaż spada poniżej progu (np. -20% vs tydzień temu)
- Manager widzi alert o 10:00, analizuje przyczynę do 10:30, podejmuje działanie do 11:00
- Klient jest obsłużony tego samego dnia
# LiveView - dashboard aktualizuje się sam
def handle_info({:new_order, order}, socket) do
stats = recalculate_stats(socket.assigns.stats, order)
# Sprawdź alert
if stats.today_vs_last_week < -0.20 do
Notifications.send_alert(socket.assigns.manager_id,
"Sprzedaż dziś: #{stats.today_total} PLN (-#{abs(stats.today_vs_last_week * 100)}% vs tydzień temu)")
end
{:noreply, assign(socket, stats: stats)}
endDashboard zarządu w Phoenix LiveView: wykres sprzedaży rysuje się punkt po punkcie, z każdą nową transakcją. Nie trzeba klikać "Odśwież". Nie trzeba generować raportu. Dane są.
Magazyn: stan na żywo zamiast inwentaryzacji
Bez real-time:
- Stany magazynowe aktualizowane raz dziennie (nocna synchronizacja)
- Rano widać "50 sztuk", ale 10 zostało sprzedanych online nocą
- Handlowiec obiecuje klientowi 50 sztuk. W magazynie jest 40
- Inwentaryzacja raz na kwartał - 3 dni zamkniętego magazynu
Z real-time:
- Każde wydanie z magazynu natychmiast aktualizuje stan w systemie
- Handlowiec widzi aktualny stan (z dokładnością do sekundy) na LiveView
- Gdy stan spada poniżej minimum - automatyczny alert + zamówienie do dostawcy
- Ciągła inwentaryzacja zamiast kwartalnej: skanowanie bieżące, różnice widoczne natychmiast
Magazynier skanuje wydanie
↓
PostgreSQL: UPDATE stany SET ilosc = ilosc - 1
↓
NOTIFY stock_change
↓
Phoenix PubSub → Wszystkie otwarte dashboardy
↓
LiveView: stan aktualizuje się na ekranie handlowca
↓
Jeśli stan < minimum → Oban: zamów u dostawcyOd skanowania do aktualizacji na ekranie handlowca: poniżej 100 milisekund. Handlowiec zawsze wie, ile towaru ma w magazynie. Nie "ile było rano" - ile jest teraz.
Logistyka: tracking bez pytania
Bez real-time:
- Klient dzwoni: "Gdzie jest moja paczka?"
- Pracownik loguje się do panelu kuriera, szuka numeru przesyłki, czyta status, przekazuje klientowi
- 5 minut na jedno pytanie × 50 pytań dziennie = 4 godziny dziennie na "gdzie jest moja paczka"
Z real-time:
- Webhook od kuriera: status przesyłki zmienił się
- System automatycznie aktualizuje status zamówienia
- Klient widzi tracking w swoim panelu (LiveView - aktualizacja bez odświeżania)
- Email/SMS wysyłany automatycznie przy zmianie statusu
- Pracownik zajmuje się czymś wartościowszym niż kopiowanie statusów
Koszt "gdzie jest moja paczka": 4h × 220 dni × 50 PLN/h = 44 000 PLN/rok na odpowiadanie na pytanie, którego system powinien rozwiązywać automatycznie.
Produkcja: monitoring linii
Bez real-time:
- Maszyna stoi 2 godziny, zanim ktoś zauważy
- Awaria odkryta, gdy pracownik przychodzi po przerwie
- Spadek wydajności widoczny w raporcie dziennym - ale jaka maszyna, o której godzinie?
Z real-time:
- Czujnik wykrywa anomalię (temperatura, wibracje, prędkość)
- Alert natychmiast do technika (push notification)
- Dashboard produkcji: OEE (Overall Equipment Effectiveness) na żywo
- Historia microawarii: "maszyna 3 miała 47 mikroprzestojów w tym tygodniu - wymaga przeglądu"
Finanse: cashflow na żywo
Bez real-time:
- Stan konta sprawdzany raz dziennie rano
- Faktura wystawiona w poniedziałek, zapłata sprawdzana w piątek
- "Czy klient X już zapłacił?" - trzeba sprawdzić w banku
Z real-time:
- Open Banking API: saldo i transakcje na żywo
- Wpłata klienta → automatyczne sparowanie z fakturą → status "Opłacone"
- Alert: "Klient Y nie zapłacił w terminie. Faktura #1234, 15 000 PLN, 7 dni po terminie"
- Dashboard CFO: cashflow, należności, zobowiązania - na żywo
Dlaczego BEAM jest stworzony do real-time
Real-time w Phoenix LiveView nie jest "feature'em do włączenia". To domyślny tryb działania. I to nie przypadek - BEAM (maszyna wirtualna Erlanga/Elixira) został zaprojektowany do systemów telekomunikacyjnych, gdzie real-time to wymóg absolutny.
Miliony połączeń jednocześnie
Każdy użytkownik dashboardu to jedno połączenie WebSocket. BEAM obsługuje miliony jednoczesnych połączeń na jednym serwerze. 500 pracowników z otwartymi dashboardami? To nawet nie rozgrzewka.
Izolacja procesów
Dashboard zarządu, który przelicza roczne statystyki, nie spowalnia dashboardu magazyniera, który skanuje przesyłki. Każdy dashboard to osobny proces BEAM z osobną pamięcią. Crash jednego nie wpływa na inne.
PubSub bez infrastruktury
Phoenix PubSub to wbudowany system publish/subscribe. Nowe zamówienie w bazie → broadcast do wszystkich zainteresowanych dashboardów. Zero Redisa, zero Kafki, zero konfiguracji.
# Broadcast po zapisie zamówienia
def create_order(attrs) do
case Repo.insert(changeset) do
{:ok, order} ->
Phoenix.PubSub.broadcast(MyApp.PubSub, "orders", {:new_order, order})
Phoenix.PubSub.broadcast(MyApp.PubSub, "stats", {:recalculate})
{:ok, order}
error -> error
end
end
# Każdy LiveView nasłuchujący na "orders" dostanie aktualizację
def mount(_params, _session, socket) do
Phoenix.PubSub.subscribe(MyApp.PubSub, "orders")
{:ok, assign(socket, orders: list_today_orders())}
endDiff HTML zamiast pełnego renderowania
Gdy nowe zamówienie pojawia się na dashboardzie, LiveView nie przerysowuje całej strony. Wysyła tylko zmieniony fragment - nowy wiersz w tabeli, zaktualizowaną sumę, przesunięty punkt na wykresie. Transfer danych: bajty, nie kilobajty.
Od raportu do dashboardu - jak migrować
Krok 1: Zidentyfikuj Top 3 raporty
Które raporty generujesz najczęściej? Które trwają najdłużej? Które blokują decyzje? Zwykle to:
- Sprzedaż - dzienna, tygodniowa, miesięczna
- Stany magazynowe - dostępność produktów
- Należności - kto nie zapłacił
Krok 2: Zbuduj jeden dashboard
Zacznij od jednego. Nie od trzech, nie od całego BI. Jeden dashboard, który zastępuje najczęstszy raport.
Dashboard sprzedaży w LiveView:
- Wykres sprzedaży dziennej (porównanie z zeszłym tygodniem/rokiem)
- Top 10 produktów dnia
- Top 10 klientów dnia
- Alerty (spadki, rekordy, anomalie)
- Filtry: data, region, handlowiec, kategoria
Wszystko aktualizuje się na żywo. Zero klikania "Generuj".
Krok 3: Dodaj alerty
Dashboard jest dla ludzi, którzy na niego patrzą. Alerty są dla ludzi, którzy nie mają czasu patrzeć na dashboard:
# Sprawdzaj co 15 minut
{"*/15 * * * *", CheckAlerts}
# Worker
def perform(_job) do
if Sales.today_vs_average() < -0.3 do
Slack.send("#sprzedaz", "Sprzedaż dziś -30% vs średnia. Sprawdź dashboard.")
end
if Inventory.critical_stock_items() |> length() > 0 do
Email.send("magazyn@firma.pl", "Produkty poniżej stanu minimalnego",
Inventory.critical_stock_items())
end
if Finance.overdue_invoices_total() > 100_000 do
Slack.send("#finanse", "Zaległe faktury przekroczyły 100k PLN.")
end
:ok
endAlerty nie zastępują dashboardu - uzupełniają go. Dashboard daje kontekst. Alert mówi "popatrz na dashboard, bo coś się dzieje".
Krok 4: Przenoś kolejne raporty
Każdy kolejny dashboard jest łatwiejszy, bo infrastruktura (LiveView, PubSub, alerty) jest już gotowa. Dodanie nowego dashboardu to dodanie nowego LiveView - dni, nie tygodnie.
Real-time to nie koszt - to przewaga
Firmy, które mają dane na żywo:
- Reagują szybciej na problemy (minuty vs dni)
- Decydują lepiej (dane aktualne, nie sprzed tygodnia)
- Obsługują klientów lepiej (odpowiedź w sekundy, nie "sprawdzę i oddzwonię")
- Tracą mniej na ręczne sprawdzanie i raportowanie
- Widzą trendy wcześniej (spadek w poniedziałek, nie w piątkowym raporcie)
Twoja konkurencja albo już to ma, albo właśnie to buduje. Pytanie nie brzmi "czy potrzebujesz real-time" - brzmi "ile tracisz, nie mając go".
Chcesz zobaczyć, jak Twój najczęstszy raport może wyglądać jako dashboard real-time? Porozmawiajmy - zbudujemy prototyp na Twoich danych w kilka dni.