Skip to content

Communication Profile

Canonical../StructureDefinition/nexus-emr-core-communication
Statusdraft (experimental) · 1.26.0
BaseCommunication (constraint)
SourceFSH · JSON

Nexus EMR profile for Communication, covering two distinct populations: WELL-internal staff chat about a patient, and eReferral correspondence passed through from or to external partners. First pass -- the pass-through boundary and message threading are not yet settled.

TypedFhir API / Pydantic schema

The typed accessor surface Communication exposes for Communication — generated from this IG's compiled profile; each typed accessor has a validating raw-FHIR twin (xRaw) where marked. The three ports are parity-enforced.

The AI-facing shape: from typed_fhir.facade.generated.schemas import CommunicationSchemamodel_json_schema() is a structured-output / tool definition; instantiating validates an extraction. Generated source.

class CommunicationSchema(BaseModel):
    """AI-facing shape of the Communication profile: the facade's typed accessor
    surface (curated + salient fields) as a pydantic model. `model_json_schema()` is a
    structured-output / tool schema; instantiating validates an extraction."""

    model_config = ConfigDict(extra="forbid")

    in_response_to: Reference | None = Field(
        None,
        description=(
            "The message this one replies to. Prior communication that this communication is in "
            "response to. Note: ⚠ FIRST PASS. The chat panel currently threads by neither "
            "`inResponseTo` nor `partOf` -- conversation order is reconstructed from timestamps, "
            "which is why concurrent messages can interleave wrongly. Declaring the element here "
            "is the first step; deciding whether threads are `inResponseTo` chains or a `partOf` "
            "grouping is open. Communication.inResponseTo — 0..*"
        ),
    )
    status: Literal[
        "completed",
        "entered-in-error",
        "in-progress",
        "not-done",
        "on-hold",
        "preparation",
        "stopped",
        "unknown",
    ] | None = Field(
        None,
        description=(
            "preparation | in-progress | not-done | completed | entered-in-error | ... The status "
            "of the transmission. Note: Internal chat writes `completed` on send. For eReferral "
            "traffic the partner's lifecycle applies and `status` is pass-through -- do not infer "
            "local workflow state from it. Communication.status — 1..1"
        ),
    )
    status_reason: Concept | None = Field(
        None,
        description=(
            "Reason for current status. Captures the reason for the current state of the "
            "Communication. Note: This is generally only used for \"exception\" statuses such as "
            "\"not-done\", \"suspended\" or \"aborted\". The reason for performing the event at all is "
            "captured in reasonCode, not here. Communication.statusReason — 0..1"
        ),
    )
    category: Concept | None = Field(
        None,
        description=(
            "Which population: internal staff chat, or external eReferral correspondence. Which "
            "population this Communication belongs to. Readers should scope on it -- internal "
            "chat and external eReferral correspondence have different authorities over their "
            "content, and a chat surface that does not scope will surface partner correspondence "
            "into a panel never designed for it. ⚠ HERITAGE EMR SITUATION -- UNRESOLVED. If "
            "heritage-EMR message history is ever migrated (see `identifier`), it becomes a THIRD "
            "population alongside internal chat and eReferral, and this element is where that "
            "distinction would have to live. No code for it exists, because the migration "
            "decision has not been made. Anyone binding a value set here must resolve that first, "
            "or the binding will need widening the moment migration is agreed. Note: ⚠ FIRST PASS "
            "-- no value set is bound yet, deliberately. Binding one requires deciding the "
            "pass-through boundary first (a partner-supplied category must remain conformant), "
            "and that decision is not made. Until then this is text-or-code and readers MUST "
            "tolerate text-only. A local NexusEmrCommunicationCategoryVS is the intended "
            "follow-up. Communication.category — 0..*"
        ),
    )
    priority: Literal["asap", "routine", "stat", "urgent"] | None = Field(
        None,
        description=(
            "routine | urgent | asap | stat. Characterizes how quickly the planned or in progress "
            "communication must be addressed. Includes concepts such as stat, urgent, routine. "
            "Note: Used to prioritize workflow (such as which communication to read first) when "
            "the communication is planned or in progress. Communication.priority — 0..1"
        ),
    )
    medium: Concept | None = Field(
        None,
        description=(
            "A channel of communication. A channel that was used for this communication (e.g. "
            "email, fax). Communication.medium — 0..*"
        ),
    )
    subject: Reference | None = Field(
        None,
        description=(
            "The patient the communication is about. The patient or group that was the focus of "
            "this communication. Note: 0..1 per R4. Internal chat about a patient SHOULD carry it "
            "-- a chat message with no subject cannot be scoped to a chart, and cannot be "
            "filtered out of one either, which is the access-control concern. "
            "Communication.subject — 0..1"
        ),
    )
    topic: Concept | None = Field(
        None,
        description=(
            "Description of the purpose/content. Description of the purpose/content, similar to a "
            "subject line in an email. Note: Communication.topic.text can be used without any "
            "codings. Communication.topic — 0..1"
        ),
    )
    sent: FuzzyDate | None = Field(
        None,
        description=(
            "When the message was sent. The time when this communication was sent. "
            "Communication.sent — 0..1"
        ),
    )
    received: FuzzyDate | None = Field(
        None,
        description=(
            "When the message was received. The time when this communication arrived at the "
            "destination. Communication.received — 0..1"
        ),
    )
    recipient: Reference | None = Field(
        None,
        description=(
            "Who the message was addressed to. The entity (e.g. person, organization, clinical "
            "information system, care team or device) which was the target of the communication. "
            "If receipts need to be tracked by an individual, a separate resource instance will "
            "need to be created for each recipient. Multiple recipient communications are "
            "intended where either receipts are not tracked (e.g. a mass mail-out) or a receipt "
            "is captured in aggregate (all emails confirmed received by a particular time). "
            "Communication.recipient — 0..*"
        ),
    )
    sender: Reference | None = Field(
        None,
        description=(
            "Who sent the message. The entity (e.g. person, organization, clinical information "
            "system, or device) which was the source of the communication. Note: Practitioner is "
            "the primary provider identity in this IG. Organization covers a partner-system "
            "sender on inbound eReferral traffic; Device covers system-generated messages. "
            "RelatedPerson covers a SUBSTITUTE DECISION-MAKER acting for the patient -- a "
            "distinct fact from the patient acting themselves, and one that must not be flattened "
            "onto Patient: where a right over the record is exercised by proxy, the record has to "
            "show that authority was delegated, because that is what is checked when the exercise "
            "is challenged. Communication.sender — 0..1"
        ),
    )
    reason_code: Concept | None = Field(
        None,
        description=(
            "Indication for message. The reason or justification for the communication. Note: "
            "Textual reasons can be captured using reasonCode.text. Communication.reasonCode — "
            "0..*"
        ),
    )
    payload: dict | None = Field(
        None,
        description=(
            "The message content. Text, attachment(s), or resource(s) that was communicated to "
            "the recipient. Note: Internal chat writes `contentString`. eReferral traffic may "
            "carry `contentAttachment` or `contentReference` -- a reader that assumes "
            "contentString will silently render an empty message. Handle all three. "
            "Communication.payload — 0..*"
        ),
    )
    date: FuzzyDate | None = Field(
        None,
        description=(
            "When the message was sent. The time when this communication was sent. Salient field "
            "— sent | received"
        ),
    )