# Pluggable Room/WebRTC Architecture

This document describes the clean separation between reusable Room/WebRTC infrastructure and application-specific game logic.

## Architecture Overview

The system is now organized in three layers:

```
┌─────────────────────────────────────────────────────┐
│  Application Layer (Game-Specific)                  │
│  - Game rules, player colors, resources             │
│  - Stored in metadata fields                        │
└─────────────────────────────────────────────────────┘
                        │
                        ├── uses metadata
                        ↓
┌─────────────────────────────────────────────────────┐
│  Adapter Layer (Backward Compatibility)             │
│  - Proxies for transparent access                   │
│  - Maps old API to new architecture                 │
└─────────────────────────────────────────────────────┘
                        │
                        ├── wraps
                        ↓
┌─────────────────────────────────────────────────────┐
│  Infrastructure Layer (Reusable)                    │
│  - Room/Session management                          │
│  - WebSocket handling                               │
│  - WebRTC signaling (MediaControl)                  │
│  - Participant lists                                │
└─────────────────────────────────────────────────────┘
```

## File Organization

### Infrastructure Layer (Reusable)

**[server/routes/room/types.ts](server/routes/room/types.ts)**
- `BaseSession`: Core session data (id, name, ws, live, has_media)
- `Session<TMetadata>`: Generic session with app-specific metadata
- `BaseRoom`: Core room data (id, name, sessions, state)
- `Room<TMetadata>`: Generic room with app-specific metadata
- `Participant`: Minimal info for participant lists
- `PeerConfig`, `PeerRegistry`: WebRTC peer management

**[server/routes/room/helpers.ts](server/routes/room/helpers.ts)**
- `getParticipants()`: Get participant list from sessions
- `createBaseSession()`: Create new session
- `getSessionName()`: Get display name
- `updateSessionActivity()`: Update last active timestamp
- `isSessionActive()`: Check if session is active
- `getActiveSessions()`: Filter active sessions
- `cleanupInactiveSessions()`: Remove stale sessions

**[client/src/MediaControl.tsx](client/src/MediaControl.tsx)**
- `MediaAgent`: WebRTC signaling and connection management
- `MediaControl`: Video feed and controls UI
- Works with `Participant` type from any application

### Application Layer (Game-Specific)

**[server/routes/games/gameMetadata.ts](server/routes/games/gameMetadata.ts)**
- `GameSessionMetadata`: Game-specific session data (color, player, resources)
- `GameRoomMetadata`: Game-specific room data (players, board, rules)
- `GameSession`: Session type with game metadata
- `GameRoom`: Room type with game metadata
- Migration helpers between old and new formats

**[server/routes/games/types.ts](server/routes/games/types.ts)**
- `Player`: Player game state
- `Turn`, `Placements`, `DevelopmentCard`: Game-specific types
- (Legacy `Session` and `Game` types - will be deprecated)

### Adapter Layer (Backward Compatibility)

**[server/routes/games/gameAdapter.ts](server/routes/games/gameAdapter.ts)**
- `wrapSession()`: Proxy for transparent metadata access
- `wrapGame()`: Proxy for transparent metadata access
- Allows code to use `session.color` instead of `session.metadata.color`
- Enables gradual migration without breaking existing code

## Type Definitions

### Infrastructure Types

```typescript
// Base Session (reusable)
interface BaseSession {
  // Identity
  id: string;
  userId?: number;
  name: string | null;

  // Connection
  ws?: WebSocket;
  live: boolean;
  lastActive: number;
  connected: boolean;

  // Media
  has_media: boolean;

  // Security/Bot
  protected?: boolean;
  bot_run_id?: string | null;
  bot_provider_id?: string | null;
  bot_instance_id?: string | null;
}

// Generic Session with metadata
interface Session<TMetadata = any> extends BaseSession {
  metadata?: TMetadata; // Your app data goes here
}

// Participant (for UI lists)
interface Participant {
  name: string | null;
  session_id: string;
  live: boolean;
  has_media: boolean;
  protected?: boolean;
  // ... bot fields
}
```

### Game-Specific Types

```typescript
// Game session metadata
interface GameSessionMetadata {
  color?: string;        // Player color in game
  player?: Player;       // Reference to player object
  resources?: number;    // Temporary resource count
}

// Game room metadata
interface GameRoomMetadata {
  players: Record<string, Player>;  // Game players by color
  developmentCards: DevelopmentCard[];
  placements: Placements;
  turn: Turn;
  // ... all game-specific data
}

// Complete game session
type GameSession = Session<GameSessionMetadata>;

// Complete game room
type GameRoom = Room<GameRoomMetadata>;
```

## Usage Examples

### Creating a New Session (Infrastructure)

```typescript
import { createBaseSession } from './room/helpers';

// Create base session (no game data)
const baseSession = createBaseSession('session-123', 'Alice');

// Add game-specific data
const gameSession: GameSession = {
  ...baseSession,
  metadata: {
    color: 'red',
    player: gamePlayerObject,
  }
};
```

### Getting Participants (Reusable)

```typescript
import { getParticipants } from './room/helpers';

// Get base participant list (works for any app)
const baseParticipants = getParticipants(room.sessions);

// Extend with game-specific data
const gameParticipants = baseParticipants.map(p => ({
  ...p,
  color: room.sessions[p.session_id].metadata?.color,
}));
```

