Files
jackboxpartypack-gamepicker/docs/archive/WEBSOCKET_FLOW_DIAGRAM.md
cottongin 8ba32e128c 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
2026-03-15 16:44:53 -04:00

18 KiB

WebSocket Event Flow Diagram

🔄 Complete Session Lifecycle

┌─────────────────────────────────────────────────────────────────┐
│                         BOT CONNECTS                             │
└─────────────────────────────────────────────────────────────────┘
                              ↓
┌─────────────────────────────────────────────────────────────────┐
│  Bot → Server: { type: "auth", token: "..." }                   │
└─────────────────────────────────────────────────────────────────┘
                              ↓
┌─────────────────────────────────────────────────────────────────┐
│  Server → Bot: { type: "auth_success" }                         │
│  ✅ Bot is now AUTHENTICATED                                     │
│  ⏳ Bot waits... (no subscription yet)                           │
└─────────────────────────────────────────────────────────────────┘
                              ↓
                              ↓
┌─────────────────────────────────────────────────────────────────┐
│                    ADMIN CREATES SESSION                         │
│  POST /api/sessions { notes: "Friday Game Night" }              │
└─────────────────────────────────────────────────────────────────┘
                              ↓
┌─────────────────────────────────────────────────────────────────┐
│  Server → ALL AUTHENTICATED CLIENTS:                            │
│  {                                                               │
│    type: "session.started",                                     │
│    data: {                                                       │
│      session: { id: 22, is_active: 1, ... }                    │
│    }                                                             │
│  }                                                               │
│  📢 Broadcast to ALL (no subscription needed)                   │
└─────────────────────────────────────────────────────────────────┘
                              ↓
┌─────────────────────────────────────────────────────────────────┐
│  Bot receives session.started                                   │
│  🎮 Bot announces: "Game Night #22 has started!"                │
│                                                                  │
│  Bot → Server: { type: "subscribe", sessionId: 22 }            │
└─────────────────────────────────────────────────────────────────┘
                              ↓
┌─────────────────────────────────────────────────────────────────┐
│  Server → Bot: { type: "subscribed", sessionId: 22 }           │
│  ✅ Bot is now SUBSCRIBED to session 22                         │
└─────────────────────────────────────────────────────────────────┘
                              ↓
                              ↓
┌─────────────────────────────────────────────────────────────────┐
│                    ADMIN ADDS GAME                               │
│  POST /api/sessions/22/games { game_id: 45 }                   │
└─────────────────────────────────────────────────────────────────┘
                              ↓
┌─────────────────────────────────────────────────────────────────┐
│  Server → SUBSCRIBED CLIENTS (session 22):                      │
│  {                                                               │
│    type: "game.added",                                          │
│    data: {                                                       │
│      game: { title: "Quiplash 3", ... }                        │
│    }                                                             │
│  }                                                               │
│  📢 Only to subscribers of session 22                           │
└─────────────────────────────────────────────────────────────────┘
                              ↓
┌─────────────────────────────────────────────────────────────────┐
│  Bot receives game.added                                        │
│  🎲 Bot announces: "Now playing: Quiplash 3"                    │
│  🗳️ Bot announces: "Vote with thisgame++ or thisgame--"        │
└─────────────────────────────────────────────────────────────────┘
                              ↓
                              ↓
┌─────────────────────────────────────────────────────────────────┐
│                    USER VOTES                                    │
│  POST /api/votes/live { username: "Alice", vote: "up" }        │
└─────────────────────────────────────────────────────────────────┘
                              ↓
┌─────────────────────────────────────────────────────────────────┐
│  Server → SUBSCRIBED CLIENTS (session 22):                      │
│  {                                                               │
│    type: "vote.received",                                       │
│    data: {                                                       │
│      vote: { username: "Alice", type: "up" }                   │
│    }                                                             │
│  }                                                               │
│  📢 Only to subscribers of session 22                           │
└─────────────────────────────────────────────────────────────────┘
                              ↓
┌─────────────────────────────────────────────────────────────────┐
│  Bot receives vote.received                                     │
│  🗳️ Bot tracks vote (may announce later)                        │
└─────────────────────────────────────────────────────────────────┘
                              ↓
                    (more games and votes...)
                              ↓
                              ↓
┌─────────────────────────────────────────────────────────────────┐
│                    ADMIN CLOSES SESSION                          │
│  POST /api/sessions/22/close                                    │
└─────────────────────────────────────────────────────────────────┘
                              ↓
┌─────────────────────────────────────────────────────────────────┐
│  Server → SUBSCRIBED CLIENTS (session 22):                      │
│  {                                                               │
│    type: "session.ended",                                       │
│    data: {                                                       │
│      session: { id: 22, is_active: 0, games_played: 5 }       │
│    }                                                             │
│  }                                                               │
│  📢 Only to subscribers of session 22                           │
└─────────────────────────────────────────────────────────────────┘
                              ↓
