# API Contract (auth-enabled) All endpoints are JSON. Most routes require the HttpOnly `player` cookie issued after register/login. Admin access is granted only via an authenticated admin user session (`IsAdmin=true` on the account). Auth and admin-sensitive routes are rate-limited and return HTTP `429` on excessive requests. ## Auth POST /api/auth/register — accepts optional `adminKey` to set `IsAdmin=true` only for bootstrap of the first admin account POST /api/auth/login POST /api/auth/logout Display names are set during registration and are immutable afterward. Passwords must be 8-128 chars and contain uppercase, lowercase, number, and symbol. ## State (requires auth) GET /api/state — returns currentPhase (for caller), votesFinal, resultsOpen, updatedAt, counts (players/suggestions/votes) GET /api/me — id, displayName, username, isAdmin, currentPhase, votesFinal ## Player (requires auth) POST /api/me/phase/next — advance caller to next phase (Suggest→Vote requires at least one own suggestion; Vote→Results is gated by resultsOpen) POST /api/me/phase/prev — admin-only move caller backward (Results→Vote→Suggest) ## Suggestions (requires auth + phase gating) GET /api/suggestions/mine — own suggestions (Suggest phase) POST /api/suggestions — create (name required ≤100; max 5 per player; validates screenshot URL) PUT /api/suggestions/{id} — update (non-admin: own suggestion; title locked after Suggest) DELETE /api/suggestions/{id} — delete (non-admin only in Suggest; admin any time) GET /api/suggestions/all — all suggestions (from Vote onward), includes author, link metadata ## Votes (requires auth + Vote phase) GET /api/votes/mine POST /api/votes — upsert vote; if suggestion is in a linked group, applies the same score to all linked siblings POST /api/votes/finalize — `{ final: bool }` toggles caller’s finalized status (blocks further vote edits when true) ## Results (requires auth + Results phase + resultsOpen) GET /api/results — leaderboard with totals, counts, averages, caller’s vote, media/links, link metadata ## Admin (requires authenticated admin user) POST /api/admin/results — `{ resultsOpen: bool }` locks/unlocks results and aligns player phases GET /api/admin/vote-status — readiness overview (who finalized) POST /api/admin/joker — `{ playerId }` grants a vote-phase joker to the target player POST /api/admin/player-phase — `{ playerId, phase }`; currently supports Vote→Suggest transitions only DELETE /api/admin/players/{playerId} — `{ password }`; deletes player account plus their suggestions/votes POST /api/admin/link-suggestions — `{ sourceSuggestionId, targetSuggestionId }`; merges vote groups during Vote, clears votes in the linked group, unfinalizes **all** players POST /api/admin/unlink-suggestions — `{ suggestionId }`; breaks links, clears votes for that group, unfinalizes **all** players POST /api/admin/reset — `{ password }`; clear suggestions/votes, keep players, reset phases/vote-final flags POST /api/admin/factory-reset — `{ password }`; wipe players, suggestions, votes, state ## Security Defaults - Security headers are set on all responses (`CSP`, `X-Content-Type-Options`, `X-Frame-Options`, `Referrer-Policy`, `Permissions-Policy`). - In production, HTTPS redirection and HSTS are enabled. - Screenshot URL validation rejects private/reserved address ranges and pins outbound connections to validated public IPs.