Game table & play - UNO-style restyle: suit-aware bolder cards (+xl size), pulsing playable glow, big "YOUR TURN" pill, active-seat ring, trick-win particle burst, round confetti, match coin-rain. - Per-league turn time via turnMsForStake: 15s starter/AI, 10s pro, 7s expert; mirrored server-side in GameRoom.TurnMs. - Speed (Blitz) mode for vs-AI/private: 5s turns, race to 5, ~halved pacing. - Matchmaking waits ~15s (randomized 12-18s) then fills bots; elapsed timer + hint. Rewards / gifts - Richer post-match modal (floating coins, XP bar), celebration overlay reveals the unlocked sticker pack, boosted daily rewards (client+server synced), themed 7-day daily with special day-7. Social - Public profile modal (identity, stats, achievement board) from leaderboard / friends / discover / end-of-game roster; rate-limited add-friend (10/hour). - Social hub: Friends / Discover (player search + suggestions) / Messages inbox. - Profile gender (shown in finder/profile) + social links with public/friends/ hidden visibility, enforced server-side. Cosmetics - Distinct card backs: per-design pattern families (stripes/argyle/grid/dots/ rays/scales/crosshatch/royal/filigree/gem) + luxury motifs (lib/cardBack.ts), consistent on table/shop/profile; +Peacock/Rose-Gold backs. - Purchasable titles (shop Titles section); title shown under the seat on the table and in discover/public profile. - 10 new sticker packs (banter/kol-kol, Persian trends, court cards, moods). - Persistent level+XP bar on Home and every inner screen. Payments - Buy-coins gateway opens in a new tab (no SPA dead-end) + focus refresh. - Store IAB scaffolding: Cafe Bazaar deep-link purchase + redirect-token capture, Myket native-bridge contract, server-side IabService.Verify for both stores, config-driven via Iab__* env. POST /api/coins/iab/verify (JWT). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
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
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 }(code1234)POST /api/auth/email{ email, password, name? }→{ token, userId, name }
SignalR hub: /hub/game (JWT required; pass ?access_token=<jwt>).
Client → server methods:
StartMatchmaking({ name, avatar, level, plan })— pro skips the queueCancelMatchmaking()ChooseTrump(suit)·PlayCard(cardId)·SendReaction(reaction)
Server → client events:
matchmaking{ phase, players, queuePosition }matchFound{ roomId, seat }stateGameStateDto(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.
Persistence (EF Core)
AppDbContext stores each profile as a JSON blob (ProfileRow) + a coin
LedgerRow audit trail. Provider is config-driven:
// appsettings.json
"Database": { "Provider": "sqlite" }, // or "postgres"
"ConnectionStrings": { "Default": "Data Source=hokm.db" }
// Postgres (Supabase): Provider="postgres",
// Default="Host=...;Database=...;Username=...;Password=...;SSL Mode=Require"
Schema is created at startup via EnsureCreated() (swap to EF migrations for prod).
Server-authoritative endpoints (JWT):
GET /api/profile·PUT /api/profile(displayName/avatar/title/cardFront/cardBack)POST /api/profile/plan(upgrade to pro)GET /api/coins/packs·POST /api/coins/buy{ packId }(credits + ledger; real Zarinpal/IDPay TODO)POST /api/match/result{ MatchSummary }→ computes rewards viaProfiles/Gamification.cs(C# port ofsrc/lib/online/gamification.ts), updates profile + ledger, returnsRewardResult
Auth (/api/auth/...) upserts the profile on first sign-in.
TODO
- Wire the Next client (
SignalrService) to these endpoints for profile/coins/match (currently still mock-backed to avoid a half-migrated economy) - EF migrations; Postgres (Supabase) connection for prod
- JWT issued by the V2 Identity Service; phone OTP via Kavenegar/SMS.ir
- Private rooms + friend invites over the hub; server-side ranked entry deduction at match start