Slot Profile¶
| Canonical | ../StructureDefinition/nexus-emr-core-slot |
|---|---|
| Status | draft · 1.26.0 |
| Base | Slot (constraint) |
| CQL primary code path | serviceType — what this means |
| Source | FSH · JSON |
Minimal Nexus EMR profile for Slot resources — an individual bookable time window owned by a Schedule. Slots are materialised from recurring templates (Phase 1: OscarPro scheduletemplate rows) into concrete date+time instances. Booking clients select a free Slot, create an Appointment referencing it, and the booking system transitions the Slot's status.
FSH
The authored source of truth: resources/StructureDefinition-nexus-emr-core-slot.fsh (edit on GitHub). One FSH file may define several related artifacts.
// NexusEmrCoreSlot.fsh
Alias: $NexusEmrCoreSlot = ../StructureDefinition/nexus-emr-core-slot
Alias: $slotstatus = http://hl7.org/fhir/ValueSet/slotstatus
// --- Profile Definition ---
Profile: NexusEmrCoreSlot
Parent: Slot
Id: nexus-emr-core-slot
Title: "Slot Profile"
Description: "Minimal Nexus EMR profile for Slot resources — an individual bookable time window owned by a Schedule. Slots are materialised from recurring templates (Phase 1: OscarPro `scheduletemplate` rows) into concrete date+time instances. Booking clients select a free Slot, create an Appointment referencing it, and the booking system transitions the Slot's status."
// THE effective date for this profile (see the EffectiveDate / NoEffectiveDate
// RuleSets): one date concept per resource, declared here rather than guessed.
* insert EffectiveDate([[start]])
// SMART on FHIR exposure -- READ-ONLY. An app may read and search this resource but not
// create, update or delete it: this is reference/directory data, maintained by the EMR
// rather than by third-party apps, and a delete here is data loss rather than workflow.
* insert SmartExposedReadOnly(slot)
* ^url = $NexusEmrCoreSlot
* ^status = #draft
* ^publisher = "WELLSTAR Technologies Corp."
// --- Element Constraints ---
* . ^short = "Nexus EMR Slot Core"
* . ^definition = """
An individual bookable time window with concrete start/end timestamps and a
status (free | busy | busy-tentative | busy-unavailable | entered-in-error).
Each Slot references exactly one Schedule via Slot.schedule (base FHIR 1..1).
"""
* 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."
* text 0..1 MS
* text ^short = "Narrative"
* text ^definition = "A human-readable narrative summary of the NexusEmrCoreSlot resource for human interpretation."
// Identifier
* identifier 0..* MS
* identifier.system 1..1
* identifier.value 1..1
* identifier ^short = "Business identifier(s) for slot"
* identifier ^definition = """
Unique identifiers for the slot.
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. Slots are derived from
templates and should use deterministic IDs (e.g. `<provider_no>-<yyyyMMdd>-<index>`)
so re-emission of the same logical slot produces an identical resource.
"""
* insert SourceIdentifier(identifier)
// schedule — required reference back to the parent Schedule (base FHIR 1..1)
* schedule 1..1 MS
* schedule only Reference(NexusEmrCoreSchedule)
* schedule ^short = "The Schedule this Slot belongs to"
* schedule ^definition = "The Schedule resource that this Slot is derived from. Required per base FHIR R4 (Slot.schedule cardinality 1..1)."
// status — required by base FHIR; do not constrain writer (see intro markdown)
* status 1..1 MS
* status from $slotstatus (required)
* status ^short = "busy | free | busy-unavailable | busy-tentative | entered-in-error"
* status ^definition = """
The free/busy state of the slot.
The IG does NOT constrain who writes this field. Phase 1 contract (see profile intro):
- Oscar-side converter writes 'free' (default) or 'busy' (when an appointment row overlaps the slot window) or 'busy-unavailable' (within-day blockout from ScheduleDate.available != '1').
- Booking system writes 'busy-tentative' during a hold flow, then transitions to 'busy' on confirm or back to 'free' on hold timeout.
- The converter NEVER writes 'busy-tentative' — that value is the booking system's exclusively.
"""
* start 1..1 MS
* start ^short = "Slot start instant (UTC with offset)"
* start ^definition = "Date/Time at which this slot starts. Source-system local time is converted to UTC with offset by the converter (Phase 1: province → IANA TZ lookup based on the clinic's Location.address)."
* end 1..1 MS
* end ^short = "Slot end instant (UTC with offset)"
* end ^definition = "Date/Time at which this slot ends. For a slot derived from a 15-minute template grid, end = start + 15 minutes. Slot duration is constant within a template (computed as 1440 / timecode.length() minutes per slot)."
// overbooked — informational; semantics in intro
* overbooked 0..1 MS
* overbooked ^short = "Whether the slot is intentionally overbooked"
* overbooked ^definition = "Set by the booking system when more than one appointment is booked into the same slot window (e.g. walk-in over a held slot). Informational; the IG does not enforce a maximum."
* comment 0..1 MS
* comment ^short = "Free-text notes about the slot (e.g. blockout reason)"
* comment ^definition = "Used to carry the ScheduleDate.reason text when a within-day blockout produces a busy-unavailable Slot."
// serviceCategory
* serviceCategory 0..* MS
* serviceCategory ^short = "Service category with raw code support"
* insert SourceCoding(serviceCategory)
* serviceCategory ^definition = """
A broad categorization of the service offered in this slot.
RECOMMENDED: Standard terminology codes when available
OPTIONAL: Raw EMR codes for source system preservation. The rawCode slice is `0..*`
(not `1..*`) because the OscarPro source converter tolerates missing
`scheduletemplatecode` lookups — slots can be emitted without a rawCode mapping.
"""
// serviceType
* serviceType 0..* MS
* serviceType ^short = "Service type with raw code support"
* insert SourceCoding(serviceType)
* serviceType ^definition = """
The specific service offered in this slot. For OscarPro-sourced slots, the rawCode
slice is populated from the corresponding `scheduletemplatecode` row (mapped via the
single-character timecode value).
The rawCode slice is `0..*` (not `1..*`) — see serviceCategory rationale above.
"""
// appointmentType
* appointmentType 0..1 MS
* appointmentType ^short = "Appointment type that fits this slot"
* insert SourceCoding(appointmentType)
* appointmentType ^definition = """
The style of appointment this slot is intended for (e.g. routine, walk-in, checkup).
Note: `Slot.appointmentType` and `Appointment.appointmentType` are independent in
this IG — a booking client MAY create an Appointment with a different
appointmentType than the slot it consumed. This supports flexible slot inventory
(e.g. a clinic that double-purposes a slot for either routine or walk-in).
RECOMMENDED that booking clients copy the slot's appointmentType to the resulting
Appointment but not REQUIRED.
"""
// CQL PRIMARY CODE PATH. Names the code-valued element a bare CQL retrieve filters on, so
// `[Slot: "some-code"]` knows what to compare. Base R4's own CQL ModelInfo declares no
// `primaryCodePath` for this resource, and the consequence is not a compile error: the
// retrieve COMPILES, the translator only warns, and the criterion silently filters on
// nothing while its data-requirements manifest emits a `codeFilter` with no `path` (which
// violates FHIR's own drq-1 invariant). Declaring it here is what makes the natural
// authoring form correct rather than merely accepted.
//
// The extension is HL7's own, from hl7.fhir.uv.extensions.r4 which this IG already depends
// on -- not a Nexus canonical. Read by ts/codegen/cql/gen-modelinfo.ts.
* ^extension[+].url = $cql-primary-code-path
* ^extension[=].valueString = "serviceType"