Communication Service — Event Schemas
Status: populated Owner: TBD Last updated: 2026-04-17 Companion: Service Template · 04 Event-Driven · NAMING
All events use CloudEvents v1.0 envelope. source = ghasi/communication-service. Stream: COMMUNICATION binding subjects communication.> (migration: also binds engage.messaging.> and legacy VIRTUAL_CARE.> until M3).
1. Produced events
1.1 Messaging
| Subject | Type | Version | Retention class | Payload (data) |
|---|---|---|---|---|
communication.thread.created | ghasi.digital_communication.thread.created | v1 | long (audit) | {threadId, tenantId, participantIds[], patientId?, encounterId?, createdBy} |
communication.message.sent | ghasi.digital_communication.message.sent | v1 | long | {threadId, messageId, senderId, tenantId, urgency, patientId?} |
communication.message.replied | ghasi.digital_communication.message.replied | v1 | long | same as sent |
communication.message.read | ghasi.digital_communication.message.read | v1 | short | {threadId, messageIds[], userId, tenantId} |
communication.thread.escalated | ghasi.digital_communication.thread.escalated | v1 | long | {threadId, escalatedBy, tenantId, reason?} |
communication.thread.archived | ghasi.digital_communication.thread.archived | v1 | long | {threadId, archivedBy, tenantId} |
1.2 Notifications
| Subject | Type | Version | Retention | Payload |
|---|---|---|---|---|
communication.notification.queued | ghasi.digital_communication.notification.queued | v1 | short | {intentId, tenantId, correlationId, category, channel, recipientRef, templateKey} |
communication.notification.dispatched | ghasi.digital_communication.notification.dispatched | v1 | medium | {dispatchId, intentId, providerMessageId, channel, tenantId} |
communication.notification.delivered | ghasi.digital_communication.notification.delivered | v1 | medium | {dispatchId, deliveredAt, channel, tenantId} |
communication.notification.failed | ghasi.digital_communication.notification.failed | v1 | medium | {dispatchId, errorCode, sanitizedMessage, channel, tenantId} |
1.3 Virtual sessions
| Subject | Type | Version | Retention | Payload |
|---|---|---|---|---|
communication.virtual_session.created | ghasi.digital_communication.virtual_session.created | v1 | long | {sessionId, tenantId, appointmentId?, patientId, providerIds[]} |
communication.virtual_session.started | ghasi.digital_communication.virtual_session.started | v1 | long | {sessionId, startedAt, tenantId} |
communication.virtual_session.participant.admitted | ghasi.digital_communication.virtual_session.participant.admitted | v1 | medium | {sessionId, participantId, admittedBy, tenantId} |
communication.virtual_session.ended | ghasi.digital_communication.virtual_session.ended | v1 | long | {sessionId, endedAt, durationMs, tenantId} |
communication.virtual_session.cancelled | ghasi.digital_communication.virtual_session.cancelled | v1 | long | {sessionId, cancelledBy, reason?, tenantId} |
communication.virtual_session.failed | ghasi.digital_communication.virtual_session.failed | v1 | long | {sessionId, errorCode, tenantId} |
communication.virtual_session.fallback.initiated | ghasi.digital_communication.virtual_session.fallback.initiated | v1 | long | {sessionId, fallbackThreadId, tenantId} |
communication.virtual_session.recording.ingested | ghasi.digital_communication.virtual_session.recording.ingested | v1 | long | {sessionId, recordingId, binaryId, tenantId} |
communication.virtual_session.billing.chargeable | ghasi.digital_communication.virtual_session.billing.chargeable | v1 | long | {sessionId, chargeableDurationMs, tenantId} |
2. Consumed events
| Subject | Producer | Handler |
|---|---|---|
scheduling.appointment.created | scheduling-service | Create virtual session if encounterClass=VR (idempotency key vc:sched-created:{tenantId}:{appointmentId}) |
scheduling.appointment.cancelled | scheduling-service | Cancel linked non-terminal session |
scheduling.appointment.reminder.sent | scheduling-service | Dispatch reminder notification intent |
portal.notification.queued | patient-portal-service | Translate to intent with category mapping |
laboratory.result.critical.flagged | laboratory-service | Escalated channel profile (push + SMS + in-app) |
radiology.report.critical.flagged | radiology-service | Same as above |
identity.user.gdpr_erasure_requested | identity-service | Mark threads/dispatch logs for anonymization |
3. Schema governance
- Canonical JSON Schemas live at
libs/event-envelope/src/communication/*.jsonin the application monorepo. - Every consumer MUST accept unknown fields (forward compatibility).
- Breaking changes require a new
v{N}type and a dual-publish window ≥ one release. - Legacy aliases
ghasi.messaging.*andVIRTUAL_CARE.*are dual-published until M3 per ADR-0047.
4. Retention classes
| Class | TTL | Examples |
|---|---|---|
| short | 7 days | read receipts, queued intents |
| medium | 90 days | dispatch outcomes |
| long | 7 years (per audit policy) | thread lifecycle, virtual-session lifecycle |