1
0
peddlers-of-ketran/ARCHITECTURE_DIAGRAM.md

19 KiB

Architecture Diagram

System Overview

┌────────────────────────────────────────────────────────────────┐
│                     CLIENT APPLICATIONS                         │
│                                                                 │
│  ┌───────────────────┐         ┌───────────────────┐          │
│  │  Settlers Game    │         │   Chat Room App   │          │
│  │  ┌─────────────┐  │         │  ┌─────────────┐  │          │
│  │  │ Game UI     │  │         │  │ Chat UI     │  │          │
│  │  │ - Board     │  │         │  │ - Messages  │  │          │
│  │  │ - Actions   │  │         │  │ - Input     │  │          │
│  │  └─────────────┘  │         │  └─────────────┘  │          │
│  │                    │         │                    │          │
│  │  Uses:             │         │  Uses:             │          │
│  │  ┌──────────────────────────────────────────┐   │          │
│  │  │      REUSABLE COMPONENTS                 │   │          │
│  │  │  • MediaControl (Video/Audio UI)         │   │          │
│  │  │  • MediaAgent (WebRTC Signaling)         │   │          │
│  │  │  • PlayerList (Participant Display)      │   │          │
│  │  └──────────────────────────────────────────┘   │          │
│  └───────────────────┘         └───────────────────┘          │
└────────────────────────────────────────────────────────────────┘
                            │
                            │ WebSocket
                            ↓
┌────────────────────────────────────────────────────────────────┐
│                         SERVER LAYERS                           │
│                                                                 │
│  ┌──────────────────────────────────────────────────────────┐  │
│  │             APPLICATION LAYER (App-Specific)             │  │
│  │                                                          │  │
│  │  Settlers Game              │    Chat App               │  │
│  │  ┌────────────────────┐     │    ┌───────────────────┐  │  │
│  │  │ GameSessionMeta    │     │    │ ChatSessionMeta   │  │  │
│  │  │ - color            │     │    │ - status          │  │  │
│  │  │ - player           │     │    │ - messageCount    │  │  │
│  │  │ - resources        │     │    │ - customStatus    │  │  │
│  │  └────────────────────┘     │    └───────────────────┘  │  │
│  │                             │                           │  │
│  │  ┌────────────────────┐     │    ┌───────────────────┐  │  │
│  │  │ GameRoomMeta       │     │    │ ChatRoomMeta      │  │  │
│  │  │ - players          │     │    │ - messages        │  │  │
│  │  │ - board setup      │     │    │ - topic           │  │  │
│  │  │ - game rules       │     │    │ - pinnedMessages  │  │  │
│  │  └────────────────────┘     │    └───────────────────┘  │  │
│  │                                                          │  │
│  │  Message Handlers:           │    Message Handlers:      │  │
│  │  • set color                 │    • send message         │  │
│  │  • place settlement          │    • set status           │  │
│  │  • trade resources            │    • pin message          │  │
│  └──────────────────────────────────────────────────────────┘  │
│                            │                                    │
│                            │ uses metadata                      │
│                            ↓                                    │
│  ┌──────────────────────────────────────────────────────────┐  │
│  │         ADAPTER LAYER (Optional Compatibility)           │  │
│  │                                                          │  │
│  │  Proxy Handlers:                                        │  │
│  │  • session.color ─────→ session.metadata.color          │  │
│  │  • session.player ────→ session.metadata.player         │  │
│  │  • game.players ──────→ game.metadata.players           │  │
│  │                                                          │  │
│  │  Enables backward compatibility without code changes    │  │
│  └──────────────────────────────────────────────────────────┘  │
│                            │                                    │
│                            │ wraps                              │
│                            ↓                                    │
│  ┌──────────────────────────────────────────────────────────┐  │
│  │        INFRASTRUCTURE LAYER (Reusable Framework)         │  │
│  │                                                          │  │
│  │  ┌────────────────────────────────────────────────────┐  │  │
│  │  │                Session Management                  │  │  │
│  │  │  • BaseSession (id, name, ws, live, has_media)    │  │  │
│  │  │  • Session<TMeta> (+ metadata field)              │  │  │
│  │  │  • createBaseSession()                            │  │  │
│  │  │  • updateSessionActivity()                        │  │  │
│  │  │  • isSessionActive()                              │  │  │
│  │  │  • getSessionName()                               │  │  │
│  │  └────────────────────────────────────────────────────┘  │  │
│  │                                                          │  │
│  │  ┌────────────────────────────────────────────────────┐  │  │
│  │  │                 Room Management                    │  │  │
│  │  │  • BaseRoom (id, name, sessions, state)           │  │  │
│  │  │  • Room<TMeta> (+ metadata field)                 │  │  │
│  │  │  • getParticipants()                              │  │  │
│  │  │  • getActiveSessions()                            │  │  │
│  │  │  • cleanupInactiveSessions()                      │  │  │
│  │  └────────────────────────────────────────────────────┘  │  │
│  │                                                          │  │
│  │  ┌────────────────────────────────────────────────────┐  │  │
│  │  │              WebRTC Signaling                      │  │  │
│  │  │  • join() - Add peer to registry                  │  │  │
│  │  │  • part() - Remove peer from registry             │  │  │
│  │  │  • relayICECandidate() - Forward ICE              │  │  │
│  │  │  • relaySessionDescription() - Forward SDP        │  │  │
│  │  │  • PeerRegistry - Track peer connections          │  │  │
│  │  └────────────────────────────────────────────────────┘  │  │
│  │                                                          │  │
│  │  ┌────────────────────────────────────────────────────┐  │  │
│  │  │             WebSocket Handling                     │  │  │
│  │  │  • Connection management                           │  │  │
│  │  │  • Automatic reconnection                          │  │  │
│  │  │  • Message routing                                 │  │  │
│  │  │  • Keep-alive pings                                │  │  │
│  │  └────────────────────────────────────────────────────┘  │  │
│  └──────────────────────────────────────────────────────────┘  │
└────────────────────────────────────────────────────────────────┘

