> 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/game-onboarding.md).

# Engineering

## Single source of truth

* Add the game once in `packages/game-registry/index.ts`.
* Keep `id`, `module`, aliases, and status (`active` / `disabled`) accurate.

## Frontend behavior

* `frontend/src/constants/games.ts` builds game entries from active registry games.
* New active games automatically appear in registry-driven surfaces (games data, aliases, footer/menus that consume `GAMES`).
* Game card images are auto-discovered from `frontend/src/assets/game-cards/*-card.png` by id naming (`<game-id>-card.png`), with coinflip as fallback.
* Optional UI polish (custom icon/card text/theme) can be added in `REGISTRY_GAME_UI` for that game id.

## Backend behavior

* `backend/src/app/config/game-config.ts` reads active registry games.
* `backend/src/indexer/indexer/event-indexer.ts` builds game-module trackers from active registry modules and resolves package keys from module names automatically (snake\_case -> camelCase contract key).
* Raw blockchain events are persisted once in the indexer loop for all module trackers (except transfer-token, which keeps handler-level dedupe semantics for notifications).
* Unknown/new game parameter events are still recorded in `SuiEvent` via that centralized raw persistence path.
* Admin analytics must be able to classify the game and resolve expected edge for every indexed bet before the game is called ready. Add dynamic parameter/config event handling or a documented static RTP config era in `backend/src/app/domains/admin/admin-panel-analytics-refresh.service.ts`, update `admin-panel-analytics.constants.ts` when a static edge is needed, and keep the admin analytics coverage tests passing.
* If historical indexed rows are missing config payloads or predate parameter events, add a source-backed legacy fallback in admin analytics and cover it with tests before expanding game classification.
* If a game emits a per-bet config id in `game_details`, add it to `backend/src/common/indexed-events/canonical-event-json.ts` and derive the matching `config:<id>` key in admin analytics joins.

## Sponsorship behavior

* Add every new game play entrypoint to `frontend/src/features/payments/sponsored-transaction-eligibility.ts` and `backend/src/configs/sponsorship.config.ts`.
* Add focused eligibility/service tests for the new target before calling the game ready.
* Verify low-SUI zkLogin uses sponsored gas, and verify direct zkLogin play still works when sponsorship is unavailable.
* Soccer is the canonical identity for the World Cup campaign game: use game id `soccer`, Move package/module `suigar_soccer::soccer`, env key `SOCCER_PACKAGE_ID`, and sponsored target suffix `::soccer::play`. Keep `world-cup` only as a frontend/campaign alias.

## Outcome math

* Persist generated-game outcome books in source control with outcome codes, weights, multipliers, flags, and target RTP.
* Add a focused test that asserts total weight and weighted RTP, so future AI changes cannot silently turn every result into the same payout.
* For Soccer, config `0` is the playable 96% RTP book. Do not default the app/backend to a refund-only or post-event config unless the campaign is explicitly over.

## Rule of thumb

* Prefer adding defaults in registry-driven builders over adding new `if`/`switch` branches in feature code.
