Schedule Profile¶
| Canonical | ../StructureDefinition/nexus-emr-core-schedule |
|---|---|
| Status | draft · 1.26.0 |
| Base | Schedule (constraint) |
| CQL primary code path | serviceType — what this means |
| Source | FSH · JSON |
Minimal Nexus EMR profile for Schedule resources, representing a clinic or provider's bookable calendar. Slots reference back to a Schedule via Slot.schedule. Phase 1 sources OscarPro provider templates (one Schedule per provider) but the profile supports room/equipment (Location) and service-line (HealthcareService) schedules as well.
FSH
The authored source of truth: resources/StructureDefinition-nexus-emr-core-schedule.fsh (edit on GitHub). One FSH file may define several related artifacts.
// NexusEmrCoreSchedule.fsh
Alias: $NexusEmrCoreSchedule = ../StructureDefinition/nexus-emr-core-schedule
// A provider actor may be named by EITHER a PractitionerRole (the clinic/role binding) or a
// raw Practitioner. Practitioner is the primary provider identity in this IG; PractitionerRole
// is used where the clinic/role binding is the assertion. Schedule is the one place a provider
// reference was a HARD requirement rather than a target-type constraint, so before this change
// a Practitioner-shaped Schedule -- the shape a primary-care writer would naturally emit --
// failed `schedule-actor-required` outright. Alternation is ordered longest-first so
// `PractitionerRole/` is never mis-read as `Practitioner/`.
Invariant: schedule-actor-required
Description: "Schedule.actor must contain at least one of a provider (PractitionerRole or Practitioner), Location, or HealthcareService"
Severity: #error
Expression: "actor.where(reference.matches('(^|/)(PractitionerRole|Practitioner|Location|HealthcareService)/')).exists()"
// Replaces `schedule-actor-practitionerrole-max`: caps the PROVIDER actor at one, whichever
// resource names them. The old rule counted only PractitionerRole, so it was silently
// unenforced against a Practitioner-shaped actor.
Invariant: schedule-actor-provider-max
Description: "At most one actor referencing a provider (PractitionerRole or Practitioner)"
Severity: #error
Expression: "actor.where(reference.matches('(^|/)PractitionerRole/') or reference.matches('(^|/)Practitioner/')).count() <= 1"
Invariant: schedule-actor-location-max
Description: "At most one actor referencing a Location"
Severity: #error
Expression: "actor.where(reference.matches('(^|/)Location/')).count() <= 1"
Invariant: schedule-actor-healthcareservice-max
Description: "At most one actor referencing a HealthcareService"
Severity: #error
Expression: "actor.where(reference.matches('(^|/)HealthcareService/')).count() <= 1"
// --- Profile Definition ---
Profile: NexusEmrCoreSchedule
Parent: Schedule
Id: nexus-emr-core-schedule
Title: "Schedule Profile"
Description: "Minimal Nexus EMR profile for Schedule resources, representing a clinic or provider's bookable calendar. Slots reference back to a Schedule via Slot.schedule. Phase 1 sources OscarPro provider templates (one Schedule per provider) but the profile supports room/equipment (Location) and service-line (HealthcareService) schedules as well."
// THE effective date for this profile (see the EffectiveDate / NoEffectiveDate
// RuleSets): one date concept per resource, declared here rather than guessed.
* insert EffectiveDate([[planningHorizon.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(schedule)
* ^url = $NexusEmrCoreSchedule
* ^status = #draft
* ^publisher = "WELLSTAR Technologies Corp."
* obeys schedule-actor-required
// --- Element Constraints ---
* . ^short = "Nexus EMR Schedule Core"
* . ^definition = """
Represents a bookable calendar — typically owned by a provider (PractitionerRole),
but may instead represent a room/equipment (Location) or a service line
(HealthcareService). Slots are produced from a Schedule and reference it via
Slot.schedule (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. Tells you which EMR instance, and the version of the pipeline code/transformations."
* text 0..1 MS
* text ^short = "Narrative"
* text ^definition = "A human-readable narrative summary of the NexusEmrCoreSchedule resource for human interpretation."
// Identifier
* identifier 0..* MS
* identifier.system 1..1
* identifier.value 1..1
* identifier ^short = "Business identifier(s) for schedule"
* identifier ^definition = """
Unique identifiers for the schedule.
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)
// active — whether the schedule is currently bookable
* active 0..1 MS
* active ^short = "Whether the schedule is in active use"
* active ^definition = "Whether this schedule record is in active use. Defaults to true if absent (FHIR R4 semantics)."
// actor — a provider (PractitionerRole or Practitioner), a Location, or a HealthcareService
// At least one must be present (enforced by schedule-actor-required invariant)
* actor 1..* MS
* actor ^short = "Who/what the schedule belongs to"
* actor ^definition = """
The resource(s) this schedule represents available booking time for.
Typically the **provider** whose calendar this is. The provider may be named by either a
**PractitionerRole** (where the clinic/role binding is the assertion -- a provider's calendar
*at this clinic, in this role*) or a raw **Practitioner** (the primary provider identity in
this IG). Both are supported and consumers must handle either.
May also be a Location (room or equipment schedule) or a HealthcareService (service-line
schedule, e.g. walk-in clinic). At least one provider / Location / HealthcareService actor
MUST be present (per schedule-actor-required invariant), and at most one provider actor
(per schedule-actor-provider-max).
"""
// Actor composition (at most one provider — PractitionerRole or Practitioner — and at most
// one each of Location and HealthcareService) is enforced by reference-type invariants rather
// than slicing: profile-discriminated slicing on resolve() is unenforceable for Nexus EMR's
// logical (non-resolvable) references — see meta/history 2026-07-06 evaluable-slicing.
* obeys schedule-actor-provider-max and schedule-actor-location-max and schedule-actor-healthcareservice-max
// planningHorizon — the period over which the schedule is bookable
* planningHorizon 0..1 MS
* planningHorizon ^short = "Rolling booking window this schedule supports"
* planningHorizon ^definition = "The period of time that this schedule covers (typically a rolling 90 days from today). Slots SHOULD only exist within this period."
// serviceCategory — broad categorisation of the service this schedule supports
* serviceCategory 0..* MS
* serviceCategory ^short = "Service category with raw code support"
* insert SourceCoding(serviceCategory)
* serviceCategory ^definition = """
A broad categorization of the service that is offered through this schedule.
RECOMMENDED: Standard terminology codes when available
OPTIONAL: Raw EMR codes for source system preservation
"""
// serviceType — specific service this schedule supports
* serviceType 0..* MS
* serviceType ^short = "Service type with raw code support"
* insert SourceCoding(serviceType)
* serviceType ^definition = """
The specific service that is offered through this schedule.
RECOMMENDED: Standard terminology codes when available
OPTIONAL: Raw EMR codes for source system preservation
"""
// comment — free-text scheduling notes (e.g. "Wednesdays are walk-in only")
* comment 0..1 MS
* comment ^short = "Free-text scheduling notes"
// CQL PRIMARY CODE PATH. Names the code-valued element a bare CQL retrieve filters on, so
// `[Schedule: "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"