OZO FHIR implementation guide
0.7.7 - ci-build
OZO FHIR implementation guide - Local Development build (v0.7.7) built by the FHIR (HL7® FHIR® Standard) Build Tools. See the Directory of published versions
requester fieldThis document analyzes the addressing problem in the FHIR proposal for team-level messaging and proposes a solution to enable team-to-team communication using CareTeam while maintaining individual auditability.
Related: See the Organization Addressing Proposal for the original business requirements and high-level solution overview.
basedOninResponseTorequester fieldrequester can be different from sendersender allows: Device, Organization, Patient, Practitioner, PractitionerRole, RelatedPerson, HealthcareServicesender to: Practitioner, RelatedPerson (excludes Organization!)recipient allows: Device, Organization, Patient, Practitioner, PractitionerRole, RelatedPerson, HealthcareService, Group, CareTeam, Endpointrecipient to: Practitioner, RelatedPerson, CareTeam (excludes Organization!)Step 1: Pharmacy sends request
CommunicationRequest:
requester = Practitioner/A1 ← Individual who initiated (auditability)
sender = Organization/Pharmacy-A ← Reply-to address
recipient = Organization/Clinic-B ← Addressed to organization
payload = "Can you review patient's medication?"
Step 2: Clinic replies
Communication:
sender = Practitioner/B1 ← Individual responds (auditability)
recipient = Organization/Pharmacy-A ← Read from CommunicationRequest.sender
basedOn = CommunicationRequest/...
payload = "Yes, I'll review it today"
Why this works:
requester tracks the individual who initiated (auditability)sender in CommunicationRequest provides the Organization reply-to addresssender in Communication tracks the individual who responds (auditability)Step 1: Pharmacy sends request
CommunicationRequest:
requester = Practitioner/A1 ← Must be Practitioner (OZO constraint)
sender = Practitioner/A1 ← Must be Practitioner (OZO constraint)
recipient = CareTeam/B ← Using CareTeam as proxy
Step 2: Clinic needs to reply
Communication:
sender = Practitioner/B1
recipient = ??? ← No Organization in original request to reply to!
The issue:
requester fieldNote: This is the recommended solution. See Detailed Analysis below for complete specification.
requester: **Keep as Practitioner |
RelatedPerson** (to track individual who initiated the conversation) |
sender: Allow CareTeam (in addition to Practitioner, RelatedPerson)recipient: **Keep as Practitioner |
RelatedPerson | CareTeam** (no change) |
sender: Allow CareTeam or **Practitioner |
RelatedPerson** (CareTeam for team-level authorization, individual for auditability) |
recipient: **Keep as Practitioner |
RelatedPerson | CareTeam** (no change) |
CommunicationRequest.requester tracks who initiated the conversationStep 1: Pharmacy A initiates conversation with first message
CommunicationRequest:
requester = Practitioner/A1 (individual who initiated - auditability)
sender = CareTeam/Pharmacy-A (team is thread owner - reply-to address)
recipient = CareTeam/Clinic-B (addressed to team)
payload = "Can you review patient's medication?" (initial message)
subject = Patient/123
Step 2: Practitioner B1 from Clinic B replies
Communication:
sender = Practitioner/B1 (individual responds for auditability)
recipient = CareTeam/Pharmacy-A (read from CommunicationRequest.sender)
basedOn = CommunicationRequest/... (links to thread)
payload = "Yes, I'll review and respond by tomorrow"
Step 3: Another practitioner A2 from Pharmacy A follows up
Communication:
sender = Practitioner/A2 (different person from same team)
recipient = CareTeam/Clinic-B (continue to same team)
basedOn = CommunicationRequest/... (links to thread)
inResponseTo = Communication/step2 (reply to previous message)
payload = "Thank you for the quick response"
| Resource | Field | Allowed Types | Note |
|---|---|---|---|
| CommunicationRequest | requester | Practitioner, RelatedPerson | No change - tracks individual who initiated |
| CommunicationRequest | sender | Practitioner, RelatedPerson, CareTeam | CareTeam added - team-level reply-to address |
| CommunicationRequest | recipient | Practitioner, RelatedPerson, CareTeam | No change |
| Communication | sender | Practitioner, RelatedPerson | No change - must be individual for auditability |
| Communication | recipient | Practitioner, RelatedPerson, CareTeam | No change |
Core Principle: Allow CareTeam as sender in both CommunicationRequest and Communication, while maintaining individual auditability through the requester field and tracking the individual team member separately.
The original OZO constraints created an impossible situation:
Relax constraints to allow CareTeam:
CommunicationRequest.requester: Practitioner | RelatedPerson (NO CHANGE - must be individual)
CommunicationRequest.sender: Practitioner | RelatedPerson | CareTeam
CommunicationRequest.recipient: Practitioner | RelatedPerson | CareTeam (NO CHANGE)
Purpose:
requester identifies the individual who initiated (auditability)sender can be CareTeam (reply-to address for the conversation, team-level authorization)recipient remains CareTeam-capable (shared inbox for receiving team)Keep constraints as-is (individual sender required):
Communication.sender: Practitioner | RelatedPerson (NO CHANGE - must be individual)
Communication.recipient: Practitioner | RelatedPerson | CareTeam (NO CHANGE)
Purpose:
Step 1: Thread Initiation
Instance: thread-pharmacy-to-clinic
InstanceOf: CommunicationRequest
* status = #active
* subject = Reference(Patient/123)
* requester = Reference(Practitioner/A1) // ← Individual who initiated
* sender = Reference(CareTeam/Pharmacy-A) // ← Reply-to address (team authorization)
* recipient = Reference(CareTeam/Clinic-B)
* payload[0].contentString = "Can you review the patient's medication list?"
Step 2: Reply from Clinic (Practitioner B1)
Instance: msg-1-pharmacy-question
InstanceOf: Communication
* status = #completed
* basedOn = Reference(CommunicationRequest/thread-pharmacy-to-clinic)
* sender = Reference(Practitioner/A1) // ← Individual auditability
* recipient = Reference(CareTeam/Clinic-B) // ← From CommunicationRequest.recipient
* payload[0].contentString = "Can you review the patient's medication list?"
Application Logic for Reply-To Discovery:
basedOn referenceCommunicationRequest.sender is CareTeam → use that as reply recipientStep 3: Reply (Practitioner B1)
Instance: msg-2-clinic-response
InstanceOf: Communication
* status = #completed
* basedOn = Reference(CommunicationRequest/thread-pharmacy-to-clinic)
* inResponseTo = Reference(Communication/msg-1-pharmacy-question)
* sender = Reference(Practitioner/B1) // ← Individual auditability
* recipient = Reference(CareTeam/Pharmacy-A) // ← From CommunicationRequest.sender
* payload[0].contentString = "Yes, I'll review it today and follow up by EOD"
Step 4: Follow-up (Different Practitioner A2)
Instance: msg-3-pharmacy-followup
InstanceOf: Communication
* status = #completed
* basedOn = Reference(CommunicationRequest/thread-pharmacy-to-clinic)
* inResponseTo = Reference(Communication/msg-2-clinic-response)
* sender = Reference(Practitioner/A2) // ← Different person, same team
* recipient = Reference(CareTeam/Clinic-B) // ← Continue to same team
* payload[0].contentString = "Thank you for the quick response!"
GET /Communication?recipient=CareTeam/Pharmacy-A&_include=Communication:based-on
Returns all Communications where recipient is the CareTeam, plus their parent CommunicationRequests.
GET /Communication?sender=Practitioner/A1
Returns all Communications sent by this individual.
GET /Communication?based-on=CommunicationRequest/thread-pharmacy-to-clinic
&_sort=sent
Returns chronologically sorted thread.
All changes below have been implemented. This section documents what was done for reference.
Since FHIR R4 CommunicationRequest.sender does not allow CareTeam references, the solution uses an extension (OZOSenderCareTeam) instead of relaxing the sender constraint directly.
File: input/fsh/profiles/ozo-communicationrequest.fsh
sender remains restricted to OZOPractitioner | OZORelatedPerson (individual sender)requester remains restricted to OZOPractitioner | OZORelatedPerson (individual who initiated)OZOSenderCareTeam extension (0..1) for CareTeam as reply-to addressrecipient unchanged: OZOPractitioner | OZORelatedPerson | OZOCareTeamFile: input/fsh/profiles/ozo-communication.fsh
sender = individual, recipient allows CareTeam.interaction-messaging.md: Added "Team-to-Team Messaging" section with examples using extension[senderCareTeam]overview.md: Updated CommunicationRequest field table and team-level messaging descriptioncommunicationrequest-team-to-team.fsh - Pharmacy-to-Clinic with senderCareTeam extensioncommunication-pharmacy-initial-message.fsh - Initial message from pharmacy practitionercommunication-clinic-response-to-pharmacy.fsh - Clinic reply to pharmacy teamcommunication-pharmacy-followup-by-pieter.fsh - Follow-up from different team membercareteam-pharmacy-a.fsh and careteam-clinic-b.fsh - Team CareTeam resourcesThe analysis above proposed adding CareTeam directly to CommunicationRequest.sender. During implementation, it was discovered that FHIR R4 does not allow CareTeam in that field. The OZOSenderCareTeam extension achieves the same goal while remaining FHIR R4 compliant. All sender fields remain restricted to individuals, preserving auditability.