Skip to content

Latest commit

 

History

History
149 lines (105 loc) · 9.43 KB

File metadata and controls

149 lines (105 loc) · 9.43 KB

Interview walkthrough & “extend it” prep

Public talking points for the 501 Cloud Developer follow-up. Rehearse the 90-second tour first; use the sections below when they ask you to go deeper or extend the system.

Cover sheet for reviewers: SUBMISSION.md


90-second demo script

  1. Live dashboard - open production (or staging). Point out session ID, player photos, scores, active status.
  2. Edit a score - bump a player score; show it persists after reload.
  3. Real-time - open a second tab; change a score in one tab; it appears in the other (Durable Object WebSocket).
  4. Match history - /history → click a completed session → video plays (poster, seek via byte-range).
  5. Security - show packages/db/src/schema.ts RLS policies; withPrincipal() in API routes.
  6. Proof - run npm run db:rls:check or npm run test:rls (isolation is tested, not assumed).
  7. Cloud - mention staging vs production: separate Neon branches, Worker envs, R2 buckets, custom domains.
  8. Analytics - expand live/final analytics panel; charts animate in on session end (rich seed data for realistic race lines).
  9. Operator polish - Share board (URL) vs Copy (UUID); keyboard ? shortcuts; undo appends correcting event (not delete).
  10. History - filter panel + tagged cards; timeline click seeks video; export scorecard preview modal.
  11. Multi-venue - switch Venue A/B; overlay transition; each owner sees isolated data (RLS + owner-scoped cache keys).

Graded README - how to talk through each section

Frontend performance

One-liner: “I treat the dashboard like a venue screen - fast first paint, no jank on score updates, and bounded bundle size.”

Points to hit:

  • Lazy-loaded routes; TanStack Query for cache + dedupe + optimistic score PATCH with rollback
  • Virtualised history list for long session lists
  • Images: fixed dimensions, lazy load, srcset where available
  • Video: preload="metadata" only until play; poster frame first
  • CI enforces bundle budget (npm run size)

If they push: mention PWA Workbox cache for read-only offline history; React Query persist to localStorage.

Arcade motion: intro splash sets brand; live scores use the same bubble/liquid language via ParticleBurst + milestone banners. Optimistic PATCH is never blocked; prefers-reduced-motion and an FX tier toggle keep it accessible on venue tablets.

Images & video

One-liner: “Media goes to R2 behind the CDN; the browser only fetches what the viewport or playback position needs.”

Points to hit:

  • Immutable hashed keys + long cache headers on public assets
  • Signed, short-lived URLs for private uploads
  • MP4 with HTTP Range for seek without full download
  • HLS field in schema + <source> support; offline npm run media:transcode for local/demo pipeline
  • Media Capabilities API ranks sources by device support

Honest gap: automated queue transcoding is designed but not deployed (cost/complexity for take-home).

At scale

One-liner: “Today’s choices work for demo scale; I’d add pagination depth, async media, and observability before thousands of concurrent venues.”

Points to hit:

  • Keyset/cursor pagination (already on list API) + composite indexes
  • Hyperdrive connection pooling; Neon read replicas for read-heavy history
  • Transcoding: R2 upload event → Queue → FFmpeg Container, retries + DLQ, multiple renditions (360p/720p/HLS)
  • WebSockets: Durable Object sharding by session; hibernation for idle rooms
  • KV cache for hot session reads; structured traces Worker → DO → Hyperdrive → Neon

Security concerns

One-liner: “Player names and photos are personal data; I assume a bug in application code and enforce isolation in the database.”

Points to hit:

  • Zod strict on all inputs
  • RLS forced on every table; withPrincipal() sets app.current_owner per transaction
  • Append-only score_events audit trail
  • CORS allowlist, CSP, React XSS defaults
  • Signed media URLs; upload mime/size limits
  • Staging never seeded from production; secrets per environment

Production mitigations

One-liner: “The take-home uses a demo API key; production swaps in real auth and layers WAF, monitoring, and rotation on top of RLS.”

Points to hit:

  • JWT or venue SSO → Worker verification → Neon authenticatedRole + RLS on auth.uid()
  • Cloudflare WAF + rate limits; least-privilege deploy tokens
  • Secret rotation; dependency scanning (CodeQL, Dependabot)
  • Backups / Neon PITR; GDPR erasure path for player photos
  • Error monitoring without leaking stack traces to clients

Likely “extend it” questions

Question Direction
Why arcade motion in an operator dashboard? Instant feedback for score changes; same 501 brand language as the intro; particles are non-blocking overlays with reduced-motion + tier controls
Share board vs Copy match ref? Share copies a deep link (/?session=) for another device; Copy is the raw UUID for support/logs
What happens when you switch demo venues? Clear persisted React Query cache, navigate off stale session routes, exchange auth, reload owner-scoped queries - RLS already isolates rows
Add auth + RBAC Auth provider → JWT in Worker → map to owner UUID → RLS policies use auth.uid() instead of GUC
10k concurrent WebSocket sessions DO per session (already); shard hot sessions; hibernation; backpressure on broadcast; consider pub/sub fan-out
Thousands of sessions in history Virtualised list (done); keyset pagination (done); add search index on created_at + owner
Real transcoding pipeline R2 event → Queue → Container FFmpeg → write HLS manifest back to R2 → update session row
Observability OpenTelemetry from Worker; trace IDs through DO and Hyperdrive; SLOs on PATCH latency and WS connect time
GDPR / data residency EU Neon region; retention job on media; erasure endpoint that deletes R2 objects + DB rows
Why Postgres not Mongo/Firestore? Relational session/player/score model; ACID score updates; RLS is a Postgres strength
Why Cloudflare not AWS? Edge Workers + R2 zero egress + DO for stateful WS; Neon for managed Postgres branching
Why not Next.js? Dashboard is authenticated SPA with live WS - no SEO need; Vite keeps Worker/Pages deploy simple

Things to flag honestly

Topic What to say
Demo API key in bundle Take-home stand-in; production uses JWT and never ships secrets in the SPA
WS ?key= query param Browser can’t set custom headers on WebSocket; production uses cookie session
FFmpeg offline only Avoids paid Container hours in a take-home; architecture doc shows queue path
E2E in CI May need DATABASE_URL secret; RLS tests prove the critical isolation path

Full gap list: checklists/03-known-gaps.md.


Files worth having open

File Why
apps/web/src/routes/Overview.tsx Live scores + optimistic PATCH
apps/api/src/routes/sessions.ts REST handlers + withPrincipal()
apps/api/src/durable-objects/session-room.ts WebSocket broadcast
packages/db/src/schema.ts Tables + RLS policy definitions
packages/db/src/with-principal.ts How RLS context is set
apps/web/src/routes/History.tsx Virtualised history + filters
apps/web/src/components/HistorySessionCard.tsx Tagged cards + game-format accents
apps/web/src/lib/auth.tsx Venue switch + owner-scoped cache reset

Questions to ask them (optional)

  • How does the 501 Hub split venue-operator vs player-facing surfaces today?
  • Where does live game state originate - on-prem hardware, edge devices, or cloud?
  • What media formats do venues upload today, and is transcoding centralised?

Shows curiosity about their domain without overstepping the take-home scope.