Add a gated `googleplay` store flavor (NEXT_PUBLIC_STORE=googleplay) so the
appeal/Play build ships a payment-free coin shop. isPurchaseDisabled() makes
BuyCoinsScreen short-circuit to a "not implemented" notice instead of starting
ZarinPal or Iranian IAB (both rejected on Play). Default web/Bazaar/Myket
builds are unaffected. New i18n key buy.notImplemented (fa+en).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Implements real Myket IAB for the Capacitor app (Myket has no purchase
deep-link like Bazaar — it uses the classic Google Play IAB v3 AIDL bound to
the Myket app):
- AIDL: com.android.vending.billing.IInAppBillingService (Myket-compatible).
- MyketBillingPlugin (Capacitor): binds ir.mservices.market via
"ir.mservices.market.InAppBillingService.BIND", runs getBuyIntent →
startIntentSenderForResult, verifies INAPP_DATA_SIGNATURE with the RSA key
(Security.java, SHA1withRSA), returns the purchaseToken; consume() too.
- MainActivity registers the plugin + forwards the purchase activity result.
- Manifest: ir.mservices.market.BILLING permission + <queries> for Android 11+
package visibility.
- build.gradle: enable buildFeatures.aidl (AGP 8 disables it by default).
- storeBilling: Myket goes through the plugin (RSA key embedded); after server
verify, BuyCoins consumes the purchase so coins can be re-bought.
Bazaar (deep-link) and web (ZarinPal) paths unchanged. Needs on-device testing
with the Myket app installed + published products.
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>
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>
Achievements: generator-driven, now 100+ across 7 categories (added Rulership)
mirrored client + server with identical ids/goals/coins. New tracked stats:
hakemRounds (be the hakem — incl. "7× Hakem"), roundsWon, plus losses metric.
Custom achievement-only sticker packs (Rulership 👑, Firestorm 🔥) with new
inline-SVG art (crown-gold, seven-zip, streak-fire), unlocked by hakem_7 /
streak_10. Server GameRoom tallies hakem rounds per seat + rounds won per team;
client tallies the same for vs-computer/private games (dealId-deduped).
Forfeit (surrender): a player can request forfeit; if the teammate is a bot it
auto-confirms, otherwise the human teammate gets a confirm/decline prompt
(20s timeout). Result: forfeiting with ≥1 round won = normal loss; 0 rounds = Kot.
Wired client↔server over the hub (RequestForfeit/ConfirmForfeit/DeclineForfeit
+ "forfeit" event); offline/vs-computer ends immediately in the store. Flag
button + confirm dialogs in the table.
Online count: never shows below 50 — live service floors the real count with a
drifting believable number (mock base lowered to ~50–170).
Matchmaking: real players get a longer priority window (9s) before bots fill;
bots now occasionally react after winning a trick (humanize).
Coins: starter pack is 95,000 Toman (50k coins); packs rescaled up (server + mock).
Verified: dotnet build + tsc + next build clean; sim unlocks 57 achievements/500
matches; live server: starter=95000, a 7-hakem win unlocks hakem_7 + wins_1 with
hakemRounds/roundsWon persisted. Images rebuilt on :1500/:1505.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- ZarinpalService (request/verify) + /api/coins/pay/request (JWT) and
/api/coins/pay/callback (verify → credit via ProfileService.BuyCoins → redirect
back with ?pay=success); merchant id from config (sandbox default)
- Client buyCoins (live) returns the StartPay redirect URL; BuyCoinsScreen
redirects; page.tsx handles the ?pay return (notify + refresh)
- Verified: sandbox request returns a real StartPay URL
- Documented Cafe Bazaar (Poolakey) / Myket IAB as the required store payment path
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Coins only matter for ranked: free games (vs computer / private friend rooms)
cost nothing; random ranked requires an entry (stake), gated by balance →
routes to buy-coins when short
- Buy Coins page (CoinPack/getCoinPacks/buyCoins; mock credits now, real
Zarinpal/IDPay TODO); TopBar coins → buy; lobby create-room is Free
- Friends: removed instant red ✕ delete; UserMinus → inline confirm before remove
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>