messaging.pdf

Messaging & Communications Decision Guide

Companion to the Messaging & Communications docs.

Companion to the Messaging & Communications docs.

Section 1: Use Case & Participants

These questions establish the “who and why” before scoping any features. The answers should shape how you frame the rest of the conversation.

1.1 Who is messaging whom?

• Patient provider ↔
• Provider provider ↔
• Care team internally (no patient in the thread) • System/automated patient (one-way notifications) →
• Some combination of the above

Why it matters: different participant types affect access control, thread structure, and whether a patient subject is always required on a thread.

1.2 What is the primary purpose of messaging in their product?

• Clinical care coordination (e.g. async visits, follow-ups) • Patient engagement / support • Internal operational communication • Outbound notifications only (reminders, results)

Why it matters: determines how much of the feature set is actually needed and whether async encounters/billing will come up.

1.3 Is this a new build or replacing something they have today?


• If replacing: what are they replacing, and what are the gaps that drove this?
• If new: is messaging central to the product or additive?

Why it matters: existing systems often carry assumptions about data model or UX that will surface as requirements. Knowing this early prevents surprises.

Section 2: Feature Scoping

Go through each together. For each: Yes / No / Nice-to-have / Not sure.

# Feature Yes No Nice-to-have Notsure
1 Live / real-time updates (new messages appear without refresh)
2 Message response tracking and routing (assigning threads to providers or queues)
3 Read receipts and unread counts
4 File and image attachments
5 Message editing and drafts
6 Automated messaging (reminders, out-of-office, SLA escalations)
7 External channel delivery (SMS, email — beyond in-app)
8 Async encounters / billing

Section 3: Feature Deep Dives

Cover each feature flagged Yes or Nice-to-have. The goal is to land on a clear recommended approach by the end of each section.

3.1 Thread Structure (always covered)

Questions:

• Are threads always tied to a specific patient, or do you need internal/admin threads with no patient context? • Are threads 1:1 only, or do you need group conversations with more than two participants? • Do threads need to be tagged or categorized (e.g. by specialty, product line, urgency)? If so, do tags need to be combinable (e.g. a thread tagged both “cardiology” and “urgent”)?

What the answers drive:

Situation Approach
Threads always tied to a patient Set subject on every thread header— enables filtering by patient across the inbox
Internal/admin threads needed subject is optional — don’t assume it’s always present in queries or UI
1:1 only Simpler participant model; simplifies read receipt implementation
Group threads needed Recipient list on thread header must include all participants including the thread creator
Tags/categories needed, single dimension Use a single category entry on both the thread header and child messages
Tags/categories needed, multiple combinable dimensions Use multiple category entries — more maintainable but queries may need to match several categories

3.2 Live Updates

Questions:

• Do new messages need to appear in real time without a page refresh? • Is this needed for the patient-facing app, the provider-facing app, or both?

What the answers drive:

Situation Approach
Real-time updates needed WebSocket subscriptions on the thread — requires this to be scoped and enabled for the project
Polling is acceptable Simpler implementation; periodic re-fetch of thread messages
Notification only (e.g. badge, push) without live message rendering Can use subscription to trigger a notification without requiring in-place message updates

3.3 Routing & Assignment

Questions:

• Do messages get assigned to specific providers, to a pool/queue by role, or both? • Can threads be reassigned or escalated after initial assignment? • After reassignment, does the previous owner need to retain visibility of the thread? • Do you need a structured audit trail of who owned a thread and why it was rerouted?

What the answers drive:

Situation Approach
Individual assignment only Set Task.owner to a specific provider; remove performerType
Pool/queue routing Set Task.performerType by role type; clear Task.owner; providers claim from pool
Both Use performerType for initial pool routing; set owner and clear performerType when claimed
Reassignment needed, previous owner loses access Update Task.owner in place; update Communication.recipient to match
Reassignment needed, previous owner retains visibility Create a new Task for the new owner; mark original as cancelled with a note pointing to the new Task
Audit trail needed (free text) Append to Task.note on each reroute with author and timestamp
Audit trail needed (structured/queryable) Create a Provenance resource on each reroute with a coded reason-queryable via Provenance?target=Task/{id}

3.4 Read Receipts & Unread State

Questions:

• Are threads ever group conversations (more than 2 participants)? • Do you need to query unread counts via API — e.g. a badge count or a list of all unread threads for a user? • Do unread counts need to be tracked per-recipient in a group thread?

What the answers drive:

