Messaging (Pub/Sub & WebSocket)
Complete event contract reference for all asynchronous communication in the Wordloop platform.
Messaging Contracts
All asynchronous communication in Wordloop uses two transports: WebSocket for real-time client ↔ server events, and Google Cloud Pub/Sub for inter-service job dispatch. The canonical source is openapi/core-asyncapi.yaml (AsyncAPI 3.0).
Transport Overview
WebSocket Protocol
Endpoint: ws://localhost:4002/ws (dev) — requires JWT authentication.
| Property | Value |
|---|---|
| Frame format | JSON text frames (events), binary frames (audio) |
| Discriminator | type field on every JSON message |
| Keepalive | Server sends ping every 54s; client must pong within 60s |
| Max message size | 1 MB |
| Reconnection | Exponential backoff: min(1000 × 2^attempt, 30000) ms |
Server → Client Events
entity_changed
Sent when a domain entity is created, updated, or deleted. Clients invalidate their SWR cache on receipt.
| Field | Type | Description |
|---|---|---|
type | string | Always entity_changed |
entity | enum | One of: meeting, person, task, note |
action | enum | One of: created, updated, deleted |
id | string | UUID of the affected entity |
transcript_segment
Sent during a live recording session when a new or updated segment is available.
| Field | Type | Description |
|---|---|---|
type | string | Always transcript_segment |
meeting_id | string | UUID of the meeting |
segment.id | string | Segment UUID assigned by Core |
segment.speaker_label | string | Raw diariser label (e.g. "Speaker A") |
segment.person_id | string | Resolved person UUID. Empty until mapped |
segment.text | string | Transcribed text content |
segment.start_ms | int64 | Start time in milliseconds |
segment.end_ms | int64 | End time in milliseconds |
segment.confidence | double | Confidence score [0, 1] |
segment.is_final | boolean | false for interim results that may be revised |
meeting_summary_updated
Sent when the AI regenerates a meeting summary.
recording_started
Confirms a live recording session is now active.
recording_stopped
Confirms a live recording session has ended.
recording_error
Reports a failure during a live recording session.
| Error Code | Meaning |
|---|---|
ml_unavailable | ML streaming service is unreachable |
transcoder_error | Audio transcoding failed |
Client → Server Commands
start_recording
Request to begin a live recording session. Only one active session per user is allowed.
stop_recording
Request to end the active live recording session.
After sending start_recording, the client should send binary frames containing raw audio data until stop_recording is sent.
Pub/Sub Protocol
Messages are serialised as JSON on the wire. The event field acts as the message type discriminator.
transcription-jobs Topic
| Property | Value |
|---|---|
| Publisher | wordloop-core (on audio upload completion) |
| Subscriber | wordloop-ml (triggers transcription pipeline) |
| Serialisation | JSON |
transcription_requested
| Field | Type | Description |
|---|---|---|
event | string | Always transcription_requested |
transcription_id | string | Transcription job UUID |
meeting_id | string | Meeting whose audio to transcribe |
storage_path | string | GCS path to the audio file |
Processing Flow
- Core receives audio upload → creates
transcriptionrecord (status:pending) → publishes message - ML subscribes → downloads audio from GCS → runs AssemblyAI transcription → diarization → feature extraction
- ML PATCHes results back to Core via
PATCH /api/transcriptions/:id - Core broadcasts
entity_changedover WebSocket → client refreshes transcript view