Care Coordination Repository (CCR) Messaging – Design and Rationale
Purpose
The CCR messaging system provides a clinical, auditable, interoperable record of asynchronous communication between clinicians, patients, and other authorised participants.
It is designed to:
- support cross-site and cross-system care coordination,
- remain human-readable without specialist software,
- withstand audit, legal, and regulatory review,
- avoid asserting certainty about human behaviour that the system cannot honestly know.
Messaging in the Care Coordination Repository is treated as clinical communication, not as a transient chat feature.
Conceptually, CCR messaging is FHIR-aligned, using the semantics of the FHIR Communication resource as a guiding model, without adopting FHIR storage formats or server behaviour.
Conceptual model (FHIR-aligned)
Each CCR message corresponds conceptually to a FHIR Communication:
- it represents something that has already been communicated,
- it has an author, recipients, a timestamp, content, and a status,
- it is a clinical artefact with medico-legal weight.
CCR does not implement FHIR JSON, REST endpoints, or transport semantics. Instead, it preserves FHIR meaning while using a versioned, repository-based storage model aligned with the Versioned Patient Repository.
This guarantees that CCR messaging can be projected to FHIR Communication in future integrations, without constraining internal design.
Core principles
1. Messaging is clinical
Messages exchanged between clinicians, patients, and other healthcare participants carry clinical and medico-legal weight equivalent to:
- written advice,
- clinic letters,
- documented telephone or video consultations.
As such, CCR messages form part of the clinical coordination record.
2. Messages are immutable
Once recorded, messages:
- MUST NOT be edited,
- MUST NOT be deleted.
This mirrors paper records, professional guidance, and legal expectations.
Errors or clarifications are handled via corrections (addenda), never by modifying the original message.
3. Context matters more than individual messages
Individual messages often do not make sense in isolation.
For example:
“Yes, I will do that doctor”
only has meaning when read alongside preceding and subsequent messages.
For this reason, the conversation thread is the meaningful clinical unit, not the individual message.
This aligns with FHIR Communication, which is frequently contextualised by related communications, encounters, or care plans.
Repository placement
Messaging is a first-class concern of the Care Coordination Repository (CCR).
It sits alongside other coordination artefacts (for example, tasks or referrals added later), and is explicitly separated from:
- clinical facts (clinical repository),
- demographics and identity (demographics repository).
File layout
Each messaging thread is stored as:
coordination/
<shard1>/
<shard2>/
<coordination-id>/
COORDINATION_STATUS.yaml
communications/
<communication-id>/
messages.md → thread.md
ledger.yaml
The coordination repository is sharded by UUID for scalability, similar to clinical records.
Conceptually:
- A communication is a thread and a ledger file
- A thread is a list of messages stored in
thread.md - The ledger contains metadata such as participants, status, policies, and visibility settings
Where:
<communication-id>is a timestamp-prefixed UUID (e.g.,20260111T143522.045Z-550e8400-e29b-41d4-a716-446655440000)thread.mdcontains the canonical clinical conversation (list of messages)ledger.yamlcontains thread metadata (participants, status, policies, visibility)
Communication identity
The <communication-id> is generated using a timestamp-prefixed identifier:
- format:
YYYYMMDDTHHMMSS.sssZ-UUID - timestamp: UTC, ISO 8601, millisecond precision
- UUID: randomly generated
Example:
20260111T143522.045Z-550e8400-e29b-41d4-a716-446655440000
This ensures communication identifiers are:
- globally unique,
- chronologically sortable,
- suitable for distributed systems.
The existing TimestampId struct is used to generate and validate these identifiers.
thread.md – Thread of messages
Purpose
thread.md is the canonical clinical record of the conversation thread.
It records:
- what was communicated,
- by whom,
- when,
- and in what coordination context.
Conceptually, each entry corresponds to a FHIR Communication instance.
Properties
- Append-only
- Immutable once written
- Human-readable
- Git-versioned
- Suitable for audit and legal review
Message identity
Every message MUST include a globally unique message_id (UUID).
Message identifiers exist to:
- unambiguously identify messages,
- allow corrections to reference prior messages,
- support projections, caches, and alert suppression.
Timestamps are used for ordering, not identity.
Message types
messages.md may contain:
- clinician messages
- patient messages
- system messages
- correction messages
System messages (for example, “participant added to thread”) are first-class entries, as they provide clinically and legally relevant coordination context.
Corrections (addenda)
Errors or clarifications are recorded as new messages, not edits.
A correction message:
- is a new message,
- has its own
message_id, - references the original message via
corrects: <message_id>.
The original message is never modified.
This preserves a truthful, auditable historical record.
Explicit non-features
thread.md does NOT record:
- read or seen status,
- urgency flags,
- acknowledgement or acceptance,
- task completion or responsibility transfer.
These concepts imply human cognition or behaviour that the system cannot verify and therefore does not assert.
Example structure
# Messages
## Message
**ID:** `3f7a8d2c-1e9b-4a6d-9f2e-5c8b7a4d1f92`
**Type:** clinician
**Timestamp:** 2026-01-11T14:36:15.234Z
**Author ID:** `4f8c2a1d-9e3b-4a7c-8f1e-6b0d2c5a9f12`
**Author:** Dr Jane Smith
Patient has reported increasing shortness of breath.
Please review chest X-ray and advise on next steps.
---
## Message
**ID:** `8b2f6a5c-3d1e-4a9b-8c7f-6d5e4a3b2c1d`
**Type:** clinician
**Timestamp:** 2026-01-11T15:42:30.567Z
**Author ID:** `a1d3c5e7-f9b2-4680-b2d4-f6e8c0a9d1e3`
**Author:** Dr Tom Patel
Reviewed X-ray. No acute changes. Continue current management
and reassess in 48 hours. If symptoms worsen, arrange urgent review.
ledger.yaml – Thread context and policy
Purpose
ledger.yaml stores contextual and policy metadata, not clinical narrative.
It answers:
“Who is involved in this conversation, and under what rules?”
Typical contents
- participants and roles
- visibility and sensitivity flags
- thread status (open, closed, archived)
- organisational access rules
communication_id: 20260111T143522.045Z-550e8400-e29b-41d4-a716-446655440000
status: open
created_at: 2026-01-11T14:35:22.045Z
last_updated_at: 2026-01-11T15:10:04.912Z
participants:
- participant_id: 4f8c2a1d-9e3b-4a7c-8f1e-6b0d2c5a9f12
role: clinician
display_name: Dr Jane Smith
- participant_id: a1d3c5e7-f9b2-4680-b2d4-f6e8c0a9d1e3
role: clinician
display_name: Dr Tom Patel
- participant_id: 9b7c6d5e-4f3a-2b1c-0e8d-7f6a5b4c3d2e
role: patient
display_name: John Doe
visibility:
sensitivity: standard
restricted: false
policies:
allow_patient_participation: true
allow_external_organisations: true
Properties
- Mutable
- Overwriteable
- Git-audited
- Changes are deliberate and relatively infrequent
last_updated_atis automatically updated when messages are added
Thread-level metadata:
- Thread status: open, closed, or archived
- Participant list with roles (organisation field removed for simplicity)
- Visibility and sensitivity settings
- Participation policies (external organisations allowed by default)
Audit trail: Inherent in Git commit history and messages.md content - no separate audit section needed.
Explicit exclusions
ledger.yaml does NOT contain:
- message content,
- interaction or navigation state,
- user interface hints.
Git Versioning
All changes to coordination records are Git-versioned for audit purposes:
coordination:create: Created messaging thread
Care-Location: Oxford University Hospitals
coordination:update: Added message to thread
Care-Location: Oxford University Hospitals
coordination:update: Updated thread participant list
Care-Location: Oxford University Hospitals
Commits include:
- Structured commit messages with domain and action
- Care location metadata
- Optional cryptographic signatures
- Full audit trail of all changes
Alerting behaviour
CCR does not record:
- Read receipts or “seen” status
- Acknowledgements
- Urgency flags
- Task completion or responsibility transfer
These concepts imply human cognition or behaviour that the system cannot verify.
Consuming systems may implement alerting by:
- Tracking their own render/presentation state externally (not in VPR)
- Comparing message timestamps to their last-viewed records
- Presenting unread indicators in their user interface
This approach:
- Avoids false certainty about human understanding
- Reduces legal and clinical ambiguity
- Maintains truthful audit trails
- Enables consistent patient experience across systems
Alerting is a user-experience concern, not a clinical record.
Thread Lifecycle
Messaging threads follow a defined lifecycle:
Creation
Threads are created via CoordinationService::communication_create():
- Generates timestamp-prefixed communication ID
- Creates
communications/<communication-id>/directory - Writes initial
thread.md(optionally with first message) - Writes
ledger.yamlwith participant list and policies - Commits atomically to Git
Message Addition
Messages are added via CoordinationService::add_message():
- Generates unique message UUID
- Appends to
thread.md(preserves immutability) - Commits with structured message and care location
- Returns the message ID for reference
Metadata Updates
Thread metadata is updated via CoordinationService::update_communication_ledger():
- Modifies
ledger.yaml(participants, status, policies) - Git commit records the change
- Audit log tracks all modifications
Status Transitions
Threads can transition between states:
- Open → Closed: Thread completed, no new messages accepted
- Closed → Archived: Thread moved to archive, hidden from default views
- Open → Archived: Direct archival without closing
Deletion
Threads are never deleted:
- Immutability is preserved
- Audit trail remains complete
- Archival is used instead of deletion
- Git history retains full record
Implementation Details
Initialization
Coordination repositories are initialized with:
#![allow(unused)]
fn main() {
CoordinationService::new(cfg)
.initialise(author, care_location, clinical_id)
}
This creates:
- Sharded directory structure:
coordination/<s1>/<s2>/<uuid>/ COORDINATION_STATUS.yamlwith link to clinical record- Git repository with initial commit
- Lifecycle state set to
active
Thread Creation
Messaging threads are created with:
#![allow(unused)]
fn main() {
service.communication_create(
&author,
care_location,
participants,
initial_message
)
}
This:
- Generates timestamp-prefixed communication ID via
TimestampIdGenerator - Creates
communications/<communication-id>/directory - Writes
thread.mdwith optional initial message - Writes
ledger.yamlwith participant list and policies - Commits both files atomically to Git
Adding Messages
Messages are appended with:
#![allow(unused)]
fn main() {
service.add_message(
&author,
care_location,
thread_id,
message_content
)
}
This:
- Generates unique message UUID
- Appends to
thread.md(preserves immutability) - Commits with structured message and care location
- Returns the message ID
Type Safety
The CoordinationService uses type-state pattern:
CoordinationService<Uninitialised>- Can only callinitialise()CoordinationService<Initialised>- Can call thread and message operations
This prevents operations on non-existent repositories at compile time.
Error Handling
Operations return PatientResult<T> with comprehensive error types:
- Author validation errors
- Git operation failures
- File I/O errors
- FHIR wire format validation errors
- UUID parsing errors
Cleanup is attempted on initialization failure to prevent partial repositories.
Design decisions explicitly rejected
The following were deliberately excluded:
- read receipts (opening does not equal reading or understanding)
- urgency flags (asynchronous messaging is not suitable for urgent care)
- acknowledgement tracking (implies responsibility transfer)
- workflow or task semantics (these may be added later using FHIR-aligned Task concepts)
These exclusions reduce legal ambiguity, false certainty, and unintended clinical inference.