Skip to content

Encounter Profile

Canonical../StructureDefinition/nexus-emr-core-encounter
Statusdraft · 1.26.0
BaseEncounter (constraint)
SourceFSH · JSON

Defines the Encounter resource constraints for the Nexus EMR project (CII), conforming to CA-Core+ requirements.

FSH

The authored source of truth: resources/StructureDefinition-nexus-emr-core-encounter.fsh (edit on GitHub). One FSH file may define several related artifacts.

// NexusEmrCoreEncounter.fhirVersion

Alias: $NexusEmrCoreEncounter = ../StructureDefinition/nexus-emr-core-encounter


// The primary-care 1:1 Appointment<->Encounter default, expressed as guidance rather than as
// cardinality. Root-level (not element-level) because it is a COUNT rule -- an element-level
// invariant on a repeating element evaluates once per repeat, where a count is meaningless.
// Warning severity is the substance of the decision, not a hedge: primary care should emit one
// appointment per encounter, and specialist/hospital writers legitimately emit zero or many.
// Tightening `appointment` to 0..1 would foreclose the combined-visit case; asserting 1..1
// would break walk-ins. See the element's prose for the full model.
Invariant:     encounter-appointment-single-in-primary-care
Description:   "Primary-care encounters SHOULD reference at most one Appointment (the 1:1 default). Zero is valid for walk-in/unscheduled visits; more than one is valid where a single encounter fulfils several bookings, and several encounters MAY share one Appointment."
Severity:      #warning
Expression:    "appointment.count() <= 1"

// Profile Definition
Profile:        NexusEmrCoreEncounter
Parent:         Encounter
Id:             nexus-emr-core-encounter
Title:          "Encounter Profile"
Description:    "Defines the Encounter resource constraints for the Nexus EMR project (CII), conforming to CA-Core+ requirements."
* ^url = $NexusEmrCoreEncounter // Canonical URL from alias
* ^status = #draft
* obeys encounter-appointment-single-in-primary-care

// THE effective date for this profile (see the EffectiveDate / NoEffectiveDate
// RuleSets): one date concept per resource, declared here rather than guessed.
* insert EffectiveDate([[period.start]])

// Salient fields — the reader/render surface (see SalientField + the Salient RuleSet).
* insert Salient(status, status, code)
* insert SalientAs(visit_class, [[class.display | class.code]], code, class)
* insert Salient(type, type, coded)
* insert Salient(period, [[period.start]], dateTime)
* insert Salient(reason_code, reasonCode, coded)
* insert Salient(service_provider, [[serviceProvider.display]], string)

// SMART on FHIR exposure -- this resource is reachable by an app, and these are the
// permissions each operation costs (see SmartExposed + the SmartExposed RuleSet).
* insert SmartExposed(encounter)

// --- Element Constraints (Mapping to CII Requirements) ---

* . ^short      = "Nexus EMR Encounter Core"
* . ^definition = """
  Represents patient interactions with healthcare providers, capturing key details
  like status, class, type, participants, and timing using standard Nexus EMR references.
  Uses instance-specific identifiers for tracking encounters across systems.
  """

* meta.source 0..1 MS
* meta.source ^short = "Identifies EMR instance & pipeline version the resource came from"
* meta.source ^definition = "A URI that identifies the EMR pipeline and version from which this resource originated.  This tells you which EMR instance (recommend using the instance identifier), and the version of the pipeline code/transformations."

* text 0..1 MS // Narrative element with human-readable summary
* text ^short = "Narrative"
* text ^definition = "A human-readable narrative summary of the NexusEmrCoreEncounter resource for human interpretation."

// Identifier (D01): Requires instance-specific source system ID. MS.
* identifier 0..* MS
* identifier.system 1..1
* identifier.value 1..1

* identifier ^short = "Business identifier(s) for encounter"
* identifier ^definition = """
Unique identifiers for the encounter.

A business identifier is recommended but not required (identifier is 0..*). Where available, carry the source-system identifier using the most appropriate system URI. No specific canonical system is mandated.
"""
* insert SourceIdentifier(identifier)


// Status (D03): Mandatory, MS. Inherited from CA-Core.
* status 1..1 MS
* status ^short = "Where the encounter is in its lifecycle"
* status ^definition = "The current status of the encounter. Tracks the lifecycle of the encounter."
* status ^comment = "This is a modifier element. The status affects how the encounter should be interpreted."
* status from http://hl7.org/fhir/ValueSet/encounter-status (required)

