Concepts

The mental model

Define the product language clearly, or your AI agent will improvise, confidently, right up until production. These are the objects every SOMVAD client reasons about.

Data hierarchy

structure

Tenant ─────────── an organisation (bank/fund); hard isolation boundary
 ├── Desk ──────── a trading desk; has a HEAD who supervises its calls
 │    └── User ─── a per-tenant PROFILE; one person may hold a distinct
 │                 profile in several tenants
 ├── Conference ── THE voice primitive: ad-hoc call, private call, hoot…
 │    │            status: created → starting → active ⇄ locked → ended
 │    │            visibility: tenant | private
 │    └── Participant ── a user's leg: invited → joining → connected → left
 ├── Call ──────── a RING pointing at a conference (signaling overlay):
 │                 ringing → accepted | declined | cancelled | missed
 ├── Entitlement ─ user ⇄ resource permission (conference / line / hoot)
 └── Hoot / Line / PrivateWire ── always-on rooms, DDI lines, ring-downs

Media plane (FreeSWITCH mixers) is reached ONLY via the control plane.
/join returns the mixer + room + its own wss:// endpoint. Audio never
touches this API.

Glossary

ObjectWhat it is
TenantAn organisation. The hard isolation boundary: data never crosses it.
DeskA trading desk within a tenant. Its head can supervise (monitor / whisper / barge) any call on the desk.
UserA per-tenant profile of a person. One identity can hold profiles in several tenants; the token's tenant_id picks which one you act as.
ConferenceThe single voice primitive. Every call, hoot, private wire, line, and DM rides this one model with different policy.
ParticipantA user's leg in a conference, with its own lifecycle and an optional role (call admin).
CallA ring pointing at a conference. A signaling overlay: accept turns a ring into a join.
Line / Hoot / Private wireTrader-voice primitives: DDI lines, always-on hoot/squawk rooms, and ring-down wires, all conferences underneath.
EntitlementThe permission linking a user to a resource they may see or join.
MixerA stateful media worker (FreeSWITCH). Conferences are pinned to a home mixer; the pool autoscales.
RecordingA captured call, optionally signed for non-repudiation and retained per tenant policy.

Roles & tenancy

Three roles, strictly ordered:

  • member: uses voice and creates conferences in their own tenant.
  • tenant_admin: manages users, desks, and lines within their tenant.
  • platform_admin: an environment allow-list, never stored in the database; manages tenants and can impersonate a tenant admin (short-lived, audited).

A desk head is not a role. It is supervision scope over one desk. Tenant isolation is enforced server-side on every list, read, and write; a token scoped to one tenant cannot see another's data.

State machines

Honest state is a platform rule. A client shows "joined" only when the SIP session is actually established, never optimistically.

Conference

created → starting → active ⇄ locked → held → ended

locked = temporary privacy. held = parked, resumable.

Participant

invited → joining → connected → left / removed

A leg's own lifecycle, independent of the room's.

Call (ring)

ringing → accepted | declined | cancelled | missed

accept → the callee joins the conference normally.

Environments

Sandbox, test, production stay separate

Promote a workflow when it is ready, not before. The sandbox gives you seeded data and simulated media so you can build and test conference flows without touching a live desk.