Skip to content

weiqi-server

apps/weiqi-server is the gateway. It validates session cookies against auth-app, owns every game record, calls KataGo through the configured IKatagoClient, persists analysis snapshots, and exposes real-time updates over Socket.IO. It is the only writer of game state.

src/main.ts:14 boots NestJS on PORT (default 3002) with:

  • Global prefix /api.
  • Swagger at /api-json.
  • cookie-parser and a custom CORS origin allow-list from CORS_ORIGINS.
  • A Socket.IO adapter for real-time.

Swagger is published at http://localhost:3002/api-json — useful for generating client types against bot-game.api.ts.

modules/accounts/presentation/guards/auth.guard.ts:30 reads the better-auth.session_token cookie. The __Secure- prefix is tried first so the same code path works in production (HTTPS-only cookie) and dev (plain cookie). The guard calls AccountsService.validateSession, which proxies to auth-app, and attaches {user, session} to the request.

Decorators:

  • Auth(...roles) (auth.decorator.ts:29) — require roles (user, mod, admin, super_admin).
  • Authenticated — any signed-in user.
  • Public — opt out of the guard.
  • WsAuthenticated — Socket.IO counterpart, in ws-auth.guard.ts:25.

All paths are /api-prefixed.

MethodPathNotes
GET/accounts/meCurrent user profile.
PATCH/accounts/meUpdate display name / avatar.
MethodPathNotes
POST/gamesCreate a PvP game record.
GET/gamesList games for the current user.
GET/games/:idFetch game metadata + last move cursor.
PATCH/games/:idUpdate metadata (e.g. archive).
POST/games/:id/movesAppend a move; validates with weiqi-engine.
GET/games/:id/movesPaginated move history.
MethodPathNotes
GET/game/bot/levelsCatalog of ten strength levels (see Bot Ladder).
POST/game/bot/gamesStart a new bot game. Body: { level, boardSize? }.
GET/game/bot/games/:idGame state (board, players, last move, status).
GET/game/bot/games/:id/movesMove list.
GET/game/bot/games/:id/reviewLatest KataGo review (runFullReview result).
POST/game/bot/games/:id/movePlayer move; replies with the bot’s move.
POST/game/bot/games/:id/resignResign the game.
POST/game/bot/games/:id/hintOne-move hint (entitlement-gated; see Bot Ladder).
POST/game/bot/games/:id/undoUndo last move (if the game allows it).
GET/game/bot/ladder/me{ rating, optIn, today }.
POST/game/bot/ladder/opt-inToggle ladder opt-in. Body: { optIn: boolean }.
GET/game/bot/ladder/history?limit=50Most recent rating deltas.
MethodPathNotes
POST/analysis/games/:id/runFullReviewOne-call whole-game review via analyzeTurns: [0..N]. See KataGo Review.
GET/analysis/games/:id/snapshotsPer-node snapshots persisted in board_ai_snapshots.
GET/analysis/games/:id/graphPlottable winrate / score-lead series.
MethodPathNotes
POST/challengesSubmit a new challenge (SGF / image).
GET/challengesBrowse approved challenges.
POST/challenges/:id/solution-attemptsSubmit a solution.
GET/challenges/moderation/listModerator queue. Role-gated.
POST/challenges/moderation/approveApprove a submission.
POST/challenges/moderation/rejectReject a submission.
GET/challenges/my-submissions/listCaller’s own submissions.

A LangGraph analytics agent backed by WeiqiAnalyticsTool. Used by the admin console for natural-language queries over solutionAttempts (e.g. “what is the most failed life-and-death shape this week?”).

Events emitted by BotRealtimeEmitter:

EventPayloadWhen
gameStateFull game snapshotAfter every state mutation.
botMove{ gameId, move, classification?, rootInfo? }After the bot plays a move.
classifiedPer-move MoveClassification (good / inaccuracy / mistake / blunder)After KataGo review run.
gameEndedFinal { winner, score, reason }On game termination.

The AnalysisGateway exposes parallel events for live runFullReview progress (turns emitted as KataGo returns them).

modules/game/infrastructure/katago/ defines IKatagoClient (types.ts:88). The active implementation is selected by env:

  • GrpcKatagoClient — default; talks to katago-service gRPC at KATAGO_GRPC_URL=localhost:50051.
  • HttpKatagoClient — used when KATAGO_SERVICE_URL is set (http://localhost:4011).
  • BullMqKatagoClient — in-process queue; useful for local dev without the dedicated katago-service.
  • MockKataGoClient — tests.

The orchestrator KatagoService (katago.service.ts:21) exposes:

  • getMove(analyzeOptions): Promise<KatagoTurnResponse>
  • getAnalysis(analyzeOptions): Promise<KatagoAnalysisResponse>
  • getGameReview(analyzeOptions): Promise<KatagoAnalysisResponse> — sets analyzeTurns to replay the entire game.
  • getPolicy(analyzeOptions): Promise<KatagoPolicyResponse>
  • analyzeForHint(gameState): Promise<HintResponse> — bounded visits.

Drizzle ORM on Postgres. Schema lives in infrastructure/database/database.module.ts:8. Tables most relevant to the public API:

  • botGames, botGameMoves, botGameReviews — bot ladder game records.
  • botRankHistory, botRatings — ladder rating per user.
  • boardRecords, boardNodes — generic board records and node tree.
  • boardAiSnapshots, boardAiReviews — KataGo snapshots and aggregated reviews.
  • solutionAttempts, solutionAttemptMoves, problems — challenge system.
  • players — minimal player metadata; canonical user lives in auth-app.
Terminal window
cp apps/weiqi-server/.env.example apps/weiqi-server/.env
cd apps/weiqi-server
docker compose up -d # Postgres 54320, Redis 6379, MinIO 9000
docker compose --profile recognition up -d # optional, for board photo scan
cd ../..
pnpm --dir apps/weiqi-server dev

Tests:

Terminal window
pnpm --dir apps/weiqi-server test # jest