Reorganize project: move docs to docs/ and test scripts to tests/

Moved 9 documentation .md files from root into docs/.
Moved 4 test scripts from root into tests/.
Updated cross-references in README.md and docs to reflect new paths.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
cottongin
2026-02-07 14:07:39 -05:00
parent 974f0e4a67
commit 84398ebdd0
14 changed files with 95 additions and 16 deletions

View File

@@ -0,0 +1,310 @@
# WebSocket Subscription Guide
## 📋 Overview
This guide explains how WebSocket subscriptions work in the Jackbox Game Picker and which events require subscriptions.
## 🔌 Connection & Authentication
### 1. Connect to WebSocket
```javascript
const ws = new WebSocket('ws://localhost:5000/api/sessions/live');
```
### 2. Authenticate
```javascript
ws.send(JSON.stringify({
type: 'auth',
token: 'YOUR_JWT_TOKEN'
}));
```
### 3. Wait for Auth Success
```javascript
ws.on('message', (data) => {
const msg = JSON.parse(data.toString());
if (msg.type === 'auth_success') {
console.log('Authenticated!');
// Now you can subscribe to sessions
}
});
```
## 📨 Event Types & Subscription Requirements
| Event Type | Requires Subscription? | Broadcast To | When to Subscribe |
|------------|------------------------|--------------|-------------------|
| `session.started` | ❌ **NO** | All authenticated clients | N/A - Automatic |
| `game.added` | ✅ **YES** | Subscribed clients only | After session.started |
| `vote.received` | ✅ **YES** | Subscribed clients only | After session.started |
| `session.ended` | ✅ **YES** | Subscribed clients only | After session.started |
## 🎯 Subscription Strategy
### Strategy 1: Auto-Subscribe to New Sessions (Recommended for Bots)
```javascript
ws.on('message', (data) => {
const msg = JSON.parse(data.toString());
// After authentication
if (msg.type === 'auth_success') {
console.log('✅ Authenticated');
}
// Auto-subscribe to new sessions
if (msg.type === 'session.started') {
const sessionId = msg.data.session.id;
console.log(`🎮 New session ${sessionId} started!`);
// Subscribe to this session
ws.send(JSON.stringify({
type: 'subscribe',
sessionId: sessionId
}));
}
// Now you'll receive game.added, vote.received, and session.ended
if (msg.type === 'game.added') {
console.log(`🎲 Game: ${msg.data.game.title}`);
}
if (msg.type === 'session.ended') {
console.log(`🌙 Session ended! ${msg.data.session.games_played} games played`);
}
});
```
### Strategy 2: Subscribe to Active Session on Connect
```javascript
ws.on('message', (data) => {
const msg = JSON.parse(data.toString());
if (msg.type === 'auth_success') {
console.log('✅ Authenticated');
// Fetch active session from API
fetch('http://localhost:5000/api/sessions/active')
.then(res => res.json())
.then(session => {
if (session && session.id) {
// Subscribe to active session
ws.send(JSON.stringify({
type: 'subscribe',
sessionId: session.id
}));
}
});
}
});
```
### Strategy 3: Subscribe to Specific Session
```javascript
ws.on('message', (data) => {
const msg = JSON.parse(data.toString());
if (msg.type === 'auth_success') {
console.log('✅ Authenticated');
// Subscribe to specific session
const sessionId = 17;
ws.send(JSON.stringify({
type: 'subscribe',
sessionId: sessionId
}));
}
if (msg.type === 'subscribed') {
console.log(`✅ Subscribed to session ${msg.sessionId}`);
}
});
```
## 🔄 Complete Bot Flow
```javascript
const WebSocket = require('ws');
class JackboxBot {
constructor(token) {
this.token = token;
this.ws = null;
this.currentSessionId = null;
}
connect() {
this.ws = new WebSocket('ws://localhost:5000/api/sessions/live');
this.ws.on('open', () => {
console.log('🔌 Connected to WebSocket');
this.authenticate();
});
this.ws.on('message', (data) => {
this.handleMessage(JSON.parse(data.toString()));
});
}
authenticate() {
this.ws.send(JSON.stringify({
type: 'auth',
token: this.token
}));
}
handleMessage(msg) {
switch (msg.type) {
case 'auth_success':
console.log('✅ Authenticated');
// Don't subscribe yet - wait for session.started
break;
case 'session.started':
this.currentSessionId = msg.data.session.id;
console.log(`🎮 Session ${this.currentSessionId} started!`);
// Auto-subscribe to this session
this.ws.send(JSON.stringify({
type: 'subscribe',
sessionId: this.currentSessionId
}));
// Announce to users
this.announce(`Game Night has started! Session #${this.currentSessionId}`);
break;
case 'subscribed':
console.log(`✅ Subscribed to session ${msg.sessionId}`);
break;
case 'game.added':
console.log(`🎲 Game: ${msg.data.game.title}`);
this.announce(`Now playing: ${msg.data.game.title}`);
break;
case 'vote.received':
console.log(`🗳️ Vote: ${msg.data.vote.type}`);
break;
case 'session.ended':
console.log(`🌙 Session ${msg.data.session.id} ended`);
this.announce(`Game Night ended! ${msg.data.session.games_played} games played`);
this.currentSessionId = null;
break;
}
}
announce(message) {
// Send to IRC/Discord/Kosmi/etc
console.log(`📢 ${message}`);
}
}
// Usage
const bot = new JackboxBot('YOUR_JWT_TOKEN');
bot.connect();
```
## 📊 Subscription Lifecycle
```
1. Connect to WebSocket
2. Send auth message
3. Receive auth_success
4. Wait for session.started (no subscription needed)
5. Receive session.started
6. Send subscribe message with sessionId
7. Receive subscribed confirmation
8. Now receive: game.added, vote.received, session.ended
9. Receive session.ended
10. Wait for next session.started (repeat from step 4)
```
## 🔍 Debugging
### Check What You're Subscribed To
The WebSocket manager tracks subscriptions. Check backend logs:
```
[WebSocket] Client subscribed to session 17
[WebSocket] Client unsubscribed from session 17
```
### Verify Event Reception
**session.started** - Should receive immediately after authentication (no subscription needed):
```
[WebSocket] Broadcasted session.started to 2 authenticated client(s)
```
**game.added, vote.received, session.ended** - Only after subscribing:
```
[WebSocket] Broadcasted game.added to 1 client(s) for session 17
```
### Common Issues
1. **Not receiving session.started:**
- ✅ Are you authenticated?
- ✅ Is your WebSocket connection open?
- ✅ Check backend logs for broadcast confirmation
2. **Not receiving game.added:**
- ✅ Did you subscribe to the session?
- ✅ Did you receive `subscribed` confirmation?
- ✅ Is the session ID correct?
3. **Not receiving session.ended:**
- ✅ Are you still subscribed to the session?
- ✅ Did the session actually close?
- ✅ Check backend logs
## 🎯 Best Practices
1. **Auto-subscribe to new sessions** when you receive `session.started`
2. **Don't subscribe before session.started** - there's nothing to subscribe to yet
3. **Handle reconnections** - re-authenticate and re-subscribe on reconnect
4. **Use polling as fallback** - poll `/api/sessions/active` every 30s as backup
5. **Unsubscribe when done** - clean up subscriptions when you're done with a session
6. **Validate session IDs** - make sure the session exists before subscribing
## 📝 Summary
### ❌ No Subscription Required
- `session.started` - Broadcast to **all authenticated clients**
### ✅ Subscription Required
- `game.added` - Only to **subscribed clients**
- `vote.received` - Only to **subscribed clients**
- `session.ended` - Only to **subscribed clients**
### 🎯 Recommended Flow
1. Authenticate
2. Wait for `session.started` (automatic)
3. Subscribe to the session
4. Receive `game.added`, `vote.received`, `session.ended`
5. Repeat from step 2 for next session
## 🔗 Related Documentation
- [SESSION_START_WEBSOCKET.md](SESSION_START_WEBSOCKET.md) - session.started event details
- [SESSION_END_WEBSOCKET.md](SESSION_END_WEBSOCKET.md) - session.ended event details
- [API_QUICK_REFERENCE.md](API_QUICK_REFERENCE.md) - API reference
- [BOT_INTEGRATION.md](BOT_INTEGRATION.md) - Bot integration guide