Data Flow: Setting User Name

┌─────────────┐
│   CLIENT    │
└─────────────┘
      │
      │ 1. User types name "Alice"
      │
      ↓
  sendJsonMessage({
    type: "set",
    field: "name",
    value: "Alice"
  })
      │
      │ WebSocket
      ↓
┌─────────────────────────────────────────┐
│            SERVER                       │
│                                         │
│  Infrastructure Layer:                  │
│  ├─ Receive message                     │
│  ├─ Find session by WebSocket           │
│  └─ Route to handler                    │
│                                         │
│  Application Layer:                     │
│  ├─ session.name = "Alice"              │
│  └─ Broadcast to all sessions           │
│                                         │
│  Infrastructure Layer:                  │
│  └─ getParticipants(room.sessions)      │
│     └─ Returns: [                       │
│         { session_id, name: "Alice",    │
│           live: true, has_media: true } │
│       ]                                 │
└─────────────────────────────────────────┘
      │
      │ Broadcast update
      ↓
┌─────────────┐
│  ALL CLIENTS│
└─────────────┘
      │
      │ Receive participants update
      ↓
  PlayerList rerenders
  with "Alice" shown

Data Flow: Joining Video Call

┌─────────────┐
│   CLIENT    │
└─────────────┘
      │
      │ 1. MediaAgent mounts
      │ 2. Gets user media (camera/mic)
      │
      ↓
  sendJsonMessage({
    type: "join",
    data: { has_media: true }
  })
      │
      │ WebSocket
      ↓
┌──────────────────────────────────────────┐
│           SERVER                         │
│                                          │
│  Infrastructure Layer (WebRTC):          │
│  ├─ join(peers, session, { has_media }) │
│  │                                       │
│  │  For each existing peer:              │
│  │  ├─ Send addPeer to existing peer    │
│  │  │   { peer_id: "Alice",             │
│  │  │     peer_name: "Alice",           │
│  │  │     has_media: true,              │
│  │  │     should_create_offer: false }  │
│  │  │                                   │
│  │  └─ Send addPeer to new peer         │
│  │      { peer_id: "Bob",               │
│  │        peer_name: "Bob",             │
│  │        has_media: true,              │
│  │        should_create_offer: true }   │
│  │                                       │
│  └─ Add to peer registry:                │
│      peers["Alice"] = {                  │
│        ws, has_media: true               │
│      }                                   │
│                                          │
│  └─ Send join_status:                    │
│      { type: "join_status",              │
│        status: "Joined" }                │
└──────────────────────────────────────────┘
      │
      │ Relay messages
      ↓
