Secure, test, and operate
Degrade gracefully and finish the board
Complete the project with a stale-state warning, manual refresh, snapshot fallback, and documented limits.
A live feature should get less live during failure, not wrong or blank. When streaming dies, our board keeps the last confirmed incidents, labels how old they are, falls back to slow polling, and offers a manual refresh.
Never delete the HTTP snapshot path after the demo works. That path is the product when the stream is down.
Degrade ladder
1. live SSE or WebSocket stream
2. reconnecting with visible staleness age
3. bounded HTTP polling every 60 seconds
4. manual "Refresh now" button -> GET /api/incidents
function enterFallback() {
setState('stale')
startPolling(60000)
showBanner('Live stream unavailable. Data may be outdated.')
}
When the stream recovers, cancel the slow poll and hide the banner. The user should see the transition, not a magic jump with no explanation.
Finish with a test matrix
Run the complete board through these cases and record pass or fail:
first load
duplicate event ignored
stale event rejected
tab disconnect and replay
server restart with snapshot
slow client disconnected
revoked operator blocked
fallback polling then recovery to live
Hand the checklist to someone else. If they cannot predict the UI from the written steps, improve the copy and the states before you ship.
Document limits beside the feature: max connections, replay window length, message size cap, and what happens when each limit trips.
What the user should see
During fallback the banner might read:
Live stream unavailable. Showing incidents from 6 minutes ago. Refresh now
Clicking refresh hits GET /api/incidents and replaces the list. When SSE connects again, remove the banner and log recovered_to_live so support can correlate tickets.
Ship limits in the same doc: five hundred retained events, thirty second max backoff, sixty second fallback poll. Operators forgive outages they can read about.
A finished board is boring on purpose. First load works offline from cache, live mode works, failure modes read honestly, and every path ends in the same incident list after recovery.
Try this on your own project: run the matrix above, keep the snapshot route alive, and write one paragraph in your README that describes the degrade ladder in plain language.
Lesson completed