- OnlineLobbyScreen: each league row is now a tappable play button (queues a
ranked match at that league's stake) with a forward arrow; the cheapest
enterable league is highlighted gold. Drops the redundant separate "ranked
random" CTA and the select-then-play step.
- Remove the background-music feature entirely: deleted the floating MusicToggle,
the TopBar music button, and the Profile audio music toggle + style picker.
sound.startMusic() is now an inert no-op so music never plays (sfx unchanged).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- PostMatchRewardsModal: short-height (landscape) compaction so the win/forfeit
result fits without overflow (smaller emoji/coins/padding, max-h 94dvh, wider).
- Chat: emoji/sticker picker (owned reactions) — tap to send; hidden on focus.
- Unread messages: online-store now tracks a total `unread` (from
listConversations); NavRail Friends icon shows a badge (unread + requests),
refreshed every 12s on every screen; Friends «پیامها» tab badged too.
(Per-conversation unread badges already existed.)
- Remove "XP گران است" / "XP is expensive" from shop.xpHint.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Room: teams side-by-side in landscape so all 4 seats fit (still scrolls).
- Achievements: rename the 5 rating tiers from «لیگ» (league) to «رتبه» (rank)
+ category «رتبه» — so "league" only means the 3 playable match leagues.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Lobby: remove private-room CTA (it's on Home now) → fits without scroll.
- Home: private rooms now cost 150 coins/player (stake 150).
- Buy Coins: drop the "secure payment" note; redesign packs as game-shop coin
boxes (coin pile + amount + gold buy-price CTA), 2/3/4-col responsive.
- Notifications: minimal single-line corner toast, explicit ✕ close, hidden
during play so it never disturbs the game.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- NavRail: vertically center items in the side rail (was top-aligned).
- ScreenHeader: showXp defaults off — the level/XP bar no longer clutters every
sub-page (it lives on Home's chip + the Profile page).
- Shop: category tabs (avatars / fronts / backs / reactions / stickers / titles
/ XP) so only one category shows at a time — no more endless scroll.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The Home screen wasn't centered like the sub-pages, so on desktop/tablet its
content drifted to the RTL start edge with dead felt on the left. Wrap it in a
centered max-w-3xl/landscape:max-w-5xl stage, vertically center the mode cards,
and size them up for tablet/desktop (min-h + larger max-w).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Make all menu screens use the width on desktop/landscape and the UNO panels:
- Shop item grid 3→up to 6 cols; BuyCoins packs 2→4 cols on lg.
- Lobby: panel league pick (2-col) + 2-col CTA buttons.
- Achievements / Notifications / Leaderboard / Friends lists → responsive
grids (1 col mobile, 2 cols on lg); glass→panel on section containers.
- Chat: centered max-w-3xl column on desktop, green send button.
All responsive for mobile + desktop. tsc + build clean.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Rebuild HomeScreen to UNO's home layout: top bar (avatar+coins) + 3 big glossy
3D mode cards in the center (Online[gold,live-count badge] / vs-Computer[teal] /
Private Room[violet]) + a bottom icon nav bar (NavRail bottom variant, drops the
redundant home item). Speed toggle + language sit in a slim controls row. Online
card shows live player count; room card creates a private room then enters it.
New menu.room/menu.roomDesc i18n.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Theme: retint to lit emerald card-table felt + gold (body radial felt, green
glass panels). New component kit in globals.css: glossy chunky 3D btn-gold +
btn-green, .panel, .ribbon. Card backs pinned to classic navy.
- Home fully redesigned UNO-style: nav rail + branding + two big 3D play
buttons (gold online / green-glass vs-computer) + speed toggle; dropped the
redundant 4 tiles (the rail covers them). Fits landscape (short: variants).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Rebuild ScreenShell into a UNO-style app shell: a persistent NavRail (vertical
side rail in landscape, bottom tab bar in portrait — Home/Profile/Shop/Friends/
Leaderboard/Achievements, active highlighted gold) + a content panel that owns
its own scroll so the page never scrolls as a whole and uses the width in
landscape. Reskins all 10 menu screens at once. Transient screens (auth,
matchmaking, room) opt out via hideNav. New nav.home i18n key.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Root cause: a landscape phone is wide (>=640px) but short, so width-based sm:
roominess inflated the title/buttons while the screen height was small -> the
right column overflowed (vs-Computer card cut off). Add a height-based
`short:` variant (@media max-height:520px) and compact Home's branding +
action cards under it so the column fits short landscape viewports.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Remove the web-app manifest link + manifest.ts route so bargevasat.ir no longer
triggers an "install/add to home screen" prompt. It's a plain marketing/SEO
site now. Only the game app (app.bargevasat.ir) remains a PWA.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Move orientation lock + RotatePrompt to app root → whole app is landscape-
first now (UNO-style), not just the game. Generalized rotate copy.
- Home: portrait unchanged; in landscape it becomes a 2-column app layout
(col A = branding + play actions, col B = tiles + footer) that fits the
short height with no scroll (landscape: Tailwind variants, overflow-hidden).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Hokm plays best wide (UNO-style). On phones held in portrait, the game screen
shows a "rotate your phone" overlay (with a play-anyway escape hatch so OS
rotation-lock can't trap anyone). Best-effort screen.orientation.lock('landscape')
on Android/PWA; iOS/desktop reject it harmlessly. i18n rotate.* (fa+en).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The fixed-position music button covered content on mobile. Removed it from
the global overlay; mute now lives in the TopBar icon group (Home), and the
in-game HUD + Profile settings already have their own audio controls.
Tightened the TopBar icon row (p-1.5, gap-1, profile max-w-44%) so the extra
button still fits 360px phones.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Home: logo and «برگ وسط» now sit on one row (prevents overflow), with
«بازی حکم آنلاین» as a small subtitle beneath the title next to the logo.
- Profile: add a خروج (Sign Out) button at the bottom (when signed in).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Profile chip: replace cramped fixed-width (w-[88px]) 3-line stack with a
clean 2-line layout (name on top; level · xp-bar · % on a flexing row),
capped at max-w-[46%] so it never crowds the icon group or overflows.
- Hero "Play online" title text-2xl→text-xl on phones (sm:text-2xl), truncate.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The Docker build 404'd on @types/react@19.2.17 (not in the Nexus mirror; npmjs
is blocked upstream). Pin shared deps to the exact versions the main app uses
(@types/react 19.2.16, etc.) and regenerate package-lock.json against the Nexus
registry so every resolved tarball is one Nexus can serve.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Logo/title/hero/tiles/footer spacing now scales down on small screens
(sm: breakpoints) so the menu fits common phone viewports — the sign-in/
language footer was being pushed below the fold.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- MatchmakingScreen: the 4 fixed w-16 slots (~292px) overflowed 320px phones;
now grid-fluid (w-full, gap-2 sm:gap-3, max-w-xs) so they always fit.
- ProfileScreen avatar picker now renders <Avatar id> (god/legend medallions)
instead of raw emoji — consistent with the displayed avatar and shop.
Swept Achievements/Leaderboard/BuyCoins/Auth/Shop/Profile/Lobby/Room — already
responsive (ScreenShell + min-w-0/truncate/shrink-0 throughout); no other
overflow found.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- GameTable Backdrop (Hakem/Trump/Round/Match-over): scroll when taller than the
viewport via overflow-y-auto + min-h-full centering — no more clipped panels.
- DailyRewardModal: cap height + scroll (was overflow-hidden, clipped the 7-day grid).
- PostMatchRewardsModal: max-h uses dvh (mobile chrome safe).
- ScreenShell: add overflow-x-hidden so a too-wide child can't scroll horizontally.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Each notification now navigates to its related screen when tapped (toast or
list): friend_request/invite -> Friends, achievement/reward -> Achievements,
daily -> opens the daily-reward modal, coin-purchase success -> Shop. An
explicit per-notification 'route' overrides the kind default.
List rows are swipeable (drag aside) and have an X to dismiss individually,
plus a Clear-all button; the toast can be flicked up to dismiss or tapped to
open. New store actions: markRead/remove/clearAll + openNotification navigator.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
No more earned-only (rank/wins) cosmetics — every avatar, card back/front,
reaction & sticker pack now has a coin price. Rank/wins/achievement become
purchase requirements (coin · coin+rank · coin+rank+achievement), enforced
client (mock + ShopScreen lock label) and server (ProfileService.ItemGate,
keyed by kind:id). Ownership = default + purchased only.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Replaced the childish animal emoji avatars with custom inline-SVG "deity
medallions" (gradient disc + gold ring + heraldic emblem) — Athena, Zeus,
Poseidon, Horus, Odin, Thor, Cyrus, Simorgh, Ishtar, Nike, etc. IDs unchanged
so owned avatars keep working; Avatar renders the art (emoji fallback for legacy
ids). Shop now shows the art + the god name (was generic "Avatar").
Files: components/online/avatarArt.tsx (new art + pantheon map), Avatar.tsx
(render art), ShopScreen Preview (avatar → <Avatar/>), mock-service avatar shop
names from AVATAR_ART.
Verified: tsc + next build clean; web rebuilt on :1500.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- nginx: serve the HTML shell with Cache-Control no-store so a new deploy (new
chunk hashes) is picked up immediately — fixes the recurring stale-bundle
"page couldn't load" at the source. Hashed /_next/static stays immutable.
- Trick offsets set to a clean symmetric cross.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Card read useCelebrationStore(s=>s.current)! but AnimatePresence keeps it
mounted through the exit animation; after dismiss() sets current=null it
re-rendered and threw "Cannot read properties of null (reading 'levelAfter')",
crashing the page after every purchase/XP/daily celebration. Pass the
celebration as a prop so the exiting card keeps its data.
Verified: tsc + next build clean; web rebuilt on :1500.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Trick area: smaller offsets (±50/52) + retuned scale so the played pile sits
centered in the felt instead of flung out to the side seats.
- ErrorBoundary around screens + overlays: a render error now shows a recoverable
in-app message with the cause (and logs componentStack) instead of the browser's
blank "page couldn't load" — helps pinpoint the post-purchase crash.
Verified: tsc + next build clean; web rebuilt on :1500.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Game table: played-card pile now uses sm cards on phones (vw<480) + slightly
tighter scale, so the center trick no longer crowds/overlaps the side seats'
avatars on a tall portrait screen.
- Profile: the screen showed two XP bars (the global header bar + the identity
card's detailed bar). Hide the header bar on Profile (showXp=false).
Verified: tsc + next build clean; web rebuilt on :1500.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The Home top bar overflowed on narrow screens; in RTL the coins pill is the
far-left item so its leading digits got clipped (showed "04,240" for 104,240).
- CoinsPill: compact big balances (104,240 → 104K, 1.2M), shrink-0 +
whitespace-nowrap; exact value in the tooltip.
- TopBar: tighter gaps, profile pill min-w-0 (shrinks/truncates first), icon+coins
group shrink-0 so it never gets squeezed.
Verified: tsc + next build clean; web rebuilt on :1500.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Deep-dive responsive audit. The post-match rewards modal used overflow-hidden
and the shop detail sheet had no height cap — both could clip content (long
reward lists / sticker packs) on short or landscape phones. Added
max-h-[90vh]/[88vh] + overflow-y-auto. Audit confirmed Leaderboard, Lobby,
PublicProfile rows/modals already handle min-w-0/truncate/scroll correctly.
Verified: tsc + next build clean; web rebuilt on :1500.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- The "This page couldn't load" after a redeploy was a stale bundle: a tab open
across a deploy requests JS chunks that no longer exist (ChunkLoadError). Added
a global error/unhandledrejection guard that reloads once to fetch the fresh
bundle (sessionStorage-guarded against loops, cleared after a healthy run).
- Reaction tray width → w-[min(270px,86vw)] so it never overflows narrow phones.
Verified: tsc + next build pass; web image rebuilt on :1500.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
docker compose build interpolates the whole file, so the ${JWT_KEY:?} guard
failed the build step when ENV_FILE lacked JWT_KEY. Default it empty (${JWT_KEY:-})
so build/db steps succeed, and enforce the secret at runtime instead: the server
throws on boot in Production if Jwt:Key is missing/dev/<32 chars.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- MusicToggle: global floating button (enable/disable music from any screen;
hidden on the table, which has its own audio control in its HUD). Uses
sound-store toggleMusic.
- Card sounds now use a synthesized card-draw "swish" (filtered noise burst with
a downward sweep) for cardPlay (+ soft landing tap) and deal (a flurry),
replacing the old beep tones.
Verified: tsc + next build pass.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Adds ~100 new purchasable gifts that are LOCKED until a level/rating gate is met,
then buyable with coins — value scales with the gate:
- 45 gift avatars (types.ts), 35 gift titles + 20 gift card backs (gamification.ts),
all reusing existing renderers. Tier (1-5) encoded in the id (-t<n>-).
- Gate model: GIFT_TIERS (shared) → reqLevel/reqRating on AvatarDef/TitleDef/
CardBackDef + ShopItem. Tiers: t1 free, t2 Lv10, t3 Lv20, t4 Lv35, t5 Rating1700.
- Shop UI: locked cards dim + show the requirement (Lock + "Level 20"), buy
disabled until met; mock buyItem enforces it offline.
- Server enforces generically — ProfileService parses the tier from the id and
checks the player's level/rating (no 100-entry mirror). Mirrors GIFT_TIERS.
- i18n shop.reqLevel/reqRating (fa+en).
Verified: tsc + sim + next build + dotnet build all pass.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- One running game per player: server rejects a 2nd matchmake while in a live
room (re-syncs the existing game); client guards Home vs-computer + Lobby
random/create — resumes the running match + notifies instead of starting another
(game-store hasActiveMatch()).
- Background music is now selectable: santoor (سنتی, calm Persian loop) and
playful (bouncy UNO-like) — sound.ts TRACKS + setMusicTrack (persisted),
sound-store musicTrack, picker in Profile → Audio. i18n added.
- Production config for bargevasat.ir (prepare-only; no live deploy):
appsettings.Production.example (CORS + ZarinPal + IAB to the domain),
docker-compose.caddy.yml + Caddyfile (auto-HTTPS reverse proxy
bargevasat.ir→web, api.bargevasat.ir→server), ENV_FILE PRODUCTION block,
PRODUCTION.md go-live + Cafe Bazaar publish/IAB checklist. Fixed IAB package
name to match Capacitor appId (com.bargevasat.app).
Verified: tsc + next build + dotnet build all pass.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Daily reward now routes through the global CelebrationOverlay: new "daily"
variant + coins count-up; claiming closes the daily modal and fires
celebrate({variant:"daily", coins}). Unifies the "you earned X" moment.
- Premium (pro) gold chat is now visible to the OTHER player: ChatMessage gains
senderPro; server resolves each participant's plan once (SocialService.IsPro)
and stamps it on ChatMessageDto; ChatScreen styles incoming bubbles with
.premium-chat when senderPro. Mock marks ~half its friends pro so it's visible
offline too.
Verified: tsc + next build + dotnet build all pass.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- MatchIntroOverlay: UNO-style pre-game reveal — the 4 seats animate into the
table (with "?" placeholders until each player's data streams in for live
matches), a 3-2-1-GO countdown, then the table shows. Wired via game-store
matchIntroPending/consumeIntro, rendered online-only in GameScreen.
- Fix: intro.found / intro.getReady / intro.go existed only in the Persian dict;
added the English strings (would have shown raw keys to EN users).
- Checkpoint of the in-progress UI/social batch (CoinsPill, shop titles section,
friend-request rate limit, etc.) — all green.
Verified: tsc + next build + scripts/sim.ts + dotnet build server/Hokm.slnx all pass.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Single source of truth for any agent/session continuing the project: run
instructions (dev + Docker stack), architecture, the client<->server
gamification sync rule, full feature status, CI/CD + Nexus HTTP-mirror cert
workaround, gotchas, and the TODO list.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Forfeit penalty reworked (client + server gamification, in sync):
- Surrendering team loses DOUBLE the entry coins; winner takes the stake.
- Forfeiter earns NO XP. No kot is applied or mentioned anymore.
- MatchSummary/Dto carry a `forfeit` flag; GameRoom.FinalizeForfeit →
ApplyRewardsAsync(team) with Forfeit=true (dropped the kot path).
- Forfeit confirm dialogs now alert the real penalty (double coins, no XP).
End-of-game roster: SeatPlayerDto/ServerSeatPlayer + game-store SeatPlayer gain
userId/isBot. New <MatchPlayersList> lists everyone at the table on the final
screen (PostMatchRewardsModal + AI MatchOverlay) with a tactile "Add" button to
send a friend request to real (non-bot, non-self) players ("Sent" after).
Verified: tsc + sim + dotnet + next build clean; stack rebuilt :1500/:1505.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Lobby: the two hero actions (random / create room) are now tactile press-3d
rounded-3xl with tinted icon chips.
- Matchmaking: seat slots use the Avatar frame with a gold border when filled
(dashed placeholder when empty + spring pop-in); cancel/start/upgrade buttons
are tactile.
- Profile: added a level badge on the avatar (casual-game style).
Verified: tsc + next build clean; web rebuilt :1500.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- New global celebration system: celebration-store (queue) + CelebrationOverlay
(animated: count-up XP, filling bar, level-up pop, achievement cards; plays
levelUp/award sounds; tap or auto-dismiss). Rendered in page.tsx.
- Shop: every purchase now celebrates — XP packs animate XP gain + level-up,
cosmetics show a "purchased!" pop. Newly-unlocked achievements (diffed from
the profile before/after) animate too.
- XP purchases now actually evaluate achievements: gamification.evaluateAchievements
(client) + Gamification.EvaluateAchievements (server, called in ShopBuy xp path)
unlock level milestones + grant their coins.
Verified live: buying XP took L1→L5, unlocked level_5 server-side and credited its
reward. tsc + dotnet + next build clean; images rebuilt :1500/:1505.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Answers "what's in this pack / how much XP": shop items now carry contents
(sticker ids / emojis), xp amount, and a fa/en description. Cards are tactile
(press-3d), show the artwork + name + a quick hint (item count or +XP) + price,
with an owned check badge. Tapping a card opens a detail sheet that shows the
full contents (every sticker/emoji rendered), the XP granted, a description,
and a Buy button (gold when affordable, "need coins" otherwise).
Verified: tsc + next build clean; web rebuilt :1500.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The HTTPS Nexus serves an incomplete cert chain that container trust stores
reject (NU1301 PartialChain / UNABLE_TO_GET_ISSUER), failing CI restore/install.
- NuGet has no strict-ssl flag → point CI + Dockerfile + compose at the plain-HTTP
Nexus (http://171.22.25.73:8081, allowInsecureConnections) — no TLS, no cert check.
- npm: add --strict-ssl=false to the CI web-check install (Dockerfile already had it);
Docker npm registry default also moved to the HTTP Nexus.
- ENV_FILE.example documents NUGET_INDEX/NPM_REGISTRY overrides.
Local dev (Windows trusts the cert) + image base pulls (Docker trusts it) are
unaffected — only in-container package feeds switch to HTTP.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Keep the Persian-luxury palette, adopt casual card-game UX:
- New .press-3d primitive (solid underside that compresses on tap, reduced-motion
aware) for tactile buttons.
- Home: a large glowing hero "Play online" button (Play icon + chevron), a
tactile vs-computer card, and chunkier mode tiles with color-tinted icon chips
(teal/sky/gold/rose). All handlers + i18n unchanged.
Verified: tsc + next build clean; web rebuilt :1500.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>