Features¶
This lists what the code actually implements today, and — just as importantly — what is gated on configuration. The backend is feature-complete for its route surface; several money- and identity-touching paths deliberately return errors until their external provider is configured, rather than pretending to work.
Terminology: "gated" = the code path exists but refuses to operate until a credential/config is present; it fails closed, never open.
Backend (aim-backend)¶
Live, dual-auth REST API under /api/v1. Full endpoint list in the
API Reference. Working capability groups:
- Auth — password register/login, SMS OTP login (auto-creates user +
wallet), token refresh, server-side logout/revocation, admin password
login (
POST /auth/admin/login, rate-limited, uniform 401), OTP email verification (/me/email/send-otp+verify-otp, see the gate below), and an optional reviewer login — a fixed OTP for exactly one configured number (REVIEWER_LOGIN_PHONE/REVIEWER_LOGIN_OTP) so payment-gateway and app-store reviewers can sign in without our SMS; only delivery changes, every gate and limit still applies, and admin accounts are excluded. - Referrals — per-user share codes (
GET /referrals/my-code), the public/r/:codeclick-logging Play Store redirect, and attribution-only signup tracking (users.referred_by+referral_attributions; explicit code first, IP-match fallback). No wallet rewards — see ADR 0012. - Storefront — public products/categories, server-authoritative quote →
order → cancel, paid from the shopping-credits wallet. Products carry an
ordered image gallery alongside the single cover image — see ADR
0013. Catalogue images are either
uploaded (
POST /api/v1/admin/uploads/image, stored content-addressed and served atGET /media/:key) or referenced by URL. - Wallet — balance, transactions, claims, daily spin, and the verified top-up flow (see the gate below).
- Fantasy — Entity Sport sync, contests + templates, teams, live scoring, Redis leaderboards, finalize/void with wallet payouts, pick-one-player sets.
- Predictions — admin-synced markets plus the user-facing orderbook (place/cancel orders, book, activity, positions).
- Account deletion — Google-Play-compliant: an unauthenticated OTP-proven web flow and an authenticated in-app flow with eligibility, status, and cancel.
- Support tickets — user + admin sides; email notification via SMTP when configured.
- Affiliates — application, KYC upload, stats/earnings, click tracking, admin approval + payouts.
- Admin — the whole
/api/v1/admin/*back office (fantasy ops, catalogue + catalogue-image uploads, gateways, users, orders/refunds/reconciliation, tickets, affiliates, predictions, Entity proxy). - Observability —
/health, Prometheus/metrics(fiberprometheus), OTLP-HTTP traces (otelfiber) whenOTEL_EXPORTER_OTLP_ENDPOINTis set.
What is gated, and on what¶
| Capability | Gate | Behaviour until configured |
|---|---|---|
| Website checkout / top-up pages | CCAVENUE_* + PHONEPE_* on the payment server |
payment endpoints return 503; storefront browsing still works (server/index.js logs a warning at boot) |
| Backend top-up initiate | TOPUP_PAGE_BASE_URL |
POST /wallet/topup-initiate returns 503 — it never routes users to an unconfigured/retired merchant page |
| Backend top-up credit callback | STORE_WEBHOOK_SECRET |
POST /wallet/topup-credit returns 503 ("callback verification not configured") — credits are impossible without HMAC verification |
| Top-up status self-heal | PHONEPE_CLIENT_ID/SECRET |
GET /wallet/topup-status/:token can't verify with PhonePe and leaves the top-up pending |
| OTP login | SMS provider (SMS_* vars, alots.in gateway in pkg/sms) |
OTP send fails with a generic error and the stored OTP is deleted; password auth still works |
| Fantasy + predictions (whole process) | ENTITY_ACCESS_TOKEN |
the backend exits at boot (mustGetEnv in config/config.go) — this is a hard requirement, not a soft feature flag |
| Firebase bearer auth | FIREBASE_SERVICE_ACCOUNT_PATH |
only the custom-JWT header works |
| Ticket emails | SMTP_* |
tickets work; notification emails are skipped |
| Email verification | SMTP_* |
POST /me/email/send-otp returns 503 {"error":"email_disabled"}; accounts simply stay unverified (email_verified: false) |
| Referral attribution | nothing — always on | n/a: share links, click logging, and signup attribution need no external provider (share hosts come from PLAY_STORE_URL / REFERRAL_SHARE_BASE_URL, which have working defaults) |
| Traces | OTEL_EXPORTER_OTLP_ENDPOINT |
no traces exported; metrics/logs unaffected |
Wallet top-up is gateway-verified only — by design
The legacy POST /wallet/topup route credited shopping_credits with no
payment, so any logged-in user could mint store currency. The route is
intentionally unrouted in routes.go (the handler survives only
because the verified gateway callbacks reuse the repo method). Money
enters exclusively via topup-initiate → hosted gateway page → verified
topup-credit / topup-status. Do not re-add the direct route.
Website (aim-store-website)¶
React 19 + Vite SPA at aimstoreorg.com, with an Express server
(server/index.js, :3001) that serves the built SPA in production and
fronts the payment gateways:
- Storefront — catalogue, search, wishlist, cart, checkout, policies (refund/return/shipping/terms), account deletion page. Product pages show the full image gallery (arrows, thumbnails, arrow-key navigation).
- Payment plumbing — CCAvenue encrypt/redirect + response handling,
PhonePe OAuth + checkout + webhook, and the wallet top-up variants of
both, which call the backend's HMAC-verified
topup-credit. Deep-links back into the app via theaimstorescheme. GET /api/healthreports{status, payments}so you can see the gate state at a glance.
Mobile app (aim-store-app)¶
Expo SDK 54 / React Native app (expo-router): OTP sign-in, storefront (home, categories, product pages with a swipeable image gallery, cart, checkout), orders + order status, wallet credits + transactions + top-up (via the website's hosted page), rewards/daily spin, gift cards & e-vouchers screens, saved addresses, support, legal pages, and the full Google-Play account-deletion flow. Env files select dev/staging/prod hosts; release builds refuse localhost/HTTP values.
Admin portal (aim-store-admin)¶
Next.js 14 App Router portal at admin.aimstoreorg.com, port 3002.
NextAuth credentials login against the backend's
POST /api/v1/auth/admin/login; the browser never holds the API token —
server-side routes proxy requests and inject x-sdk-access-token.
Operational pages map onto the /api/v1/admin/* modules (dashboard, users,
orders/refunds, products, gateways, fantasy ops, tickets, affiliates,
predictions), plus a link out to Grafana (NEXT_PUBLIC_MONITORING_URL).
Deploy & CI/CD (deploy/, .github/workflows/)¶
Push to main → GitHub Actions build → GHCR → SSH pull-deploy to the VPS,
with pg_dump + mongodump backups and SQL migrations on backend deploys,
and pinned curl --resolve health verification. The Expo app is the exception:
it releases through EAS Workflows (aim-store-app/.eas/workflows/), which
build and submit to Google Play automatically on merge. Details in
Deployment.
Monitoring (monitoring/)¶
Grafana + Prometheus + Loki + Tempo + Alloy at monitor.aimstoreorg.com.
Prometheus scrapes the backend's /metrics; Alloy ships container logs to
Loki; Tempo receives the backend's OTLP traces. Dashboards and alert
rules are provisioned from git (see ADR
0007).