Wordloop Platform
Schemas Data

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

Rendering architecture map...

WebSocket Protocol

Endpoint: ws://localhost:4002/ws (dev) — requires JWT authentication.

PropertyValue
Frame formatJSON text frames (events), binary frames (audio)
Discriminatortype field on every JSON message
KeepaliveServer sends ping every 54s; client must pong within 60s
Max message size1 MB
ReconnectionExponential 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.

{
  "type": "entity_changed",
  "entity": "meeting | person | task | note",
  "action": "created | updated | deleted",
  "id": "<uuid>"
}
FieldTypeDescription
typestringAlways entity_changed
entityenumOne of: meeting, person, task, note
actionenumOne of: created, updated, deleted
idstringUUID of the affected entity

transcript_segment

Sent during a live recording session when a new or updated segment is available.

{
  "type": "transcript_segment",
  "meeting_id": "<uuid>",
  "segment": {
    "id": "<uuid>",
    "speaker_label": "Speaker A",
    "person_id": "",
    "text": "Let's discuss the roadmap.",
    "start_ms": 12500,
    "end_ms": 14200,
    "confidence": 0.94,
    "is_final": true
  }
}
FieldTypeDescription
typestringAlways transcript_segment
meeting_idstringUUID of the meeting
segment.idstringSegment UUID assigned by Core
segment.speaker_labelstringRaw diariser label (e.g. "Speaker A")
segment.person_idstringResolved person UUID. Empty until mapped
segment.textstringTranscribed text content
segment.start_msint64Start time in milliseconds
segment.end_msint64End time in milliseconds
segment.confidencedoubleConfidence score [0, 1]
segment.is_finalbooleanfalse for interim results that may be revised

meeting_summary_updated

Sent when the AI regenerates a meeting summary.

{
  "type": "meeting_summary_updated",
  "meeting_id": "<uuid>",
  "summary": "Discussed Q3 roadmap priorities..."
}

recording_started

Confirms a live recording session is now active.

{
  "type": "recording_started",
  "meeting_id": "<uuid>",
  "session_id": "<opaque-ml-session-id>"
}

recording_stopped

Confirms a live recording session has ended.

{
  "type": "recording_stopped",
  "meeting_id": "<uuid>"
}

recording_error

Reports a failure during a live recording session.

{
  "type": "recording_error",
  "meeting_id": "<uuid>",
  "error": "ML streaming service is unreachable",
  "code": "ml_unavailable"
}
Error CodeMeaning
ml_unavailableML streaming service is unreachable
transcoder_errorAudio transcoding failed

Client → Server Commands

start_recording

Request to begin a live recording session. Only one active session per user is allowed.

{
  "type": "start_recording",
  "meeting_id": "<uuid>"
}

stop_recording

Request to end the active live recording session.

{
  "type": "stop_recording",
  "meeting_id": "<uuid>"
}

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

PropertyValue
Publisherwordloop-core (on audio upload completion)
Subscriberwordloop-ml (triggers transcription pipeline)
SerialisationJSON

transcription_requested

{
  "event": "transcription_requested",
  "transcription_id": "<uuid>",
  "meeting_id": "<uuid>",
  "storage_path": "meetings/<uuid>/audio.mp3"
}
FieldTypeDescription
eventstringAlways transcription_requested
transcription_idstringTranscription job UUID
meeting_idstringMeeting whose audio to transcribe
storage_pathstringGCS path to the audio file

Processing Flow

  1. Core receives audio upload → creates transcription record (status: pending) → publishes message
  2. ML subscribes → downloads audio from GCS → runs AssemblyAI transcription → diarization → feature extraction
  3. ML PATCHes results back to Core via PATCH /api/transcriptions/:id
  4. Core broadcasts entity_changed over WebSocket → client refreshes transcript view