┌─────────────────────────────────────────────────────────────────┐
│  Bot receives session.ended                                     │
│  🗳️ Bot announces: "Final votes for Quiplash 3: 5👍 1👎"       │
│  🌙 Bot announces: "Game Night ended! 5 games played"           │
│  ⏳ Bot waits for next session.started...                       │
└─────────────────────────────────────────────────────────────────┘

📊 Broadcast Scope Comparison

session.started (Global Broadcast)

┌─────────────────────────────────────────────────────────────────┐
│                         SERVER                                   │
│                                                                  │
│  broadcastToAll('session.started', data)                        │
└─────────────────────────────────────────────────────────────────┘
                    ↓           ↓           ↓
         ┌──────────┴───────────┴───────────┴──────────┐
         ↓                      ↓                       ↓
    ┌────────┐            ┌────────┐             ┌────────┐
    │ Bot A  │            │ Bot B  │             │ Bot C  │
    │   ✅   │            │   ✅   │             │   ✅   │
    └────────┘            └────────┘             └────────┘
    
    ALL authenticated clients receive it
    (no subscription required)

game.added, vote.received, session.ended (Session-Specific)

┌─────────────────────────────────────────────────────────────────┐
│                         SERVER                                   │
│                                                                  │
│  broadcastEvent('game.added', data, sessionId: 22)              │
└─────────────────────────────────────────────────────────────────┘
                              ↓
                    ┌─────────┴─────────┐
                    ↓                   ↓
               ┌────────┐          ┌────────┐          ┌────────┐
               │ Bot A  │          │ Bot B  │          │ Bot C  │
               │   ✅   │          │   ❌   │          │   ✅   │
               │subscr. │          │  not   │          │subscr. │
               │sess 22 │          │subscr. │          │sess 22 │
               └────────┘          └────────┘          └────────┘
    
    ONLY subscribers to session 22 receive it

🎯 Bot State Machine

┌─────────────┐
│ DISCONNECTED│
└──────┬──────┘
       │ connect()
       ↓
┌─────────────┐
│  CONNECTED  │
└──────┬──────┘
       │ send auth
       ↓
┌─────────────┐
│AUTHENTICATED│ ← Wait here for session.started
└──────┬──────┘   (no subscription yet)
       │
       │ receive session.started
       ↓
┌─────────────┐
│   WAITING   │
│     TO      │
│  SUBSCRIBE  │
└──────┬──────┘
       │ send subscribe
       ↓
┌─────────────┐
│ SUBSCRIBED  │ ← Now receive game.added, vote.received, session.ended
└──────┬──────┘
       │
       │ receive session.ended
       ↓
┌─────────────┐
│AUTHENTICATED│ ← Back to waiting for next session.started
└─────────────┘   (still authenticated, but not subscribed)

🔍 Event Flow by Subscription Status

Before Subscription (Just Authenticated)

Server Events:              Bot Receives:
─────────────               ─────────────
session.started      ✅      YES (broadcast to all)
game.added           ❌      NO  (not subscribed yet)
vote.received        ❌      NO  (not subscribed yet)
session.ended        ❌      NO  (not subscribed yet)

After Subscription (Subscribed to Session 22)

Server Events:              Bot Receives:
─────────────               ─────────────
session.started      ✅      YES (still broadcast to all)
game.added           ✅      YES (subscribed to session 22)
vote.received        ✅      YES (subscribed to session 22)
session.ended        ✅      YES (subscribed to session 22)

🎮 Multiple Sessions Example

Time    Event                           Bot A (sess 22)    Bot B (sess 23)
────    ─────                           ───────────────    ───────────────
10:00   session.started (sess 22)       ✅ Receives        ✅ Receives
10:01   Bot A subscribes to sess 22     ✅ Subscribed      ❌ Not subscribed
10:02   game.added (sess 22)            ✅ Receives        ❌ Doesn't receive
10:05   session.started (sess 23)       ✅ Receives        ✅ Receives
10:06   Bot B subscribes to sess 23     ✅ Still sess 22   ✅ Subscribed
10:07   game.added (sess 22)            ✅ Receives        ❌ Doesn't receive
10:08   game.added (sess 23)            ❌ Doesn't receive ✅ Receives
10:10   session.ended (sess 22)         ✅ Receives        ❌ Doesn't receive
10:15   session.ended (sess 23)         ❌ Doesn't receive ✅ Receives

📝 Quick Reference

Event Broadcast Method Scope Subscription Required?
session.started broadcastToAll() All authenticated clients ❌ NO
game.added broadcastEvent() Session subscribers only ✅ YES
vote.received broadcastEvent() Session subscribers only ✅ YES
session.ended broadcastEvent() Session subscribers only ✅ YES