Phase 05 — sync infrastructure and documentation with the typed-protobuf refactor: - docker-compose.yml: drop 1024/1025 mappings, single "1999:1999" - server/Dockerfile: EXPOSE 1999, -p 1999 entrypoint - README.md: rewrite transport description, architecture diagram, protocol section, server options, project structure, add proto:gen script note - docs/project-overview.md: update transport + dependencies sections - docs/system-architecture.md: rewrite diagrams + pipeline + file inventory for the WebSocket-only typed-dispatch path - docs/codebase-summary.md: refresh file tree, java package inventory, gradle deps, vite deps, networking and game-flow sections - docs/deployment-guide.md: single-port walkthrough for local / docker / systemd / nginx; remove all 1024/1025 firewall and troubleshooting - docs/code-standards.md: replace dead ServerEventListener_CODE_* class-name example, fix sample ws:// URL to port 1999
13 KiB
Codebase Summary
Directory Structure
caro/
├── .github/
│ └── workflows/
│ └── build.yml CI: build + test (Java 25 + Node 22)
├── server/ Standalone Netty server (Java 25, Gradle)
│ ├── src/main/java/com/miti99/caro/
│ │ ├── common/
│ │ │ ├── channel/ Netty utilities (ChannelUtils)
│ │ │ ├── entity/ Data models (Board, Room, GameMove, ClientSide)
│ │ │ ├── enums/ ClientEventCode, PieceType, GameResult, RoomType, etc.
│ │ │ ├── exception/ LandlordException
│ │ │ ├── features/ Feature flags
│ │ │ ├── helper/ GomokuHelper (win detection)
│ │ │ ├── print/ SimplePrinter
│ │ │ ├── robot/ AI engine (GomokuAI)
│ │ │ └── utils/ ListUtils, OptionsUtils, StreamUtils
│ │ └── server/
│ │ ├── event/
│ │ │ ├── request/ ClientRequest sealed interface + record variants (14 types)
│ │ │ ├── handler/ 14 typed request handlers (*Handler.java)
│ │ │ ├── RequestConverter.java Protobuf→ClientRequest conversion
│ │ │ └── RequestDispatcher.java Pattern-match dispatch logic
│ │ ├── handler/ Netty pipeline (WebsocketTransferHandler)
│ │ ├── timer/ RoomClearTask
│ │ ├── SimpleServer.java Server entry point
│ │ └── ServerContains.java Global state container
│ ├── src/main/proto/
│ │ ├── request.proto Client→server typed message definitions
│ │ └── response.proto Server→client typed message definitions
│ ├── src/test/java/com/miti99/caro/common/
│ │ ├── helper/tests/GomokuHelperTest.java 29 JUnit 5 tests
│ │ └── robot/tests/GomokuAITest.java 8 JUnit 5 tests
│ ├── gradle/wrapper/ Gradle wrapper (9.2.1)
│ ├── gradlew, gradlew.bat Wrapper launchers
│ ├── settings.gradle.kts Root project name
│ ├── build.gradle.kts Standalone build (Kotlin DSL) with Shadow plugin
│ └── Dockerfile Multi-stage (eclipse-temurin:25-jdk, eclipse-temurin:25-jre-alpine)
├── client/ Phaser 3 + Vite client
│ ├── src/
│ │ ├── main.js Phaser boot
│ │ ├── config/
│ │ │ ├── game-config.js Phaser configuration
│ │ │ └── protocol-constants.js Event code enums
│ │ ├── scenes/
│ │ │ ├── boot-scene.js Initialize, connect to server
│ │ │ ├── menu-scene.js Menus (overlay DOM)
│ │ │ └── game-scene.js Main gameplay scene
│ │ ├── services/
│ │ │ ├── event-bus.js Pub/sub event dispatcher
│ │ │ ├── connection-service.js WebSocket client
│ │ │ └── game-state-service.js Client-side state
│ │ ├── objects/
│ │ │ ├── board.js Game board renderer
│ │ │ └── stone.js Individual stone sprite
│ │ └── ui/
│ │ ├── menu-ui.js Menu components
│ │ └── game-ui.js Game HUD & notifications
│ ├── Dockerfile Nginx-based static server
│ ├── index.html
│ ├── vite.config.js
│ └── package.json caro-client 0.0.1
├── docs/ (this directory)
│ ├── project-overview.md
│ ├── system-architecture.md
│ ├── codebase-summary.md
│ ├── code-standards.md
│ └── deployment-guide.md
├── plans/ Implementation plans
├── docker-compose.yml services: server, client
├── README.md
├── LICENSE
└── .gitignore
Key Java Packages
com.miti99.caro.common (Shared code)
Entities:
Board.java— 15x15 game board, move validation, win/draw detection (BOARD_SIZE=15,WIN_CONDITION=5)Room.java— Game session state (id, type, status, players, board, moveHistory)GameMove.java— Single move (row, col, piece, playerId, timestamp)ClientSide.java— Player connection state (nickname, status, role)- Generated proto messages —
Request,Responseoneof wrappers (inserver/build/generated/sources/proto/main/java/)
Enums:
ServerEventCode— client→server action codesClientEventCode— server→client response codesPieceType— EMPTY, BLACK, WHITEGameResult— IN_PROGRESS, BLACK_WIN, WHITE_WIN, DRAWRoomType,RoomStatus,ClientRole,ClientStatus
Game Logic:
GomokuHelper.java— Win detection (4 directions), board renderingGomokuAI.java— AI move selection (Easy/Medium/Hard)
Utilities:
ListUtils,OptionsUtils,StreamUtils
Dispatch (typed records):
ClientRequest— Sealed interface representing all possible client requests (14 variants)- Record types:
SetNicknameRequest,CreateRoomRequest,CreatePveRoomRequest,GetRoomsRequest,JoinRoomRequest,GameStartingRequest,GameReadyRequest,GameMoveRequest,GameResetRequest,WatchGameRequest,WatchGameExitRequest,ClientExitRequest,ClientOfflineRequest,SetClientInfoRequest
com.miti99.caro.server (Server code)
Entry Point:
SimpleServer.java— Bootstrap (WebSocket server defaults to port 1999 at/ratel)ServerContains.java— Singleton global state (rooms, client sides, channel map)
*Event Handlers (14 Handler classes):
SetNicknameHandler,CreateRoomHandler,CreatePveRoomHandler,GetRoomsHandler,JoinRoomHandlerGameStartingHandler,GameReadyHandler,GameMoveHandler,GameResetHandlerWatchGameHandler,WatchGameExitHandler,ClientExitHandler,ClientOfflineHandler,SetClientInfoHandler
Request Processing:
RequestConverter— DecodesRequestoneof from binary wire format → typedClientRequestvariantRequestDispatcher— Pattern-matchesClientRequestvariant → dispatches to corresponding handler
Network Handler:
WebsocketTransferHandler— Netty pipeline handler: decodes binary frame toRequestprotobuf message
Background Tasks:
RoomClearTask— Periodic cleanup
Client (JavaScript/Phaser 3)
Boot:
main.js— Create Phaser game instance, start boot scene
Config:
game-config.js— Phaser config (800x800, Scale.FIT, scenes: [BootScene, MenuScene, GameScene])protocol-constants.js— Export event code enums matching server
Scenes:
BootScene— Create services, connect WebSocket, load assets, transition to menuMenuScene— Nickname input, lobby, room list, difficulty selectorGameScene— Board + stones, click handling, move history, turn indicator, game over
Services:
EventBus— Pub/sub decoupling scenes and servicesConnectionService— WebSocket client with heartbeat + auto-reconnectGameStateService— Client-side state container
Game Objects:
Board— 15x15 wood-textured gridStone— Gradient stone sprite with drop animation
UI:
MenuUI— Nickname form, room list, settingsGameUI— HUD, move history, game over modal, toasts
Build Configuration
Gradle (Java)
Files:
server/build.gradle.kts— standalone Gradle build script (Kotlin DSL)server/settings.gradle.kts— root project name (caro-server)server/gradle/wrapper/— committed wrapper (Gradle 9.2.1)server/gradlew/server/gradlew.bat— wrapper launchers
Coordinates: com.miti99.caro:caro-server:0.0.1
Plugins:
java— standard Java plugincom.google.protobuf:0.9.6— protobuf code generationcom.gradleup.shadow:8.3.8— fat jar packaging
Toolchain: JavaLanguageVersion.of(25) — Gradle auto-provisions Java 25 if missing.
Dependencies:
io.netty:netty-all:4.1.128.Final— async networkingcom.google.protobuf:protobuf-java:3.25.5— binary serialization, generated codecom.google.protobuf:protoc:3.25.5— protobuf compiler (build time)org.junit:junit-bom:5.11.4(platform) +org.junit.jupiter:junit-jupiter— testing
Shadow jar config:
- Main class:
com.miti99.caro.server.SimpleServer - No special command-line args (server defaults to port 1999)
mergeServiceFiles()— preserve Netty SPIs- Excludes signing metadata (
*.SF,*.DSA,*.RSA)
Build Command:
./server/gradlew -p server clean build
# Produces: server/build/libs/caro-server-0.0.1.jar (shaded fat jar)
Vite (JavaScript)
File: client/package.json
Package: caro-client 0.0.1
Scripts:
npm run dev— Dev server (port 5173, hot reload)npm run build— Production build todist/npm run preview— Preview production buildnpm run proto:gen— Regenerate protobuf code from server.protofiles (usespbjs+pbts)
Dependencies:
phaser ^3.87.0— Game engineprotobufjs ^7.5.4— JavaScript protobuf codecvite ^6.3.1— Bundler (dev-only)@protobufjs/cli ^1.1.3— Protobuf code generator (dev-only)
Output: client/dist/ (index.html + bundled JS, ~1.5 MB / 346 KB gzipped)
Testing
Test Framework: JUnit 5 (org.junit.jupiter.api)
Test Files:
server/src/test/java/com/miti99/caro/common/helper/tests/GomokuHelperTest.java— 29 tests (win detection, edges, draw, game flow)server/src/test/java/com/miti99/caro/common/robot/tests/GomokuAITest.java— 8 tests (Easy/Medium/Hard AI)
Run Tests:
./server/gradlew -p server clean test
Coverage: ~100% for game logic (Board, GomokuHelper, GomokuAI)
Dependencies Summary
| Scope | Dependencies |
|---|---|
| server runtime | Netty 4.1.128, Protobuf 3.25.5 (generated code) |
| server test | JUnit Jupiter 5.11.4 |
| server build | Gradle 9.2.1, Protobuf Gradle plugin 0.9.6, Shadow 8.3.8 |
| client runtime | Phaser 3.87, protobufjs 7.5.4 |
| client build | Vite 6.3, protobufjs-cli 1.1.3 |
Important Files by Feature
Game Logic
server/src/main/java/com/miti99/caro/common/entity/Board.javaserver/src/main/java/com/miti99/caro/common/helper/GomokuHelper.javaserver/src/main/java/com/miti99/caro/common/robot/GomokuAI.java
Networking
server/src/main/java/com/miti99/caro/server/handler/WebsocketTransferHandler.java— Binary decoderserver/src/main/java/com/miti99/caro/server/event/RequestConverter.java— Protobuf→record conversionserver/src/main/java/com/miti99/caro/server/event/RequestDispatcher.java— Dispatch logicserver/src/main/java/com/miti99/caro/common/channel/ChannelUtils.java— Response encoder/senderclient/src/services/connection-service.js— WebSocket client (binary mode)server/src/main/proto/*.proto— Message definitions
Game Flow
server/src/main/java/com/miti99/caro/server/event/handler/GameMoveHandler.javaserver/src/main/java/com/miti99/caro/server/event/handler/GameStartingHandler.javaclient/src/scenes/game-scene.js
UI
client/src/objects/board.jsclient/src/ui/game-ui.jsclient/src/ui/menu-ui.js
Code Quality
Metrics:
- Lines of Code: ~5,000 Java, ~1,500 JavaScript
- Test Coverage: Game logic ~100%, server flow ~80%, client varies
- File Size: Most Java files < 200 lines, JavaScript < 300 lines
Java 25 features in use:
recordfor immutable DTOs (Msg)- Switch expressions (
GomokuHelper.getWinnerMessage,GomokuAI.getNextMove) varfor obvious local types
Build Artifacts
| Artifact | Location | Purpose |
|---|---|---|
| Server jar | server/build/libs/caro-server-0.0.1.jar |
Shaded executable fat jar |
| Client dist | client/dist/ |
Static files for web UI |
Continuous Integration
GitHub Actions:
build.yml
- Trigger: push/PR on master (ignores
.mdand.gitignore) - Jobs:
build-server— Setup Java 25 (Temurin) +gradle/actions/setup-gradle, run./gradlew -p server --no-daemon clean buildbuild-client— Setup Node 22,npm ci,npm run build
Deployment is handled via Docker Compose from this repo; there is no hosted deployment pipeline.
Version & Release
Current Version: 0.0.1 (both caro-server and caro-client)
Versioning: Semantic versioning (MAJOR.MINOR.PATCH).