Problem. Patron phones poll every 2s (SessionParticipant/Lobby POLL_MS=2000, RoundOrigin active-count 2s). At ~1000 concurrent users that is ~500 DB-touching req/s, sustained. On Vercel serverless the asyncpg pool (api/db.py max_size=5) is per-λ-instance, so concurrency multiplies connections into a single small Neon Postgres — this is the real first scaling wall (before missing indexes bite).
Fix. Supabase Realtime broadcast is already the planned transport (useSessionChannel exists, hook is wired in both participant + origin views). Drive view updates from broadcast events and demote the HTTP poll to a slow safety net (~10–15s) instead of 2s. Cuts sustained QPS ~10–50×.
Note. Polling is the dominant lever; fixing this makes the index question largely moot at launch scale.
Problem. Patron phones poll every 2s (
SessionParticipant/LobbyPOLL_MS=2000,RoundOriginactive-count 2s). At ~1000 concurrent users that is ~500 DB-touching req/s, sustained. On Vercel serverless the asyncpg pool (api/db.pymax_size=5) is per-λ-instance, so concurrency multiplies connections into a single small Neon Postgres — this is the real first scaling wall (before missing indexes bite).Fix. Supabase Realtime broadcast is already the planned transport (
useSessionChannelexists, hook is wired in both participant + origin views). Drive view updates from broadcast events and demote the HTTP poll to a slow safety net (~10–15s) instead of 2s. Cuts sustained QPS ~10–50×.Note. Polling is the dominant lever; fixing this makes the index question largely moot at launch scale.