8.1 KiB
overview-api Specification
Purpose
The overview endpoint: one cheap, index-backed response with the live counters, today's totals, recent rooms and stale hints that the Overview page and the live counter tiles poll.
Requirements
Requirement: Overview endpoint
Edition: CE. GET /api/v1/overview SHALL require a bearer token, accept only tz (IANA zone or UTC, default
UTC) and answer 200 with generatedAt, live, today and recentRooms; an unknown tz SHALL be rejected with
400. The writer health, schema and migration are served by GET /api/v1/status.
Scenario: Default response
- GIVEN a deployment with a running writer
- WHEN the client requests
GET /api/v1/overviewwith a valid token - THEN the response is
200withgeneratedAtwithin one second of the server clock and the keyslive,todayandrecentRooms, and nonodeskey on CE
Scenario: Unknown timezone
- WHEN the client requests
GET /api/v1/overview?tz=Mars/Olympus - THEN the response is
400with codeVALIDATION_ERRORanddetails.issues[0].pathequal to["tz"]
Requirement: Live counters
Edition: CE. live SHALL carry rooms (status active), participants (status active, kind STANDARD),
services (status active, every kind but STANDARD), participantsByKind (every kind, 0 when absent),
publishers (active STANDARD with isPublisher), egresses (status starting, active or ending) and
ingressSessions (status publishing).
Scenario: Mixed kinds
- GIVEN 12 active rooms holding 85 active STANDARD, 2 SIP, 3 EGRESS and 2 AGENT participants, 54 STANDARD publishers and 1 INGRESS publisher, 3 egresses in status
active, 1 inendingand 1complete, and 1publishingingress session - WHEN the client requests the overview
- THEN
liveis{ rooms: 12, participants: 85, services: 7, participantsByKind: { STANDARD: 85, SIP: 2, INGRESS: 0, EGRESS: 3, AGENT: 2, CONNECTOR: 0, BRIDGE: 0 }, publishers: 54, egresses: 4, ingressSessions: 1, stale: … }
Scenario: Joining participants are not active
- GIVEN a room with one
activeand onejoiningSTANDARD participant - WHEN the client requests the overview
- THEN
live.participantsis1
Requirement: Stale hints
Edition: CE. live.stale SHALL carry rooms and participants, the number of active documents whose lastStatsAt
is older than olderThanMs at generatedAt, and olderThanMs itself: the stale window max(90 s, 60 s + I + 15 s) of
the batch interval I that GET /api/v1/status reports as writer.batchIntervalMs (the largest among the nodes seen in
the last hour, 10 s when none reports one); documents without lastStatsAt SHALL NOT be counted.
Scenario: Stale room and participants
- GIVEN nodes reporting
batchIntervalMs: 10000, an active room whoselastStatsAtis 100 s old with two active participants withlastStatsAt100 s old, and another active room with fresh stats - WHEN the client requests the overview
- THEN
live.staleis{ rooms: 1, participants: 2, olderThanMs: 90000 }
Scenario: Signal-only participant
- GIVEN an active participant that never published nor subscribed and has no
lastStatsAt - WHEN the client requests the overview
- THEN it is not counted in
live.stale.participants
Scenario: Slow writer
- GIVEN a node seen in the last hour with
batchIntervalMs: 60000and an active room with one active participant, both withlastStatsAt100 s old - WHEN the client requests the overview
- THEN
live.staleis{ rooms: 0, participants: 0, olderThanMs: 135000 }
Scenario: Nodes without a reported interval
- GIVEN node documents without
batchIntervalMs - WHEN the client requests the overview
- THEN
live.stale.olderThanMsis90000
Scenario: Window at the default interval
- GIVEN the default batch interval of 10 s
- WHEN the overview is requested
- THEN
live.stale.olderThanMsis 90 000
Requirement: Today's figures
Edition: CE. today SHALL carry tz, since (local midnight of tz in UTC), rooms, participantSessions,
participantMinutes, egresses, ingressSessions and approximate, summed from the global hourly rollups
whose bucket starts at or after the hour containing since; approximate is true when since is not on an
hour boundary.
Scenario: Whole-hour zone
- GIVEN
tz=Europe/Madridat 12:40 local time on 2026-10-13 and hourlyglobalrollups since 22:00 UTC of the previous day summingrooms.created143,participants.joined1204,participants.minutes18340,egress.started21 andingress.sessionsStarted4 - WHEN the client requests the overview
- THEN
todayis{ tz: "Europe/Madrid", since: "2026-10-12T22:00:00.000Z", rooms: 143, participantSessions: 1204, participantMinutes: 18340, egresses: 21, ingressSessions: 4, approximate: false }
Scenario: Half-hour zone
- GIVEN
tz=Asia/Kolkata - WHEN the client requests the overview
- THEN
today.sinceis 18:30 UTC of the previous day, the sum starts at the 18:00 UTC bucket andapproximateistrue
Scenario: No rollups yet
- GIVEN an empty
analytics_hourlycollection - WHEN the client requests the overview
- THEN every counter of
todayis0andapproximateisfalse
Requirement: Recent rooms
Edition: CE. recentRooms SHALL list at most 10 rooms of any status ordered by createdAt descending, each with
sid, name, status, createdAt, endedAt?, durationMs?, closedBy?, participants { active, sessions, unique } (unique: distinct STANDARD identities), nodeId?, lastStatsAt? and stale? (true for an active room
whose lastStatsAt is older than the stale window at generatedAt), never internal id arrays, schemaVersion or
expiresAt.
Scenario: Twelve rooms
- GIVEN 12 rooms, the newest two active
- WHEN the client requests the overview
- THEN
recentRoomshas 10 items starting with the two active rooms, each with the listed fields and noparticipantSids
Scenario: Unique identities of a recent room
- GIVEN a closed room with 7 STANDARD sessions of 4 identities and one EGRESS session
- WHEN the client requests the overview
- THEN its
recentRoomsitem hasparticipants: { active: 0, sessions: 7, unique: 4 }
Scenario: Stale recent room
- GIVEN an active room whose
lastStatsAtis 2 minutes beforegeneratedAtand a writer batch interval of 10 s - WHEN the client requests the overview
- THEN its
recentRoomsitem hasstale: trueand an active room with stats 20 s old has nostalefield
Scenario: Empty database
- WHEN no room exists
- THEN
recentRoomsis[]
Requirement: Conditional overview
Edition: CE. The response SHALL carry a weak ETag derived from the body without generatedAt and
Cache-Control: private, no-cache; a request whose If-None-Match matches SHALL answer 304 without a body.
Scenario: Quiet deployment
- GIVEN a client holding the
ETagof the last overview - WHEN it polls again 10 s later and no counter, room, rollup or node fact changed
- THEN the response is
304with the sameETagand an empty body
Scenario: Writer batch without changes on CE
- GIVEN the same client on CE
- WHEN a batch updated only
nodes.lastSeenAt - THEN the response is
304
Requirement: Index-backed overview
Edition: CE. Every overview query SHALL use an index of the shared contract (rooms { status, createdAt },
participants { status, kind }, egresses { status, startedAt }, ingress_sessions { status },
analytics_hourly { scope, bucket }), examining at most each collection's active documents plus 20 rooms; nodes,
bounded by the node count, is read whole for the stale window's batch interval; schema_meta is not read.
Scenario: Explain plans
- GIVEN a database generated by the data generator at scenario M
- WHEN each overview query is explained
- THEN no plan on
rooms,participants,egresses,ingress_sessionsoranalytics_hourlycontainsCOLLSCAN, andtotalDocsExaminedof the room and participant aggregations equals the number of active documents