- GET /games/me/active and /games/me (Bearer token), /games/popular (live
games, or the most spectated finished ones), and /game/:id now also
returns saved records of finished games
- Lists are cached in Valkey for 10 seconds, cleared when a game is saved,
and empty instead of failing while the database is down
- Live game previews over WebSocket: subscribers get the top 5 on
subscribe and on change, at most once per second, without counting as
spectators; ids are public ids
- RTMT supports several connection listeners
- Games record start and move times, spectator peak and distinct count
- Games end as completed, left (the leaver loses), timeout (5 minutes
offline on your turn while the opponent is online) or inactive (both
offline for 30 minutes); everyone gets on_game_end
- Connection info carries offlineSince for the countdown
- A new game is rejected while the user has one in progress
- Live games are written to Valkey after every change and restored on
startup; finished games are saved to Postgres with public ids, and
saves that fail are kept and retried every 30 seconds
- Clients get a trimmed game without spectator ids
- Startup waits for Valkey, restores games, then accepts connections;
migrations are retried while Postgres is unreachable
- Spectators are removed from games when they disconnect; the lookup
iterated an iterator with for...in and never found anything
- Finished and left games are removed from memory, not only from the
player mappings
- The connection info is sent once when a game starts