Refresh repository documentation
Some checks failed
Deploy to Production / test (push) Failing after 33s

- Rewrite AGENTS and README files to match the current app layout
- Document API routes, trivia UI, and the active panel design language
This commit is contained in:
syntaxbullet
2026-04-09 21:10:10 +02:00
parent 8369d10bab
commit 6abbd4652a
17 changed files with 893 additions and 639 deletions

View File

@@ -1,31 +1,68 @@
# API Layer
# API layer
## Server
- Bun's native `serve()` API — no Express/Fastify. Custom `handleRequest()` dispatcher with pathname prefix matching.
- Route modules export `{ name: string, handler: RouteHandler }`. Handlers return `null` for non-matching paths.
## Server shape
## Authentication
- Discord OAuth2 with session cookies (`aurora_session`, HttpOnly, 7-day TTL).
- In-memory session store — sessions lost on restart.
- Role-based: `admin` vs `player` (admins set via `ADMIN_USER_IDS` env var).
- Non-enrolled users (not in DB) get 403 even with valid Discord auth.
- Call `getSession(req)` for all protected routes.
- Aurora uses Bun's native `serve()` API in `api/src/server.ts`.
- Route modules are aggregated in `api/src/routes/index.ts`.
- A route module returns `null` when it does not match so the dispatcher can continue.
- After route handling, the server tries `panel/dist` for SPA/static files.
## Response Conventions
- Success: `jsonResponse(data, status)` — uses custom BigInt-safe JSON replacer.
- Error: `errorResponse(message, status, details?)``{ error, details? }`
- Validation: `validationErrorResponse(zodError)``{ error: "Invalid payload", issues: [...] }`
- Zod schemas centralized in `schemas.ts`.
## Authentication and authorization
- OAuth routes live in `api/src/routes/auth.routes.ts`.
- Sessions are stored in memory and keyed by the `aurora_session` cookie.
- Session TTL is 7 days.
- Login succeeds only for users already present in the `users` table.
- Role is `admin` if the Discord ID is in `ADMIN_USER_IDS`, otherwise `player`.
- Redirects after login are intentionally restricted to localhost or relative paths.
Current access rules from `api/src/routes/index.ts`:
- public: `/auth/*`, `/api/health`
- player allow-list: `/api/stats`, `/api/health`, `/api/me`
- everything else under `/api/*`: admin-only
`/api/me/inventory` is handled by `users.routes.ts` and still depends on a valid session.
## Response conventions
- `jsonResponse()` serializes `bigint` values as strings.
- `errorResponse()` returns `{ error, details? }`.
- `parseBody()` and `parseQuery()` validate with Zod and return a `Response` on failure.
- The API does not use a framework-level middleware stack; each route handles its own parsing and branching.
## WebSocket
- Upgrade via `/ws` endpoint (requires auth).
- Pub/sub via Bun's `.publish()` / `.subscribe()` on channels: `dashboard`, `lobby`, `room:${roomId}`.
- Dashboard stats broadcast every 5 seconds. Game events are room-scoped.
- Hard limit: 200 concurrent WS connections (429 rejection), 16KB max payload, 60s idle timeout.
- Fire-and-forget broadcasts — no ack mechanism.
- Endpoint: `/ws`
- Requires an authenticated session
- Dashboard channel: `dashboard`
- Lobby channel: `lobby`
- Room-specific messaging is handled inside `GameServer`
- Dashboard broadcasts `STATS_UPDATE` every 5 seconds while clients are connected
- `NEW_EVENT` broadcasts are wired from `shared/lib/events`
Hard limits:
- max connections: 200
- max payload: 16 KB
- idle timeout: 60 seconds
## Static files
- Built panel assets are served from `panel/dist`
- `/assets/*` serves files from `bot/assets/graphics`
- `/api/*`, `/auth/*`, `/ws`, and `/assets/*` bypass the SPA fallback
## Route notes
- `items.routes.ts` supports both JSON and multipart form data for item creation.
- `settings.routes.ts` writes DB-backed game settings and emits the reload-commands event.
- `guild-settings.routes.ts` invalidates the guild config cache after writes.
- `lootdrops.routes.ts` delegates spawning/deletion to bot-side handlers because Discord message creation happens there.
## Gotchas
- All DB IDs are BigInt — JSON responses must use the custom `jsonReplacer`.
- No rate limiting on HTTP routes.
- Some routes accept multipart form data (e.g., item icon upload) — manual parsing, not abstracted.
- Asset directories resolve relative to `import.meta.dir`.
- Sessions and some caches are in-memory only and are lost on restart.
- The server registers game plugins at startup; duplicate registration throws.
- BigInt-safe JSON matters for nearly every domain route.
- The panel's auth flow depends on `PANEL_BASE_URL` matching the OAuth callback origin.