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.
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-tentative → free 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):
GET Schedule?actor=PractitionerRole/<id>&active=true— find the provider's calendarGET Slot?schedule=Schedule/<id>&status=free&start=ge2026-06-01— fetch free slots- User selects a slot in the UI; booking client PATCHes
Slot.status = busy-tentative - User confirms; booking client
POSTs anAppointmentwith.slot[] = [Slot/<id>], then PATCHesSlot.status = busy - (If user abandons) hold-timeout job sees stale
busy-tentativeslot and PATCHes back tofree
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 durationSlot.serviceType.coding[rawCode]— from thescheduletemplatecodelookup (single-char code + description).0..*cardinality (not1..*) because the OscarPro converter tolerates lookup misses and emits Slots without the rawCode mapping when no matching code exists.Slot.appointmentType— also fromscheduletemplatecodeif availableSlot.status—freeby default;busyif theappointmenttable has a row overlapping[start, end);busy-unavailableifScheduleDate.available != '1'
Terminology bindings
| Path | Strength | Value set |
|---|---|---|
Slot.status |
required | slotstatus |