Skip to content

Improvement Backlog

Prioritized improvements identified in May 2026. Ordered from quick wins to larger architectural changes. Redis is already planned — see Roadmap for the full implementation spec.


Medium Effort — High Value

5. Push notifications for game-ending events

Files: apps/server/src/game/game.gateway.ts

Currently push notifications only fire on "your turn." Adding notifications for gameAbandoned and turnTimeout is a small addition — same notificationsService.sendPushNotification() call with new message templates. Meaningful UX improvement for testers not watching the screen when their opponent leaves or times out.

Suggested messages:

EventTitleBody
Opponent timed out"You win!""{opponentName} ran out of time"
Opponent abandoned"You win!""{opponentName} abandoned the match"

7. Socket connection hardening (playerId spoofing prevention)

Files: apps/server/src/matchmaking/matchmaking.gateway.ts, new auth utility

The identify event accepts any playerId string without verification that it matches the connected Clerk user. Before opening to testers, add a short-lived server-issued connection token (issued at REST login, validated on identify) so players cannot claim each other's IDs. More critical than it sounds once multiple accounts share a device or session.


Larger Changes

8. Rate limiting on socket events

Files: apps/server/src/game/game.gateway.ts, apps/server/src/matchmaking/matchmaking.gateway.ts

makeMove and joinQueue have no per-socket throttle. Before the 10–15 person test phase, add a sliding-window rate limiter in the gateway layer. NestJS @nestjs/throttler supports WebSocket guards. Prevents accidental double-submits, reconnect storms, and deliberate abuse.

bash
pnpm --filter @band-game/server add @nestjs/throttler

9. Automated DB migrations in the deploy pipeline

Files: apps/server/railway.json

db:push is currently a manual step — the wiki notes it must be run before or after deploying breaking schema changes. A missed step leaves schema and code out of sync in production. Add drizzle-kit push as a pre-start command in railway.json so migrations apply automatically on every Railway deploy.

json
"deploy": {
  "startCommand": "pnpm run db:push && pnpm run build && node dist/main"
}

10. Client state management refactor (prerequisite for Redis)

Files: apps/client/services/GameService.ts, new apps/client/stores/

GameService currently has 38+ listener Sets as a pure singleton. Adding more real-time events makes state ownership harder to track and debug. Migrating client state to Zustand with typed slices (matchSlice, queueSlice, friendsSlice) would improve maintainability and is a natural prerequisite for the multi-instance Socket.IO changes the Redis rollout will require.

This is the largest item here — do it before Redis, not after.



Dropped / Superseded

In-memory Spotify band validation cache

Dropped in favour of a planned three-tier validation pipeline:

text
Submit band
  → check recent 100 played bands (fast DB query, hot bands)
  → miss → check full bands table (historical)
  → miss → hit Spotify

An in-memory server cache would sit between layers 2 and 3 and add complexity without meaningful benefit — the DB lookup is already fast and survives restarts. Implement the "recent 100" layer instead when the time comes.


Done

Pre-commit hooks (Husky + lint-staged) + GitHub Actions CI

Shipped: May 2026 — commit d31702c
Files: root package.json, .husky/pre-commit, .husky/pre-push, .github/workflows/ci.yml

Husky + lint-staged runs ESLint + Prettier on staged apps/server/src/**/*.ts files before every commit. A pre-push hook runs the full Vitest suite and tsc --noEmit before anything reaches the remote. The GitHub Actions workflow (lint → typecheck → test) runs on every push to main/feat/** and on PRs — Railway can be configured to only deploy on workflow success, completing the CI gate.


Spotify API failure → retry / non-fatal path

Shipped: May 2026
Files: apps/server/src/spotify/spotify.service.ts, apps/server/src/game/game.service.ts

On API failure, validateBand now retries once (forcing a fresh token on retry). If the second attempt also fails, it returns apiError: true with the message "We couldn't verify this band, please try again". makeMove short-circuits on apiError — the move is rejected non-fatally so the player can resubmit. Only genuine "band not found" or "too few followers" results end the game.


Reorder validation: letter-chain check before Spotify lookup

Shipped: May 2026 — commit d012099
Files: apps/server/src/game/game.service.ts

Moved the letter-chain check before the Spotify lookup so obvious chain violations fail instantly with zero network calls. Also checks "The " + submittedName as a fallback so submitting e.g. "beatles" when the last band ends in T still passes through to Spotify (the canonical "The Beatles" satisfies the special-T rule). A post-Spotify re-check is retained for the rare case where the canonical name differs from the submitted name and changes the chain outcome.