openvidu/openvidu-dashboard/openspec/changes/writer-review-fixes/specs/server-analytics-writer/spec.md

73 lines
4.3 KiB
Markdown

## MODIFIED Requirements
### Requirement: Lifted keys and room resolution
Edition: CE and PRO. Every document SHALL carry lifted references resolved from the event: `ROOM_CREATED`
from `room.sid`, egress events from `egress.room_id` and `egress.room_name`, ingress events from
`ingress.state.room_id`, which the server fills from the active room of `ingress.room_name` when the ingress reports
none, and `ingress.room_name`, track events from the minimal `room {sid, name}`; a missing room leaves the reference
absent.
#### Scenario: ROOM_CREATED without room_id
- **GIVEN** a `ROOM_CREATED` event with empty `room_id`, `room.sid = "RM_x"` and `room.creation_time_ms`
- **WHEN** it is projected
- **THEN** the `rooms` document has `_id: "RM_x"` and `createdAt` from `creation_time_ms`, and the raw event has `roomSid: "RM_x"`
#### Scenario: Egress before any room event
- **GIVEN** an `EGRESS_STARTED` with `egress.room_id` and `egress.room_name` and no prior room event
- **WHEN** it is projected
- **THEN** the `egresses` document and the raw event carry `roomSid` and `roomName`, and the `rooms` document is upserted with `features.egress: true` and its egress counter
#### Scenario: Web egress without room
- **GIVEN** a web egress with empty `room_id`
- **WHEN** it is projected
- **THEN** `roomSid` is absent from the egress document and the raw event, and no `rooms` write model is produced
#### Scenario: Ingress session key
- **GIVEN** an `INGRESS_STARTED` with `ingress.state.resource_id`
- **WHEN** it is projected
- **THEN** the `ingress_sessions` document has `_id` equal to `resource_id`, `ingressId` and `roomSid` from `state.room_id`, and the raw event has `ingressSessionId`
#### Scenario: Ingress publishing before its state names the room
- **GIVEN** an ingress of room `qa-ingress`, active as `RM_x`, whose service sends the publishing state without
`room_id`
- **WHEN** the server handles the state update and the writer projects its `INGRESS_STARTED`
- **THEN** the event carries `state.room_id: "RM_x"`, the `ingress_sessions` document has `roomSid: "RM_x"` while it
publishes, and the room counts the session as active
#### Scenario: Ingress of a room that is not active
- **GIVEN** an ingress whose state has no `room_id` and whose room name has no active room
- **WHEN** the server handles the state update
- **THEN** the state keeps no `room_id` and the session document has no `roomSid` until an event names the room
#### Scenario: Subscriber identity resolved
- **GIVEN** a participant session `PA_1` already projected with identity `alice`
- **WHEN** a `TRACK_SUBSCRIBED` with `participant {sid: "PA_1"}` and `publisher {sid, identity}` is processed
- **THEN** the subscription has `subscriberIdentity: "alice"`, `publisherSid` and `publisherIdentity` from `publisher`
### Requirement: Rollup counters from events
Edition: CE and PRO. Each projected event SHALL increment the hourly and daily counters of its UTC bucket
in both scopes, and its 5-minute lifecycle counters, once: an event stored raw counts only when its raw insert
succeeds, so an event already stored by a previous process never counts again; an event not stored raw counts when
it is projected; an in-process retry never reapplies a rollup step that succeeded. Map keys SHALL be enum names or a
fixed vocabulary, never user input.
#### Scenario: Batch retried after a transient error
- **GIVEN** a batch whose raw inserts succeeded and whose rollup step failed with a network error
- **WHEN** the batch is retried
- **THEN** raw inserts are skipped as duplicates, the rollup step is applied once and the counters equal the event counts
#### Scenario: Replayed events from another process
- **GIVEN** events already stored by a previous process
- **WHEN** they are processed again
- **THEN** the rollup counters are unchanged
#### Scenario: Vocabulary keys
- **GIVEN** a `PARTICIPANT_JOINED` with `client_info.sdk: JS`, `os: "Windows 11"` and `browser: "Chrome 130"`
- **WHEN** it is projected
- **THEN** the hourly rollup increments `participants.bySdk.JS`, `participants.byOs.windows` and `participants.byBrowser.chrome`, and a value outside the vocabulary increments `other`
#### Scenario: Session without a browser
- **GIVEN** a `PARTICIPANT_JOINED` with `client_info.sdk: GO` and an empty `browser`
- **WHEN** it is projected
- **THEN** the hourly rollup increments `participants.byBrowser.none`, not `participants.byBrowser.other`