Skip to main content

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

SubjectTypeVersionRetention classPayload (data)
communication.thread.createdghasi.digital_communication.thread.createdv1long (audit){threadId, tenantId, participantIds[], patientId?, encounterId?, createdBy}
communication.message.sentghasi.digital_communication.message.sentv1long{threadId, messageId, senderId, tenantId, urgency, patientId?}
communication.message.repliedghasi.digital_communication.message.repliedv1longsame as sent
communication.message.readghasi.digital_communication.message.readv1short{threadId, messageIds[], userId, tenantId}
communication.thread.escalatedghasi.digital_communication.thread.escalatedv1long{threadId, escalatedBy, tenantId, reason?}
communication.thread.archivedghasi.digital_communication.thread.archivedv1long{threadId, archivedBy, tenantId}

1.2 Notifications

SubjectTypeVersionRetentionPayload
communication.notification.queuedghasi.digital_communication.notification.queuedv1short{intentId, tenantId, correlationId, category, channel, recipientRef, templateKey}
communication.notification.dispatchedghasi.digital_communication.notification.dispatchedv1medium{dispatchId, intentId, providerMessageId, channel, tenantId}
communication.notification.deliveredghasi.digital_communication.notification.deliveredv1medium{dispatchId, deliveredAt, channel, tenantId}
communication.notification.failedghasi.digital_communication.notification.failedv1medium{dispatchId, errorCode, sanitizedMessage, channel, tenantId}

1.3 Virtual sessions

SubjectTypeVersionRetentionPayload
communication.virtual_session.createdghasi.digital_communication.virtual_session.createdv1long{sessionId, tenantId, appointmentId?, patientId, providerIds[]}
communication.virtual_session.startedghasi.digital_communication.virtual_session.startedv1long{sessionId, startedAt, tenantId}
communication.virtual_session.participant.admittedghasi.digital_communication.virtual_session.participant.admittedv1medium{sessionId, participantId, admittedBy, tenantId}
communication.virtual_session.endedghasi.digital_communication.virtual_session.endedv1long{sessionId, endedAt, durationMs, tenantId}
communication.virtual_session.cancelledghasi.digital_communication.virtual_session.cancelledv1long{sessionId, cancelledBy, reason?, tenantId}
communication.virtual_session.failedghasi.digital_communication.virtual_session.failedv1long{sessionId, errorCode, tenantId}
communication.virtual_session.fallback.initiatedghasi.digital_communication.virtual_session.fallback.initiatedv1long{sessionId, fallbackThreadId, tenantId}
communication.virtual_session.recording.ingestedghasi.digital_communication.virtual_session.recording.ingestedv1long{sessionId, recordingId, binaryId, tenantId}
communication.virtual_session.billing.chargeableghasi.digital_communication.virtual_session.billing.chargeablev1long{sessionId, chargeableDurationMs, tenantId}

2. Consumed events

SubjectProducerHandler
scheduling.appointment.createdscheduling-serviceCreate virtual session if encounterClass=VR (idempotency key vc:sched-created:{tenantId}:{appointmentId})
scheduling.appointment.cancelledscheduling-serviceCancel linked non-terminal session
scheduling.appointment.reminder.sentscheduling-serviceDispatch reminder notification intent
portal.notification.queuedpatient-portal-serviceTranslate to intent with category mapping
laboratory.result.critical.flaggedlaboratory-serviceEscalated channel profile (push + SMS + in-app)
radiology.report.critical.flaggedradiology-serviceSame as above
identity.user.gdpr_erasure_requestedidentity-serviceMark threads/dispatch logs for anonymization

3. Schema governance

  • Canonical JSON Schemas live at libs/event-envelope/src/communication/*.json in 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.* and VIRTUAL_CARE.* are dual-published until M3 per ADR-0047.

4. Retention classes

ClassTTLExamples
short7 daysread receipts, queued intents
medium90 daysdispatch outcomes
long7 years (per audit policy)thread lifecycle, virtual-session lifecycle