> For the complete documentation index, see [llms.txt](https://suigar.gitbook.io/suigar-docs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://suigar.gitbook.io/suigar-docs/end-to-end-ai-map/backend.md).

# Backend

> Snapshot of the NestJS service that powers the Suigar platform. Keep this up to date as modules, env vars, or integrations evolve.

## TL;DR

* NestJS 11 API powering Suigar gameplay data, questing, chat relay, analytics/leaderboards, fiat on-ramps, gift drops, and social auth.
* `pnpm run dev` (`env-cmd -f .env nest start --watch`) runs on `GENERAL.PORT` (default 3000) with a global `/api` prefix; production entry is `node dist/main`.
* Depends on Postgres (`DATABASE_URL`), Mysten Sui RPC, Discord/Telegram/X credentials, CoinGecko demo key, ProxyCheck API key, Moonpay + Coinbase CDP secrets, and Enoki/Google/Twitch/GA auth material.

## Architecture Overview

* `AppModule` loads typed config (general, sui, discord, telegram, x), `ScheduleModule`, Redis-backed admission control, and a global JWT module, then wires quest services, analytics + leaderboard ingestion (`IndexerService`), fiat connectors, chat relay, gift distribution, and social OAuth helpers.
* Controllers live under `src/presentation/controllers` (REST for price, quests, gifts, analytics, auth, users, etc.) with `DiscordGateway` in `src/presentation/gateways/discord.gateway.ts` broadcasting chat, activity, typing, and clustered presence events.
* Core logic sits in `src/app` (services, quests, config, interfaces, filters) with shared DTOs/utilities under `src/domain`.
* `SuiClient` (in `src/infra`) signs/queues blockchain writes via `JobQueueService`; `src/indexer` maintains long-lived Sui listeners that hydrate Prisma event + leaderboard tables.

## Project Layout

* `src/main.ts`: bootstraps NestExpress, applies helmet/hpp, body limits, validation pipe, global filters/interceptors, 5s timeout, CORS, the Redis Socket.IO adapter, trusted-proxy rules, and `/api` prefix.
* `src/app/`: config, controllers, filters, interfaces, quests, services, and shared types (quest orchestration, analytics, auth, fiat, social, gifts).
* `src/presentation/`: REST controllers (price, quests, gifts, analytics, stats, auth, users, moonpay, coinbase, chat, health) plus the Socket gateway.
* `src/domain/`: DTOs (`CreateAuthTokenDto`, `SendMessageDto`, etc.) and mapper helpers shared between layers.
* `src/infra/`: Mysten Sui client wrapper backed by `JobQueueService` to serialize writes and expose helpers.
* `src/configs`: env loader + typed config builders (`general`, `sui`, `discord`, `telegram`, `x`, `jwt`).
* `src/indexer`: event listener entrypoint, handlers, and aggregators for on-chain events feeding leaderboard tables.
* `src/middlewares` & `src/job-queue`: guards, filters, interceptors, and the in-memory queue implementation.
* `prisma/`: schema + migrations; `backend/docs/` contains quest/XP reference notes.

## Data & Persistence

* Prisma (Postgres) models cover quests (`QuestClaim`, `QuestProgress`), campaign metadata, ZkLogin accounts, gift throttling (`GetStashedGift`, `GiftDeliveryLimit`, `GiftDeliverySchedule`), profile + social links (providers `discord`/`telegram`/`x`), and email verification tokens. Generic raw `SuiEvent` persistence has been retired; typed event tables are the indexed source.
* Leaderboard + analytics tables (`ReferralLeaderboard`, `BetLeaderboard`, `WeeklyBetLeaderboard`, `XpLeaderboard`) and per-module event mirrors (`PlayerVipExpProgressEvent`, `DailyStreak*`, referral/house/sweethouse events) power dashboards and quest evaluation.
* `Campaign` rows store partner metadata (`type`, `startAt`, `endAt`, `managesClaims`, optional copy) for quests and claims.
* `QuestClaim` enforces uniqueness on `(questKey, campaignSlug, playerAddress, timePeriod, periodStart)`; rewards record XP, timestamps, and optional tx hash for auditing.
* The indexer persists move-event cursors in the `cursor` table; gift delivery counts reset nightly via cron and rely on ProxyCheck-backed IP checks.
* No seed scripts live in repo; apply Prisma migrations and seed data manually as needed.

## Configuration & Environment

* `src/configs/env.config.ts` loads layered env files: development uses repo `.env.shared` then `.env.local.shared` + `backend/.env` (+ `backend/.env.local`), production uses `.env.<network>.shared` + `backend/.env.<network>`; `NODE_ENV` selects dev vs prod and `NETWORK` drives the network name.
* `ConfigModule.forRoot` registers `general`, `sui`, `discord`, `telegram`, and `x` configs globally; the async JWT config (`jwt.config.ts`) feeds `JwtModule`.
* Critical env vars: `DATABASE_URL`, `GENERAL.PORT`, `GENERAL.PROXYCHECK_API_KEY`, `GENERAL.GA_PROPERTY_ID`, `GENERAL.WELCOME_WHEEL_MAX_REWARD`, `SUI.BACKEND_WALLET_PRIVATE_KEY`, giveaway settlement controls (`SUI.GIVEAWAY_AUTO_SETTLEMENT_DISABLED`, `SUI.GIVEAWAY_SETTLEMENT_GRACE_MS`, `SUI.GIVEAWAY_SETTLEMENT_BATCH_SIZE`), `SUI.SUINS_PARENT_DOMAIN`, `SUI.SUINS_PARENT_NFT_ID`, `SUI.SUINS_MIN_VIP_LEVEL`, `SUI.SUINS_SUBNAME_EXPIRATION_DAYS`, `SUI.SUI_PRICE_API_KEY`, OAuth client IDs (Google/Twitch), Enoki API key, Moonpay secret, Coinbase CDP key trio, Discord bot + client credentials, Telegram bot tokens, X OAuth keys, and `JWT_SECRET`. Google Analytics can use `GA_SERVICE_ACCOUNT_KEY` from SSM or Application Default Credentials when the runtime is given a Google WIF credential config.
* Indexer listeners expect `SUIGAR_PACKAGE_ID`, optional `NETWORK`/`POLLING_INTERVAL_MS`, and database access to keep `cursor` rows fresh; set `INDEXER_DISABLED=true` to skip listeners in tests or one-off tasks.
* `CACHE_STORE=redis` plus `REDIS_URL` (or `REDIS_HOST`/`REDIS_PORT`/`REDIS_DB`/credentials) supplies shared HTTP/WebSocket counters, connection leases, broadcasts, and presence across replicas. Bounded local fallbacks preserve availability during Redis outages.
* `TRUSTED_PROXY_CIDRS` controls which upstream addresses may supply forwarded client IPs. Docker defaults to loopback/link-local/private ranges; use the exact Traefik/webgateway CIDR when the deployment subnet is pinned.

## Interfaces & Integrations

* REST endpoints (prefixed `/api`):
  * `/price` returns cached SUI/USDC prices sourced from CoinGecko.
  * `/quests` exposes status lookups (default or `/campaigns/:slug/:mode/:questKey/status`), `POST /campaigns/:slug/status` batch checks, `/campaigns/:slug/performance_daily/status`, `GET /list`, and throttled `/campaigns/:slug/:questKey/claim` which validates periods/duplicates before awarding XP.
  * `/gift` provides throttled gift URLs (`GET /get`) plus remaining counters per project or IP; responses leverage ProxyCheck and Prisma-backed quotas.
  * `/analytics` and `/stats` power dashboards: live actives, cache stats/clear, referral/bet/xp leaderboards, game activity feeds.
  * `/auth` issues or refreshes auth tokens, collects zkLogin JWTs, and logs out; `/users` serves profile fetch/update, email verification, and Discord/Telegram/X OAuth connect/disconnect flows.
* `/moonpay/sign-url`, `/coinbase-cdp/session-token` (requires `hexAddress`, `blockchains`, and `assets`; the service hashes the wallet with the fixed `suigar-cdp` salt using SHA-256, base64url-encodes the digest, then trims/pads it to a 40-char `partnerUserRef` returned alongside the session token for Coinbase flows), `/chat/message` (Discord relay + history), and `/health` round out utility endpoints. Message creation and reactions now flow exclusively through the websocket gateway.
* WebSockets: `DiscordGateway` broadcasts chat and presence events, authenticates optional handshake JWTs, enforces connection and event caps per socket/IP/verified wallet, caps payloads at 16 KiB, caches/debounces typing and clustered presence work, and queues Discord mutations with bounded concurrency. Traefik affinity cookies keep Socket.IO polling on one replica while Redis carries broadcasts and socket-management requests across replicas.
* External services: Mysten Sui RPC + signing, CoinGecko (price polling), ProxyCheck (anti-proxy), Moonpay, Coinbase CDP, Enoki zkLogin, Google/Twitch OAuth, Discord bot/webhooks, Telegram bot API, and X OAuth.
* Auth: wallet signatures or zkLogin issue JWTs (renewed via `AuthService`), while social links are managed through dedicated Discord/Telegram/X OAuth services tied into `UserService`.

## Commands & Tooling

* Scripts (`package.json`): `pnpm run dev`, `pnpm run start`, `pnpm run build`, `pnpm run prod`, `pnpm run lint`, `pnpm run test`, `pnpm run test:watch`, `pnpm run test:cov`, `pnpm run test:e2e`, `pnpm run format`. Postinstall runs `prisma generate`.
* Root tooling guard: run `pnpm run check:toolchain` after changing Node, pnpm, CI setup, shared actions, or dependency metadata so local and GitHub runtimes stay pinned together.
* Prisma workflows: `pnpm exec prisma migrate dev`, `pnpm exec prisma db push`, `pnpm exec prisma generate` (add scripts if preferred).
* Nest CLI installed as dependency; configuration in `nest-cli.json`.

## Testing Strategy

* Unit/integration tests with Jest + ts-jest; specs under `src/**` or `test/**`. Quest-specific suites in `test/quests` validate XP calculator and registry logic.
* E2E setup via `test/jest-e2e.json`, e.g., `pnpm run test:e2e` spins Nest app with Supertest (ensure test DB/env configured). `http-throttling.spec.ts` proves route and verified-wallet 429 behavior; `discord-gateway.e2e.spec.ts` exercises admission over an actual Socket.IO transport.
* Coverage command `pnpm run test:cov` writes to `coverage/`.

## Observability & Operations

* Nest `Logger` is used across services (quests, auth, discord relay, analytics cache, indexer, gift delivery); tune verbosity via Nest config or environment.
* Admission control logs when Redis is unavailable and the process switches to its bounded local fallback. Alert on that warning in multi-replica deployments because limits and presence are no longer shared until Redis reconnects/restarts.
* Scheduled jobs include CoinGecko polling every 5 minutes and nightly gift delivery counter resets; indexer listeners run continuously and log cursor progress.
* `OpsJobHeartbeat` remains the complete latest-state view for monitoring. Routine successful `OpsJobRun` history is sampled once per job key per five-minute window, while slow successes, failures, and meaningful skips remain complete.
* Success history older than the configured hot window is archived as gzip NDJSON with compressed/content/row SHA-256 checks. The worker reads every object back and restores it into a temporary Postgres table before the source transaction can prune it.
* Quest service logging captures lifecycle state (`active`, `upcoming`, `expired`, `inactive`) with campaign context for support triage.
* Health endpoint `/api/health` is basic, so add DB / Sui RPC diagnostics before production hardening.
* No metrics/tracing shipped; integrate (e.g., OpenTelemetry, Prometheus exporters) if you need visibility into poller latency or queue depth.

## Deployment & CI/CD

* Build with `pnpm run build` (Nest compiler to `dist/`). `Dockerfile` present for containerized deploy; `start.sh` / `remote-exec.sh` scripts support infrastructure automation.
* Ensure migrations run (`prisma migrate deploy`) before starting app; secrets provisioned using layered env files or platform secrets manager.
* HTTP admission control defaults to 300 requests per 60 seconds, honors controller `default` overrides, and charges authenticated traffic to both trusted client IP and verified wallet. Traefik adds a 50 requests/second average and 100-request burst at the edge.

## Troubleshooting & Gotchas

* Startup prints env load status (✅/❌) from `src/configs/env.config.ts`; missing layered files or mismatched `NODE_ENV` → network mapping are the usual culprit.
* On-chain writes must flow through `SuiClient.signAndExec` (which queues via `JobQueueService`) to avoid nonce contention.
* Indexer listeners rely on `cursor` rows and `SUIGAR_PACKAGE_ID`; stale cursors or missing package IDs halt leaderboard updates, so check logs before reprocessing.
* ProxyCheck failures degrade gracefully but return fewer details, so monitor gift logs if users report denial despite valid IPs.
* HTTP payloads are capped at 1 MB; Socket.IO payloads are capped at 16 KiB with smaller per-event limits. Raise a limit only with matching DTO validation and admission tests.
* Quest evaluation depends on ingested on-chain events (e.g., `bet_result_event` rows). If statuses never advance, verify indexer ingestion before debugging quest logic.

## Reference Links

* Quest system docs: `backend/docs/EXPECTED_VALUE_XP_MIGRATION.md`, `backend/docs/SIMPLIFIED_XP_SYSTEM.md`.
* Prisma models: `backend/prisma/schema.prisma` (run `prisma studio` for inspection).
* Frontend consumption patterns documented in `docs/codex/frontend.md`.

## Open Questions

* Outline the preferred production ingestion runbook for the indexer listeners.
* Capture monitoring and rotation procedures for Discord/Telegram/X credentials, ProxyCheck keys, Moonpay, and Coinbase CDP secrets.
* Document Google Analytics service account setup plus expected latency/accuracy for realtime dashboards.
* Define alerting or dashboards for leaderboard ingestion lag (cursor staleness, Prisma write failures).
