Scheduling & Bed/OR Management Data Specifications

Scheduling & Bed/OR Management Data Specifications

Shared Entity References

This module owns the canonical encounter entities and references the following shared entities defined in their owning modules.

Shared Entity Owning Module Table(s) FK Used Here
Patients ehr-patient-mgmt patients, patient_demographics patients.patient_id
Providers ehr-patient-mgmt providers, provider_credentials providers.provider_id
Users & Auth ehr-patient-mgmt users, roles, permissions users.user_id
Facilities ehr-patient-mgmt facilities, departments, locations facilities.facility_id
Departments ehr-patient-mgmt departments departments.department_id
Locations ehr-patient-mgmt locations locations.location_id
Payers policy-contract-mgmt payers, insurance_plans, contracts payers.payer_id, insurance_plans.insurance_plan_id

Entity Relationship Diagram

erDiagram patients ||--o{ encounters : "has" patients ||--o{ appointments : "has" patients ||--o{ bed_assignments : "has" patients ||--o{ bed_transfers : "has" patients ||--o{ or_cases : "has" patients ||--o{ waitlist_entries : "on" providers ||--o{ encounters : "attending/admitting" providers ||--o{ appointments : "for" providers ||--o{ provider_schedules : "owns" providers ||--o{ or_schedules : "surgeon/anesth" providers ||--o{ or_cases : "surgeon/anesth" facilities ||--o{ encounters : "at" facilities ||--o{ appointments : "at" facilities ||--o{ beds : "contains" facilities ||--o{ or_rooms : "contains" facilities ||--o{ provider_schedules : "at" facilities ||--o{ scheduling_rules : "for" departments ||--o{ encounters : "service" departments ||--o{ appointments : "clinic" departments ||--o{ beds : "ward" departments ||--o{ provider_schedules : "clinic" departments ||--o{ scheduling_rules : "for" locations ||--o{ beds : "located" locations ||--o{ encounters : "location" payers ||--o{ encounters : "covered by" encounters ||--o{ encounter_details : "has" encounters ||--o{ appointments : "may originate" encounters ||--o{ bed_assignments : "uses" encounters ||--o{ bed_transfers : "moves" encounters ||--o{ or_cases : "includes" appointment_types ||--o{ appointments : "typed as" provider_schedules ||--o{ appointment_slots : "generate" appointment_slots ||--o{ appointments : "booked in" scheduling_templates ||--o{ provider_schedules : "instantiates" scheduling_rules ||--o{ appointments : "govern" scheduling_rules ||--o{ appointment_slots : "govern" beds ||--o{ bed_assignments : "assigned" beds ||--o{ bed_transfers : "from/to" or_rooms ||--o{ or_schedules : "for" or_schedules ||--o{ or_cases : "contains" waitlist_entries ||--o{ appointments : "resolved by" encounters { bigint encounter_id PK bigint patient_id FK bigint facility_id FK bigint department_id FK bigint attending_provider_id FK bigint admitting_provider_id FK bigint referring_provider_id FK bigint payer_id FK bigint insurance_plan_id FK } encounter_details { bigint detail_id PK bigint encounter_id FK bigint bed_id FK } appointments { bigint appointment_id PK bigint patient_id FK bigint encounter_id FK bigint provider_id FK bigint department_id FK bigint facility_id FK bigint appointment_type_id FK bigint slot_id FK bigint rescheduled_from FK bigint waitlist_entry_id FK bigint created_by FK } appointment_slots { bigint slot_id PK bigint schedule_template_id FK bigint provider_id FK bigint department_id FK bigint facility_id FK } appointment_types { bigint type_id PK } beds { bigint bed_id PK bigint location_id FK bigint facility_id FK bigint department_id FK } bed_assignments { bigint assignment_id PK bigint bed_id FK bigint patient_id FK bigint encounter_id FK } bed_transfers { bigint transfer_id PK bigint encounter_id FK bigint patient_id FK bigint from_bed_id FK bigint to_bed_id FK bigint requested_by FK bigint approved_by FK } or_rooms { bigint room_id PK bigint facility_id FK } or_schedules { bigint schedule_id PK bigint or_room_id FK bigint surgeon_id FK bigint anesthesiologist_id FK } or_cases { bigint case_id PK bigint schedule_id FK bigint patient_id FK bigint encounter_id FK bigint surgeon_id FK bigint anesthesiologist_id FK } waitlist_entries { bigint entry_id PK bigint patient_id FK bigint preferred_provider_id FK } provider_schedules { bigint schedule_id PK bigint provider_id FK bigint facility_id FK bigint department_id FK } scheduling_rules { bigint rule_id PK bigint facility_id FK bigint department_id FK bigint appointment_type_id FK } scheduling_templates { bigint template_id PK bigint provider_id FK bigint department_id FK bigint created_by FK }

Table Definitions

Note: SQL examples assume PostgreSQL 14+. Adapt types/constraints as needed for the target RDBMS.


1. encounters

Purpose
Canonical encounter record for all patient visits/admissions (outpatient, ED, inpatient, day surgery). Referenced by all clinical and RCM modules.

Fields

Field Type Nullable Default Constraint Description
encounter_id BIGINT NO IDENTITY PK Unique encounter identifier
patient_id BIGINT NO FK → patients.patient_id Patient
encounter_type VARCHAR(30) NO CHECK in controlled set Local type (e.g. OPD, ED, IP, DS)
encounter_class VARCHAR(10) NO HL7 v3 class codes AMB, EMER, IMP, OBS, etc.
encounter_status VARCHAR(20) NO 'planned' CHECK planned, in-progress, onleave, finished, cancelled
admission_datetime TIMESTAMP YES Admission/visit start (for IP/ED)
discharge_datetime TIMESTAMP YES CHECK ≥ admission Discharge/visit end
facility_id BIGINT NO FK → facilities.facility_id Facility where encounter occurs
department_id BIGINT YES FK → departments.department_id Clinical department/service
location_id BIGINT YES FK → locations.location_id Primary location/ward/clinic
attending_provider_id BIGINT YES FK → providers.provider_id Attending physician
admitting_provider_id BIGINT YES FK → providers.provider_id Admitting physician
referring_provider_id BIGINT YES FK → providers.provider_id Referring physician
admission_source VARCHAR(20) YES HL7 Table 0023 subset e.g. ER, OPD, TRANSFER, BORN
discharge_disposition VARCHAR(20) YES HL7 Table 0112 + UAE e.g. HOME, TRANSFER, AMA, EXPIRED
payer_id BIGINT YES FK → payers.payer_id Primary payer
insurance_plan_id BIGINT YES FK → insurance_plans.insurance_plan_id Plan (e.g. THIQA, Daman)
expected_los NUMERIC(5,2) YES ≥ 0 Expected length of stay (days)
actual_los NUMERIC(5,2) YES ≥ 0 Calculated LOS (days)
chief_complaint VARCHAR(500) YES Chief complaint (free text)
chief_complaint_snomed VARCHAR(20) YES SNOMED CT code Structured chief complaint
uae_emirate_code VARCHAR(2) YES IN ('AD','DU','SH','AJ','RA','FU','UA') Emirate of facility
created_by BIGINT NO FK → users.user_id User who created encounter
updated_by BIGINT YES FK → users.user_id Last updating user
created_at TIMESTAMP NO CURRENT_TIMESTAMP Creation timestamp
updated_at TIMESTAMP NO CURRENT_TIMESTAMP ON UPDATE Last update timestamp

SQL DDL

SQL
CREATE TABLE encounters (
    encounter_id           BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
    patient_id             BIGINT NOT NULL,
    encounter_type         VARCHAR(30) NOT NULL,
    encounter_class        VARCHAR(10) NOT NULL,
    encounter_status       VARCHAR(20) NOT NULL DEFAULT 'planned',
    admission_datetime     TIMESTAMP NULL,
    discharge_datetime     TIMESTAMP NULL,
    facility_id            BIGINT NOT NULL,
    department_id          BIGINT NULL,
    location_id            BIGINT NULL,
    attending_provider_id  BIGINT NULL,
    admitting_provider_id  BIGINT NULL,
    referring_provider_id  BIGINT NULL,
    admission_source       VARCHAR(20) NULL,
    discharge_disposition  VARCHAR(20) NULL,
    payer_id               BIGINT NULL,
    insurance_plan_id      BIGINT NULL,
    expected_los           NUMERIC(5,2) NULL,
    actual_los             NUMERIC(5,2) NULL,
    chief_complaint        VARCHAR(500) NULL,
    chief_complaint_snomed VARCHAR(20) NULL,
    uae_emirate_code       VARCHAR(2) NULL,
    created_by             BIGINT NOT NULL,
    updated_by             BIGINT NULL,
    created_at             TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    updated_at             TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,

    CONSTRAINT chk_encounter_class
        CHECK (encounter_class IN ('AMB','EMER','IMP','OBS','VR','HH')),
    CONSTRAINT chk_encounter_status
        CHECK (encounter_status IN ('planned','in-progress','onleave','finished','cancelled')),
    CONSTRAINT chk_encounter_dates
        CHECK (discharge_datetime IS NULL OR admission_datetime IS NULL
               OR discharge_datetime >= admission_datetime),
    CONSTRAINT chk_los_non_negative
        CHECK ((expected_los IS NULL OR expected_los >= 0)
           AND (actual_los IS NULL OR actual_los >= 0)),
    CONSTRAINT chk_uae_emirate_code
        CHECK (uae_emirate_code IS NULL OR uae_emirate_code IN ('AD','DU','SH','AJ','RA','FU','UA'))
);

-- FKs
ALTER TABLE encounters
  ADD CONSTRAINT fk_enc_patient
    FOREIGN KEY (patient_id) REFERENCES patients(patient_id) ON UPDATE CASCADE,
  ADD CONSTRAINT fk_enc_facility
    FOREIGN KEY (facility_id) REFERENCES facilities(facility_id) ON UPDATE CASCADE,
  ADD CONSTRAINT fk_enc_department
    FOREIGN KEY (department_id) REFERENCES departments(department_id) ON UPDATE CASCADE,
  ADD CONSTRAINT fk_enc_location
    FOREIGN KEY (location_id) REFERENCES locations(location_id) ON UPDATE CASCADE,
  ADD CONSTRAINT fk_enc_attending
    FOREIGN KEY (attending_provider_id) REFERENCES providers(provider_id) ON UPDATE CASCADE,
  ADD CONSTRAINT fk_enc_admitting
    FOREIGN KEY (admitting_provider_id) REFERENCES providers(provider_id) ON UPDATE CASCADE,
  ADD CONSTRAINT fk_enc_referring
    FOREIGN KEY (referring_provider_id) REFERENCES providers(provider_id) ON UPDATE CASCADE,
  ADD CONSTRAINT fk_enc_payer
    FOREIGN KEY (payer_id) REFERENCES payers(payer_id) ON UPDATE CASCADE,
  ADD CONSTRAINT fk_enc_plan
    FOREIGN KEY (insurance_plan_id) REFERENCES insurance_plans(insurance_plan_id) ON UPDATE CASCADE,
  ADD CONSTRAINT fk_enc_created_by
    FOREIGN KEY (created_by) REFERENCES users(user_id),
  ADD CONSTRAINT fk_enc_updated_by
    FOREIGN KEY (updated_by) REFERENCES users(user_id);

-- Indexes
CREATE INDEX idx_encounters_patient ON encounters(patient_id);
CREATE INDEX idx_encounters_facility_status ON encounters(facility_id, encounter_status);
CREATE INDEX idx_encounters_admission_dt ON encounters(admission_datetime);
CREATE INDEX idx_encounters_discharge_dt ON encounters(discharge_datetime);
CREATE INDEX idx_encounters_payer ON encounters(payer_id);
CREATE INDEX idx_encounters_attending ON encounters(attending_provider_id);
CREATE INDEX idx_encounters_class_status ON encounters(encounter_class, encounter_status);
CREATE INDEX idx_encounters_active_ip
    ON encounters(facility_id, department_id, encounter_status)
    WHERE encounter_class IN ('IMP','EMER') AND encounter_status IN ('in-progress','onleave');

Terminology Bindings

Field Terminology Example Value
encounter_class HL7 v3 ActCode IMP
encounter_type Local + SNOMED CT (where mapped) OPD, ED, DAY_SURGERY
admission_source HL7 v2 Table 0023 (subset) ER, OPD, TRANSFER
discharge_disposition HL7 v2 Table 0112 + UAE extensions HOME, TRANSFER, AMA
chief_complaint_snomed SNOMED CT 422587007 (Chest pain)
uae_emirate_code Local UAE code set DU (Dubai)

FHIR Mapping

Table Field FHIR Resource FHIR Path
encounter_id Encounter Encounter.id
patient_id Encounter Encounter.subject.reference
encounter_class Encounter Encounter.class.code
encounter_type Encounter Encounter.type[0].coding[0].code
encounter_status Encounter Encounter.status
admission_datetime Encounter Encounter.period.start
discharge_datetime Encounter Encounter.period.end
facility_id Encounter Encounter.serviceProvider.reference
department_id Encounter Encounter.location[0].extension(department) (extension)
location_id Encounter Encounter.location[0].location.reference
attending_provider_id Encounter Encounter.participant[type=attender].individual
admitting_provider_id Encounter Encounter.participant[type=admitter].individual
referring_provider_id Encounter Encounter.participant[type=referrer].individual
admission_source Encounter Encounter.hospitalization.admitSource
discharge_disposition Encounter Encounter.hospitalization.dischargeDisposition
payer_id Coverage Coverage.payor (linked via Encounter.account)
expected_los Encounter Extension expectedLengthOfStay
actual_los Encounter Derived from Encounter.period
chief_complaint Condition Condition.note or Condition.code.text
chief_complaint_snomed Condition Condition.code.coding[0].code

2. encounter_details

Purpose
Extended encounter metadata used for coding, DRG grouping, and bed/isolation context.

Fields

Field Type Nullable Default Constraint Description
detail_id BIGINT NO IDENTITY PK Unique detail row
encounter_id BIGINT NO FK → encounters.encounter_id Encounter
admission_diagnosis_icd10 VARCHAR(10) YES ICD-10-AM Admission diagnosis
principal_diagnosis_icd10 VARCHAR(10) YES ICD-10-AM Principal diagnosis
drg_code VARCHAR(10) YES Local/UAE DRG Grouping code
case_weight NUMERIC(6,3) YES ≥ 0 DRG weight
financial_class VARCHAR(20) YES Local code SELF, GOV, PRIVATE, etc.
pre_auth_number VARCHAR(50) YES Insurance pre-authorization
bed_id BIGINT YES FK → beds.bed_id Current bed (for IP)
room_type_requested VARCHAR(20) YES Local PRIVATE, SEMI, WARD, VIP
isolation_required BOOLEAN NO FALSE Isolation flag
isolation_reason_snomed VARCHAR(20) YES SNOMED CT Reason for isolation
created_at TIMESTAMP NO CURRENT_TIMESTAMP Created
updated_at TIMESTAMP NO CURRENT_TIMESTAMP ON UPDATE Updated

SQL DDL

SQL
CREATE TABLE encounter_details (
    detail_id                  BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
    encounter_id               BIGINT NOT NULL,
    admission_diagnosis_icd10  VARCHAR(10) NULL,
    principal_diagnosis_icd10  VARCHAR(10) NULL,
    drg_code                   VARCHAR(10) NULL,
    case_weight                NUMERIC(6,3) NULL,
    financial_class            VARCHAR(20) NULL,
    pre_auth_number            VARCHAR(50) NULL,
    bed_id                     BIGINT NULL,
    room_type_requested        VARCHAR(20) NULL,
    isolation_required         BOOLEAN NOT NULL DEFAULT FALSE,
    isolation_reason_snomed    VARCHAR(20) NULL,
    created_at                 TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    updated_at                 TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,

    CONSTRAINT fk_encdet_encounter
        FOREIGN KEY (encounter_id) REFERENCES encounters(encounter_id) ON DELETE CASCADE,
    CONSTRAINT fk_encdet_bed
        FOREIGN KEY (bed_id) REFERENCES beds(bed_id) ON UPDATE CASCADE,
    CONSTRAINT chk_encdet_case_weight
        CHECK (case_weight IS NULL OR case_weight >= 0),
    CONSTRAINT chk_encdet_room_type
        CHECK (room_type_requested IS NULL OR room_type_requested IN ('PRIVATE','SEMI','WARD','VIP'))
);

CREATE UNIQUE INDEX ux_encounter_details_encounter
    ON encounter_details(encounter_id);

CREATE INDEX idx_encdet_principal_dx ON encounter_details(principal_diagnosis_icd10);
CREATE INDEX idx_encdet_drg ON encounter_details(drg_code);

Terminology Bindings

Field Terminology Example Value
admission_diagnosis_icd10 ICD-10-AM J18.9
principal_diagnosis_icd10 ICD-10-AM I21.9
drg_code UAE DRG A-04-10
financial_class Local GOV, PRIVATE, SELF
isolation_reason_snomed SNOMED CT 186747009 (Infectious disease carrier)

FHIR Mapping

Table Field FHIR Resource FHIR Path
encounter_id Encounter Encounter.id
admission_diagnosis_icd10 Condition Condition.code.coding[system=ICD-10-AM].code
principal_diagnosis_icd10 Condition Condition.code.coding[system=ICD-10-AM].code
drg_code Encounter Encounter.diagnosis[use=DRG].packageCode
case_weight Encounter Extension drgCaseWeight
financial_class Encounter Encounter.classHistory or Account.type
bed_id Encounter Encounter.location[0].physicalType + extension (bed)
room_type_requested Encounter Encounter.hospitalization.accommodation (extension)
isolation_required Encounter Extension isolationStatus

3. appointments

Purpose
Stores all outpatient and procedural appointments, including linkage to encounters, waitlist, and check-in.

Fields

Field Type Nullable Default Constraint Description
appointment_id BIGINT NO IDENTITY PK Appointment
patient_id BIGINT NO FK → patients.patient_id Patient
encounter_id BIGINT YES FK → encounters.encounter_id Linked encounter (shell or active)
provider_id BIGINT NO FK → providers.provider_id Primary provider
department_id BIGINT NO FK → departments.department_id Clinic department
facility_id BIGINT NO FK → facilities.facility_id Facility
appointment_type_id BIGINT NO FK → appointment_types.type_id Type
slot_id BIGINT YES FK → appointment_slots.slot_id Slot used
appointment_datetime TIMESTAMP NO Start datetime
duration_minutes INT NO 15 > 0 Duration
status VARCHAR(20) NO 'booked' CHECK booked, checked_in, completed, cancelled, no_show
check_in_time TIMESTAMP YES Check-in timestamp
reason_for_visit VARCHAR(500) YES Reason (free text)
reason_for_visit_snomed VARCHAR(20) YES SNOMED CT Structured reason
cancellation_reason VARCHAR(50) YES Local code From cancellation master
rescheduled_from BIGINT YES FK → appointments.appointment_id Previous appointment
waitlist_entry_id BIGINT YES FK → waitlist_entries.entry_id Source waitlist
created_by BIGINT NO FK → users.user_id Booking user
updated_by BIGINT YES FK → users.user_id Last updating user
created_at TIMESTAMP NO CURRENT_TIMESTAMP Created
updated_at TIMESTAMP NO CURRENT_TIMESTAMP ON UPDATE Updated

SQL DDL

SQL
CREATE TABLE appointments (
    appointment_id           BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
    patient_id               BIGINT NOT NULL,
    encounter_id             BIGINT NULL,
    provider_id              BIGINT NOT NULL,
    department_id            BIGINT NOT NULL,
    facility_id              BIGINT NOT NULL,
    appointment_type_id      BIGINT NOT NULL,
    slot_id                  BIGINT NULL,
    appointment_datetime     TIMESTAMP NOT NULL,
    duration_minutes         INT NOT NULL DEFAULT 15,
    status                   VARCHAR(20) NOT NULL DEFAULT 'booked',
    check_in_time            TIMESTAMP NULL,
    reason_for_visit         VARCHAR(500) NULL,
    reason_for_visit_snomed  VARCHAR(20) NULL,
    cancellation_reason      VARCHAR(50) NULL,
    rescheduled_from         BIGINT NULL,
    waitlist_entry_id        BIGINT NULL,
    created_by               BIGINT NOT NULL,
    updated_by               BIGINT NULL,
    created_at               TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    updated_at               TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,

    CONSTRAINT chk_appointment_status
        CHECK (status IN ('booked','checked_in','completed','cancelled','no_show')),
    CONSTRAINT chk_appointment_duration
        CHECK (duration_minutes > 0)
);

ALTER TABLE appointments
  ADD CONSTRAINT fk_appt_patient
    FOREIGN KEY (patient_id) REFERENCES patients(patient_id) ON UPDATE CASCADE,
  ADD CONSTRAINT fk_appt_encounter
    FOREIGN KEY (encounter_id) REFERENCES encounters(encounter_id) ON DELETE SET NULL,
  ADD CONSTRAINT fk_appt_provider
    FOREIGN KEY (provider_id) REFERENCES providers(provider_id) ON UPDATE CASCADE,
  ADD CONSTRAINT fk_appt_department
    FOREIGN KEY (department_id) REFERENCES departments(department_id) ON UPDATE CASCADE,
  ADD CONSTRAINT fk_appt_facility
    FOREIGN KEY (facility_id) REFERENCES facilities(facility_id) ON UPDATE CASCADE,
  ADD CONSTRAINT fk_appt_type
    FOREIGN KEY (appointment_type_id) REFERENCES appointment_types(type_id),
  ADD CONSTRAINT fk_appt_slot
    FOREIGN KEY (slot_id) REFERENCES appointment_slots(slot_id) ON DELETE SET NULL,
  ADD CONSTRAINT fk_appt_rescheduled_from
    FOREIGN KEY (rescheduled_from) REFERENCES appointments(appointment_id),
  ADD CONSTRAINT fk_appt_waitlist
    FOREIGN KEY (waitlist_entry_id) REFERENCES waitlist_entries(entry_id),
  ADD CONSTRAINT fk_appt_created_by
    FOREIGN KEY (created_by) REFERENCES users(user_id),
  ADD CONSTRAINT fk_appt_updated_by
    FOREIGN KEY (updated_by) REFERENCES users(user_id);

CREATE INDEX idx_appt_patient ON appointments(patient_id, appointment_datetime);
CREATE INDEX idx_appt_provider_date ON appointments(provider_id, appointment_datetime);
CREATE INDEX idx_appt_facility_dept_date ON appointments(facility_id, department_id, appointment_datetime);
CREATE INDEX idx_appt_status ON appointments(status);
CREATE INDEX idx_appt_waitlist ON appointments(waitlist_entry_id);
CREATE INDEX idx_appt_encounter ON appointments(encounter_id);

Terminology Bindings

Field Terminology Example Value
reason_for_visit_snomed SNOMED CT 65363002 (Otitis media)
cancellation_reason Local PATIENT_REQUEST, NO_SHOW_POLICY, PROVIDER_UNAVAILABLE
status HL7 / FHIR AppointmentStatus booked, cancelled

FHIR Mapping

Table Field FHIR Resource FHIR Path
appointment_id Appointment Appointment.id
patient_id Appointment Appointment.participant[patient].actor
provider_id Appointment Appointment.participant[practitioner].actor
facility_id Appointment Appointment.serviceProvider
department_id Appointment Extension department
appointment_type_id Appointment Appointment.appointmentType
appointment_datetime Appointment Appointment.start
duration_minutes Appointment Appointment.minutesDuration
status Appointment Appointment.status
reason_for_visit Appointment Appointment.description
reason_for_visit_snomed Appointment Appointment.reasonCode[0].coding[0].code
check_in_time Encounter Encounter.statusHistory or extension
encounter_id Encounter Encounter.id and Appointment.basedOn

4. appointment_slots

Purpose
Represents discrete bookable slots generated from provider schedules/templates.

Fields

Field Type Nullable Default Constraint Description
slot_id BIGINT NO IDENTITY PK Slot
schedule_template_id BIGINT YES FK → scheduling_templates.template_id Source template
provider_id BIGINT NO FK → providers.provider_id Provider
department_id BIGINT NO FK → departments.department_id Department
facility_id BIGINT NO FK → facilities.facility_id Facility
slot_date DATE NO Date
start_time TIME NO Start time
end_time TIME NO CHECK > start End time
slot_type VARCHAR(20) NO 'standard' Local standard, urgent, followup, procedure
max_overbooking INT NO 0 ≥ 0 Allowed overbook count
current_bookings INT NO 0 ≥ 0 Current bookings
is_blocked BOOLEAN NO FALSE Blocked flag
block_reason VARCHAR(200) YES Reason if blocked
created_at TIMESTAMP NO CURRENT_TIMESTAMP Created
updated_at TIMESTAMP NO CURRENT_TIMESTAMP ON UPDATE Updated

SQL DDL

SQL
CREATE TABLE appointment_slots (
    slot_id             BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
    schedule_template_id BIGINT NULL,
    provider_id         BIGINT NOT NULL,
    department_id       BIGINT NOT NULL,
    facility_id         BIGINT NOT NULL,
    slot_date           DATE NOT NULL,
    start_time          TIME NOT NULL,
    end_time            TIME NOT NULL,
    slot_type           VARCHAR(20) NOT NULL DEFAULT 'standard',
    max_overbooking     INT NOT NULL DEFAULT 0,
    current_bookings    INT NOT NULL DEFAULT 0,
    is_blocked          BOOLEAN NOT NULL DEFAULT FALSE,
    block_reason        VARCHAR(200) NULL,
    created_at          TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    updated_at          TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,

    CONSTRAINT chk_slot_time
        CHECK (end_time > start_time),
    CONSTRAINT chk_slot_overbooking
        CHECK (max_overbooking >= 0 AND current_bookings >= 0)
);

ALTER TABLE appointment_slots
  ADD CONSTRAINT fk_slot_template
    FOREIGN KEY (schedule_template_id) REFERENCES scheduling_templates(template_id) ON DELETE SET NULL,
  ADD CONSTRAINT fk_slot_provider
    FOREIGN KEY (provider_id) REFERENCES providers(provider_id),
  ADD CONSTRAINT fk_slot_department
    FOREIGN KEY (department_id) REFERENCES departments(department_id),
  ADD CONSTRAINT fk_slot_facility
    FOREIGN KEY (facility_id) REFERENCES facilities(facility_id);

CREATE INDEX idx_slots_provider_date
    ON appointment_slots(provider_id, slot_date, start_time);
CREATE INDEX idx_slots_facility_dept_date
    ON appointment_slots(facility_id, department_id, slot_date);
CREATE INDEX idx_slots_availability
    ON appointment_slots(provider_id, slot_date)
    WHERE is_blocked = FALSE;

Terminology Bindings

Field Terminology Example Value
slot_type Local standard, urgent

FHIR Mapping

Table Field FHIR Resource FHIR Path
slot_id Slot Slot.id
provider_id Slot Slot.schedule.actor (Practitioner)
facility_id Slot Slot.schedule.actor (Organization)
slot_date + start_time Slot Slot.start
slot_date + end_time Slot Slot.end
is_blocked Slot Slot.status (busy-unavailable if TRUE)

5. appointment_types

Purpose
Master data for appointment categories (new, follow-up, procedure, telehealth) with default durations and flags.

Fields

Field Type Nullable Default Constraint Description
type_id BIGINT NO IDENTITY PK Type
type_name_en VARCHAR(100) NO English name
type_name_ar VARCHAR(100) NO Arabic name
default_duration INT NO 15 > 0 Default minutes
prep_time INT NO 0 ≥ 0 Pre-visit buffer (min)
post_time INT NO 0 ≥ 0 Post-visit buffer (min)
color_code VARCHAR(7) YES #RRGGBB UI color
requires_referral BOOLEAN NO FALSE Referral required
requires_pre_auth BOOLEAN NO FALSE Insurance pre-auth required
is_active BOOLEAN NO TRUE Active flag
created_at TIMESTAMP NO CURRENT_TIMESTAMP Created
updated_at TIMESTAMP NO CURRENT_TIMESTAMP ON UPDATE Updated

SQL DDL

SQL
CREATE TABLE appointment_types (
    type_id            BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
    type_name_en       VARCHAR(100) NOT NULL,
    type_name_ar       VARCHAR(100) NOT NULL,
    default_duration   INT NOT NULL DEFAULT 15,
    prep_time          INT NOT NULL DEFAULT 0,
    post_time          INT NOT NULL DEFAULT 0,
    color_code         VARCHAR(7) NULL,
    requires_referral  BOOLEAN NOT NULL DEFAULT FALSE,
    requires_pre_auth  BOOLEAN NOT NULL DEFAULT FALSE,
    is_active          BOOLEAN NOT NULL DEFAULT TRUE,
    created_at         TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    updated_at         TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,

    CONSTRAINT chk_appttype_duration
        CHECK (default_duration > 0 AND prep_time >= 0 AND post_time >= 0),
    CONSTRAINT chk_appttype_color
        CHECK (color_code IS NULL OR color_code ~ '^#[0-9A-Fa-f]{6}$')
);

CREATE UNIQUE INDEX ux_appttype_name_en ON appointment_types(type_name_en);

Terminology Bindings

Local master; no external terminology required.

FHIR Mapping

Table Field FHIR Resource FHIR Path
type_id Appointment Appointment.appointmentType.coding.code (local system)
type_name_en Appointment Appointment.appointmentType.text
requires_referral Appointment Extension requiresReferral

6. beds

Purpose
Physical bed registry with ward, gender, isolation, and cleaning status; used for real-time bed board.

Fields

Field Type Nullable Default Constraint Description
bed_id BIGINT NO IDENTITY PK Bed
location_id BIGINT NO FK → locations.location_id Physical location
facility_id BIGINT NO FK → facilities.facility_id Facility
department_id BIGINT NO FK → departments.department_id Ward/department
ward_type VARCHAR(30) NO Local MEDICAL, SURGICAL, ICU, PICU, etc.
bed_number VARCHAR(20) NO Unique per ward Human-readable bed label
bed_status VARCHAR(20) NO 'available' CHECK available, occupied, reserved, out_of_service
is_isolation BOOLEAN NO FALSE Isolation-capable
gender_restriction VARCHAR(10) YES M, F, MIXED Gender restriction
is_active BOOLEAN NO TRUE Active bed
cleaning_status VARCHAR(20) NO 'ready' CHECK ready, needs_cleaning, in_progress
last_cleaned_at TIMESTAMP YES Last cleaning time
created_at TIMESTAMP NO CURRENT_TIMESTAMP Created
updated_at TIMESTAMP NO CURRENT_TIMESTAMP ON UPDATE Updated

SQL DDL

SQL
CREATE TABLE beds (
    bed_id             BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
    location_id        BIGINT NOT NULL,
    facility_id        BIGINT NOT NULL,
    department_id      BIGINT NOT NULL,
    ward_type          VARCHAR(30) NOT NULL,
    bed_number         VARCHAR(20) NOT NULL,
    bed_status         VARCHAR(20) NOT NULL DEFAULT 'available',
    is_isolation       BOOLEAN NOT NULL DEFAULT FALSE,
    gender_restriction VARCHAR(10) NULL,
    is_active          BOOLEAN NOT NULL DEFAULT TRUE,
    cleaning_status    VARCHAR(20) NOT NULL DEFAULT 'ready',
    last_cleaned_at    TIMESTAMP NULL,
    created_at         TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    updated_at         TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,

    CONSTRAINT chk_bed_status
        CHECK (bed_status IN ('available','occupied','reserved','out_of_service')),
    CONSTRAINT chk_bed_cleaning_status
        CHECK (cleaning_status IN ('ready','needs_cleaning','in_progress')),
    CONSTRAINT chk_bed_gender
        CHECK (gender_restriction IS NULL OR gender_restriction IN ('M','F','MIXED'))
);

ALTER TABLE beds
  ADD CONSTRAINT fk_bed_location
    FOREIGN KEY (location_id) REFERENCES locations(location_id),
  ADD CONSTRAINT fk_bed_facility
    FOREIGN KEY (facility_id) REFERENCES facilities(facility_id),
  ADD CONSTRAINT fk_bed_department
    FOREIGN KEY (department_id) REFERENCES departments(department_id);

CREATE UNIQUE INDEX ux_bed_facility_number
    ON beds(facility_id, bed_number);

CREATE INDEX idx_beds_status
    ON beds(facility_id, department_id, bed_status, cleaning_status);

Terminology Bindings

Field Terminology Example Value
ward_type Local ICU, MEDICAL
bed_status Local available
cleaning_status Local needs_cleaning

FHIR Mapping

Table Field FHIR Resource FHIR Path
bed_id Location Location.id
bed_number Location Location.identifier / Location.name
facility_id Location Location.partOf
ward_type Location Location.type
bed_status Encounter Encounter.location.status
is_isolation Location Extension isIsolationBed
gender_restriction Location Extension genderRestriction

7. bed_assignments

Purpose
Tracks current and historical bed occupancy per encounter/patient.

Fields

Field Type Nullable Default Constraint Description
assignment_id BIGINT NO IDENTITY PK Assignment
bed_id BIGINT NO FK → beds.bed_id Bed
patient_id BIGINT NO FK → patients.patient_id Patient
encounter_id BIGINT NO FK → encounters.encounter_id Encounter
assigned_datetime TIMESTAMP NO Start
released_datetime TIMESTAMP YES ≥ assigned End
assignment_reason VARCHAR(100) YES Reason (admission, transfer, overflow)
is_current BOOLEAN NO TRUE Current flag
created_at TIMESTAMP NO CURRENT_TIMESTAMP Created

SQL DDL

SQL
CREATE TABLE bed_assignments (
    assignment_id      BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
    bed_id             BIGINT NOT NULL,
    patient_id         BIGINT NOT NULL,
    encounter_id       BIGINT NOT NULL,
    assigned_datetime  TIMESTAMP NOT NULL,
    released_datetime  TIMESTAMP NULL,
    assignment_reason  VARCHAR(100) NULL,
    is_current         BOOLEAN NOT NULL DEFAULT TRUE,
    created_at         TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,

    CONSTRAINT chk_bedassign_dates
        CHECK (released_datetime IS NULL OR released_datetime >= assigned_datetime)
);

ALTER TABLE bed_assignments
  ADD CONSTRAINT fk_bedassign_bed
    FOREIGN KEY (bed_id) REFERENCES beds(bed_id),
  ADD CONSTRAINT fk_bedassign_patient
    FOREIGN KEY (patient_id) REFERENCES patients(patient_id),
  ADD CONSTRAINT fk_bedassign_encounter
    FOREIGN KEY (encounter_id) REFERENCES encounters(encounter_id) ON DELETE CASCADE;

CREATE INDEX idx_bedassign_bed_current
    ON bed_assignments(bed_id)
    WHERE is_current = TRUE;

CREATE INDEX idx_bedassign_encounter
    ON bed_assignments(encounter_id, is_current);

Terminology Bindings

Field Terminology Example Value
assignment_reason Local ADMISSION, TRANSFER, BOARDING

FHIR Mapping

Table Field FHIR Resource FHIR Path
bed_id Encounter Encounter.location.location
assigned_datetime Encounter Encounter.location.period.start
released_datetime Encounter Encounter.location.period.end
is_current Encounter Encounter.location.status

8. bed_transfers

Purpose
Logs transfers between beds/wards, including approvals and ADT message linkage.

Fields

Field Type Nullable Default Constraint Description
transfer_id BIGINT NO IDENTITY PK Transfer
encounter_id BIGINT NO FK → encounters.encounter_id Encounter
patient_id BIGINT NO FK → patients.patient_id Patient
from_bed_id BIGINT YES FK → beds.bed_id Source bed
to_bed_id BIGINT NO FK → beds.bed_id Target bed
transfer_reason VARCHAR(200) NO Reason (clinical, isolation, step-down)
requested_by BIGINT NO FK → users.user_id Requesting user
approved_by BIGINT YES FK → users.user_id Approver
transfer_datetime TIMESTAMP NO Transfer time
adt_message_id BIGINT YES FK → integration_message_log.message_id ADT A02 reference
created_at TIMESTAMP NO CURRENT_TIMESTAMP Created

SQL DDL

SQL
CREATE TABLE bed_transfers (
    transfer_id        BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
    encounter_id       BIGINT NOT NULL,
    patient_id         BIGINT NOT NULL,
    from_bed_id        BIGINT NULL,
    to_bed_id          BIGINT NOT NULL,
    transfer_reason    VARCHAR(200) NOT NULL,
    requested_by       BIGINT NOT NULL,
    approved_by        BIGINT NULL,
    transfer_datetime  TIMESTAMP NOT NULL,
    adt_message_id     BIGINT NULL,
    created_at         TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
);

ALTER TABLE bed_transfers
  ADD CONSTRAINT fk_bedtr_encounter
    FOREIGN KEY (encounter_id) REFERENCES encounters(encounter_id) ON DELETE CASCADE,
  ADD CONSTRAINT fk_bedtr_patient
    FOREIGN KEY (patient_id) REFERENCES patients(patient_id),
  ADD CONSTRAINT fk_bedtr_from_bed
    FOREIGN KEY (from_bed_id) REFERENCES beds(bed_id),
  ADD CONSTRAINT fk_bedtr_to_bed
    FOREIGN KEY (to_bed_id) REFERENCES beds(bed_id),
  ADD CONSTRAINT fk_bedtr_requested_by
    FOREIGN KEY (requested_by) REFERENCES users(user_id),
  ADD CONSTRAINT fk_bedtr_approved_by
    FOREIGN KEY (approved_by) REFERENCES users(user_id);

CREATE INDEX idx_bedtr_encounter ON bed_transfers(encounter_id, transfer_datetime);
CREATE INDEX idx_bedtr_patient ON bed_transfers(patient_id, transfer_datetime);

Terminology Bindings

Field Terminology Example Value
transfer_reason Local STEP_DOWN, ISOLATION, SPECIALTY_CHANGE

FHIR Mapping

Table Field FHIR Resource FHIR Path
from_bed_id Encounter Encounter.location[0]
to_bed_id Encounter Encounter.location[1]
transfer_datetime Encounter Encounter.location.period.start

9. or_rooms

Purpose
Operating room registry with capabilities and cleaning turnaround.

Fields

Field Type Nullable Default Constraint Description
room_id BIGINT NO IDENTITY PK OR room
facility_id BIGINT NO FK → facilities.facility_id Facility
room_name VARCHAR(50) NO Name/number
room_type VARCHAR(20) NO Local MAIN_OR, DAY_SURGERY, CATH_LAB, etc.
equipment_list TEXT YES JSON or CSV Equipment summary
is_active BOOLEAN NO TRUE Active
max_daily_hours INT NO 24 0–24 Max schedulable hours
cleaning_turnaround_minutes INT NO 30 ≥ 0 Turnover time
created_at TIMESTAMP NO CURRENT_TIMESTAMP Created
updated_at TIMESTAMP NO CURRENT_TIMESTAMP ON UPDATE Updated

SQL DDL

SQL
CREATE TABLE or_rooms (
    room_id                     BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
    facility_id                 BIGINT NOT NULL,
    room_name                   VARCHAR(50) NOT NULL,
    room_type                   VARCHAR(20) NOT NULL,
    equipment_list              TEXT NULL,
    is_active                   BOOLEAN NOT NULL DEFAULT TRUE,
    max_daily_hours             INT NOT NULL DEFAULT 24,
    cleaning_turnaround_minutes INT NOT NULL DEFAULT 30,
    created_at                  TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    updated_at                  TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,

    CONSTRAINT chk_orroom_hours
        CHECK (max_daily_hours BETWEEN 0 AND 24),
    CONSTRAINT chk_orroom_turnaround
        CHECK (cleaning_turnaround_minutes >= 0)
);

ALTER TABLE or_rooms
  ADD CONSTRAINT fk_orroom_facility
    FOREIGN KEY (facility_id) REFERENCES facilities(facility_id);

CREATE UNIQUE INDEX ux_orroom_facility_name
    ON or_rooms(facility_id, room_name);

Terminology Bindings

Field Terminology Example Value
room_type Local MAIN_OR, DAY_SURGERY

FHIR Mapping

Table Field FHIR Resource FHIR Path
room_id Location Location.id
room_name Location Location.name
room_type Location Location.type

10. or_schedules

Purpose
Daily OR block schedules per room, including surgeon/anesthesiologist block ownership.

Fields

Field Type Nullable Default Constraint Description
schedule_id BIGINT NO IDENTITY PK Schedule block
or_room_id BIGINT NO FK → or_rooms.room_id OR room
schedule_date DATE NO Date
block_start TIME NO Block start
block_end TIME NO CHECK > start Block end
surgeon_id BIGINT YES FK → providers.provider_id Block owner surgeon
anesthesiologist_id BIGINT YES FK → providers.provider_id Block owner anesth
status VARCHAR(20) NO 'open' Local open, released, cancelled
block_type VARCHAR(20) NO Local BLOCKED, OPEN, EMERGENCY
created_at TIMESTAMP NO CURRENT_TIMESTAMP Created
updated_at TIMESTAMP NO CURRENT_TIMESTAMP ON UPDATE Updated

SQL DDL

SQL
CREATE TABLE or_schedules (
    schedule_id         BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
    or_room_id          BIGINT NOT NULL,
    schedule_date       DATE NOT NULL,
    block_start         TIME NOT NULL,
    block_end           TIME NOT NULL,
    surgeon_id          BIGINT NULL,
    anesthesiologist_id BIGINT NULL,
    status              VARCHAR(20) NOT NULL DEFAULT 'open',
    block_type          VARCHAR(20) NOT NULL,
    created_at          TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    updated_at          TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,

    CONSTRAINT chk_orsched_time
        CHECK (block_end > block_start),
    CONSTRAINT chk_orsched_status
        CHECK (status IN ('open','released','cancelled')),
    CONSTRAINT chk_orsched_block_type
        CHECK (block_type IN ('BLOCKED','OPEN','EMERGENCY'))
);

ALTER TABLE or_schedules
  ADD CONSTRAINT fk_orsched_room
    FOREIGN KEY (or_room_id) REFERENCES or_rooms(room_id),
  ADD CONSTRAINT fk_orsched_surgeon
    FOREIGN KEY (surgeon_id) REFERENCES providers(provider_id),
  ADD CONSTRAINT fk_orsched_anesth
    FOREIGN KEY (anesthesiologist_id) REFERENCES providers(provider_id);

CREATE INDEX idx_orsched_room_date
    ON or_schedules(or_room_id, schedule_date);

Terminology Bindings

Local only.

FHIR Mapping

Table Field FHIR Resource FHIR Path
schedule_id Schedule Schedule.id
or_room_id Schedule Schedule.actor (Location)
schedule_date + times Slot Slot.start / Slot.end (for OR-specific slots)

11. or_cases

Purpose
Individual surgical cases scheduled within OR blocks, including CPT procedure codes and timing.

Fields

Field Type Nullable Default Constraint Description
case_id BIGINT NO IDENTITY PK Case
schedule_id BIGINT NO FK → or_schedules.schedule_id OR schedule
patient_id BIGINT NO FK → patients.patient_id Patient
encounter_id BIGINT NO FK → encounters.encounter_id Encounter
surgeon_id BIGINT NO FK → providers.provider_id Surgeon
anesthesiologist_id BIGINT YES FK → providers.provider_id Anesthesiologist
procedure_code_cpt VARCHAR(10) NO CPT Primary procedure
procedure_description VARCHAR(255) NO Description
estimated_duration INT NO > 0 Minutes
actual_start TIMESTAMP YES Actual start
actual_end TIMESTAMP YES ≥ start Actual end
case_status VARCHAR(20) NO 'scheduled' Local scheduled, in_progress, completed, cancelled, postponed
pre_op_checklist_complete BOOLEAN NO FALSE Pre-op checklist done
consent_verified BOOLEAN NO FALSE Consent verified
created_at TIMESTAMP NO CURRENT_TIMESTAMP Created
updated_at TIMESTAMP NO CURRENT_TIMESTAMP ON UPDATE Updated

SQL DDL

SQL
CREATE TABLE or_cases (
    case_id                    BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
    schedule_id                BIGINT NOT NULL,
    patient_id                 BIGINT NOT NULL,
    encounter_id               BIGINT NOT NULL,
    surgeon_id                 BIGINT NOT NULL,
    anesthesiologist_id        BIGINT NULL,
    procedure_code_cpt         VARCHAR(10) NOT NULL,
    procedure_description      VARCHAR(255) NOT NULL,
    estimated_duration         INT NOT NULL,
    actual_start               TIMESTAMP NULL,
    actual_end                 TIMESTAMP NULL,
    case_status                VARCHAR(20) NOT NULL DEFAULT 'scheduled',
    pre_op_checklist_complete  BOOLEAN NOT NULL DEFAULT FALSE,
    consent_verified           BOOLEAN NOT NULL DEFAULT FALSE,
    created_at                 TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    updated_at                 TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,

    CONSTRAINT chk_orcase_duration
        CHECK (estimated_duration > 0),
    CONSTRAINT chk_orcase_times
        CHECK (actual_end IS NULL OR actual_start IS NULL OR actual_end >= actual_start),
    CONSTRAINT chk_orcase_status
        CHECK (case_status IN ('scheduled','in_progress','completed','cancelled','postponed'))
);

ALTER TABLE or_cases
  ADD CONSTRAINT fk_orcase_schedule
    FOREIGN KEY (schedule_id) REFERENCES or_schedules(schedule_id) ON DELETE CASCADE,
  ADD CONSTRAINT fk_orcase_patient
    FOREIGN KEY (patient_id) REFERENCES patients(patient_id),
  ADD CONSTRAINT fk_orcase_encounter
    FOREIGN KEY (encounter_id) REFERENCES encounters(encounter_id),
  ADD CONSTRAINT fk_orcase_surgeon
    FOREIGN KEY (surgeon_id) REFERENCES providers(provider_id),
  ADD CONSTRAINT fk_orcase_anesth
    FOREIGN KEY (anesthesiologist_id) REFERENCES providers(provider_id);

CREATE INDEX idx_orcase_schedule ON or_cases(schedule_id);
CREATE INDEX idx_orcase_patient ON or_cases(patient_id);
CREATE INDEX idx_orcase_status ON or_cases(case_status);

Terminology Bindings

Field Terminology Example Value
procedure_code_cpt CPT 27447 (Total knee arthroplasty)

FHIR Mapping

Table Field FHIR Resource FHIR Path
case_id Procedure Procedure.id
patient_id Procedure Procedure.subject
encounter_id Procedure Procedure.encounter
procedure_code_cpt Procedure Procedure.code.coding[system=CPT].code
procedure_description Procedure Procedure.code.text
actual_start Procedure Procedure.performedPeriod.start
actual_end Procedure Procedure.performedPeriod.end
case_status Procedure Procedure.status

12. waitlist_entries

Purpose
Tracks patients waiting for appointments or beds, with priority and resolution.

Fields

Field Type Nullable Default Constraint Description
entry_id BIGINT NO IDENTITY PK Waitlist entry
patient_id BIGINT NO FK → patients.patient_id Patient
waitlist_type VARCHAR(20) NO Local APPOINTMENT, BED, OR
requested_service VARCHAR(100) NO e.g. specialty or procedure
preferred_provider_id BIGINT YES FK → providers.provider_id Preferred provider
priority VARCHAR(20) NO 'routine' Local urgent, routine
added_datetime TIMESTAMP NO CURRENT_TIMESTAMP Added
target_date_from DATE YES Earliest acceptable date
target_date_to DATE YES Latest acceptable date
status VARCHAR(20) NO 'active' Local active, offered, resolved, cancelled
offered_count INT NO 0 ≥ 0 Number of offers
resolved_datetime TIMESTAMP YES Resolution time
resolution_type VARCHAR(20) YES Local booked, declined, no_response, cancelled
notes VARCHAR(500) YES Free text
created_by BIGINT NO FK → users.user_id Creator

SQL DDL

SQL
CREATE TABLE waitlist_entries (
    entry_id            BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
    patient_id          BIGINT NOT NULL,
    waitlist_type       VARCHAR(20) NOT NULL,
    requested_service   VARCHAR(100) NOT NULL,
    preferred_provider_id BIGINT NULL,
    priority            VARCHAR(20) NOT NULL DEFAULT 'routine',
    added_datetime      TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    target_date_from    DATE NULL,
    target_date_to      DATE NULL,
    status              VARCHAR(20) NOT NULL DEFAULT 'active',
    offered_count       INT NOT NULL DEFAULT 0,
    resolved_datetime   TIMESTAMP NULL,
    resolution_type     VARCHAR(20) NULL,
    notes               VARCHAR(500) NULL,
    created_by          BIGINT NOT NULL,

    CONSTRAINT chk_waitlist_type
        CHECK (waitlist_type IN ('APPOINTMENT','BED','OR')),
    CONSTRAINT chk_waitlist_priority
        CHECK (priority IN ('urgent','routine')),
    CONSTRAINT chk_waitlist_status
        CHECK (status IN ('active','offered','resolved','cancelled')),
    CONSTRAINT chk_waitlist_offered
        CHECK (offered_count >= 0)
);

ALTER TABLE waitlist_entries
  ADD CONSTRAINT fk_waitlist_patient
    FOREIGN KEY (patient_id) REFERENCES patients(patient_id),
  ADD CONSTRAINT fk_waitlist_provider
    FOREIGN KEY (preferred_provider_id) REFERENCES providers(provider_id),
  ADD CONSTRAINT fk_waitlist_created_by
    FOREIGN KEY (created_by) REFERENCES users(user_id);

CREATE INDEX idx_waitlist_type_status
    ON waitlist_entries(waitlist_type, status, priority, added_datetime);
CREATE INDEX idx_waitlist_patient
    ON waitlist_entries(patient_id, status);

Terminology Bindings

Local only.

FHIR Mapping

No direct core resource; can be represented as:

  • ServiceRequest (for appointment waitlist) with extension waitlistStatus
  • Appointment with Appointment.status = proposed and extension for priority.

13. provider_schedules

Purpose
Defines provider availability sessions (e.g. Monday 9–13) used to generate slots.

Fields

Field Type Nullable Default Constraint Description
schedule_id BIGINT NO IDENTITY PK Provider schedule
provider_id BIGINT NO FK → providers.provider_id Provider
facility_id BIGINT NO FK → facilities.facility_id Facility
department_id BIGINT NO FK → departments.department_id Department
day_of_week INT NO 1–7 1=Monday … 7=Sunday
start_time TIME NO Session start
end_time TIME NO > start Session end
session_type VARCHAR(20) NO 'clinic' Local clinic, procedure, telehealth
effective_from DATE NO CURRENT_DATE Start date
effective_to DATE YES ≥ from End date
is_recurring BOOLEAN NO TRUE Recurring
max_patients INT NO 0 ≥ 0 Capacity
created_at TIMESTAMP NO CURRENT_TIMESTAMP Created
updated_at TIMESTAMP NO CURRENT_TIMESTAMP ON UPDATE Updated

SQL DDL

SQL
CREATE TABLE provider_schedules (
    schedule_id    BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
    provider_id    BIGINT NOT NULL,
    facility_id    BIGINT NOT NULL,
    department_id  BIGINT NOT NULL,
    day_of_week    INT NOT NULL,
    start_time     TIME NOT NULL,
    end_time       TIME NOT NULL,
    session_type   VARCHAR(20) NOT NULL DEFAULT 'clinic',
    effective_from DATE NOT NULL DEFAULT CURRENT_DATE,
    effective_to   DATE NULL,
    is_recurring   BOOLEAN NOT NULL DEFAULT TRUE,
    max_patients   INT NOT NULL DEFAULT 0,
    created_at     TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    updated_at     TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,

    CONSTRAINT chk_provsched_day
        CHECK (day_of_week BETWEEN 1 AND 7),
    CONSTRAINT chk_provsched_time
        CHECK (end_time > start_time),
    CONSTRAINT chk_provsched_dates
        CHECK (effective_to IS NULL OR effective_to >= effective_from),
    CONSTRAINT chk_provsched_capacity
        CHECK (max_patients >= 0)
);

ALTER TABLE provider_schedules
  ADD CONSTRAINT fk_provsched_provider
    FOREIGN KEY (provider_id) REFERENCES providers(provider_id),
  ADD CONSTRAINT fk_provsched_facility
    FOREIGN KEY (facility_id) REFERENCES facilities(facility_id),
  ADD CONSTRAINT fk_provsched_department
    FOREIGN KEY (department_id) REFERENCES departments(department_id);

CREATE INDEX idx_provsched_provider
    ON provider_schedules(provider_id, day_of_week, effective_from);

Terminology Bindings

Local only.

FHIR Mapping

Table Field FHIR Resource FHIR Path
schedule_id Schedule Schedule.id
provider_id Schedule Schedule.actor
facility_id Schedule Schedule.actor (Org)
day_of_week Schedule Schedule.planningHorizon (pattern)
start_time/end_time Schedule Schedule.planningHorizon

14. scheduling_rules

Purpose
Configurable business rules (lead time, overbooking, cancellation policies) applied at facility/department/appointment-type level.

Fields

Field Type Nullable Default Constraint Description
rule_id BIGINT NO IDENTITY PK Rule
rule_type VARCHAR(50) NO Local LEAD_TIME, OVERBOOKING, CANCELLATION, etc.
rule_name VARCHAR(100) NO Human-readable name
rule_parameters_json JSONB NO '{}' Parameters (e.g. { "min_hours_before_booking": 24 })
facility_id BIGINT YES FK → facilities.facility_id Scope facility
department_id BIGINT YES FK → departments.department_id Scope department
appointment_type_id BIGINT YES FK → appointment_types.type_id Scope appointment type
is_active BOOLEAN NO TRUE Active
created_by BIGINT NO FK → users.user_id Creator
created_at TIMESTAMP NO CURRENT_TIMESTAMP Created
updated_at TIMESTAMP NO CURRENT_TIMESTAMP ON UPDATE Updated

SQL DDL

SQL
CREATE TABLE scheduling_rules (
    rule_id              BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
    rule_type            VARCHAR(50) NOT NULL,
    rule_name            VARCHAR(100) NOT NULL,
    rule_parameters_json JSONB NOT NULL DEFAULT '{}'::jsonb,
    facility_id          BIGINT NULL,
    department_id        BIGINT NULL,
    appointment_type_id  BIGINT NULL,
    is_active            BOOLEAN NOT NULL DEFAULT TRUE,
    created_by           BIGINT NOT NULL,
    created_at           TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    updated_at           TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
);

ALTER TABLE scheduling_rules
  ADD CONSTRAINT fk_schrule_facility
    FOREIGN KEY (facility_id) REFERENCES facilities(facility_id),
  ADD CONSTRAINT fk_schrule_department
    FOREIGN KEY (department_id) REFERENCES departments(department_id),
  ADD CONSTRAINT fk_schrule_appttype
    FOREIGN KEY (appointment_type_id) REFERENCES appointment_types(type_id),
  ADD CONSTRAINT fk_schrule_created_by
    FOREIGN KEY (created_by) REFERENCES users(user_id);

CREATE INDEX idx_schrule_scope
    ON scheduling_rules(facility_id, department_id, appointment_type_id, is_active);
CREATE INDEX idx_schrule_type
    ON scheduling_rules(rule_type);

Terminology Bindings

Local only.

FHIR Mapping

Represent as PlanDefinition or Library with extensions; no direct core mapping.


15. scheduling_templates

Purpose
Reusable weekly patterns for provider schedules and slot generation.

Fields

Field Type Nullable Default Constraint Description
template_id BIGINT NO IDENTITY PK Template
template_name VARCHAR(100) NO Name
provider_id BIGINT YES FK → providers.provider_id Provider-specific or generic
department_id BIGINT YES FK → departments.department_id Department
effective_period DATERANGE NO Validity range
slots_json JSONB NO Definition of slots (day-of-week, start, end, type)
is_active BOOLEAN NO TRUE Active
created_by BIGINT NO FK → users.user_id Creator
created_at TIMESTAMP NO CURRENT_TIMESTAMP Created
updated_at TIMESTAMP NO CURRENT_TIMESTAMP ON UPDATE Updated

SQL DDL

SQL
CREATE TABLE scheduling_templates (
    template_id      BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
    template_name    VARCHAR(100) NOT NULL,
    provider_id      BIGINT NULL,
    department_id    BIGINT NULL,
    effective_period DATERANGE NOT NULL,
    slots_json       JSONB NOT NULL,
    is_active        BOOLEAN NOT NULL DEFAULT TRUE,
    created_by       BIGINT NOT NULL,
    created_at       TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    updated_at       TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
);

ALTER TABLE scheduling_templates
  ADD CONSTRAINT fk_schtemplate_provider
    FOREIGN KEY (provider_id) REFERENCES providers(provider_id),
  ADD CONSTRAINT fk_schtemplate_department
    FOREIGN KEY (department_id) REFERENCES departments(department_id),
  ADD CONSTRAINT fk_schtemplate_created_by
    FOREIGN KEY (created_by) REFERENCES users(user_id);

CREATE INDEX idx_schtemplate_active
    ON scheduling_templates(is_active);

Terminology Bindings

Local only.

FHIR Mapping

No direct mapping; can be represented as Schedule + Slot generation logic.


Data Volume Estimates

Approximate for a 300-bed UAE tertiary hospital.

Table Initial Rows Annual Growth Notes
encounters 0 ~250,000 OPD + ED + IP; 5–10 years retained online
encounter_details 0 ~250,000 1:1 with encounters
appointments 0 ~600,000 High-volume OPD
appointment_slots ~200,000 ~200,000 Rolling 12–18 months
appointment_types ~50 +5/year Low churn
beds ~400 Stable Physical inventory
bed_assignments 0 ~80,000 Each admission + transfers
bed_transfers 0 ~20,000 Depends on acuity
or_rooms ~15 Stable Physical inventory
or_schedules 0 ~5,000 Blocks per OR per day
or_cases 0 ~12,000 Surgical volume
waitlist_entries 0 ~50,000 Appointments + beds
provider_schedules ~500 +50/year Per provider/site
scheduling_rules ~30 +5/year Configuration
scheduling_templates ~200 +20/year Templates

Indexes and partitioning (e.g. by year on encounters, appointments) should be considered for installations with >5 years of data.


Data Retention Policy (UAE Context)

Retention must comply with UAE MOH, DOH, DHA regulations and UAE PDPL (Federal Decree-Law No. 45/2021). Policies below are defaults; facility-specific policies may be stricter.

Table Recommended Retention Rationale / Notes
encounters Minimum 25 years from last encounter or as per MOH/DOH/DHA guidance Core medico-legal record; typically retained long-term. Archive to cold storage after 10 years of inactivity.
encounter_details Same as encounters Required for coding, DRG audits, medico-legal review.
appointments 10 years Supports operational analytics (no-show patterns, access metrics). Older data may be aggregated/anonymised.
appointment_slots 5 years Operational; can be purged/aggregated once appointment history is stable.
appointment_types Indefinite (with soft-delete) Master data; historical versions needed for audit.
beds Indefinite (with soft-delete) Physical inventory; do not delete, only inactivate.
bed_assignments Same as encounters Part of inpatient care history and bed occupancy audit.
bed_transfers Same as encounters Clinical and operational trace of patient movement.
or_rooms Indefinite (with soft-delete) Physical inventory; historical references in or_cases.
or_schedules 15 years Supports OR utilization analysis and medico-legal trace.
or_cases Same as encounters Surgical history is core clinical record.
waitlist_entries 5–10 years Useful for access KPIs; can be anonymised after 5 years.
provider_schedules 10 years Needed for reconstructing provider workload and medico-legal context.
scheduling_rules 10 years For audit of historical scheduling decisions.
scheduling_templates 10 years For audit and analytics.

PDPL Considerations

  • All tables containing patient identifiers (patient_id) are personal data and must support:
  • Data subject access and export (e.g. via FHIR APIs).
  • Restriction of processing and erasure requests, subject to healthcare exemptions for medico-legal retention.
  • For analytics beyond retention windows, data should be anonymised or pseudonymised (removing patient_id, provider_id, etc.).
  • Access to scheduling and bed data must be role-based (per roles in module brief) and logged in the central audit trail module.
content/clinical/scheduling/03-data-specifications.md Generated 2026-02-20 22:54