- Remove unused initCount state from useAuthGate hook
- Replace magic number with MAX_SAVES_PER_USER constant in saves route
- Extract duplicated EMAIL_REGEX and MIN_PASSWORD_LENGTH in auth routes
- Fix game-simulation typecheck failure by adding DOM lib to tsconfig
- Extract store UI types (ActivePage, InfraNav, etc.) to store/types.ts
- Fix let→const for non-reassigned arrays in servingPipeline
- Fix useless initial assignments in reputationSystem
- Fix ambiguous multiline array access in sanityChecks
- Add minimal ESLint config with typescript-eslint
- Add .planning/ and *.log to .gitignore
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Stop 401 responses from wiping local saves and force-reloading. Fix logout
race condition with final cloud save before token invalidation. Replace
hard 3-failure cap with exponential backoff (2min to 30min). Switch cloud
save interval from tick-based (30s) to wall-clock (5min). Add cloud save
status indicator and Force Save button in TopBar. Show save conflict
dialog on login when both local and cloud saves exist. Add cloud save
list, download, and delete in Settings. Server now keeps 10 save snapshots
per user instead of overwriting a single save.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Cloud saves were fully built but never wired up — useCloudSave() hook was
never called, no load-from-cloud flow existed, and there was no way to
continue a saved game. Logout was completely missing (no endpoint, no UI).
Accounts felt like a gate behind the invite wall rather than real accounts.
Backend: add tokenVersion to users for server-side token invalidation,
POST /auth/logout bumps it to revoke all JWTs, GET /auth/me returns
profile, GET /saves/latest returns most recent save with full gameData.
All createToken calls now include tokenVersion. Auth middleware rejects
tokens with stale tokenVersion.
Frontend: wire up useCloudSave() in App (auto-saves every 60 ticks with
error handling), fetch cloud save on startup for registered users, show
"Continue Your Game" card on NewGameScreen, add Log Out button with
confirmation in Settings, show username in sidebar, 401 interceptor
clears auth and reloads.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Seed checks for any admin role instead of username='admin'
- Username change open to all registered users (was admin-only)
- New change-email endpoint requiring password confirmation
- Settings page: inline editing for username and email
- Invitations: await refresh after generate so list updates visibly
- Invitations: revoke button to delete unused invites (admin only)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Frontend API_BASE is /api in production, so health check was hitting
/api/health which didn't exist. Added /api/health on the server and
removed the now-unnecessary separate nginx /health proxy rule.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Run Drizzle migrations before seeding admin user so tables exist
on fresh database. Migration files generated from current schema.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The production Docker stage was copying pnpm symlinks between stages
which broke module resolution. Now does a fresh pnpm install --prod
in the production stage and runs from the server working directory.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Server app (apps/server) with Hono framework and Drizzle ORM:
- PostgreSQL schema: users, saves, leaderboard, achievements tables
- Anonymous auth with UUID tokens, optional email/password linking
- Cloud save API: list, get, upsert, delete with auto-save hook
- Leaderboard API: per-category rankings with score submission
- CORS configured for dev server ports
- Typed middleware with Hono env variables
Frontend cloud save integration:
- API client with auth token management in localStorage
- useCloudSave hook auto-saves every 300 ticks when authenticated
- Vite env type declarations for VITE_API_URL
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>