Skip to content

Slot Profile

Canonical../StructureDefinition/nexus-emr-core-slot
Statusdraft · 1.26.0
BaseSlot (constraint)
CQL primary code pathserviceTypewhat this means
SourceFSH · 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.

Overview

Overview

The Nexus EMR Core Slot profile represents an individual bookable time window on a Schedule. Each Slot has concrete start/end instants and a status (free / busy / busy-tentative / busy-unavailable / entered-in-error). Booking clients discover free Slots, present them to the user, and create an Appointment referencing the chosen Slot via Appointment.slot.

In Phase 1, Slots are materialised from OscarPro scheduletemplate rows by the Oscar-side converter — one Slot per non-_ character of the timecode string per scheduled date.

Slot.status — writer ownership

The IG does NOT constrain who writes Slot.status or when. This is intentional: in a real booking system at least three actors update slot state:

Actor Writes
Oscar-side converter free (default) or busy (when an appointment row overlaps the slot window) or busy-unavailable (when ScheduleDate.available != '1' indicates a within-day blockout)
Booking system busy-tentative during a hold flow, then transitions to busy on confirm or back to free on hold timeout
Reconciliation jobs May downgrade busy-tentativefree after hold timeouts

The converter NEVER writes busy-tentative. That value is the booking system's exclusively.

If race conditions surface in production (two writers updating the same slot concurrently), the IG-level mitigation is for the booking system to use If-Match for optimistic concurrency. That requirement is not currently enforced at the profile level.

Nexus EMR ID — deterministic IDs for materialised resources

Slots are derived from templates, not stored as first-class records in OscarPro. To support cache stability and re-emission idempotency, Slot IDs are deterministic:

Slot.id = <provider_no>-<yyyyMMdd>-<slot-index> (e.g. 42-20260601-36)

Slot.identifier.value is the same value. Re-running the converter for the same (provider, date) produces identical Slot resources — safe to cache by reference.

The '_' no-slot convention

In OscarPro's timecode string, an underscore character ('_') indicates "no slot at this index" — the clinic is not bookable during that time window. The Oscar converter skips these characters entirely (no Slot resource is emitted). So a clinic that's only open 8 AM–5 PM has '_' characters for the rest of the 24-hour grid; consumers see no Slots outside business hours rather than a stream of busy-unavailable Slots.

overbooked

Slot.overbooked is set by the booking system when more than one Appointment is booked into the same slot window (e.g. a walk-in is squeezed in over a held slot). Informational only — the IG does not enforce a maximum or define cardinality semantics. Default is unset (treated as false).

Holiday handling

Holidays produce no Slots. Per Phase 1's converter migration spec, when a date appears in OscarPro's scheduleholiday table, the converter emits no Slots for that day — the absence of Slots is the signal that the clinic isn't bookable. This is preferred over emitting busy-unavailable Slots for every grid position on a holiday (which would create dozens of phantom resources).

Within-day blockouts (ScheduleDate.available != '1') DO produce Slots with status = busy-unavailable and the ScheduleDate.reason text carried in Slot.comment.

Booking workflow

Typical end-to-end flow (informational; not normative):

  1. GET Schedule?actor=PractitionerRole/<id>&active=true — find the provider's calendar
  2. GET Slot?schedule=Schedule/<id>&status=free&start=ge2026-06-01 — fetch free slots
  3. User selects a slot in the UI; booking client PATCHes Slot.status = busy-tentative
  4. User confirms; booking client POSTs an Appointment with .slot[] = [Slot/<id>], then PATCHes Slot.status = busy
  5. (If user abandons) hold-timeout job sees stale busy-tentative slot and PATCHes back to free

The Oscar-side converter is uninvolved past step 1's data — it only emits the initial free/busy state from the appointment-overlay logic.

Source data: OscarPro scheduletemplate + scheduletemplatecode

The Oscar-side converter (see docs/guide/features/scheduling/converter-contracts.md) derives Slot fields from:

  • Slot.start / Slot.end — from the timecode position and (24h × 60min) / timecode.length() per-slot duration
  • Slot.serviceType.coding[rawCode] — from the scheduletemplatecode lookup (single-char code + description). 0..* cardinality (not 1..*) because the OscarPro converter tolerates lookup misses and emits Slots without the rawCode mapping when no matching code exists.
  • Slot.appointmentType — also from scheduletemplatecode if available
  • Slot.statusfree by default; busy if the appointment table has a row overlapping [start, end); busy-unavailable if ScheduleDate.available != '1'

Terminology bindings

Path Strength Value set
Slot.status required slotstatus