# ADR-0003: Multi-Client Sessions with Connection-Scoped Routing ## Status Accepted ## Context Users expect to stay logged in on multiple devices simultaneously (Discord-style). The signaling server already issued multiple session tokens per user, but WebSocket broadcasts deduplicated by `oderId`, which prevented a user's second device from receiving chat, typing, or voice-state updates from their first device. Voice had no per-device identity, so two clients could both attempt to transmit audio. ## Decision Introduce a stable per-install `clientInstanceId` on the product client. Route server broadcasts by **connection id** (exclude only the sender socket) while keeping presence `user_joined` / `user_left` identity-scoped. Track `voiceActive` per connection; relay RTC to the voice-active socket. Enforce single voice owner per user via `VoiceState.clientInstanceId` and `voice_client_takeover` handoff between connections. ## Consequences - **Positive:** Chat and presence sync across a user's devices; voice behaves like Discord (one transmitting client, passive viewers, explicit takeover). - **Positive:** Stale-tab hygiene uses `(oderId, connectionScope, clientInstanceId)` eviction without kicking other devices. - **Negative:** `findUserByOderId` semantics change — RTC now prefers voice-active connections; callers must not assume one socket per user. - **Negative:** Clients must include `clientInstanceId` on identify and voice payloads; older builds without it still work but cannot participate in multi-device voice exclusivity reliably.