mancala/TODO.md

3.9 KiB

TODO

Auth

Mobile login with Keycloak (phase 5)

The web app logs in with Keycloak; the mobile app still uses the legacy ?userKey= login.

  • Add a mancala-mobile public client to apps/keycloak/realm/mancala-realm.json (PKCE S256, redirect com.mancala_mobile://callback) and to KEYCLOAK_CLIENT_IDS for the backend
  • Add react-native-app-auth with the redirect scheme set up for Android and iOS
  • Log in as a guest on first launch (guest=true), with offline_access; keep tokens in MMKV
  • Connect with rtmt.connectWebSocket(url, getToken) instead of ?userKey= (apps/mobile/src/App.tsx) and call reauthenticate after refreshing the token
  • Log in / sign up / log out in the app, player names on the game screen (getPlayerDisplayName in core)
  • Decide whether guests may skip the browser tab on first launch (would need a custom grant type in the Keycloak extension)
  • Delete the unused copy of the WebSocket client in apps/mobile/src/rtmt
  • Test on a device

After the mobile release

  • Turn off LEGACY_USERKEY_AUTH once old app versions are no longer in use; this also removes /register

Later

  • Let guests turn their guest user into an account without changing identity (Keycloak required action)
  • Stats and game history for logged in users (needs a database)
  • Social logins (Keycloak identity providers)
  • Restrict the Keycloak admin console in production

Deployment

  • Build the backend and frontend images from the repo root in CI: docker build -f apps/backend/Dockerfile . and docker build -f apps/frontend/Dockerfile .
  • Pass --build-arg KEYCLOAK_URL=https://auth.playmancala.app when building the frontend image
  • Deploy Keycloak (apps/.env with KEYCLOAK_DB_PASSWORD, KEYCLOAK_ADMIN_PASSWORD, KEYCLOAK_HOSTNAME=https://auth.playmancala.app) and reload nginx with the new auth.playmancala.app block
  • Deploy the backend before the web app; the new web app needs token auth on the server

Security

  • Move the Android signing passwords out of apps/mobile/release_android.sh (committed in bb1c750) into ~/.gradle/gradle.properties or environment variables, and consider resetting the upload key
  • Add apps/mobile/mancala-upload-key.jks to .gitignore (only android/app/mancala-upload-key.jks is ignored)
  • Validate moves before running them instead of treating every invalid move as a crash: each one writes a file to crashes/ and is broadcast to the players (GameManager.onGameError)

Bugs

  • GameStoreImpl.getSpeactatingGameIdsByUser loops with for...in over an iterator, so it never finds anything and spectators are never removed on disconnect; use for...of
  • Finished and abandoned games are never removed from gameStore (deleteGame only removes the user mappings), so they stay in memory until restart
  • PitAnimator.animatePit: previousPitIndex > 0 should be >= 0; a one-stone move from pit 0 does not empty that pit during the animation
  • PitAnimator.dispose removes a newly bound function, so the theme listener is never removed
  • Sowing puts stones into the opponent's store; check against the intended Mangala rules and add a test
  • MatchMaker.join does not check whether the player is already in a game
  • GameManager.startGame sends the connection info twice
  • onGameError broadcasts an Error, which serializes to {}

Maintenance

  • The web and mobile apps duplicate components and stores; move shared code into packages/core
  • Mixed lockfiles: packages/* and apps/mobile have both yarn.lock and package-lock.json
  • Align TypeScript and Jest versions across packages
  • Tests for GameManager, MatchMaker and PitAnimator
  • CI that runs the tests
  • Pre-existing type errors: 4 in the frontend, 11 in mobile; the frontend has no tsconfig.json, so nothing type-checks it