### Using the Adapter (Backward Compatibility)

```typescript
import { wrapSession, wrapGame } from './games/gameAdapter';

// Old code can still work
const session = wrapSession(gameSession);
console.log(session.color); // Accesses session.metadata.color transparently

const game = wrapGame(gameRoom);
console.log(game.players); // Accesses game.metadata.players transparently
```

## Reusing for Another Application

To use the Room/WebRTC infrastructure for a different application:

### 1. Define Your Metadata Types

```typescript
// myapp/metadata.ts
export interface MySessionMetadata {
  score: number;
  team: string;
  role: string;
}

export interface MyRoomMetadata {
  gameMode: string;
  maxPlayers: number;
  settings: any;
}

export type MySession = Session<MySessionMetadata>;
export type MyRoom = Room<MyRoomMetadata>;
```

### 2. Use Infrastructure Helpers

```typescript
import { createBaseSession, getParticipants } from './room/helpers';

// Create session with your metadata
const session: MySession = {
  ...createBaseSession('user-456', 'Bob'),
  metadata: {
    score: 0,
    team: 'blue',
    role: 'defender',
  }
};

// Get participants (works out of the box)
const participants = getParticipants(room.sessions);
```

### 3. Extend Participants with Your Data

```typescript
function getMyAppParticipants(room: MyRoom) {
  const base = getParticipants(room.sessions);

  return base.map(p => ({
    ...p,
    team: room.sessions[p.session_id].metadata?.team,
    role: room.sessions[p.session_id].metadata?.role,
  }));
}
```

### 4. Use MediaControl As-Is

```typescript
// client/src/MyApp.tsx
import { MediaAgent, MediaControl } from './MediaControl';

// Works with your participant type
<MediaAgent
  socketUrl={socketUrl}
  session={session}
  peers={peers}
  setPeers={setPeers}
/>
```

## Migration Path

### Phase 1: Add Metadata Layer (Current)
- ✅ Create new types with metadata separation
- ✅ Create adapter layer for backward compatibility
- ✅ Document architecture
- Existing code continues to work unchanged

### Phase 2: Gradual Migration (Future)
- Update `getParticipants()` to use `import { getParticipants } from './room/helpers'`
- Move game logic to use `session.metadata.color` explicitly
- Update session creation to use new format
- Remove adapter proxies where code is migrated

### Phase 3: Complete Separation (Future)
- Extract room/WebRTC code to separate package
- Publish as reusable library
- Game code only depends on metadata types
- Full separation achieved

## Benefits

### For Current Game

1. **Cleaner Code**: Game logic is clearly separated from infrastructure
2. **Easier Testing**: Can mock sessions without game data
3. **Better Type Safety**: Explicit metadata types
4. **Maintainability**: Clear boundaries between layers

### For Reusability

1. **Drop-In WebRTC**: MediaControl works with any app
2. **Flexible Metadata**: Easy to add app-specific data
3. **Minimal Coupling**: Infrastructure has zero game dependencies
4. **Proven Patterns**: Well-documented extension points

## Current Implementation Status

- ✅ **Infrastructure types defined** ([server/routes/room/types.ts](server/routes/room/types.ts))
- ✅ **Helper functions created** ([server/routes/room/helpers.ts](server/routes/room/helpers.ts))
- ✅ **Game metadata types defined** ([server/routes/games/gameMetadata.ts](server/routes/games/gameMetadata.ts))
- ✅ **Adapter layer implemented** ([server/routes/games/gameAdapter.ts](server/routes/games/gameAdapter.ts))
- ✅ **Documentation complete** (this file)
- ⏳ **Existing code uses adapter** (backward compatible, no changes needed)
- ⏳ **Gradual migration** (future work, optional)

## Example: Todo List App Using This Infrastructure

```typescript
// todo-metadata.ts
interface TodoSessionMetadata {
  completedCount: number;
  role: 'viewer' | 'editor' | 'admin';
}

interface TodoRoomMetadata {
  todos: Array<{ id: string; text: string; done: boolean }>;
  createdBy: string;
}

// todo-app.ts
import { createBaseSession, getParticipants } from './room/helpers';
import { MediaAgent } from './MediaControl';

type TodoSession = Session<TodoSessionMetadata>;
type TodoRoom = Room<TodoRoomMetadata>;

// Create room
const room: TodoRoom = {
  ...createBaseRoom('room-123'),
  metadata: {
    todos: [],
    createdBy: 'user-1',
  }
};

// Add session
room.sessions['user-1'] = {
  ...createBaseSession('user-1', 'Alice'),
  metadata: {
    completedCount: 0,
    role: 'admin',
  }
};

// Get participants with WebRTC (works out of box)
const participants = getParticipants(room.sessions);

// Use MediaControl for video chat while working on todos
<MediaAgent session={session} peers={peers} setPeers={setPeers} />
```

The Todo app gets WebRTC/video for free, with clean separation!

## Summary

This architecture provides:
- ✅ **Clean separation** between infrastructure and application
- ✅ **Reusable components** (Room, Session, MediaControl, WebRTC)
- ✅ **Type-safe metadata** for application-specific data
- ✅ **Backward compatibility** via adapter layer
- ✅ **Easy migration path** with no breaking changes
- ✅ **Well-documented** extension points for new applications
