chore(prod): real leaderboard, prod guards, payment hardening
CI/CD / CI - API (dotnet build + engine sim) (push) Successful in 2m4s
CI/CD / CI - Web (tsc + next build) (push) Successful in 1m9s
CI/CD / Deploy - local stack (db + server + web) (push) Successful in 2m11s

Production-readiness pass — remove mock-in-prod and harden the server:
- leaderboard: new DB-backed LeaderboardService + /api/leaderboard (ranked by
  rating, 30s cache, bounded scan); client now calls it instead of mock fake data.
- online count: client uses real /api/stats/online (dropped the fabricated ≥50 floor).
- boot guards (Production): refuse to start if Sms:ApiKey is missing (OTP would
  run in dev mode = fixed code for any phone) or Iab:AllowUnverified is true
  (forged tokens could mint coins).
- payments: ZarinPal + IAB HttpClients get 15s timeouts; ZarinPal/FlatPay gateway
  failures are now logged instead of silently swallowed.
- OTP: periodic prune of expired codes + stale rate-limit logs (was an unbounded
  in-memory leak over a long-running process).
- DB: EnableRetryOnFailure for Postgres (transient-fault resilience).
- docker-compose: ZarinPal sandbox now defaults to false (real payments).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
soroush.asadi
2026-06-17 09:03:12 +03:30
parent 4739018488
commit 0790ad6fe0
8 changed files with 150 additions and 16 deletions
@@ -45,7 +45,8 @@ public sealed class IabOptions
/// </summary>
public sealed class IabService
{
private static readonly HttpClient Http = new();
// Bounded timeout so a hung store API can't tie up request threads.
private static readonly HttpClient Http = new() { Timeout = TimeSpan.FromSeconds(15) };
private readonly IabOptions _opts;
private readonly ILogger<IabService> _log;