// Class (D4): Encounter class/mode. Bound, NOT fixed -- and it used to be fixed to AMB.
//
// WHY THE FIXED VALUE WAS REMOVED. It made two published statements of this guide contradict each
// other, and the contradiction resolved in the direction that loses the truth. The appointment
// modality extension states the mapping from modality onto this element -- video, telephone and
// secure-message encounters carry #VR -- and it is this guide's only statement of how modality
// reaches an Encounter. A fixed AMB refused every one of those. An implementer following the
// extension wrote a resource the profile rejected; an implementer following the profile wrote
// #AMB on a video consult, which asserts the visit happened in the room. There is no third
// reading, and only one of the two is a lie about care that was delivered.
//
// The required binding on the next line was already here and already said what is legal. The
// fixed value said something narrower and newer than the binding, without saying why.
//
// A SECOND THING THE FIXED VALUE DECIDED BY CONSTRUCTION. It also refused #IMP, so this guide did
// not model an inpatient encounter at all -- not as a scope decision, but as a side effect of a
// default. Whether an admission belongs in a Nexus EMR estate is a real question; a fixed value is
// not the place to answer it, and a discharge summary needs an encounter to hang from.
//
// AMB REMAINS THE OVERWHELMING CASE. Nothing here encourages the others: read the absence of the
// fixed value as "say what actually happened", not as an invitation to widen scope.
* class 1..1 MS
* class ^short = "Classification of patient encounter"
* class ^definition = """
Classification of patient encounter, from the required v3-ActEncounterCode binding.

Ambulatory (`AMB`) is the common case and the expected default for a clinic visit. It is NOT fixed:
a virtual encounter is `VR` and an admission is `IMP`, and writing `AMB` for either asserts
something the record does not support.
"""
* class ^comment = """
**Map from the appointment's modality, where one is known.** In-person becomes `AMB`; video,
telephone and secure-message all become `VR`. That mapping is the one this guide states, and it is
the reason this element is not fixed to `AMB` -- the modality axis exists precisely to distinguish
a video consult from one in the room, and collapsing it here would leave that distinction living
only on an extension of the Appointment, which not every Encounter has.

A reader should NOT infer scope from the breadth of the binding. Nexus EMR encounters are
predominantly ambulatory; `IMP` is admitted so that an admission a discharge summary refers to can
be represented at all, not as a statement that inpatient workflows are modelled here.
"""
* class from http://terminology.hl7.org/ValueSet/v3-ActEncounterCode (required)

// Type: Specific type of encounter
* type 0..* MS
* type ^short = "Encounter type with raw code support"
* type ^definition = """
Specific type of encounter (e.g., consultation, follow-up, emergency).

RECOMMENDED: Standard terminology codes when available
OPTIONAL: Raw EMR codes for source system preservation

Where this code was mapped from a source system's own vocabulary, carry the raw coding alongside the mapped one, flagged `userSelected = true`. See [Carrying the raw code](../guide/patterns/raw-codes.md).
"""


// ServiceType: Broad categorization of the service
* serviceType 0..1 MS
* serviceType ^short = "Service type with raw code support"
* insert SourceCoding(serviceType)
* serviceType ^definition = """
Broad categorization of the service that is to be provided during this encounter.

RECOMMENDED: Standard terminology codes when available
OPTIONAL: Raw EMR codes for source system preservation
"""


// Period (D3): Encounter Date. Mandatory, MS. Start mandatory, MS.
* period 1..1 MS
* period ^short = "The start and end time of the encounter"
* period ^definition = "The start and end time of the encounter. Start time is required, end time is optional for ongoing encounters."
* period ^comment = "If the encounter is ongoing, the end date will be empty."
* period.start 1..1 MS
* period.start ^short = "When the encounter started"
* period.end 0..1 MS
* period.end ^short = "When the encounter ended (if finished)"

