# Signaling Server (server)

Owns the shared, internet-reachable runtime: HTTP routes for server directory / invites / join requests / link metadata, WebSocket signaling between clients (P2P session setup, presence, status), CQRS command and query handlers, and the shared TypeORM + sql.js persistence layer that holds signaling state.

> **Format reference:**
> - **Vocabulary** — bold term, one-sentence definition, aliases to avoid.
> - **Relationships** — bullets with bold terms and cardinality.
> - **Boundaries / IO** — what this subdomain exposes and consumes.
> - **Invariants** — rules that always hold.
> - **Flagged ambiguities** — terms in dispute with proposed resolutions.
>
> See `agents-docs/AGENTS_CONTEXT.md` for the contract. Update in the same turn a trigger fires (see `agents-docs/AGENT_WORKFLOW.md` § CONTEXT.md upkeep).

## Vocabulary

| Term | Definition | Aliases to avoid |
|------|------------|------------------|
| **Envelope** | The on-the-wire shape of a WebSocket message — `type`, `payload`, and routing metadata, typed in `src/websocket/types.ts` and mirrored in `toju-app/src/app/shared-kernel/signaling-contracts.ts`. | "packet", "frame" |
| **Handler** | A WebSocket message handler registered in `src/websocket/handler.ts`; one per envelope type. | "listener" |
| **CQRS command/query** | A typed request dispatched through `src/cqrs/` — commands mutate state, queries read it; both return a typed result. | "action" (NgRx term) |
| **Server directory** | The catalog of joinable chat servers, exposed by `src/routes/servers.ts` plus invite and join-request routes. | "guild list" |
| **SSRF guard** | The outbound-fetch policy enforced by `src/routes/ssrf-guard.ts` — gates link-metadata and proxy routes that fetch user-supplied URLs. | "proxy filter" |
| **Variables file** | `data/variables.json` — runtime config (klipy key, server host/protocol, release manifest URL, link-preview toggle) normalized on startup. | "config", ".env" (those are separate) |
| **Session token** | Opaque bearer token issued on login/register, stored in `session_tokens`, required on mutating REST routes and WebSocket `identify`. Multiple valid tokens may exist per user (multi-device login). | "API key", "JWT" |
| **Client instance id** | Opaque per-install string on WebSocket `identify` and `voice_state`; used to distinguish connections for the same `oderId` and to track which connection owns active voice. | "device id" |
| **Voice-active connection** | WebSocket connection for a user with `voiceActive=true` after a connected `voice_state`; preferred target for RTC relay. | "voice owner socket" |

## Relationships

- A **WebSocket connection** carries many **Envelopes**; each envelope is routed to exactly one **Handler**.
- A **Route** (HTTP) may dispatch zero or more **CQRS commands/queries** to mutate or read persistent state.
- The **Server directory** depends on **Invites** and **Join requests** — listing, accepting, and revoking flows are split across `routes/servers.ts`, `routes/invites.ts`, `routes/join-requests.ts`.
- **Persistence** entities in `src/entities/` are owned by this subdomain and never shipped to the renderer; the wire envelope is the contract instead.
- **SSRF guard** is consumed by `link-metadata`, `proxy`, and `klipy` routes that fetch user-supplied URLs.

## Boundaries / IO

- **Exposes:**
  - HTTP routes under `src/routes/`: `health`, `users`, `servers`, `invites`, `join-requests`, `games`, `klipy`, `link-metadata`, `proxy`, `plugin-support`, `openapi-docs`.
  - WebSocket envelopes typed in `src/websocket/types.ts` — the realtime contract shared with `toju-app/src/app/shared-kernel/signaling-contracts.ts`.
  - OpenAPI document served by `openapi-docs` route.
- **Consumes:**
  - The shared TypeORM SQLite database via `src/db/` (entities in `src/entities/`, migrations in `src/migrations/`).
  - `data/variables.json` for runtime configuration; `.env` for `PORT` / SSL toggles.
  - Optional outbound HTTP for link previews and klipy (all gated by **SSRF guard**).

## Invariants

- Every database schema change ships as a TypeORM **migration**; the live database is never mutated outside the migration system.
- WebSocket **Envelope** types are defined once in `src/websocket/types.ts` and **must** stay structurally compatible with `toju-app/src/app/shared-kernel/signaling-contracts.ts` — drift between the two is a wire-protocol break.
- User-supplied URLs are **never** fetched without going through `ssrf-guard.ts`.
- Secrets (klipy API key, OAuth tokens, signing keys) live in `data/variables.json` or environment variables — never in code, never in logs.

## Flagged ambiguities

- _None recorded yet — add entries when an envelope type or route name resists clean definition._

---

*Agent-procedural rules (TDD, lint, build) live in `/AGENTS.md`. WebSocket envelope schemas and HTTP request/response shapes belong in `agents-docs/features/` when they cross subdomain boundaries. This file is the bounded-context domain artefact for the signaling server.*