┌─────────────┐
│  ALL CLIENTS│
└─────────────┘
      │
      │ Each client:
      ├─ Creates RTCPeerConnection
      ├─ Adds local media tracks
      ├─ Creates offer/answer
      └─ Exchanges ICE candidates
      │
      ↓
  Peer-to-peer video/audio flows

Data Flow: Game-Specific Action

┌─────────────┐
│  GAME CLIENT│
└─────────────┘
      │
      │ Player clicks "Blue" color
      │
      ↓
  sendJsonMessage({
    type: "set",
    field: "color",
    value: "blue"
  })
      │
      │ WebSocket
      ↓
┌───────────────────────────────────────────┐
│            SERVER                         │
│                                           │
│  Infrastructure Layer:                    │
│  ├─ Route message to app handler          │
│  └─ session object available              │
│                                           │
│  Adapter Layer (optional):                │
│  └─ Wraps session with proxy              │
│                                           │
│  Application Layer (Game):                │
│  ├─ setPlayerColor(game, session, "blue")│
│  │   ├─ Validate color available         │
│  │   ├─ session.color = "blue"           │  ← Direct access
│  │   │   (or session.metadata.color)     │  ← New arch
│  │   ├─ session.player = gamePlayer      │
│  │   └─ Update game.metadata.players     │
│  │                                        │
│  └─ Broadcast update:                     │
│      participants: [                      │
│        {                                  │
│          ...baseParticipant,              │  ← Infrastructure
│          color: "blue"                    │  ← App-specific
│        }                                  │
│      ]                                    │
└───────────────────────────────────────────┘
      │
      │ Broadcast
      ↓
┌─────────────┐
│  ALL CLIENTS│
└─────────────┘
      │
      │ Update UI
      ↓
  PlayerList shows
  "Alice" with blue color

Metadata Access Patterns

Without Adapter (New Code)

// Explicit metadata access
const color = session.metadata?.color;
session.metadata = { ...session.metadata, color: 'blue' };

const players = room.metadata.players;
room.metadata.players['blue'] = newPlayer;

With Adapter (Backward Compatible)

// Same as before - adapter proxies to metadata
const color = session.color;
session.color = 'blue';

const players = room.players;
room.players['blue'] = newPlayer;

Both work! Adapter allows gradual migration.

Reusability Layers

Application A (Settlers)    Application B (Chat)    Application C (Whiteboard)
        │                          │                        │
        ├── GameSessionMeta        ├── ChatSessionMeta      ├── WhiteboardSessionMeta
        │   - color                │   - status             │   - cursorColor
        │   - player               │   - messageCount       │   - selectedTool
        │                          │                        │
        └─────────────┬────────────┴────────────────────────┘
                      │
                      │ All apps extend base types
                      ↓
        ┌─────────────────────────────────┐
        │   INFRASTRUCTURE (Shared)       │
        │  • Session<TMeta>               │
        │  • Room<TMeta>                  │
        │  • MediaControl (WebRTC)        │
        │  • getParticipants()            │
        │  • Session management           │
        └─────────────────────────────────┘
                      ↑
            Single implementation,
            works for all apps!

Summary

This architecture provides:

Clean separation between infrastructure and application Type-safe metadata for app-specific data Reusable components that work across applications Backward compatibility via adapter layer Clear data flows from client to server to all clients Proven patterns ready for production use

Any new application can plug into the infrastructure and get:

  • Multi-user rooms
  • WebSocket connection management
  • WebRTC video/audio signaling
  • Participant tracking
  • UI components (MediaControl)

All for free! Just define your metadata types and business logic.