Junior
What protocol delivers live commentary to the browser, and why not regular HTTP requests?
What protocol delivers live commentary to the browser, and why not regular HTTP requests?
Where does the 'status' (scheduled/live/finished) of a match come from?
Where does the 'status' (scheduled/live/finished) of a match come from?
startTime and endTime relative to now, not stored as a user input. Before start = scheduled, between = live, after end = finished.What does HOST=0.0.0.0 mean and why does the container need it?
What does HOST=0.0.0.0 mean and why does the container need it?
127.0.0.1 means only the container itself, so Render’s proxy couldn’t reach it. 0.0.0.0 lets external traffic in.Mid
A new commentary event arrives over WebSocket. Trace how it reaches the screen.
A new commentary event arrives over WebSocket. Trace how it reaches the screen.
useWebSocket’s onmessage → routes to onCommentary → addEvent → setQueryData prepends it to ['commentary', matchId] → the panel re-renders → the new CommentaryEvent animates in.Why is Arcjet mocked in tests instead of using a real key?
Why is Arcjet mocked in tests instead of using a real key?
protect() makes a real network call, which would make tests flaky (network/uptime), slow (round-trip per request), and consume quota. The mock always allows, so tests are fast, offline, deterministic.Why does the commentary query use enabled: matchId !== null?
Why does the commentary query use enabled: matchId !== null?
/matches/null/commentary and 404). It activates automatically the moment a match is chosen.Senior
Why is broadcastCommentary room-scoped but broadcastMatchCreated global?
Why is broadcastCommentary room-scoped but broadcastMatchCreated global?
matchSubscribers map). Sending all commentary to all clients would be wasteful and leak unrelated matches’ data.Explain the three SSL cases in db.ts, and why disabling cert checks is not the same as disabling SSL.
Explain the three SSL cases in db.ts, and why disabling cert checks is not the same as disabling SSL.
{ rejectUnauthorized: false } still attempts a handshake; ssl: false skips it entirely. The plain test DB refuses any handshake, so it needs ssl: false.What's the single change that lets the WebSocket layer scale past one instance?
What's the single change that lets the WebSocket layer scale past one instance?
matchSubscribers map only knows about one instance’s connections.Staff
Argue for keeping the synchronous in-process broadcast, then state the exact condition that invalidates the argument.
Argue for keeping the synchronous in-process broadcast, then state the exact condition that invalidates the argument.
A known 500-vs-404 bug exists with a test pinning the wrong behavior. Why might that be the correct staff decision?
A known 500-vs-404 bug exists with a test pinning the wrong behavior. Why might that be the correct staff decision?
By domain
The level-based sets above span topics. These sets drill a single domain deep.Frontend
Why does MatchCard use React.memo with a custom comparator rather than a default memo?
Why does MatchCard use React.memo with a custom comparator rather than a default memo?
Why is the continuous 'live' pulse done in CSS but the new-event entrance in Framer Motion?
Why is the continuous 'live' pulse done in CSS but the new-event entrance in Framer Motion?
Why are the observability providers nested in a specific order in layout.tsx?
Why are the observability providers nested in a specific order in layout.tsx?
What breaks if you animate a card's height instead of using transform?
What breaks if you animate a card's height instead of using transform?
Why is the 'Live' label's color a theme-aware --live token rather than a fixed red?
Why is the 'Live' label's color a theme-aware --live token rather than a fixed red?
--live holds a different value per theme (#c81e1e light, #f87171 dark). Only colors on a fixed background (the always-yellow header) can be hardcoded.The lint rule flags `setState` in an effect. Why, and what do you do instead?
The lint rule flags `setState` in an effect. Why, and what do you do instead?
wsStatus === 'disconnected' && !errorDismissed), or move the update into the callback of the real external event (reconnect side effects fire from the socket’s onopen, not a status-watching effect). Effects are for syncing with external systems, not for reacting to state to set more state.Why can't you read a ref's .current during render?
Why can't you read a ref's .current during render?
A deployed Next.js site is fetching from localhost. What happened?
A deployed Next.js site is fetching from localhost. What happened?
?? 'http://localhost:8000' fallback got frozen in. Fix: set the var in the deploy env and REBUILD (a Vercel redeploy / a Docker build with the right —build-arg); changing it without rebuilding does nothing.Why do the WS handlers dedup by id before writing to the React Query cache?
Why do the WS handlers dedup by id before writing to the React Query cache?
Matches kept stacking on screen until a refresh fixed it. What was wrong?
Matches kept stacking on screen until a refresh fixed it. What was wrong?
Backend & real-time
Why must close() clear the heartbeat interval, and what went wrong before it existed?
Why must close() clear the heartbeat interval, and what went wrong before it existed?
A malformed JSON frame arrives on the socket. What happens, and why not crash?
A malformed JSON frame arrives on the socket. What happens, and why not crash?
{ type: 'error', message: 'Invalid JSON' } rather than throwing. A single client’s bad frame must never crash the server or affect other clients, hence defensive parsing at the boundary.Why does Arcjet run on the WebSocket upgrade, not just HTTP routes?
Why does Arcjet run on the WebSocket upgrade, not just HTTP routes?
commentary is room-scoped but score_update is broadcast to ALL clients. Why the difference?
commentary is room-scoped but score_update is broadcast to ALL clients. Why the difference?
What does DEMO_MODE do, and why is it in-process instead of an external script hitting the API?
What does DEMO_MODE do, and why is it in-process instead of an external script hitting the API?
Why does the New Relic agent need its own bootstrap.ts entry file instead of just importing it at the top of index.ts?
Why does the New Relic agent need its own bootstrap.ts entry file instead of just importing it at the top of index.ts?
require('newrelic') as the first line works because requires run in the order written. Under ESM, that guarantee breaks: static imports in a file are evaluated before that file’s own body runs, regardless of where they appear in the source, so even a conditional import written above import express would lose, because express’s module gets evaluated first anyway. bootstrap.ts has no other imports of its own, so its conditional New Relic import is guaranteed to run before it dynamically imports index.ts (and everything index.ts pulls in). (See ADR-013.)Data & persistence
Why RESTART IDENTITY in the test reset, beyond just emptying tables?
Why RESTART IDENTITY in the test reset, beyond just emptying tables?
Posting commentary for a non-existent match: what does the DB do, and what does the user see?
Posting commentary for a non-existent match: what does the DB do, and what does the user see?
DevOps, CI/CD & deploy
Why does the Dockerfile copy package*.json before the source code?
Why does the Dockerfile copy package*.json before the source code?
Render doesn't run migrations. What's the consequence and the fix?
Render doesn't run migrations. What's the consequence and the fix?
Why prefer logging to stdout in production over file transports?
Why prefer logging to stdout in production over file transports?
CI runs on every push. Does that stop bad code reaching production?
CI runs on every push. Does that stop bad code reaching production?
Why isn't the deployed smoke test part of CI?
Why isn't the deployed smoke test part of CI?
npm run test:e2e:deployed (excluded from the normal suite with —grep-invert @deployed). Automating it AFTER a deploy, not as a per-push gate, is the right home for it.Testing & quality
The full e2e suite fails with timeouts, but every spec passes when you run it alone, and which specs fail changes between runs. What's the diagnosis?
The full e2e suite fails with timeouts, but every spec passes when you run it alone, and which specs fail changes between runs. What's the diagnosis?
next dev compiling routes on first request: under fullyParallel, several cold compiles serialize past the 30s timeout. Running serially removes the contention (proves it), and the real fix is testing a production build.Why do the Playwright tests run against `next build && next start` instead of `next dev`, and on port 3100?
Why do the Playwright tests run against `next build && next start` instead of `next dev`, and on port 3100?
Why mock the WebSocket with page.routeWebSocket instead of letting the test hit the real backend?
Why mock the WebSocket with page.routeWebSocket instead of letting the test hit the real backend?
Why does the a11y scan wait for opacity:1 before running axe?
Why does the a11y scan wait for opacity:1 before running axe?
The onboarding tour auto-opens on a first visit. Why would that break the e2e suite, and how is it prevented?
The onboarding tour auto-opens on a first visit. Why would that break the e2e suite, and how is it prevented?
navigator.webdriver, which also protects the deployed smoke test), and the mock setup deterministically pre-sets the “seen” flag with page.addInitScript. General rule: any first-run popup must be suppressible in automated runs.Security & scaling
Does Sportz need CSRF protection today? Will it ever?
Does Sportz need CSRF protection today? Will it ever?
At what user count does client-side React Query caching stop helping with DB load?
At what user count does client-side React Query caching stop helping with DB load?
Why does cursor pagination beat offset for a real-time match list?
Why does cursor pagination beat offset for a real-time match list?
offset=100 points at different rows between requests, causing duplicates/skips. CURSOR (keyset) pagination anchors on a fixed value (?after=<createdAt|id> → WHERE createdAt < :cursor), so pages stay stable as new rows arrive. (Cursor pagination isn’t built; the route accepts only limit.)Practical exercise
npm run dev:docker and POST a match + a commentary event with curl while watching a wscat -c ws://localhost:8000/ws connection receive the broadcast. If the event arrives in the socket, you’ve exercised the entire real-time path end to end. Then, in sportz-ui, run npm run test:e2e and watch Playwright build a prod server on :3100 and drive the same path through the real browser: the front-to-back loop, both sides covered.