Kilo Dispatch
A live control room for 900 couriers
The web console dispatchers use to watch every courier, reassign orders and spot late deliveries before customers do. It renders the whole fleet live on one map without dropping frames.
- 900
- couriers tracked live
- 60fps
- map with the full fleet on screen
- −31%
- late orders in the first quarter
The problem
Dispatchers juggled three tools: a map that refreshed every 30 seconds, a spreadsheet of orders and a group chat with drivers. Late orders were noticed when a customer phoned in.
Constraints
- Up to 900 moving markers and 4,000 open orders on screen at once.
- Dispatchers keep the console open for a 10-hour shift, so memory must stay flat.
- It must share the same real-time channel as the courier app.
How it fits together
In the browser
- Next.js console
- MapLibre GL symbol layer
- Order queue with live ETAs
In the cloud
- WebSocket gateway
- Redis pub/sub
- ETA service
- PostgreSQL
Key decisions
Markers drawn by the GPU, not the DOM
Couriers render as a single MapLibre symbol layer fed from a typed array and updated in place. Moving off DOM markers took a full-fleet frame from 48 ms to under 6 ms.
One socket, shared with the app backend
The console subscribes to the same Redis-backed channels as the courier app, with sequence numbers for replay, so the map and the drivers never disagree.
Lateness is predicted, not reported
Each order carries an ETA that updates with the courier’s position. Orders at risk rise to the top of the queue ten minutes before they are late.
Outcome
Late orders fell 31% in the first quarter, and dispatchers retired the spreadsheet and the group chat in the second week.
What I’d change
Keyboard shortcuts came late. Dispatchers live in this screen all day and should have been able to reassign an order without touching the mouse from the start.
Stack
- Next.js
- React
- TypeScript
- MapLibre GL
- WebSockets
- TanStack Query
- Playwright