Backend API for ranked voting rounds, raid telemetry, Grab-Box shot inventory, and supervisor review desk. Built with AdonisJS 6, PostgreSQL, and Redis, integrating @platform/internal-logic.
- Discord OAuth: voter authentication and token management with role hierarchy (voter, contributor, senior_contributor, supervisor, admin).
- Voting Rounds & Ballots: 3-2-1 ranked ballots, anti-stacking validation, and mass conservation audits.
- Raid Telemetry & Quarantine: real-time velocity Z-scores and auto-quarantine for brigaded entries.
- Leaderboard: Borda tallies regularized with Bayesian shrinkage and cached in Redis.
- Grab-Box Inventory: shot claiming with 1-shot concurrency limit, tier-based deadlines (5-14 days), and Senior priority window locks.
- Storage & Video Submissions: presigned S3/R2 upload URLs for .mp4 and .blend files.
- Supervisor Review Desk: review queue with video playback, approval/revision state machine, and senior promotions.
- Expiry Daemon: automated 15-minute background task that reclaims abandoned shots.
npm install
cp .env.example .env # fill in APP_KEY, DB_PASSWORD and the discord application values
# postgres and redis in docker, the api with hot reload on the host
docker compose -f docker-compose.yml -f docker-compose.local.yml up -d postgres redis
node ace migration:run
node ace db:seed
npm run dev
npm test@platform/internal-logic is installed straight from its git repository at a pinned tag (see
package.json); npm install needs git on the PATH and builds the package on the fly. To move to
a newer release, bump the #v… ref and run npm install so the lockfile records the new commit.
GET /health– 200 when Postgres and Redis are reachable, 503 otherwise (used by the container health check)
GET /api/v1/auth/discord/callbackGET /api/v1/auth/meDELETE /api/v1/auth/logout
GET /api/v1/roundsGET /api/v1/rounds/:idPOST /api/v1/rounds(admin)PATCH /api/v1/rounds/:id(admin)POST /api/v1/rounds/:id/finalize(admin)GET /api/v1/rounds/:roundId/entriesPOST /api/v1/rounds/:roundId/entries(admin)PATCH /api/v1/rounds/:roundId/entries/:id(admin)DELETE /api/v1/rounds/:roundId/entries/:id(admin)POST /api/v1/rounds/:roundId/entries/:id/reinstate(admin)
POST /api/v1/rounds/:roundId/ballotsGET /api/v1/rounds/:roundId/ballots/mineGET /api/v1/rounds/:roundId/leaderboardGET /api/v1/rounds/:roundId/resultsGET /api/v1/rounds/:roundId/telemetry(supervisor+)GET /api/v1/rounds/:roundId/events(supervisor+)
GET /api/v1/shots(filter by sceneNumber, difficultyTier, status)GET /api/v1/shots/:idPOST /api/v1/shots/:id/claim(contributor+)POST /api/v1/shots/:id/release(contributor+)POST /api/v1/shots/:id/upload-url(contributor+)POST /api/v1/shots/:id/submit(contributor+)POST /api/v1/shots(supervisor+)PATCH /api/v1/shots/:id(supervisor+)DELETE /api/v1/shots/:id(admin)
GET /api/v1/reviews(supervisor+)POST /api/v1/reviews/:submissionId(supervisor+)POST /api/v1/supervisors/promote/:userId(supervisor+)POST /api/v1/shots/reclaim-expired(supervisor+)