A cloud-kitchen brand ran 38 kitchens across 7 cities, taking orders from Swiggy, Zomato, and its own app. The ops team watched five tabs per city and still missed kitchens that quietly fell 20 minutes behind during the dinner rush. We built one live dashboard that shows every order's state in real time, balances load across kitchens in the same zone, and flags a kitchen before it breaches SLA. Average order-ready delay in the peak hour dropped from 19 minutes to 7. This is the architecture, the WebSocket choices, and the KPIs that turned out to matter.
7 min
Peak-Hour Order-Ready Delay (was 19)
38
Kitchens On One Live Board
~900ms
Order-Event to Dashboard Update
31%
Fewer SLA Breaches in Month 1
## The answer in 60 words
We built a single React dashboard fed by a WebSocket gateway. Order events from Swiggy, Zomato, and the in-house app land in a queue, get normalised, and stream to the dashboard and a Postgres + Redis store. A load-balancing service watches kitchens in the same zone and suggests rerouting new orders away from any kitchen trending late. Build time: 6 weeks. Run cost: about ₹34,000/month on AWS Mumbai.
## Why a polling dashboard wasn't enough
The brand's first attempt was a dashboard that polled each platform's API every 30 seconds. During the dinner rush, 30 seconds is the difference between catching a backed-up kitchen and finding out when a customer complains. Polling also hammered rate limits and gave a stale, jumpy view. The ops head's actual ask was blunt: "I want to see a kitchen going red before the food does." That needs a push pipeline, not a poll. As
Manvi, our QA lead, framed it during testing: a dashboard you don't trust in the rush is a dashboard nobody opens.
## The before state
🗂️
Five Tabs Per City
Each city ops person juggled Swiggy partner, Zomato partner, the app's admin, a WhatsApp group, and a spreadsheet. No single view of "where is every order right now."
⏱️
30-Second Stale Data
Polling meant the board lagged reality by up to half a minute. Late kitchens surfaced after the SLA was already at risk, not before.
🔥
No Zone-Level Load View
Two kitchens 3 km apart: one slammed, one idle. No tool surfaced this, so orders kept stacking on the busy one until it breached.
📞
Reactive, Not Proactive
The ops team learned about delays from customer-care escalations. By then the damage — a 1-star rating, a refund — was done.
## The architecture — how order events flow
📥
Platform webhooks + app events land in an SQS queue
🧹
A normaliser maps every platform to one order schema
💾
State written to Postgres (durable) + Redis (live)
📡
WebSocket gateway pushes deltas to the dashboard
⚖️
Load service flags late kitchens + suggests reroutes
### Why a queue in front of the WebSocket layer
Swiggy and Zomato fire webhooks in bursts. If those hit the WebSocket layer directly, one platform's retry storm can stall the whole board. We put an Amazon SQS queue in front so spikes are absorbed and the normaliser processes at a steady rate. The dashboard reads a clean, ordered stream — never the raw firehose.
### Why Postgres and Redis, not one or the other
Postgres holds the durable record — every order, every state transition, queryable for the KPIs. Redis holds the live picture each kitchen and city needs right now, and backs the WebSocket fan-out. Reads for the live board hit Redis in single-digit milliseconds; the analytics and audit trail come from Postgres. Splitting them kept the rush-hour board fast without giving up history.
## The WebSocket layer — the choices that mattered
We used a Node.js gateway with the
ws library behind an AWS Application Load Balancer with sticky sessions. Each connected client subscribes to a city, and within it to a set of kitchens. We push deltas, not full snapshots — a single order's state change is a few hundred bytes, so the board stays current at about 900 ms from event to pixel even on a city ops laptop on office wifi.
The decision that saved us: push deltas keyed by order ID, and have the client keep its own state map. Re-sending the whole board on every change looked simpler in week one and fell over at 38 kitchens. Deltas plus a periodic reconciliation snapshot every 60 seconds gave us both speed and a self-healing client.
### Reconnection without losing state
Wifi drops. A laptop sleeps. When a client reconnects, it sends the last event sequence number it saw; the gateway replays anything missed from a short Redis buffer, then resumes the live stream. No full reload, no blank board mid-rush. We learned this the hard way — the first version showed an empty board for a few seconds on every reconnect, which ops people read as "the system is down."
## Kitchen-load balancing — the part that moved the metric
The live view was useful. The load service is what dropped the delay number. It watches, per zone, each kitchen's open-order count, its rolling average prep time over the last 20 minutes, and its rider-pickup backlog. When a kitchen trends late, new orders in that zone get a "suggest reroute" flag pointing at a nearby idle kitchen.
| Signal | What it measures | Reroute trigger |
|---|---|---|
| Open-order count | Orders accepted, not yet ready | More than 1.5x zone median |
| Rolling prep time | Last-20-min average ready time | Trending up 30% vs the kitchen's baseline |
| Rider backlog | Ready orders waiting for pickup | 3+ orders waiting over 6 minutes |
| Composite "heat" | Weighted blend, 0–100 | Above 75 turns the kitchen amber, 90 red |
We deliberately made reroute a suggestion, not an automatic action. A human ops lead confirms, because the model can't see a fryer that just went down or a delivery partner that's out of riders in that pocket. Suggestion plus one-click confirm beat full automation in every week of testing.
## The DIY-grade build notes
-
Frontend: React with a thin state store; the WebSocket client owns the live order map. Color states (green/amber/red) computed client-side from the composite heat score the server sends.
-
Gateway: Node.js +
ws, fronted by an ALB with sticky sessions; horizontal scale by city shard.
-
Queue: Amazon SQS for burst absorption; a dead-letter queue catches malformed platform payloads for replay.
-
Stores: Postgres 16 for durable order history and KPI queries; Redis 7 for live state and the reconnect replay buffer.
-
Infra: AWS Mumbai (ap-south-1), about ₹34,000/month at this scale, tested May 2026.
The clock-skew trap: order timestamps come from three platforms plus your own app, and they don't agree to the second. We normalise every timestamp to UTC at ingestion and treat the gateway's receive time as the source of truth for "how late is this order." Trusting platform-supplied timestamps gave us kitchens that looked early and late at the same instant. Pick one clock and convert everything to it.
## Common mistakes — when a real-time dashboard is the wrong call
Mistake 1 — building WebSockets when you take 50 orders a day. Under a few hundred orders a day, a 10-second poll is honestly fine and a tenth of the cost. We only reach for a push pipeline when stale data has a visible business cost during a peak. If your rush isn't sharp, you may not need this.
Mistake 2 — auto-rerouting orders with no human in the loop. The model can't see a broken fryer or a rider shortage in one pocket. Auto-reroute will confidently send orders to a kitchen that's about to go down. Keep the human confirm.
Mistake 3 — putting analytics queries on the live path. A heavy "orders by city this month" query against the same store the live board reads will stutter the board mid-rush. Run analytics off Postgres read replicas or a nightly rollup, never off the Redis live layer.
Mistake 4 — no reconnect strategy. A board that blanks on every wifi blip trains ops to distrust it. Sequence numbers plus a short replay buffer are not optional at this scale.
## Real example — the metric that surprised us
Across the 38 kitchens, peak-hour order-ready delay fell from 19 minutes to 7 in the first month, and SLA breaches dropped 31%. Those were the targets. The surprise was a zone-level finding the dashboard surfaced once load was visible: in one city, two kitchens 3 km apart had wildly different prep times for the same menu — one consistently ran 8 minutes slower. The board made it obvious, the ops head visited, and the cause was a single under-trained station. A two-day retraining closed most of the gap. The dashboard's biggest win was making a hidden operational problem impossible to ignore.
We applied the same event-streaming spine our
web application team uses on real-time builds. For a different live-tracking domain, see our case study on a
fleet-tracking dashboard for 60 trucks on MQTT and TimescaleDB, and for the logistics SaaS variant,
a logistics fleet-tracking SaaS dashboard on AWS. The proof-of-work pattern is the same as the live pipeline behind
TalkDrill's session telemetry. As
Hrishikesh notes, real-time is a discipline, not a feature: you earn it by handling reconnects, skew, and backpressure before you add a single chart.
- Your peak-hour volume makes 30-second-stale data visibly expensive
- You take orders from 2+ sources (Swiggy, Zomato, own app) you must unify
- You can put a queue (SQS or similar) in front of your WebSocket layer
- You split durable history (Postgres) from live state (Redis)
- You push deltas, not full snapshots, and keep client-side state
- You handle reconnect with sequence numbers and a replay buffer
- You normalise every timestamp to one clock at ingestion
- You keep load-balancing as a suggestion with a human confirm
- You run analytics off replicas, never the live read path
## FAQ
### Why WebSockets and not server-sent events or polling?
Polling lags reality and burns rate limits during a rush. Server-sent events work for one-way pushes and are simpler, but we wanted the client to send subscription changes (switch city, focus a kitchen) over the same connection, so a full-duplex WebSocket fit better. For a read-only board with no client-to-server messages, SSE is a fair, simpler choice.
### How do you keep the dashboard fast with 38 kitchens streaming at once?
Three things: push small deltas keyed by order ID rather than full snapshots, serve live reads from Redis instead of Postgres, and shard WebSocket connections by city so no single gateway carries all traffic. Event-to-pixel stays around 900 ms even on office wifi.
### What happens when a delivery platform's webhook is delayed or fails?
Webhooks land in SQS, so a delay just means the event arrives later and the order's state catches up. For total platform outages we fall back to a slower poll for that one source while keeping the rest live. Malformed payloads go to a dead-letter queue for replay rather than crashing the normaliser.
### Can the load balancer reroute orders automatically?
Technically yes, but we ship it as a suggestion with one-click confirm. The system can't see a broken appliance or a local rider shortage, so a human ops lead makes the final call. After a month of correct suggestions, some clients enable auto-reroute for low-risk zones only.
### What does a build like this cost and how long does it take?
Six weeks for a 7-city, multi-platform build with load balancing, and about ₹34,000/month to run on AWS Mumbai at 38 kitchens. A single-city pilot to prove the pipeline runs in roughly two to three weeks and a fraction of the infra cost.
### Does this work for retail or field service, not just food?
Yes. The spine — event queue, normaliser, durable plus live stores, WebSocket fan-out, a load or status service — is the same for any business tracking many live jobs across locations. We've used variants for field-service dispatch and warehouse pick-and-pack. Only the domain rules and the KPI definitions change.
Need a Real-Time Operations Dashboard Built?
We build live order, fleet, and field-service dashboards for Indian operations teams — WebSocket pipelines, multi-source order unification, and load views that flag trouble before customers do. Single-city pilot in 2–3 weeks. First call is technical, with the engineer who'd lead your build.
Book a 20-min Call