# Hokm — .NET 10 + SignalR backend Authoritative realtime server for the Hokm game. The TypeScript engine (`../src/lib/hokm`) is ported to C# here so the server is the source of truth. ## Projects | Project | What | |---|---| | `src/Hokm.Engine` | Pure C# rules + AI (port of `src/lib/hokm`) — deal, hakem, trump, tricks, scoring, Kot, bot | | `src/Hokm.Server` | ASP.NET Core + **SignalR** `GameHub`, in-memory matchmaking/rooms, JWT auth | | `tools/Hokm.Sim` | All-AI simulation that validates the engine port | ## NuGet sources `NuGet.config` restores **only** from the configured mirrors (no nuget.org): - `https://mirror.soroushasadi.com/repository/nuget-group/index.json` (Nexus) - `https://package-mirror.liara.ir/repository/nuget/index.json` (Liara) `Directory.Build.props` disables NuGet audit (avoids reaching api.nuget.org). ## Run ```bash cd server dotnet run --project tools/Hokm.Sim -c Release # validate the engine dotnet run --project src/Hokm.Server -c Release # → http://localhost:5005 ``` ## API Dev auth (replace with the V2 Identity Service + Kavenegar/SMS.ir later): - `POST /api/auth/otp/request` `{ phone }` → `{ devCode: "1234" }` - `POST /api/auth/otp/verify` `{ phone, code, name? }` → `{ token, userId, name }` (code `1234`) - `POST /api/auth/email` `{ email, password, name? }` → `{ token, userId, name }` SignalR hub: **`/hub/game`** (JWT required; pass `?access_token=`). Client → server methods: - `StartMatchmaking({ name, avatar, level, plan })` — pro skips the queue - `CancelMatchmaking()` - `ChooseTrump(suit)` · `PlayCard(cardId)` · `SendReaction(reaction)` Server → client events: - `matchmaking` `{ phase, players, queuePosition }` - `matchFound` `{ roomId, seat }` - `state` `GameStateDto` (per-seat: only your own hand is included; others are counts) - `reaction` `{ seat, reaction }` The server runs server-side **turn timers** (20s → AI auto-plays), fills empty seats with **bots**, drives bot turns, and handles **disconnect** (the seat is marked offline and the timer auto-plays until they reconnect). ## Wiring the Next.js client (next step) Implement `SignalrService` in `../src/lib/online/signalr-service.ts` against the existing `OnlineService` interface (`@microsoft/signalr`), then switch `getService()` in `../src/lib/online/service.ts` from the mock to it. The hub's `GameStateDto` is shaped to map directly onto the client `GameState`. ## TODO - EF Core + Postgres persistence (profiles, coins, rank, cosmetics, match history) - JWT issued by the V2 Identity Service; phone OTP via Kavenegar/SMS.ir - Private rooms + friend invites over the hub (engine/room already support 4 seats) - Server-side reward calculation (currently client/profile-side)