// -----------------------------------------
// Appointment -- the scheduling link, and the association anchor for the visit
// -----------------------------------------
// THE PRIMARY-CARE MODEL. In primary care an Appointment and its Encounter are effectively
// 1:1 -- one booked slot, one visit -- and Encounter is the association anchor: clinical
// resources produced during the visit reference `.encounter`, not the Appointment.
//
// This is modelled as a DEFAULT, not a constraint, and the distinction is the whole point.
// R4 permits many Encounters to reference the same Appointment (a booked visit that splits
// into several encounters -- specialist and hospital workflows do this routinely), and
// `Encounter.appointment` is `0..*` precisely so one Encounter can fulfil several
// Appointments (a combined or double-booked visit). Both remain conformant here. Tightening
// this to `0..1`, or asserting a 1:1 in the base cardinality, would foreclose the specialist
// case and have to be unwound later -- so the 1:1 lives in a WARNING invariant and in this
// prose, where a primary-care writer gets guidance and a specialist writer does not get an
// error.
//
// Terminology note, because it caused confusion when this was decided conversationally:
// an Encounter is NOT "a container around an Appointment". They are distinct resources with
// distinct lifecycles -- an Appointment is a booking (it can be cancelled, no-showed, and
// never become an Encounter), an Encounter is the visit that happened. The relation is
// Appointment <-fulfilled-by- Encounter, expressed on THIS element. There is no
// `Appointment.encounter` in R4; this is the only place the link lives, which is why an
// Appointment-side reader has to search Encounter by appointment rather than dereference.
* appointment 0..* MS
* appointment only Reference(NexusEmrCoreAppointment)
* appointment ^short = "The appointment this encounter fulfils (1:1 in primary care)"
* appointment ^definition = """
The Appointment that scheduled this Encounter.

**Primary care: exactly one.** The booked appointment and the visit that happened are the same
event seen from the scheduling and clinical sides, and consumers may assume one appointment per
encounter for primary-care data.

**Not guaranteed in general.** Zero is valid (a walk-in or unscheduled visit has no
appointment). More than one is valid (an Encounter fulfilling several bookings). And several
Encounters MAY reference the same Appointment -- that is how a booked visit that becomes
multiple encounters is represented, and nothing here forbids it.

Clinical resources arising from the visit associate to the **Encounter**, not to the
Appointment. Encounter is the anchor; the Appointment is how the visit got scheduled.
"""
* appointment ^comment = "A reader wanting 'the appointment for this visit' takes the single entry in primary-care data and MUST tolerate zero. A reader wanting 'the encounter(s) for this appointment' must SEARCH Encounter by this element -- R4 has no reverse element on Appointment. See the query-capability note: search support for that direction is not yet declared in a CapabilityStatement."

// Subject: Patient or Group. Mandatory, MS. Use identifier.
* subject 1..1 MS
* subject ^short = "The patient present at the encounter"
* subject ^definition = "The patient who is the focus of the encounter. Must reference using Nexus EMR patient identifier."
* subject ^comment = "References should use identifier-based references following Nexus EMR patterns."
* subject only Reference(NexusEmrCorePatient)

// Location: Inherited reference constraints from CA-Core. MS.
* location 0..* MS
* location ^short = "List of locations where the encounter occurred"
* location ^definition = "List of locations where the patient has been during this encounter."
* location ^comment = "Multiple locations may indicate patient movement during the encounter."
* location.location 1..1 MS
* location.location ^short = "Location the encounter takes place"
* location.location only Reference(NexusEmrCoreLocation)
* location.status 0..1 MS
* location.status ^short = "planned | active | reserved | completed"
* location.period 0..1 MS
* location.period ^short = "Time period during which the patient was at location"

// Service Provider: Org responsible. Optional, MS. Use identifier.
* serviceProvider 0..1 MS
* serviceProvider ^short = "The organization providing the service"
* serviceProvider ^definition = "The organization that is primarily responsible for this encounter's services."
* serviceProvider ^comment = "This may be different from the location's managing organization."
* serviceProvider only Reference(NexusEmrCoreOrganization)
* serviceProvider.identifier 0..1 MS
* serviceProvider.identifier ^short = "Nexus EMR organization identifier reference"

// Reason Code (D2): Optional, MS per CA-Core.
* reasonCode 0..* MS
* reasonCode ^short = "Encounter reason with raw code support"
* reasonCode ^definition = """
Coded reason the encounter takes place.

RECOMMENDED: SNOMED CT or other standard terminology when available
OPTIONAL: Raw EMR codes for source system preservation

Where this code was mapped from a source system's own vocabulary, carry the raw coding alongside the mapped one, flagged `userSelected = true`. See [Carrying the raw code](../guide/patterns/raw-codes.md).
"""


// Participant: List of participants involved in the encounter (Nexus EMR only supports 1 participant)
* participant 0..1 MS
* participant ^short = "List of participants involved in the encounter"
* participant ^definition = "The healthcare professionals and organizations participating in the encounter."
* participant.type 0..* 
* participant.type ^short = "Role of participant in encounter"
* participant.period 0..1 
* participant.period ^short = "Period of participation"
* participant.individual 0..1 
* participant.individual ^short = "Persons involved in the encounter"
* participant.individual only Reference(NexusEmrCorePractitionerRole or NexusEmrCorePractitioner)

// Diagnosis: List of diagnoses relevant to this encounter
* diagnosis 0..* MS
* diagnosis ^short = "The list of diagnoses relevant to this encounter"
* diagnosis ^definition = "The diagnoses relevant to this encounter. These may be conditions identified during the encounter."
* diagnosis.condition 1..1 MS
* diagnosis.condition ^short = "The diagnosis or condition relevant to the encounter"
* diagnosis.condition only Reference(NexusEmrCoreCondition)
* diagnosis.use 0..1 MS
* diagnosis.use ^short = "Role of diagnosis in encounter (e.g., admission, billing, discharge)"
* diagnosis.rank 0..1 MS
* diagnosis.rank ^short = "Ranking of the diagnosis (primary, secondary, etc.)"