7 Commits
Author SHA1 Message Date
tiennm99 42d94a2aed fix: wire up spectator mode end-to-end
Watch feature was half-implemented since day one and stayed broken through
the typed-protobuf migration:

1. Server (WatchGameHandler): only pushed the WatchGameSuccessResponse ack.
   A mid-game watcher joined a blank scene because the server never told
   them who the players were or what moves had been played.
2. Client: had a Watch button that sent the request but no event bus
   handler for GAME_WATCH_SUCCESSFUL, so nothing happened visually.

Server fix:
- On successful watch, if room.status == STARTING, bootstrap the watcher
  with a synthesised GameStartingResponse (player ids, nicknames, board
  size) and replay every move in room.getMoveHistory() as individual
  GameMoveSuccessResponse messages on that channel.
- Black/white player lookup uses room.getBlackPlayerId/getWhitePlayerId
  against the clientSideMap so we don't reassign roles.
- Move replay resolves playerNickname from the same map.

Client fix:
- menu-ui.js: new GAME_WATCH_SUCCESSFUL handler flips gameState.isSpectating
  = true. The subsequent GameStartingResponse flows through the existing
  menu-scene handler (transitions to GameScene) and the existing
  game-state-service handler (populates room state, resets moves).
- Move replay events propagate through the global GAME_MOVE_SUCCESS handler
  in game-state-service before GameScene.create() runs, so GameScene's
  existing rejoin/spectate loop at create() renders every stone.
2026-04-11 09:22:54 +07:00
tiennm99 cea36323c9 fix(client): unwrap rooms array from ShowRoomsResponse payload
After the typed-protobuf migration the event bus delivers the full
ShowRoomsResponse message to the handler — a {rooms: [...]} object, not
the raw array the old JSON envelope used to unwrap. showRoomList was
still doing `Array.isArray(rooms) ? rooms : []`, so the guard always
failed and the UI rendered "No rooms available" even when rooms existed
server-side.

Repro: create a PVP room from tab A, open Join Room from tab B — empty list.

Fix: read payload.rooms (defensively default to [] so the empty-state row
still shows when protobufjs strips the empty repeated field).
2026-04-11 09:07:35 +07:00
tiennm99 f70c0eaa5f fix(client): drop stale COPY public in Dockerfile
docker build failed with "/public: not found" at the client stage. The
client tree has never contained a public/ directory (vite doesn't need one
for this project — index.html lives at the client root and vite.config.js
has no publicDir override). Remove the dead COPY line.

Verified: docker build -f client/Dockerfile client succeeds end-to-end.
2026-04-11 08:53:35 +07:00
tiennm99 ecc617790e refactor(client): typed protobuf binary websocket on port 1999
Phase 04 of the WebSocket protobuf migration:
- Add protobufjs@7.5.4 runtime dep and protobufjs-cli@1.1.3 devDep
- Add proto:gen npm script that runs pbjs + pbts against server/src/main/proto/
- Commit static-module output at client/src/generated/protocol.{js,d.ts}
- Rewrite connection-service.js:
  * Set binaryType='arraybuffer' and default URL to ws://localhost:1999/ratel
  * Replace string-keyed send(code, data) with 13 typed send helpers
    (sendNickname, sendGameMove, sendCreatePveRoom, ...)
  * Decode incoming BinaryWebSocketFrame via Response.decode and map
    each oneof case to a ClientEventCode for the event bus
- Update 14 call sites across menu-ui, game-ui, game-scene
- game-state-service CLIENT_CONNECT now reads data.clientId
- menu-ui NICKNAME_SET toast only triggers when invalidLength > 0
- Drop ServerEventCode enum from protocol-constants.js
2026-04-11 08:25:20 +07:00
tiennm99 45e22124ac chore: bump version to 0.0.1 and replace "frontend" with "client"
Version change:
- Drop the "-beta" suffix across all version declarations.
- server/build.gradle.kts: version = "0.0.1"
- client/package.json: "version": "0.0.1"
- client/package-lock.json: regenerated
- server/Dockerfile: COPY path references the new jar filename
- All docs + README refer to caro-server-0.0.1.jar.

Terminology cleanup:
- Replace the word "frontend" with "client" so the whole project uses
  one consistent term (server / client).
- README.md Credits section: "Frontend build tool" -> "Client build tool".
- No other "frontend" occurrences found in code or docs.

Also correct two lingering Maven-era stale paths in deployment-guide.md
("server/target/..." -> Gradle output location) that slipped past the
earlier Maven-to-Gradle commit.

Versioning note in codebase-summary.md simplified to plain MAJOR.MINOR.PATCH
(dropped the "-beta suffix during pre-1.0" clause).

Validation: gradlew clean shadowJar + test passes (37 tests on Java 25);
client build succeeds with new package name/version.
2026-04-10 20:55:29 +07:00
tiennm99 4feee3b858 chore: remove deploy-pages workflow and cleanup unused files
- Remove .github/workflows/deploy-pages.yml. Docker Compose is now the
  canonical deployment path.
- Delete unreferenced demo.gif (tracked, no markdown references).
- Delete stale landlords-client/ leftover from pre-refactor Maven cache.
- Delete empty client/public/ directory.
- Drop demo.gif entry from .dockerignore.
- Clean up .gitignore: dedupe target/.project/.classpath/.settings/.DS_Store
  entries, remove stale /ratel-landlords/.project line, group by purpose.
- Bump client/README.md Node.js requirement 18+ to 22+ (aligns with CI).
- Update docs to drop GitHub Pages references:
  - codebase-summary.md: drop deploy-pages.yml from tree and CI section.
  - deployment-guide.md: replace Option A (GH Pages) with Docker Compose.
  - project-overview-pdr.md: Phase 4 no longer mentions GH Pages.
  - project-roadmap.md: Phase 6 describes CI-only, notes deploy-pages
    removal; Phase 7 entry lists cleanup items; maintenance schedule
    now says rebuild Docker images.
  - system-architecture.md: deployment diagram shows Docker Compose only.

Validation: mvn -f server/pom.xml clean verify passes 37 tests on Java 25.
2026-04-10 19:48:19 +07:00
tiennm99 1297b7d25a refactor: rename web-client/ to client/ and update compose + CI references
- git mv web-client/ -> client/ (internal files untouched, history preserved).
- docker-compose.yml: rename service web-client -> client, container
  caro-web-client -> caro-client, build context ./web-client -> ./client.
- .github/workflows/build.yml: rename job build-web-client -> build-client,
  working-directory web-client -> client, cache-dependency-path updated.
- .github/workflows/deploy-pages.yml: update paths filter, working-directory,
  cache-dependency-path, upload-pages-artifact path (web-client/** -> client/**),
  workflow display name.
- client/package.json: rename npm package caro-web-client -> caro-client,
  version 1.0.0 -> 0.0.1-beta to align with server artifact.
- Regenerate package-lock.json with new name/version.
- .gitignore: web-client/dist -> client/dist.

Validation: npm run build in client/ succeeds (20 modules transformed).
2026-04-10 19:22:39 +07:00