Realtime analytics2024Full-stack engineer3 months
Live Sales Board
A realtime sales dashboard streaming aggregated metrics over WebSockets, built to stay smooth on a TV in the ops room for days without a reload.
- Node.js
- WebSockets
- ClickHouse
- React
<1s
data freshness
0
queries against OLTP
7 days
uptime per tab without memory growth
The problem
Reports were generated hourly from the transactional database and slowed checkout whenever someone ran one.
Constraints
- No load on the OLTP database
- Sub-second freshness
- Runs unattended for days
Architecture
Ingest
Kafka
Stream worker
Store
ClickHouse
Rollups
Serve
WS gateway
React board
Key decisions
Decision 01
Push deltas, not snapshots
The gateway sends only changed tiles every 500ms, which kept bandwidth flat as metrics grew.
Trade-off: Clients must resync after reconnecting, handled with a sequence number.
In the code
gateway/src/broadcast.ts
1let seq = 0;23setInterval(async () => {4 const delta = await rollups.changedSince(lastTick);5 if (delta.length === 0) return;6 lastTick = Date.now();78 const frame = JSON.stringify({ seq: ++seq, delta });9 for (const client of wss.clients) {10 if (client.readyState === WebSocket.OPEN) client.send(frame);11 }12}, 500);What I learned
- Long-lived tabs expose every leak. Profile memory, not just frames.