docs: comprehensive API documentation from source code
Replace existing docs with fresh documentation built entirely from source code analysis. OpenAPI 3.1 spec as source of truth, plus human-readable Markdown with curl examples, response samples, and workflow guides. - OpenAPI 3.1 spec covering all 42 endpoints (validated against source) - 7 endpoint reference docs (auth, games, sessions, picker, stats, votes, webhooks) - WebSocket protocol documentation (auth, subscriptions, 4 event types) - 4 guide documents (getting started, session lifecycle, voting, webhooks) - API README with overview, auth docs, and quick reference table - Old docs archived to docs/archive/ Made-with: Cursor
This commit is contained in:
768
docs/plans/2026-03-15-api-documentation-implementation.md
Normal file
768
docs/plans/2026-03-15-api-documentation-implementation.md
Normal file
@@ -0,0 +1,768 @@
|
||||
# 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 <token>`. 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 <token>`. 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": "<jwt>" }`. 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": <number> }`. Response: `{ "type": "subscribed", "sessionId": <number>, "message": "..." }`. Can subscribe to multiple sessions. Unsubscribe with `{ "type": "unsubscribe", "sessionId": <number> }`.
|
||||
- **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": "<event-type>", "timestamp": "<ISO 8601>", "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"
|
||||
```
|
||||
Reference in New Issue
Block a user