The Jenkins job's steps live only in Jenkins; note the image builds, the env file, the nginx block and the checks the Java backend needs.
9.3 KiB
9.3 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-mobilepublic client toapps/keycloak/realm/mancala-realm.json(PKCE S256, redirectcom.mancala_mobile://callback) and toKEYCLOAK_CLIENT_IDSfor the backend - Add
react-native-app-authwith the redirect scheme set up for Android and iOS - Log in as a guest on first launch (
guest=true), withoffline_access; keep tokens in MMKV - Connect with
rtmt.connectWebSocket(url, getToken)instead of?userKey=(apps/mobile/src/App.tsx) and callreauthenticateafter refreshing the token - Log in / sign up / log out in the app, player names on the game screen (
getPlayerDisplayNamein 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
Game history on mobile
The web app has game history (see docs/specs/game-history); the mobile app needs Keycloak login first.
- Ongoing-game banner, live and popular games, recent games on the home screen
- Move list and looking back during a live game; replay of finished games
After the mobile release
- Turn off
LEGACY_USERKEY_AUTHonce 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)
- Statistics for logged in users (wins, losses), now that games are saved
- Social logins (Keycloak identity providers)
- Keycloak email theme in the game's look (password reset emails still use Keycloak's)
- Restrict the Keycloak admin console in production
Game history
- A page with all of a user's games (the home page shows the last 3)
- Show games of deleted accounts differently, once accounts can be deleted
- Live game state, previews and spectators assume a single backend instance; share them (e.g. Valkey pub/sub) before running more than one
- If Valkey is unreachable when the backend starts, live games are not restored until the next restart
Game clock
See docs/specs/game-clock.
- Other time controls or time added per move; a long move animates on the next player's time
- Clocks in the home page's live game previews and in the ongoing-game banner
- Try the mobile clocks on a device; only the type check and the bundle were run
Game bot
See docs/specs/game-bot.
- Play against the bot without a connection (a bot in the TypeScript engine on the device)
- Keep bot games apart once there are statistics or ratings
- Hints or move analysis for players, with the same search
- Rebuild
MancalaGameonPosition, or usePositionto check moves before running them (see Security) - Tune the levels from real games (
games.botholds each game's level, strength and seed) - Try the bot on a mobile device; only the type check and the bundle were run
Tutorial
See docs/specs/tutorial.
- Lessons and hints in the mobile app, once it has the new design (it has the rules screen)
- Hints that look ahead, e.g. a warning when a move lets the opponent capture (the bot's search could do it)
- Strategy lessons beyond the rules
- Tutorial progress per account instead of per device
- If the end-of-game rule changes (Game rules below), update
RuleEndOfGameText2inen.tsandtr.ts
Web redesign
See docs/specs/web-redesign.
- Bring the new design to the mobile app (themes, board, game screen)
- The design's "Sound effects" switch in the settings menu, once the app has sounds
Rematch
See docs/specs/rematch.
- Rematch and the series strip in the mobile app, with its new design; until then a web player's request to a mobile player ends after a minute
- Series of a fixed length ("best of 3") and a series winner
- Group series in the game history and on the home page (
games.series_id) - Take spectators along to the next game of a series
- Leaving the game page does not answer a request; the opponent waits for the minute to pass
Deployment
- Document the deployment (e.g.
docs/deployment.md, or aJenkinsfilein the repo). Today it is a Jenkins job atci.playmancala.appwhose shell steps live only in Jenkins; it still builds fromapps/backendandapps/frontendand runscd apps && docker compose up -d. For the Java backend it needs: -docker build -f apps/backend/Dockerfile -t jhalitaksoy/mancala-backend:latest .from the repo root -docker build -f apps/frontend/Dockerfilewith--build-argSERVER_ADDRESS=https://api.playmancala.app,WS_SERVER_ADDRESS=wss://api.playmancala.app,KEYCLOAK_URL=https://auth.playmancala.app-docker build -t jhalitaksoy/mancala-keycloak:latest apps/keycloak-docker compose --env-file <path>/mancala.env up -dinapps, with the env file kept outside the Jenkins workspace (POSTGRES_PASSWORD,KEYCLOAK_DB_PASSWORD,MANCALA_DB_PASSWORD,KEYCLOAK_ADMIN_USERNAME,KEYCLOAK_ADMIN_PASSWORD,KEYCLOAK_HOSTNAME=https://auth.playmancala.app,LEGACY_USERKEY_AUTH) - Once, by hand: theauth.playmancala.appblock ofconfig/nginx.confon the server and an nginx reload. DNS and the certificate forauth.playmancala.appalready exist - If Jenkins runs in a container with the host's Docker socket, the./postgres/initbind mount points at a path the host does not have and the databases are not created; check before the first deploy - Which branch the job builds, and whether it builds on push - Build the backend and frontend images from the repo root in CI:
docker build -f apps/backend/Dockerfile .anddocker build -f apps/frontend/Dockerfile . - Pass
--build-arg KEYCLOAK_URL=https://auth.playmancala.appwhen building the frontend image - Deploy Keycloak (
apps/.envwithKEYCLOAK_DB_PASSWORD,KEYCLOAK_ADMIN_PASSWORD,KEYCLOAK_HOSTNAME=https://auth.playmancala.app) and reload nginx with the newauth.playmancala.appblock - Deploy the backend before the web app; the new web app needs token auth on the server
- The backend is now Java (Quarkus, see
docs/specs/quarkus-backend); the compose file passes the database asDATABASE_JDBC_URL/DATABASE_USERNAME/DATABASE_PASSWORDbuilt from the sameMANCALA_DB_PASSWORD, soapps/.envneeds no change. It reads the Node backend's database and live games, so it can replace it (and be rolled back) without ending games - Release the mobile update with the game clock before or with the backend: older app versions do not show the
clock and do not handle
on_game_end, so a game they lose on time does not end for them - Back up the Postgres volume (Keycloak and saved games), e.g. a daily
pg_dumpall - Set
MANCALA_DB_PASSWORDandPOSTGRES_PASSWORDinapps/.envon the server; thepostgresvolume replaceskeycloak-db, so Keycloak starts with a fresh database there - Last step: publish a new
mancala.jsto npm (it is at0.0.2-beta.3from 2022), so the published engine skips the opponent's store when sowing. The apps do not need it; they usepackages/mancala.jsthroughlink:
Security
- Move the Android signing passwords out of
apps/mobile/release_android.sh(committed inbb1c750) into~/.gradle/gradle.propertiesor environment variables, and consider resetting the upload key - Add
apps/mobile/mancala-upload-key.jksto.gitignore(onlyandroid/app/mancala-upload-key.jksis 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, kept as it was in the Node backend)
Game rules
- Decide who gets the remaining stones when a move empties the opponent's side (e.g. a capture takes their last
stones). Now the player whose side is empty always gets the other side's stones (
GRClearBoardAtEnd), even when the opponent emptied it; some Mangala rules give them only to a player who emptied their own side. Analyse the rule first, then decide
Bugs
PitAnimator.disposeremoves a newly bound function, so the theme listener is never removedonGameErrorbroadcasts{}instead of the error (the Java backend sends{}on purpose, as the Node backend did)
Maintenance
- The web and mobile apps duplicate components and stores; move shared code into
packages/core - Mixed lockfiles:
packages/*andapps/mobilehave bothyarn.lockandpackage-lock.json - Align TypeScript and Jest versions across packages
- Tests for
MatchMaker;PitAnimatoris only tested for the first frame of a move - CI that runs the tests (the backend's need a JDK 25 and Docker)
- The rules exist twice, in
packages/mancala.jsand in the backend's Java port; a parity test keeps them alike, but every rule change has to be made in both - Pre-existing type errors: 1 in the frontend (
react-dom/client), 11 in mobile; the frontend has notsconfig.json, so nothing type-checks it