Situation Approach
1:1 threads only Option A: mark message status = completed when read; query unread via status filter. Simplest model.
Group threads, no API unread query needed Option B: store per-participant read state as an extension on the thread header. Shows unread dot in UI; not searchable via API.
Group threads, API unread query needed Option C: create a read-receipt Task per recipient per message; complete it when read. Supports badge counts and unread queries. Most complex.

3.5 Attachments

Questions:

• What file types need to be supported? • Do attachments need to be searchable or referenceable as clinical documents — e.g. queryable by patient or document type — or are they just files to download within a message?

What the answers drive:

Situation Approach
Files are just downloads within a message Store as contentAttachment on the message payload — simple, no separate resource needed
Attachments need to be clinical documents (searchable, referenceable by patient/type) Create a DocumentReference and attach via contentReference on the payload — file becomes a first-class searchable clinical document.
Attachments are references to existing clinical resources (e.g. a lab result) Use contentReference pointing at the relevant FHIR resource (e.g. DiagnosticReport)

3.6 Editing & Drafts

Questions:

• Can sent messages be corrected or retracted after sending? • If so, does the original message content need to be discoverable via search (e.g. “show all edited messages”), or is it sufficient for the history to exist but not be directly queryable? • Do users need to save a draft and return to it across sessions or devices, or is per-device/browser draft storage acceptable?

What the answers drive:

Situation Approach
Sent messages cannot be edited No special handling needed
Sent messages can be corrected; edits need to be searchable Retract-and-correct: mark original status = entered-in-error, create new message with corrected content linked via inResponseTo and tagged with a correction category.
Sent messages can be corrected; searchability of edits not required In-place payload update via patchResource. Full version history still exists but is not searchable.
Drafts only needed per browser/device Store in browser localStorage keyed by threadID — no server resources needed, but lost if user clears storage or switches devices
Drafts need to persist across devices/sessions Store as Communication with status=preparation; update as user types (debounced); promote to in-progress with a sent timestamp when sent.

3.7 Automations

Questions:

• Are there events that should trigger automated messages (e.g. new lab result, appointment reminder)? • Are there SLA or response-time requirements (e.g. all messages responded to within 4 hours)? • Do providers have out-of-office or availability states that should affect routing? • Do you need to report on SLA compliance or response time metrics?

What the answers drive:

Situation Approach
Event-triggered automation Bot triggered by a Subscription on the relevant resource type
Recurring automation Cron-scheduled Bot that scans for stale threads and creates reminder Tasks
Out-of-office/availability-based rerouting Bot triggered on new message checks provider Schedule; reroutes Task to pool if provider has no available slots
SLA reporting needed Task data should be exported to an analytics platform.

3.8 External Channels

Questions:

• Which channels — SMS, email, other? • Is this outbound-only (notify the patient) or does the patient reply back into the thread? • If inbound replies are needed, how is the patient identified from an incoming message? • Does the external provider have its own conversation ID that can be stored for thread matching?

What the answers drive:

Situation Approach
Outbound notifications only App creates the Communication, then calls executeBot directly to send via the external channel.
Inbound replies needed Inbound webhook Bot receives the payload, identifies the patient, matches or creates a thread.
External conversation ID available Upsert thread header by that identifier on first message; use it as conditional partOf reference on all inbound messages.
No external conversation ID Match thread by patient phone/email and open thread status; ambiguous cases need a defined fallback strategy.
Round-trip Store channel on thread header as medium; app creates the Communication then calls executeBot to dispatch outbound.
Webhook retry / duplicate messages likely Use createResourceIfNoneExist with the provider’s message ID as an identifier to prevent duplicate inbound Communications.

3.9 Async Encounters / Billing

Questions:

• Does the customer intend to bill for messaging-based care? • How do you define a “session”? — one thread per session, grouped by day, or patient-initiated? • Can a single messaging session involve multiple patients? • Do you need to capture diagnosis codes, service type, or other clinical details per encounter?

What the answers drive:

Situation Approach
No billing intent No Encounter resource needed; thread stands alone
Billing needed, one patient per session Create an Encounter per session; link to the thread header via Communication.encounter
One thread = one session Straightforward 1:1 mapping of thread to Encounter
Rolling interaction model One Encounter spans multiple threads or a time window; multiple thread headers link to the same Encounter
Multiple patients can be in one session Create a parent session Encounter + one child Encounter per patient.
Clinical documentation needed for billing Populate Encounter.participant, Encounter.reasonCode, and Encounter.serviceType per patient Encounter.