Leaderboards¶
Purpose¶
The Leaderboards screen manages tournament-style leaderboards (daily / weekly / monthly), schedules, and prize distributions. Players see live ranks on the player site; admins configure them, watch progress, and manually award prizes to winners.
Audience¶
Marketing (configure prizes), customer support ("am I really #5?" disputes), risk (validate non-bot top ranks).
Path in admin-fe¶
| Screen | URL | Page |
|---|---|---|
| Leaderboards list | /leaderboards |
ebit-admin-fe/src/app/(dashboard)/leaderboards/page.tsx |
| Leaderboard detail | /leaderboards/[slug] |
ebit-admin-fe/src/app/(dashboard)/leaderboards/[slug]/page.tsx |
Backing API endpoints¶
| Endpoint | Source |
|---|---|
GET /admin/leaderboards/schedule (list schedule slots) |
apps/api/src/leaderboard/admin.leaderboard.controller.ts:45 |
GET /admin/leaderboards/schedule/:id (one slot) |
apps/api/src/leaderboard/admin.leaderboard.controller.ts:51 |
POST /admin/leaderboards/schedule/:id (upsert schedule) |
apps/api/src/leaderboard/admin.leaderboard.controller.ts:57 |
GET /admin/leaderboards (list active leaderboards) |
apps/api/src/leaderboard/admin.leaderboard.controller.ts:72 |
GET /admin/leaderboards/:leaderboardId/users (paginated leaderboard) |
apps/api/src/leaderboard/admin.leaderboard.controller.ts:79 |
GET /admin/leaderboards/:leaderboardId/users/:userId (drill one user's rank) |
apps/api/src/leaderboard/admin.leaderboard.controller.ts:91 |
GET /admin/leaderboards/:leaderboardId (config + summary) |
apps/api/src/leaderboard/admin.leaderboard.controller.ts:109 |
POST /admin/leaderboards/give-prize |
apps/api/src/leaderboard/admin.leaderboard.controller.ts:103 |
Frontend wiring: ebit-admin-fe/src/queries/leaderboards/.
Key actions¶
| Action | Required permission | API call | DB tables touched | Audit-logged? |
|---|---|---|---|---|
| List leaderboards | leaderboard.view |
GET /admin/leaderboards |
Leaderboard |
yes |
| List schedule slots | leaderboard.view |
GET /admin/leaderboards/schedule |
LeaderboardSchedule |
yes |
| Edit schedule (start/end, prize pool) | leaderboard.edit |
POST /admin/leaderboards/schedule/:id |
LeaderboardSchedule |
yes |
| List ranks for a leaderboard | leaderboard.view |
GET /admin/leaderboards/:leaderboardId/users |
LeaderboardUser, User |
yes |
| Drill one user | leaderboard.view |
GET /admin/leaderboards/:leaderboardId/users/:userId |
same | yes |
| Manually award a prize | leaderboard.give-prize |
POST /admin/leaderboards/give-prize |
LeaderboardPrize, Transaction, Account |
yes |
The runtime that calculates rank deltas runs on a BullMQ leaderboard queue (apps/api/src/leaderboard/queue/) — admin only configures and reads.
Filters and views¶
- Status —
UPCOMING/LIVE/ENDED. - Type / scope — daily / weekly / monthly / event.
- Game filter — leaderboards can be game-specific.
- Top-N view — pagination defaults to top 100; supports infinite scroll.
Common workflows¶
- Configure a weekly leaderboard. Marketing opens
/leaderboards, picks the week's slot, edits prize pool: 1st = 1000 USDT, 2-5 = 200 each, 6-20 = 50 each. Saves viaPOST /admin/leaderboards/schedule/:id. Player site picks up at next refresh. - Review live ranks. CS views
/leaderboards/[slug]. Spot-check top 10 — are any flagged as bot or banned? If so, trigger a recalculation: engineering republishes the queue (out-of-band). - Award prizes after end. When a leaderboard ends, marketing reviews top 20, click
Give Prizeper row. Backend writes to player accounts viaTransaction. Prizes log intoLeaderboardPrizetable. - Dispute "I should be #3". Drill into the user via
GET /admin/leaderboards/:lbId/users/:userId. See score breakdown + bet contribution timestamps. Cross-reference with bets-history.md. - Cancel a leaderboard. Set status
CANCELLEDvia schedule edit. Prize pool not awarded; player site shows cancellation note.
Edge cases / gotchas¶
give-prizeis per-user, not bulk. For 50 winners, that's 50 calls. Front-end loops; engineering may script out-of-band for huge tournaments.- Bot users are filtered out at rank-calculation time by the BullMQ queue — bot bets don't count.
- Banned users keep their rank until manually removed. Operator should manually
give-prizeto the next eligible player. - Leaderboard score formulas vary. Some leaderboards weight by wager, some by net loss, some by # of plays. The formula is captured in
Leaderboard.scoringMethodand applied in the BullMQ runtime. - Schedule edits during a live leaderboard are dangerous. Changing prize pool mid-run can confuse players. Avoid; or post a customer notice via
handover/customer-comms/. give-prizewrites a single Transaction. It does NOT mark the position as awarded automatically — operator must keep the record.- Per-game leaderboards — slug-scoped (e.g., "Plinko Weekly"). Schema link is
Leaderboard.gameSlug. - Time zones: leaderboard windows are UTC. A "weekly" leaderboard runs Mon 00:00 UTC to Sun 23:59 UTC.
Cross-links¶
- Player-side leaderboard view:
apps/api/src/leaderboard/leaderboard.controller.ts+leaderboard.gateway.controller.ts - BullMQ queue:
apps/api/src/leaderboard/queue/ - Per-user contributing bets: bets-history.md
- Bot exclusion: bots.md
- Audit: admin-logs.md
- Permission keys:
libs/auth/src/permissions/const.ts:69-79
Sequence — manually awarding a prize after leaderboard ends¶
sequenceDiagram
actor mkt as Marketing
participant admin-fe
participant api
participant pg as Postgres
mkt->>admin-fe: open /leaderboards/[slug]/ (status=ENDED)
admin-fe->>api: GET /admin/leaderboards/:id/users?page=1
api->>api: PermissionGuard('leaderboard.view')
api->>pg: SELECT LeaderboardUser ORDER BY rank
pg-->>api: rows
api-->>admin-fe: top 100
loop top N winners
mkt->>admin-fe: click Give Prize on row
admin-fe->>api: POST /admin/leaderboards/give-prize { leaderboardId, userId, amount, currency }
api->>api: PermissionGuard('leaderboard.give-prize')
api->>pg: BEGIN — INSERT Transaction — UPDATE Account — INSERT LeaderboardPrize — INSERT AdminActionLog — COMMIT
api-->>admin-fe: 200 OK
end
admin-fe-->>mkt: rows show prize-awarded badge