# API Documentation Implementation Plan > **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task. **Goal:** Create comprehensive, accurate API documentation from source code — OpenAPI 3.1 spec as source of truth, plus human-readable Markdown with examples and guide-style prose. **Architecture:** OpenAPI YAML spec covers all 41 REST endpoints. Separate Markdown files per route group with curl examples and response samples. WebSocket protocol documented in dedicated Markdown. Guide files connect endpoints into workflows. **Tech Stack:** OpenAPI 3.1 YAML, Markdown, curl for examples --- ### Task 1: Archive existing docs and create directory structure **Files:** - Move: `docs/*.md` → `docs/archive/` - Create directories: `docs/api/`, `docs/api/endpoints/`, `docs/api/guides/` **Step 1: Create the archive directory** ```bash mkdir -p docs/archive docs/api/endpoints docs/api/guides ``` **Step 2: Move existing docs to archive** ```bash mv docs/API_QUICK_REFERENCE.md docs/archive/ mv docs/BOT_INTEGRATION.md docs/archive/ mv docs/SESSION_END_QUICK_START.md docs/archive/ mv docs/SESSION_END_WEBSOCKET.md docs/archive/ mv docs/SESSION_START_WEBSOCKET.md docs/archive/ mv docs/WEBSOCKET_FLOW_DIAGRAM.md docs/archive/ mv docs/WEBSOCKET_SUBSCRIPTION_GUIDE.md docs/archive/ mv docs/WEBSOCKET_TESTING.md docs/archive/ mv docs/todos.md docs/archive/ ``` **Step 3: Verify structure** ```bash ls -R docs/ ``` Expected: `archive/` with old files, `api/endpoints/` and `api/guides/` empty, `plans/` with design docs. **Step 4: Commit** ```bash git add docs/ git commit -m "docs: archive old documentation, create new docs structure" ``` --- ### Task 2: Write OpenAPI spec — info, servers, security, and component schemas **Files:** - Create: `docs/api/openapi.yaml` **Step 1: Write the OpenAPI header, servers, security schemes, and all reusable component schemas** Write `docs/api/openapi.yaml` with: ```yaml openapi: 3.1.0 info: title: Jackbox Game Picker API description: API for managing Jackbox Party Pack games, sessions, voting, and integrations. version: "1.0" license: name: MIT servers: - url: http://localhost:5000 description: Local development (backend direct) - url: http://localhost:3000/api description: Docker Compose (via Vite/Nginx proxy) security: [] tags: - name: Auth description: Authentication endpoints - name: Games description: Game management and filtering - name: Sessions description: Session lifecycle and game tracking - name: Picker description: Weighted random game selection - name: Stats description: Aggregate statistics - name: Votes description: Real-time popularity voting - name: Webhooks description: Webhook management for external integrations components: securitySchemes: bearerAuth: type: http scheme: bearer bearerFormat: JWT description: > JWT token obtained from POST /api/auth/login. Pass as `Authorization: Bearer `. Tokens expire after 24 hours. schemas: Error: type: object properties: error: type: string required: - error Game: type: object properties: id: type: integer pack_name: type: string title: type: string min_players: type: integer max_players: type: integer length_minutes: type: integer nullable: true has_audience: type: integer enum: [0, 1] family_friendly: type: integer enum: [0, 1] game_type: type: string nullable: true secondary_type: type: string nullable: true play_count: type: integer popularity_score: type: integer upvotes: type: integer downvotes: type: integer enabled: type: integer enum: [0, 1] favor_bias: type: integer enum: [-1, 0, 1] created_at: type: string format: date-time Session: type: object properties: id: type: integer created_at: type: string format: date-time closed_at: type: string format: date-time nullable: true is_active: type: integer enum: [0, 1] notes: type: string nullable: true games_played: type: integer SessionGame: type: object properties: id: type: integer session_id: type: integer game_id: type: integer played_at: type: string format: date-time manually_added: type: integer enum: [0, 1] status: type: string enum: [playing, played, skipped] room_code: type: string nullable: true player_count: type: integer nullable: true player_count_check_status: type: string nullable: true pack_name: type: string title: type: string game_type: type: string nullable: true min_players: type: integer max_players: type: integer popularity_score: type: integer upvotes: type: integer downvotes: type: integer Pack: type: object properties: id: type: integer name: type: string favor_bias: type: integer enum: [-1, 0, 1] created_at: type: string format: date-time PackMeta: type: object properties: name: type: string total_count: type: integer enabled_count: type: integer total_plays: type: integer Webhook: type: object properties: id: type: integer name: type: string url: type: string format: uri events: type: array items: type: string enabled: type: boolean created_at: type: string format: date-time WebhookLog: type: object properties: id: type: integer webhook_id: type: integer event_type: type: string payload: type: object response_status: type: integer nullable: true error_message: type: string nullable: true created_at: type: string format: date-time ``` **Step 2: Validate YAML syntax** ```bash node -e "const fs=require('fs'); const y=require('yaml'); y.parse(fs.readFileSync('docs/api/openapi.yaml','utf8')); console.log('Valid YAML')" ``` If `yaml` module not available, use: `npx -y yaml-cli docs/api/openapi.yaml` or manually verify structure. **Step 3: Commit** ```bash git add docs/api/openapi.yaml git commit -m "docs: add OpenAPI spec with schemas and security definitions" ``` --- ### Task 3: Write OpenAPI paths — Auth and Games endpoints **Files:** - Modify: `docs/api/openapi.yaml` **Step 1: Add `paths` section with Auth endpoints** Source: `backend/routes/auth.js` — 2 endpoints. Add paths for: - `POST /api/auth/login` — Body: `{ key }`, responses: 200 (token+message+expiresIn), 400 (missing key), 401 (invalid key) - `POST /api/auth/verify` — Security: bearerAuth, responses: 200 (`{ valid, user: { role, timestamp } }`) **Step 2: Add Games endpoints** Source: `backend/routes/games.js` — 13 endpoints. Add paths for: - `GET /api/games` — Query params: `enabled`, `minPlayers`, `maxPlayers`, `playerCount`, `drawing` (only/exclude), `length` (short/medium/long), `familyFriendly`, `pack`. Response: array of Game. - `GET /api/games/packs` — Response: array of Pack. - `GET /api/games/meta/packs` — Response: array of PackMeta. - `GET /api/games/export/csv` — Security: bearerAuth. Response: CSV file (text/csv). - `PATCH /api/games/packs/{name}/favor` — Security: bearerAuth. Body: `{ favor_bias }` (-1/0/1). Response: `{ message, favor_bias }`. Error 400 for invalid value. - `GET /api/games/{id}` — Response: Game or 404. - `POST /api/games` — Security: bearerAuth. Body: `{ pack_name, title, min_players, max_players, length_minutes?, has_audience?, family_friendly?, game_type?, secondary_type? }`. Response 201: Game. Error 400: missing fields. - `PUT /api/games/{id}` — Security: bearerAuth. Body: same fields (all optional). Response: Game or 404. - `DELETE /api/games/{id}` — Security: bearerAuth. Response: `{ message }` or 404. - `PATCH /api/games/{id}/toggle` — Security: bearerAuth. Response: Game (with toggled enabled) or 404. - `PATCH /api/games/packs/{name}/toggle` — Security: bearerAuth. Body: `{ enabled }`. Response: `{ message, gamesAffected }`. Error 400: missing enabled. - `POST /api/games/import/csv` — Security: bearerAuth. Body: `{ csvData, mode }` (mode: "append" or "replace"). Response: `{ message, count, mode }`. Error 400: missing csvData. CSV columns: Game Pack, Game Title, Min. Players, Max. Players, Length, Audience, Family Friendly?, Game Type, Secondary Type. - `PATCH /api/games/{id}/favor` — Security: bearerAuth. Body: `{ favor_bias }` (-1/0/1). Response: `{ message, favor_bias }`. Error 400/404. **Step 3: Validate YAML syntax** Same validation command as Task 2 Step 2. **Step 4: Commit** ```bash git add docs/api/openapi.yaml git commit -m "docs: add Auth and Games endpoint paths to OpenAPI spec" ``` --- ### Task 4: Write OpenAPI paths — Sessions, Picker, Stats, Votes, Webhooks **Files:** - Modify: `docs/api/openapi.yaml` **Step 1: Add Sessions endpoints (15 endpoints)** Source: `backend/routes/sessions.js` Add paths for: - `GET /api/sessions` — Response: array of Session (with games_played count). - `GET /api/sessions/active` — Response: Session object or `{ session: null, message }`. - `GET /api/sessions/{id}` — Response: Session or 404. - `POST /api/sessions` — Security: bearerAuth. Body: `{ notes? }`. Response 201: Session. Error 400: active session already exists (`{ error, activeSessionId }`). Triggers WebSocket `session.started` broadcast. - `POST /api/sessions/{id}/close` — Security: bearerAuth. Body: `{ notes? }`. Response: closed Session (with games_played). Error 404/400 (already closed). Sets all 'playing' games to 'played'. Triggers WebSocket `session.ended`. - `DELETE /api/sessions/{id}` — Security: bearerAuth. Response: `{ message, sessionId }`. Error 404/400 (cannot delete active). Cascades: deletes chat_logs and session_games. - `GET /api/sessions/{id}/games` — Response: array of SessionGame (joined with game data). - `POST /api/sessions/{id}/games` — Security: bearerAuth. Body: `{ game_id, manually_added?, room_code? }`. Response 201: SessionGame. Error 400 (closed session, missing game_id), 404 (session/game not found). Side effects: increments play_count, sets previous 'playing' games to 'played', triggers `game.added` webhook + WebSocket, auto-starts room monitor if room_code provided. - `POST /api/sessions/{id}/chat-import` — Security: bearerAuth. Body: `{ chatData: [{ username, message, timestamp }] }`. Response: `{ message, messagesImported, duplicatesSkipped, votesProcessed, votesByGame, debug }`. Vote patterns: "thisgame++" = upvote, "thisgame--" = downvote. Matches votes to games by timestamp intervals. - `PATCH /api/sessions/{sessionId}/games/{gameId}/status` — Security: bearerAuth. Body: `{ status }` (playing/played/skipped). Response: `{ message, status }`. Error 400/404. If setting to 'playing', auto-sets other playing games to 'played'. - `DELETE /api/sessions/{sessionId}/games/{gameId}` — Security: bearerAuth. Response: `{ message }`. Error 404. Stops room monitor/player count check. - `PATCH /api/sessions/{sessionId}/games/{gameId}/room-code` — Security: bearerAuth. Body: `{ room_code }` (exactly 4 chars, A-Z0-9). Response: SessionGame. Error 400 (invalid format)/404. - `GET /api/sessions/{id}/export` — Security: bearerAuth. Query: `format` ("json" or "txt", default "txt"). Response: file download (application/json or text/plain). - `POST /api/sessions/{sessionId}/games/{gameId}/start-player-check` — Security: bearerAuth. Response: `{ message, status: "monitoring" }`. Error 400 (no room code)/404. - `POST /api/sessions/{sessionId}/games/{gameId}/stop-player-check` — Security: bearerAuth. Response: `{ message, status: "stopped" }`. - `PATCH /api/sessions/{sessionId}/games/{gameId}/player-count` — Security: bearerAuth. Body: `{ player_count }` (non-negative integer). Response: `{ message, player_count }`. Error 400/404. Triggers WebSocket `player-count.updated`. **Step 2: Add Picker endpoint** Source: `backend/routes/picker.js` — mounted at `/api` (not `/api/picker`). - `POST /api/pick` — No auth. Body: `{ playerCount?, drawing?, length?, familyFriendly?, sessionId?, excludePlayed? }`. Response 200: `{ game: Game, poolSize, totalEnabled }`. Response 404: `{ error, suggestion, recentlyPlayed? }`. Bias: game favor_bias 1=3x, -1=0.2x; pack favor_bias 1=2x, -1=0.3x. Repeat avoidance: excludes last 2 played games by default, or all played if excludePlayed=true. **Step 3: Add Stats endpoint** Source: `backend/routes/stats.js` - `GET /api/stats` — No auth. Response: `{ games: { count }, gamesEnabled: { count }, packs: { count }, sessions: { count }, activeSessions: { count }, totalGamesPlayed: { count }, mostPlayedGames: [...], topRatedGames: [...] }`. The game arrays include: id, title, pack_name, play_count, popularity_score, upvotes, downvotes. Limited to top 10. **Step 4: Add Votes endpoint** Source: `backend/routes/votes.js` - `POST /api/votes/live` — Security: bearerAuth. Body: `{ username, vote, timestamp }` where vote is "up" or "down", timestamp is ISO 8601. Response 200: `{ success, message, session: { id, games_played }, game: { id, title, upvotes, downvotes, popularity_score }, vote: { username, type, timestamp } }`. Error 400 (missing fields, invalid vote/timestamp), 404 (no active session, no games, vote doesn't match a game), 409 (duplicate within 1 second). **Step 5: Add Webhooks endpoints (7 endpoints)** Source: `backend/routes/webhooks.js` - `GET /api/webhooks` — Security: bearerAuth. Response: array of Webhook (events parsed from JSON, enabled as boolean). - `GET /api/webhooks/{id}` — Security: bearerAuth. Response: Webhook or 404. - `POST /api/webhooks` — Security: bearerAuth. Body: `{ name, url, secret, events }` where events is string array. Response 201: Webhook + `{ message }`. Error 400: missing fields, invalid URL, events not array. - `PATCH /api/webhooks/{id}` — Security: bearerAuth. Body: `{ name?, url?, secret?, events?, enabled? }`. Response: Webhook + `{ message }`. Error 400 (no fields, invalid URL, events not array)/404. - `DELETE /api/webhooks/{id}` — Security: bearerAuth. Response: `{ message, webhookId }`. Error 404. - `POST /api/webhooks/test/{id}` — Security: bearerAuth. Sends test `game.added` payload. Response: `{ message, note }`. Error 404. - `GET /api/webhooks/{id}/logs` — Security: bearerAuth. Query: `limit` (default 50). Response: array of WebhookLog (payload parsed from JSON). **Step 6: Add Health endpoint** - `GET /health` — No auth. Response: `{ status: "ok", message: "Jackbox Game Picker API is running" }`. **Step 7: Validate YAML syntax** Same validation as before. **Step 8: Commit** ```bash git add docs/api/openapi.yaml git commit -m "docs: complete all OpenAPI endpoint paths" ``` --- ### Task 5: Write API README **Files:** - Create: `docs/api/README.md` **Step 1: Write the API overview document** Content should include: - **Overview:** What the API does (manage Jackbox games, run sessions, track popularity, pick games with weighted randomness) - **Base URL:** `http://localhost:5000` (direct) or `http://localhost:3000/api` (Docker proxy). All REST endpoints prefixed with `/api/` except `/health`. - **Authentication:** POST to `/api/auth/login` with admin key → receive JWT. Include as `Authorization: Bearer `. Tokens expire in 24 hours. Public endpoints (GET games, GET sessions, GET stats, POST pick, GET health) don't require auth. All write operations require auth. - **Request/Response format:** JSON request/response. `Content-Type: application/json`. Exceptions: CSV export returns `text/csv`, session export can return `text/plain`. - **Error handling:** All errors return `{ "error": "message" }`. HTTP status codes: 400 (bad request/validation), 401 (no token), 403 (invalid/expired token), 404 (not found), 409 (conflict/duplicate), 500 (server error). - **Boolean fields:** SQLite stores booleans as integers (0/1). In request bodies, pass JS booleans; the API converts. In responses, expect 0/1 except for Webhook.enabled which returns a JS boolean. - **Pagination:** No pagination — all list endpoints return full result sets. - **Quick reference table:** All 41 endpoints in a single table: Method | Path | Auth | Description - **Links:** to endpoint docs, WebSocket docs, and guides **Step 2: Commit** ```bash git add docs/api/README.md git commit -m "docs: add API README with overview, auth, and quick reference" ``` --- ### Task 6: Write endpoint docs — Auth and Games **Files:** - Create: `docs/api/endpoints/auth.md` - Create: `docs/api/endpoints/games.md` **Step 1: Write auth.md** Cover the 2 auth endpoints with the template from the design doc. Include: - Overview: simple admin-key authentication. One role (admin). No user management. - Endpoint table - For each endpoint: description, auth, parameters, request body, response, errors, curl example - curl examples must use realistic sample data **Step 2: Write games.md** Cover all 13 games endpoints with the template. Important details to include from source code: - GET /api/games filter behavior: `drawing=only` matches `game_type='Drawing'`, `drawing=exclude` excludes Drawing. `length=short` is ≤15min (including NULL), `medium` is 16-25min, `long` is >25min. Results ordered by pack_name, title. - POST /api/games requires: pack_name, title, min_players, max_players. Optional: length_minutes, has_audience, family_friendly, game_type, secondary_type. - PUT /api/games/:id uses COALESCE for most fields (only updates what's provided), but length_minutes, game_type, secondary_type accept explicit null. - CSV import expects columns: Game Pack, Game Title, Min. Players, Max. Players, Length, Audience, Family Friendly?, Game Type, Secondary Type. Mode "replace" deletes ALL existing games first. - Favor bias: 1=favor, -1=disfavor, 0=neutral. Applies to picker weighting. **Step 3: Commit** ```bash git add docs/api/endpoints/auth.md docs/api/endpoints/games.md git commit -m "docs: add Auth and Games endpoint documentation" ``` --- ### Task 7: Write endpoint docs — Sessions **Files:** - Create: `docs/api/endpoints/sessions.md` **Step 1: Write sessions.md** Cover all 15 sessions endpoints. Important details from source code: - Only one active session at a time. Creating a session when one exists returns 400 with activeSessionId. - Closing a session auto-sets all 'playing' games to 'played'. - Cannot delete active sessions — must close first. Delete cascades chat_logs and session_games. - Adding a game to session: auto-sets previous 'playing' games to 'played' (skipped games stay skipped), increments game play_count, triggers `game.added` webhook + WebSocket, auto-starts room monitor if room_code provided. - Chat import: matches vote timestamps to games using interval logic (vote belongs to game whose played_at is most recent before vote timestamp). Deduplicates by SHA-256 hash of `username:message:timestamp`. - Status update to 'playing' auto-sets other 'playing' games to 'played'. - Room code: exactly 4 chars, uppercase A-Z and 0-9 only. Regex: `/^[A-Z0-9]{4}$/`. - Export formats: JSON (structured with session+games+chat_logs) and TXT (human-readable plaintext). - Player count: body is `{ player_count }`, must be non-negative integer. Sets `player_count_check_status` to 'completed'. Broadcasts `player-count.updated` via WebSocket. - The `gameId` parameter in session game sub-routes refers to `session_games.id`, NOT `games.id`. **Step 2: Commit** ```bash git add docs/api/endpoints/sessions.md git commit -m "docs: add Sessions endpoint documentation" ``` --- ### Task 8: Write endpoint docs — Picker, Stats, Votes, Webhooks **Files:** - Create: `docs/api/endpoints/picker.md` - Create: `docs/api/endpoints/stats.md` - Create: `docs/api/endpoints/votes.md` - Create: `docs/api/endpoints/webhooks.md` **Step 1: Write picker.md** Key details from source code: - Filters enabled games only (enabled=1) - Weighted random: game favor_bias 1 = 3x weight, -1 = 0.2x weight. Pack favor_bias 1 = 2x weight, -1 = 0.3x weight. Biases multiply. - Repeat avoidance: with sessionId, excludes last 2 games by default. With excludePlayed=true, excludes ALL games played in session. - 404 when no games match filters (with suggestion), or when all eligible games have been played. **Step 2: Write stats.md** Key details: single endpoint, no auth, returns aggregate counts and top-10 lists (most played, top rated). mostPlayedGames sorted by play_count DESC, topRatedGames sorted by popularity_score DESC, both only include games with > 0 in respective metric. **Step 3: Write votes.md** Key details: - Requires auth. Body: `{ username, vote, timestamp }`. - `vote` must be "up" or "down". `timestamp` must be valid ISO 8601. - Automatically matches vote to the correct game in the active session using timestamp interval logic. - Deduplication: rejects votes from same username within 1 second (409). - Updates game upvotes/downvotes/popularity_score atomically in a transaction. **Step 4: Write webhooks.md** Key details: - All endpoints require auth. - Events stored as JSON string in DB, returned as parsed array. - `enabled` stored as 0/1 in DB, returned as JS boolean. - Secret is never returned in GET responses (excluded from SELECT). - Test sends a `game.added` event with dummy data. - Logs include parsed payload, limited by `limit` query param (default 50). **Step 5: Commit** ```bash git add docs/api/endpoints/picker.md docs/api/endpoints/stats.md docs/api/endpoints/votes.md docs/api/endpoints/webhooks.md git commit -m "docs: add Picker, Stats, Votes, and Webhooks endpoint documentation" ``` --- ### Task 9: Write WebSocket documentation **Files:** - Create: `docs/api/websocket.md` **Step 1: Write websocket.md** Cover the full WebSocket protocol from `backend/utils/websocket-manager.js`: - **Connection:** `ws://host:port/api/sessions/live`. No query params needed. Connection established without auth. - **Authentication:** Send `{ "type": "auth", "token": "" }`. Server responds with `{ "type": "auth_success", "message": "Authenticated successfully" }` or `{ "type": "auth_error", "message": "..." }`. Auth required for subscribe/unsubscribe. - **Subscription model:** Subscribe to a specific session's events with `{ "type": "subscribe", "sessionId": }`. Response: `{ "type": "subscribed", "sessionId": , "message": "..." }`. Can subscribe to multiple sessions. Unsubscribe with `{ "type": "unsubscribe", "sessionId": }`. - **Heartbeat:** Client sends `{ "type": "ping" }`, server responds `{ "type": "pong" }`. Timeout: 60 seconds since last ping — server terminates connection. Heartbeat check runs every 30 seconds. - **Events (server → client):** - `session.started` — broadcast to ALL authenticated clients (not session-specific). Data: `{ session: { id, is_active, created_at, notes } }`. Triggered when `POST /api/sessions` creates a new session. - `game.added` — broadcast to session subscribers. Data: `{ session: { id, is_active, games_played }, game: { id, title, pack_name, min_players, max_players, manually_added, room_code } }`. Triggered when `POST /api/sessions/:id/games` adds a game. - `session.ended` — broadcast to session subscribers. Data: `{ session: { id, is_active, games_played } }`. Triggered when `POST /api/sessions/:id/close` closes session. - `player-count.updated` — broadcast to session subscribers. Data: `{ sessionId, gameId, playerCount, status }`. Triggered when player count is updated. - **Event envelope:** `{ "type": "", "timestamp": "", "data": { ... } }` - **Error messages:** `{ "type": "error", "message": "..." }` for general errors, `{ "type": "auth_error", "message": "..." }` for auth failures. - **Connection lifecycle example:** Connect → auth → subscribe → receive events → ping/pong loop → unsubscribe → close. - **Reconnection:** Server doesn't maintain state across disconnects. Client must re-authenticate and re-subscribe after reconnecting. **Step 2: Commit** ```bash git add docs/api/websocket.md git commit -m "docs: add WebSocket protocol documentation" ``` --- ### Task 10: Write guide — Getting Started **Files:** - Create: `docs/api/guides/getting-started.md` **Step 1: Write getting-started.md** Narrative guide walking through the minimum viable integration: 1. Health check — verify API is running 2. Authenticate — get a JWT token 3. Browse games — list all games, filter by player count 4. Pick a game — use the picker with filters 5. Start a session — create session, add the picked game 6. Close the session Each step includes a curl example and expected response. Cross-references the endpoint docs for full details. **Step 2: Commit** ```bash git add docs/api/guides/getting-started.md git commit -m "docs: add Getting Started guide" ``` --- ### Task 11: Write guide — Session Lifecycle **Files:** - Create: `docs/api/guides/session-lifecycle.md` **Step 1: Write session-lifecycle.md** Narrative guide covering: 1. Creating a session (one active at a time constraint) 2. Adding games (via picker or manual), understanding auto-status-transitions 3. Tracking game status (playing → played/skipped) 4. Room codes and player count monitoring 5. Closing sessions (auto-finalizes playing games) 6. Exporting session data (JSON and TXT formats) 7. Deleting old sessions (must close first, cascades) 8. WebSocket integration for real-time updates **Step 2: Commit** ```bash git add docs/api/guides/session-lifecycle.md git commit -m "docs: add Session Lifecycle guide" ``` --- ### Task 12: Write guide — Voting and Popularity **Files:** - Create: `docs/api/guides/voting-and-popularity.md` **Step 1: Write voting-and-popularity.md** Narrative guide covering: 1. How popularity works: `popularity_score = upvotes - downvotes` 2. Two voting mechanisms: chat import (batch, after-the-fact) and live votes (real-time, from bots) 3. Chat import flow: collect chat logs with `thisgame++`/`thisgame--` patterns, POST to chat-import, timestamp-matching algorithm explained 4. Live vote flow: bot sends votes in real-time via POST /api/votes/live, same timestamp-matching logic, deduplication within 1 second 5. How voting affects the picker: popularity_score doesn't directly affect picker weights (favor_bias does), but topRatedGames in stats uses it 6. Favor bias vs popularity: favor_bias is admin-controlled weighting for the picker; popularity is community-driven sentiment tracking **Step 2: Commit** ```bash git add docs/api/guides/voting-and-popularity.md git commit -m "docs: add Voting and Popularity guide" ``` --- ### Task 13: Write guide — Webhooks and Events **Files:** - Create: `docs/api/guides/webhooks-and-events.md` **Step 1: Write webhooks-and-events.md** Narrative guide covering: 1. Two notification systems: Webhooks (HTTP callbacks) and WebSocket (persistent connections) 2. When to use which: Webhooks for server-to-server integrations (bots, Discord); WebSocket for real-time UI or tools that maintain persistent connections 3. Webhook setup: create webhook, specify events, provide URL and secret 4. Webhook events: `game.added` (currently the only webhook event triggered in code — verify this). Payload shape. 5. Webhook delivery: async, logged in webhook_logs. Test with POST /api/webhooks/test/:id. 6. WebSocket events: `session.started`, `game.added`, `session.ended`, `player-count.updated`. Which are broadcast to all clients vs session subscribers. 7. Event payload reference (linking to websocket.md) **Step 2: Commit** ```bash git add docs/api/guides/webhooks-and-events.md git commit -m "docs: add Webhooks and Events guide" ``` --- ### Task 14: Validate documentation against source code **Files:** - Read: all `backend/routes/*.js` files - Read: `docs/api/openapi.yaml` - Read: all `docs/api/endpoints/*.md` files **Step 1: Cross-reference every route handler against the OpenAPI spec** For each file in `backend/routes/`: - Count endpoints in source code - Count corresponding paths in `openapi.yaml` - Verify HTTP methods match - Verify path patterns match (including parameter names) - Verify auth requirements match (`authenticateToken` usage) **Step 2: Verify request/response shapes** For each endpoint: - Compare request body fields to what the route handler destructures from `req.body` - Compare response shapes to what the route handler actually sends via `res.json()` - Check error status codes and messages match **Step 3: Fix any discrepancies found** Edit the OpenAPI spec and/or Markdown files to match the source code. **Step 4: Commit any fixes** ```bash git add docs/ git commit -m "docs: fix discrepancies found during validation" ``` --- ### Task 15: Final review and summary commit **Step 1: Verify all files exist** ```bash ls -la docs/api/ ls -la docs/api/endpoints/ ls -la docs/api/guides/ ls -la docs/archive/ ``` Expected: - `docs/api/`: openapi.yaml, README.md, websocket.md - `docs/api/endpoints/`: auth.md, games.md, sessions.md, picker.md, stats.md, votes.md, webhooks.md - `docs/api/guides/`: getting-started.md, session-lifecycle.md, voting-and-popularity.md, webhooks-and-events.md - `docs/archive/`: 9 old doc files **Step 2: Verify total endpoint count in OpenAPI spec** ```bash grep -c "operationId:" docs/api/openapi.yaml ``` Expected: 42 (41 API endpoints + 1 health check) **Step 3: Final commit if any files were missed** ```bash git add docs/ git status git commit -m "docs: complete API documentation with OpenAPI spec, endpoint docs, WebSocket, and guides" ```