medOS ultra

IPD Medication & Order Master Contracts

Source of truth for the IPD medication & order system: entity contracts, 12 status enums, event payloads, dispense-cycle engine, dose patterns.

36 min read diagramsUpdated 2026-05-19docs/architecture/ipd-medication-order-master-contracts.md

Single source of truth for entity contracts, status progressions, event payloads, read-model schemas, and the end-to-end lifecycle from doctor order → pharmacy → nurse administration.

Last updated: 2026-05-19


Table of Contents

  1. System Overview
  2. Entity Contracts (MongoDB — Write Model)
  3. Status Enums & Progressions
  4. Hospital Events & Payloads
  5. Read-Model Tables (Supabase)
  6. Orchestrator Handlers & Side Effects
  7. Dispense Cycle Engine
  8. Order Bus (Cross-Department Stream)
  9. Policy Gates & Safety
  10. REST API Endpoints
  11. Frontend Component Map
  12. Dose Pattern System
  13. Related Docs (Index)

1. System Overview

Two-Layer Source of Truth

┌─────────────────────────────────────────────────────────────────────┐
│                     CANONICAL WRITE MODEL                          │
│                                                                     │
│  NestJS Medication Service  ──NATS──▶  MongoDB                     │
│  (orderRequest, medicationRequest,     (order_request,              │
│   medicationAdministration, etc.)       medication_request,         │
│                                         medication_administration)  │
└──────────────────────────┬──────────────────────────────────────────┘
                           │ hospital_events (INSERT)
                           ▼
┌─────────────────────────────────────────────────────────────────────┐
│                     READ MODEL / PROJECTION                        │
│                                                                     │
│  Supabase (PostgreSQL)                                             │
│  ├─ hospital_events          (append-only event log)               │
│  ├─ encounter_journey_cache  (per-encounter manifest)              │
│  ├─ department_queues        (operational worklists)               │
│  ├─ medication_requests      (IPD Rx projection)                   │
│  ├─ medication_holds         (auto-hold tracking)                  │
│  ├─ medication_administration_cycles  (e-MAR time slots)           │
│  ├─ medication_administrations        (permanent EMAR record)      │
│  ├─ medication_label_qrcodes          (barcode/QR labels)          │
│  ├─ mar_audit                (append-only MAR audit)               │
│  ├─ order_bus                (cross-dept order stream)             │
│  ├─ dispense_cycle_configs   (materialization rules)               │
│  └─ dispense_cycle_runs      (execution log)                       │
│                                                                     │
│  encounter-orchestrator (Deno Edge Function)                       │
│  └─ inpatient-handlers/      (event → side-effect handlers)       │
│                                                                     │
│  dispense-cycle-runner (Deno Edge Function)                        │
│  └─ materializes e-MAR cycles from medication_requests             │
└─────────────────────────────────────────────────────────────────────┘

End-to-End Lifecycle (Happy Path)

5-Step IPD Medication Flow:

 ┌──────────┐   ┌──────────┐   ┌──────────┐   ┌──────────┐   ┌──────────┐
 │  Doctor   │──▶│  Nurse   │──▶│ Pharmacy │──▶│ Dispense │──▶│  e-MAR   │
 │  Order    │   │  Ack     │   │ (Screen/ │   │  Rounds  │   │  Admin   │
 │           │   │ Checklist│   │ Prep/    │   │ (รอบยา)  │   │ (ให้ยา)  │
 │ คำสั่ง    │   │ รับทราบ  │   │ Dispense)│   │          │   │          │
 └──────────┘   └──────────┘   └──────────┘   └──────────┘   └──────────┘

Detailed Event Flow:

Doctor orders medication
    │
    ▼
OrderRequest (MongoDB)  ─────────▶  hospital_events: ORDER_CREATED
    │                                      │
    ▼                                      ▼
MedicationRequest (MongoDB)         encounter-orchestrator
    │                                      │
    ▼                                      ▼
Workflow: wait-acknowledgement      department_queues: wait-acknowledgement
    │
    ▼ (Nurse reviews & acknowledges via DialogNurseAcknowledge)
POST /orderRequests/updateAcknowledge/:_id
    │  sets acknowledgeBy + acknowledgeAt
    │  items grouped by productType:
    │    drug → T (queues_screening_pharmacy)
    │    lab  → L (queues_lab)
    │    image → X (queues_radiology)
    │    nutrition → N (queues_nutrition)
    │    procedure → P (queues_procedure)
    │
    ├─ hospital_events: ORDERS_ACKNOWLEDGED
    ├─ syncDepartmentQueue → POST /encounterJourney/queue-transition
    │    (wait-acknowledgement → wait-result)
    │
    ▼ (Pharmacy receives acknowledged drug orders)
hospital_events: RX_PRESCRIBED ───▶ handleRxPrescribed
    │                               ├─ department_queues: ipd_pharmacy_pending
    │                               ├─ encounter_journey_cache: has_active_medications
    │                               └─ acknowledgement_requests (if urgent)
    │
    ▼ (Pharmacist screens & verifies)
hospital_events: RX_VERIFIED ─────▶ handleRxVerified
    │                               ├─ close ipd_pharmacy_pending → COMPLETED
    │                               ├─ department_queues: ipd_pharmacy_verified
    │                               └─ close urgent ack requests
    │
    ▼ (Pharmacist prepares & dispenses)
hospital_events: RX_DISPENSED ────▶ handleRxDispensed
    │                               ├─ close ipd_pharmacy_verified → COMPLETED
    │                               └─ department_queues: ipd_pharmacy_dispensed (audit)
    │
    ▼ (Nurse assigns dispensed drugs to dispense rounds)
medication_requests INSERT/UPDATE ─▶ trg_medication_request_materialize_cycles
    │                               └─ hospital_events: manifest.rx.cycles_requested
    │                                      │
    │                                      ▼
    │                               handleRxCycleMaterialization
    │                               ├─ upsert_medication_request() RPC
    │                               ├─ invoke dispense-cycle-runner edge fn
    │                               └─ encounter_journey_cache: pending_cycle_count
    │
    ▼ (dispense-cycle-runner materializes time slots per round)
medication_administration_cycles ──▶ e-MAR UI (nurse view)
    │   rounds: เช้า 06:00 / กลางวัน 12:00 / เย็น 18:00 / ก่อนนอน 22:00
    │
    ▼ (Nurse scans patient + drug, administers)
hospital_events: MAR_ADMINISTERED ─▶ handleMarAdministered
    │                               └─ mar_audit (append-only)
    │
    ▼
medication_administrations (Supabase) ── permanent EMAR record
MedicationAdministration (MongoDB)   ── canonical write

2. Entity Contracts

2.1 OrderRequest (MongoDB: order_request)

The meta-order wrapper — one per prescribing session. Contains line items for all order types.

Field Type Required Notes
_id ObjectId auto
encounter Ref → Encounter yes
patient Ref → Patient yes
category OrderRequestCategoryType no inpatient/outpatient/forensic/community/discharge
requester Ref → User yes Prescribing doctor
status OrderRequestStatusType yes See §3.1
code String yes Unique order identifier
priority OrderRequestItemPriority no See §3.7
isForward Boolean no IPD/OPD indicator
isBillable Boolean no Financial tracking flag
labReportResult[] Array no Lab results (if order type = lab)

Schema file: packages/platform-api-schema/src/medication/orderRequest/entity/OrderRequest.ts

2.2 OrderRequestItem (MongoDB: order_request_item)

Individual line item within an OrderRequest.

Field Type Required Notes
_id ObjectId auto
orderRequest Ref → OrderRequest yes Parent
product Ref → Product yes Medication/lab/supply
status StatusOrderApprove no request/accepted/reject
quantity Number no
dosage String no
frequency String no
priority OrderRequestItemPriority no See §3.7
icd9Ref Ref → ICD9 no Clinical indication
injection[] OrderRequestItemInjection[] no IV/IM injection details
taperRamp[] OrderRequestItemTaperRamp[] no Taper schedule steps
medicationRequestType MedicationRequestType no ‘continue’ or ‘oneday’

Schema file: packages/platform-api-schema/src/medication/orderRequestItem/entity/OrderRequestItem.ts

2.3 MedicationRequest (MongoDB: medication_request)

IPD/OPD medication prescription. Created per pharmacy batch from an OrderRequest.

Field Type Required Notes
_id ObjectId auto
orderRequest Ref → OrderRequest yes Parent order
items[] MedicationRequestItem[] yes Drug line items
status MedicationRequestStatus yes See §3.2
priority OrderRequestItemPriority no
isIPD Boolean no Inpatient flag
isScreened Boolean no Pharmacist reviewed
screenedBy Ref → User no First-pass screener
screenedAt Date no
qcVerifiedBy Ref → User no Second-pass QC
qcVerifiedAt Date no
multipleScreenedUser[] Ref[] → User no Multiple screeners
receivedBy Ref → User no Pharmacy receipt
receivedAt Date no
isMedicationSupply Boolean no Bulk supply flag
isMedReconcile Boolean no Medication reconciliation
isHomeMed Boolean no Home medication
sortingMethod String no Ward stock sorting strategy

Schema file: packages/platform-api-schema/src/medication/medicationRequest/entity/MedicationRequest.ts

2.4 MedicationAdministration (MongoDB: medication_administration)

MAR record — tracks actual drug administration to patient.

Field Type Required Notes
_id ObjectId auto
medicationRequestRef Ref → MedicationRequest yes Prescription
resourceId Ref → MedicationRequestItem yes Drug line item
status MedicationAdministrationStatus yes See §3.4
eventRef Ref → MedicationAdministrationEvent no
start, end, time Date no Administration timing
fiveRightsCheck[] { rightName, rightValue }[] no 5R verification
infusion { rate, hour, bagNumber } no IV infusion details
medicationProviderRef Ref → User no Administering nurse
medicationVerificationProviderRef Ref → User no Verifying provider

Schema file: packages/platform-api-schema/src/medication/medicationAdministration/entity/MedicationAdministration.ts

2.5 OrderRequestProductDispense (MongoDB: order_request_product_dispense)

Tracks physical dispensing event per line item.

Field Type Required Notes
_id ObjectId auto
orderRequestItem Ref → OrderRequestItem yes
status OrderRequestProductDispenseStatusType yes See §3.5
quantity Number no
daysSupply Number no IPD: supplies for N days
preparedAt Date no
handedOverAt Date no
remark String no

Schema file: packages/platform-api-schema/src/medication/orderRequestProductDispense/entity/OrderRequestProductDispense.ts

2.6 MedicationCart (MongoDB: medication_cart)

Batches multiple medication requests for dispensing.

Field Type Required Notes
_id ObjectId auto
refMedicationRequest[] Ref[] → MedicationRequest yes Batch
user Ref → User yes Pharmacist/Dispenser
status MedicationCartStatus yes pending / success

2.7 MedicationReturnSystem (MongoDB: medication_return_system)

Drug returns and waste tracking.

Field Type Required Notes
_id ObjectId auto
medicationRequestRef Ref → MedicationRequest yes Original Rx
quantity Number yes
returnedQuantity Number no
remainingQuantity Number no
status MedicationReturnSystemStatus yes See §3.6
returningStatus MedicationReturnAmountStatus no returned/not returned/partially returned

3. Status Enums & Progressions

3.1 OrderRequestStatusType

File: packages/platform-api-schema/src/medication/orderRequest/entity/OrderRequestStatusType.ts

enum OrderRequestStatusType {
  DRAFT        = 'draft',
  PRE_PENDING  = 'pre-pending',
  PENDING      = 'pending',
  ACCEPTED     = 'accepted',
  COMPLETED    = 'completed',
  CANCELLED    = 'cancelled',
}

Progression:

  DRAFT ──▶ PRE_PENDING ──▶ PENDING ──▶ ACCEPTED ──▶ COMPLETED
    │            │              │            │
    └────────────┴──────────────┴────────────┴──────▶ CANCELLED
Transition Trigger
DRAFT → PRE_PENDING Doctor submits order (auto on save)
PRE_PENDING → PENDING Price check / stock check passed
PENDING → ACCEPTED All items dispatched to departments
ACCEPTED → COMPLETED All items fulfilled
Any → CANCELLED Doctor cancels order

3.1b OrderRequestStatus (HL7 Standard Codes)

File: packages/platform-api-schema/src/medication/orderRequest/entity/OrderRequestStatus.ts

Used for HL7v2/FHIR interop mapping:

Code Meaning
A Some, but not all, results available
CA Order was canceled
CM Order is completed
DC Order was discontinued
ER Error, order not found
HD Order is on hold
IP In process, unspecified
RP Order has been replaced
SC In process, scheduled

3.2 MedicationRequestStatus

File: packages/platform-api-schema/src/medication/medicationRequest/entity/MedicationRequestStatus.ts

enum MedicationRequestStatus {
  CHECK_PRICE                 = 'check_price',
  PENDING                     = 'pending',
  DRAFT                       = 'draft',
  ACCEPTED                    = 'accepted',
  COMPLETED                   = 'completed',
  CANCELLED                   = 'cancelled',
  REVIEW                      = 'reviewing',
  AUDIT                       = 'AUDIT',
  EDITTED                     = 'editted',
  // Compounding room
  CHECKING_BEFORE_COMPOUNDING = 'audit_before_compounding',
  COMPOUNDING                 = 'compounding',
  CHECKING_AFTER_COMPOUNDING  = 'audit_after_compounding',
  // Mix drug
  REVIEW_BEFORE_MIX           = 'reviewBeforeMix',
  MIXDRUG                     = 'mixdrug',
  REVIEW_AFTER_MIX            = 'reviewAfterMix',
}

Standard Pharmacy Progression:

  CHECK_PRICE ──▶ DRAFT ──▶ PENDING ──▶ REVIEW ──▶ AUDIT ──▶ ACCEPTED ──▶ COMPLETED
                                                                  │
                                                              EDITTED (loop back)
                                                                  │
                                                              CANCELLED

Compounding Room Progression:

  PENDING ──▶ CHECKING_BEFORE_COMPOUNDING ──▶ COMPOUNDING ──▶ CHECKING_AFTER_COMPOUNDING ──▶ ACCEPTED

Mix Drug Progression:

  PENDING ──▶ REVIEW_BEFORE_MIX ──▶ MIXDRUG ──▶ REVIEW_AFTER_MIX ──▶ ACCEPTED

3.2b Pharmacy UI OrderStatus (Frontend Step Mapping)

File: web/packages/medical-kit/src/pharmacy/components/interface.ts

enum OrderStatus {
  ORDERED   = 'Ordered',    // Step 0: New order arrived
  SCREENED  = 'Screened',   // Step 1: Pharmacist screened
  PREPARED  = 'Prepared',   // Step 2: Physically picked & packed
  VERIFIED  = 'Verified',   // Step 3: Final QC check
  ACCEPTED  = 'Accepted',   // Step 4: Ready for handoff
  DONE      = 'Done',       // Step 5: Dispensed to patient/ward
  HOLD      = 'HOLD',
  CANCEL    = 'Cancel',
  EDITTED   = 'Editted',
  ORDEROSRC = 'ใบสั่งยานอก',  // External prescription
}
  ORDERED ──▶ SCREENED ──▶ PREPARED ──▶ VERIFIED ──▶ ACCEPTED ──▶ DONE
                                                        │
                                                    HOLD / CANCEL / EDITTED

3.3 MedicationRequestItemStatus

File: packages/platform-api-schema/src/medication/medicationRequestItem/entity/MedicationRequestItemStatus.ts

enum MedicationRequestItemStatus {
  PENDING          = 'pending',
  ACCEPTED         = 'accepted',
  COMPLETED        = 'completed',
  CANCELLED        = 'cancelled',
  REVIEW           = 'reviewing',
  AUDIT            = 'AUDIT',
  EDITED           = 'edited',
  OFF              = 'off',        // หยุดยา (medication stopped)
  CONTINUE         = 'continue',   // ใช้ยาต่อ (medication continued)
  REVIEW_BEFORE_MIX = 'reviewBeforeMix',
  MIXDRUG          = 'mixdrug',
  REVIEW_AFTER_MIX = 'reviewAfterMix',
}

IPD Medication Continuation:

  CONTINUE ◀──▶ OFF     (toggle: nurse/doctor can pause/resume individual drug)

3.4 MedicationAdministrationStatus

File: packages/platform-api-schema/src/medication/medicationAdministration/entity/MedicationAdministrationStatus.ts

enum MedicationAdministrationStatus {
  PENDING      = 'pending',
  IN_PROGRESS  = 'in-progress',
  COMPLETED    = 'completed',
  OFF_SCHEDULE = 'off-schedule',
  OVERDUE      = 'overdue',
}

Progression:

  PENDING ──▶ IN_PROGRESS ──▶ COMPLETED
    │                │
    ▼                ▼
  OVERDUE      OFF_SCHEDULE
  (time elapsed)  (schedule changed)

3.5 OrderRequestProductDispenseStatusType

File: packages/platform-api-schema/src/medication/orderRequestProductDispense/entity/OrderRequestProductDispenseStatusType.ts

enum OrderRequestProductDispenseStatusType {
  PREPARATION      = 'preparation',
  INPROGRESS       = 'in-progress',
  CANCELLED        = 'cancelled',
  ONHOLD           = 'on-hold',
  COMPLETED        = 'completed',
  ENTERED_IN_ERROR = 'entered-in-error',
  STOPPPED         = 'stopped',      // note: typo is canonical
  DECLINED         = 'declined',
  UNKNOWN          = 'unknown',
}
  PREPARATION ──▶ INPROGRESS ──▶ COMPLETED
       │              │
       ▼              ▼
    ONHOLD        STOPPPED / CANCELLED / DECLINED / ENTERED_IN_ERROR

3.6 MedicationReturnSystemStatus & MedicationReturnAmountStatus

enum MedicationReturnSystemStatus {
  PENDING   = 'pending',
  CANCELLED = 'cancelled',
  COMPLETED = 'completed',
}

enum MedicationReturnAmountStatus {
  RETURNED           = 'returned',
  NOT_RETURNED       = 'not returned',
  PARTIALLY_RETURNED = 'partially returned',
}

3.7 OrderRequestItemPriority

File: packages/platform-api-schema/src/medication/orderRequestItem/entity/OrderRequestItemPriority.ts

enum OrderRequestItemPriority {
  ROUTINE             = 'routine',
  STAT                = 'stat',
  URGENT              = 'urgent',
  ASAP                = 'asap',
  MEDICATIONRECONCILE = 'medicationreconcile',
  HOME_MED            = 'homeMed',
  HALF_HOUR           = '30 min',
  ONE_HOUR            = '60 min',
}

Priority Level Mapping (numeric sort order):

Level Priority SLA
1 30 min Must arrive in 30 min
2 60 min Must arrive in 60 min
3 medicationreconcile Reconciliation batch
4 routine Standard processing
5 urgent Expedited
6 stat Immediate
7 asap As soon as possible
8 homeMed Home medication (discharge)

OPD vs IPD visibility:

Priority OPD IPD
routine yes yes
stat yes yes
urgent no yes
asap no yes
30 min no yes
60 min no yes

3.8 OrderRequestCategoryType

enum OrderRequestCategoryType {
  INPATIENT  = 'inpatient',
  OUTPATIENT = 'outpatient',
  FORENSIC   = 'forensic',
  COMMUNITY  = 'community',
  DISCHARGE  = 'discharge',
}

3.9 MedicationRequestType (Order Duration)

enum MedicationRequestType {
  ONEDAY   = 'oneday',    // Auto-expires (one-time supply)
  CONTINUE = 'continue',  // Standing order (repeats per schedule)
}

Rule: STAT priority forces ONEDAY. OPD auto-hides toggle (always ONEDAY). IPD shows toggle.

3.10 StatusOrderApprove

enum StatusOrderApprove {
  REQUEST  = 'request',
  ACCEPTED = 'accepted',
  REJECT   = 'reject',
}

3.11 MedicationCartStatus

enum MedicationCartStatus {
  PENDING = 'pending',
  SUCCES  = 'success',   // note: typo is canonical
}

3.12 Supabase Read-Model Statuses

These are TEXT columns (not enums) — values used by handlers and edge functions:

medication_requests.status:

  • pendingactiveverifiedin_progresscompleted
  • Also: discontinued, cancelled
  • Trigger fires on: active, verified, in_progress (IMP only)

medication_holds.status:

  • activeresumed | cancelled

medication_administration_cycles.status:

  • pendingin_progresscompleted | skipped

medication_administrations.status (permanent EMAR):

  • administered, held, refused, omitted, self_administered, not_given

medication_administrations.witness_status:

  • pendingconfirmed | declined

department_queues.status:

  • WAITINGIN_PROGRESSCOMPLETED | CANCELLED

4. Hospital Events & Payloads

All events are INSERT-only rows in the hospital_events table. The encounter-orchestrator Deno edge function routes each event_type to the corresponding handler.

4.1 Rx Pipeline Events

RX_PRESCRIBED / rx.prescribed

Emitted by: encounterJourney.service.tsemitRxPrescribed()

{
  event_type: 'RX_PRESCRIBED',  // or 'rx.prescribed' in handler routing
  encounter_id: string,
  patient_id: string,
  target_id: string,  // rx_id
  payload: {
    rx_id: string,
    rx_item_id?: string,
    encounter_id: string,
    patient_id: string,
    hn_snapshot?: string,
    an_snapshot?: string,
    patient_name_snapshot?: string,
    ward_id: string,
    order_type: 'continuous' | 'one_day' | 'home_medication',
    is_urgent: boolean,            // default: false
    drug_name_th?: string,
    drug_name_en: string,
    is_out_of_formulary: boolean,  // default: false
    prescriber_doctor_id: string,
    occurred_at: string,           // ISO 8601
  }
}

RX_VERIFIED / rx.verified

Emitted by: encounterJourney.service.tsemitRxVerified()

{
  event_type: 'RX_VERIFIED',
  payload: {
    rx_id: string,
    rx_item_id?: string,
    encounter_id: string,
    patient_id: string,
    hn_snapshot?: string,
    ward_id: string,
    pharmacist_id: string,
    verified_at: string,           // ISO 8601
    verification_notes?: string,
    occurred_at: string,
  }
}

RX_DISPENSED / rx.dispensed

Emitted by: encounterJourney.service.tsemitRxDispensed()

{
  event_type: 'RX_DISPENSED',
  payload: {
    rx_id: string,
    rx_item_id?: string,
    encounter_id: string,
    patient_id: string,
    ward_id: string,
    dispensed_qty: number,         // default: 0
    dispenser_pharmacist_id: string,
    dispensed_at: string,          // ISO 8601
    occurred_at: string,
  }
}

4.2 Medication Administration Events

MEDICATION_ADMINISTERED / mar.administered

Emitted by: encounterJourney.service.tsemitMedicationAdministered()

{
  event_type: 'MEDICATION_ADMINISTERED',
  payload: {
    // Service-layer shape (camelCase):
    medicationRequestId: string,
    productId: string,
    productName: string,
    administeredAt: string,
    dose?: number,
    unit?: string,

    // Handler-expected shape (snake_case):
    mar_event_id: string,
    rx_id: string,
    rx_item_id: string,
    encounter_id: string,
    patient_id: string,
    ward_id: string,
    bed_id?: string,
    drug_name_th?: string,
    drug_name_en: string,
    dose_administered: string,     // e.g., "500mg"
    route?: string,                // PO, IV, IM
    administered_at: string,
    administered_by_nurse_id: string,
    scan_method: 'camera' | 'hid_keyboard' | 'manual_paste' | 'manual_override',
    notes?: string,
  }
}

4.3 Cycle Materialization Event

manifest.rx.cycles_requested

Emitted by: Postgres trigger trg_medication_request_materialize_cycles() on medication_requests table (IMP only, on INSERT or UPDATE OF status to active/verified/in_progress).

{
  event_type: 'manifest.rx.cycles_requested',
  encounter_id: string,
  patient_id: string,
  target_id: string,  // medication_requests.id (UUID)
  payload: {
    rx_id: string,              // UUID
    encounter_id: string,
    patient_id: string,
    ward_id: string,
    frequency?: string,         // OD, BID, TID, Q8H, etc.
    medication_name?: string,
    medication_name_th?: string,
    order_type: 'continuous' | 'one_day' | 'home_medication',
    is_urgent: boolean,
    triggered_by: 'medication_request_trigger' | 'orchestrator',
  }
}

4.4 Medication Hold/Release Events

manifest.medication.auto_held

{
  event_type: 'manifest.medication.auto_held',
  payload: {
    encounter_id: string,
    patient_id?: string,
    reason: string,  // 'NPO', 'discharge_pending', 'transfer'
  }
}

manifest.medication.auto_resumed

{
  event_type: 'manifest.medication.auto_resumed',
  payload: {
    encounter_id: string,
    patient_id?: string,
    reason: string,
  }
}

4.5 Order Lifecycle Events

Event Type Trigger Payload Key Fields
ORDER_CREATED Doctor submits order orderId, orderType, items[], encounterId
ORDERS_ACKNOWLEDGED Nurse batch-acks (see §4.5a) orderIds[], acknowledgedBy, queuesPushed[]
ORDER_DISPATCH_HELD Policy: nurse ack required orderId, reason
ORDER_DISPATCH_RELEASED Nurse releases held order orderId, releasedBy
SUPPLEMENTAL_ORDER_CREATED Late-added order orderId, parentOrderId
PHARMACY_SCREENING_COMPLETED Pharmacist done screening medicationRequestIds[], screened_at
PHARMACY_DISPENSED Pharmacy dispensed batch medicationRequestIds[], dispensed_at

4.5a Nurse Acknowledgement Flow (Step 2)

Critical step between Doctor Order and Pharmacy. After a doctor writes orders, the nurse reviews ALL order types (drugs, labs, x-rays, procedures, nutrition, notes) via a checklist dialog and acknowledges them. Only acknowledged drug orders flow to the pharmacy queue.

Workflow State: wait-acknowledgementwait-result

UI Component: DialogNurseAcknowledge.tsx — 11-section checklist (Chief Complaint, Present Illness, Past Medical History, Order, Pre-order Admit, Surgery/Procedure, Lab Specimen, X-ray, Medicine/EMAR, Doctor Note, Healthcare Note, Note to Nurse)

Service: web/src/services/nurse-acknowledgement.service.tsacknowledgeAndPushToQueues()

Acknowledge API

POST /api/v2/orderRequests/updateAcknowledge/:orderId

Body: { _id: orderRequestId, reasoncancel: '', patient: patientId }

Response: Items grouped by backend type key:
  { medicationRequest: [...], labRequest: [...], imageRequest: [...],
    procedureRequest: [...], nutritionRequest: [...], pathologyRequest: [...] }

Product Type → Queue Mapping

After acknowledge, items are grouped by productType and pushed to destination queues:

Product Type Queue Prefix Firestore Collection Supabase dept_type
drug T queues_screening_pharmacy_{pathName} pharmacy_screening
lab L queues_lab_{pathName} LAB
image X queues_radiology_{pathName} RADIOLOGY
procedure P queues_procedure_{pathName} PROCEDURE
nutrition N queues_nutrition_{pathName} NUTRITION
blood-bank B queues_blood_bank_{pathName} BLOOD_BANK
pathology PA queues_pathology_{pathName} PATHOLOGY
physical-therapy PT queues_physical_therapy_{pathName} PHYSICAL_THERAPY
medical-supply MS queues_medical_supply_{pathName} MEDICAL_SUPPLY
transport TR queues_transport_{pathName} TRANSPORT

API Response Key → productType mapping:

Backend Response Key Internal productType
medicationRequest drug
labRequest lab
imageRequest image
procedureRequest procedure
nutritionRequest nutrition
pathologyRequest pathology

Post-Acknowledge Workflow Transition

1. POST /orderRequests/updateAcknowledge/:orderId
   → sets acknowledgeBy + acknowledgeAt on all items
   → returns items grouped by type

2. Items grouped by productType via API_RESPONSE_TYPE_MAPPING

3. Each group → push to destination Firestore queue
   (drug items → queues_screening_pharmacy with queue number T1, T2, etc.)

4. POST /v2/medication/encounterJourney/queue-transition
   { encounterId, targetWorkflowState: 'wait-result', fromWorkflowState: 'wait-acknowledgement' }

5. Non-blocking audit: INSERT nurse_acknowledgement_log (Supabase)

Bulk Acknowledge Variant

POST /api/v2/orderRequests/updateAcknowledgeAllOrderRequest

Sets acknowledgeBy + acknowledgeAt on ALL items in the order.
Groups items by productType → creates SalesOrder → pushes to queues.

The order_dispatch_policies table controls whether auto-dispatch is allowed:

  • If requires_nurse_ack = true for a dept_type + scope, orders are held until nurse ack
  • If auto_dispatch = true, orders skip the acknowledgement step and go directly to department queues
  • Priority resolution: location > sub_clinic > clinic > global

4.6 Clinical Alert Event

{
  event_type: 'CLINICAL_ALERT',
  payload: {
    tier: 0 | 1 | 2 | 3,  // 0=passive, 1=info, 2=soft-stop, 3=hard-stop
    alert_type: string,     // drug_interaction, allergy, dosage_limit, etc.
    message_en: string,
    message_th?: string,
    source_order_id?: string,
    encounter_id: string,
  }
}

5. Read-Model Tables

5.1 medication_requests (Supabase)

Migration: 20260518h_ipd_medication_orchestrator.sql

Projection table for the dispense-cycle-runner to scan. Shared OPD+IPD, filtered by encounter_class.

Column Type Default Notes
id UUID PK
encounter_id TEXT NOT NULL
patient_id TEXT NOT NULL
ward_id TEXT
encounter_class TEXT ‘IMP’, ‘AMB’, ‘EMER’
status TEXT ‘pending’ pending/active/verified/in_progress/completed/discontinued/cancelled
frequency TEXT OD, BID, TID, Q8H, etc.
rrule TEXT RFC 5545 RRULE string
start_date TIMESTAMPTZ
end_date TIMESTAMPTZ
medication_name TEXT
medication_name_th TEXT
med_category TEXT drug, medical-supply, blood-product
amount_generate_drug INTEGER
next_dispense_date DATE
is_urgent BOOLEAN false
is_out_of_formulary BOOLEAN false
is_home_med BOOLEAN false
order_type TEXT ‘continuous’ continuous, one_day, home_medication
prescriber_doctor_id TEXT
rx_mongo_id TEXT Back-ref to MongoDB MedicationRequest._id
rx_item_mongo_id TEXT Back-ref to MongoDB MedicationRequestItem._id
created_at TIMESTAMPTZ NOW()
updated_at TIMESTAMPTZ NOW()

Indexes: encounter, patient, status, ward, encounter_class

RPC: upsert_medication_request() — idempotent ON CONFLICT UPDATE

5.2 medication_holds (Supabase)

Migration: 20260518h_ipd_medication_orchestrator.sql

Column Type Default Notes
id UUID PK
patient_id TEXT
encounter_id TEXT NOT NULL
medication_request_id UUID FK → medication_requests
medication_name TEXT ‘unknown’
hold_reason TEXT NOT NULL NPO, discharge_pending, transfer
hold_reason_detail TEXT
hold_duration TEXT ‘1_dose’, ‘1_day’, ‘until_order’
status TEXT ‘active’ active, resumed, cancelled
resumed_at TIMESTAMPTZ
resumed_by UUID
resume_notes TEXT
created_by TEXT sentinel UUID
created_at TIMESTAMPTZ NOW()
updated_at TIMESTAMPTZ NOW()

5.3 medication_administration_cycles (Supabase)

Migration: 20260518h_ipd_medication_orchestrator.sql

Materialized e-MAR time slots from dispense-cycle-runner.

Column Type Default Notes
id UUID PK
patient_id TEXT
encounter_id TEXT NOT NULL
medication_request_id UUID FK → medication_requests
medication_name TEXT ‘unknown’
cycle_number INTEGER 1
total_cycles INTEGER 1
scheduled_times TEXT[] [‘08:00’, ‘14:00’, ‘20:00’]
scheduled_at TIMESTAMPTZ
frequency TEXT
status TEXT ‘pending’ pending, in_progress, completed, skipped
ward_id TEXT
config_id UUID FK → dispense_cycle_configs
administered_at TIMESTAMPTZ
administered_by UUID
administered_by_name TEXT
notes TEXT
skip_reason TEXT
created_at TIMESTAMPTZ NOW()
updated_at TIMESTAMPTZ NOW()

5.4 medication_administrations (Supabase — Permanent EMAR)

Migration: web/supabase/migrations/20260507_medication_administrations.sql

Column Type Notes
id UUID PK
organization_id UUID
patient_id, encounter_id, admission_id UUID
medication_request_id, med_order_id UUID/VARCHAR
medication_name, medication_name_th, generic_name VARCHAR
dose, dose_value, dose_unit, route, frequency TEXT/NUMERIC
administered_at TIMESTAMPTZ NOT NULL
scheduled_at TIMESTAMPTZ
status VARCHAR(30) administered/held/refused/omitted/self_administered/not_given
administered_by, administered_by_name, administered_by_role, administered_by_license UUID/VARCHAR
Witness (high-alert)
witness_required BOOLEAN
witness_by, witness_by_name, witness_at UUID/VARCHAR/TIMESTAMPTZ
witness_status VARCHAR pending/confirmed/declined
BCMA / Five Rights
scanned_2id, patient_barcode_scanned, medication_barcode_scanned, five_rights_verified BOOLEAN
scan_proof JSONB { method, scannedValue, expectedValue, matched, confidence }
verification_method VARCHAR qr, barcode, voice, manual
Infusion
is_infusion BOOLEAN
pump_id, infusion_rate, rate_unit, bag_volume_ml, bag_remaining_ml VARCHAR/NUMERIC
Notes & Overrides
notes, override_reason, not_given_reason, hold_reason TEXT
is_high_alert, high_alert_category BOOLEAN/VARCHAR
device_id, ip_address VARCHAR

5.5 medication_label_qrcodes (Supabase)

Migration: web/supabase/migrations/20260507_medication_administrations.sql

Column Type Notes
id UUID PK
medication_request_id UUID
medication_name, dose, route, frequency VARCHAR
patient_id, patient_hn, patient_name, encounter_id UUID/VARCHAR
qr_payload TEXT JSON string encoded in QR
barcode_value VARCHAR Linear barcode
format VARCHAR qr, code128, code39
valid_from, valid_until TIMESTAMPTZ
is_active BOOLEAN
printed_at, printed_by, print_count TIMESTAMPTZ/UUID/INTEGER

5.6 encounter_journey_cache — Medication Columns

Added by: 20260518h_ipd_medication_orchestrator.sql

Column Type Default Set by
has_active_medications BOOLEAN false handleRxPrescribed
active_rx_count INTEGER 0 handleRxPrescribed (increment)
has_held_medications BOOLEAN false handleMedicationAutoHeld/Resumed
hold_reason TEXT null handleMedicationAutoHeld
pending_cycle_count INTEGER 0 handleRxCycleMaterialization
last_cycle_materialized_at TIMESTAMPTZ null handleRxCycleMaterialization

5.7 department_queues — IPD Pharmacy Queue Types

dept_type Created by Meaning
ipd_pharmacy_pending handleRxPrescribed New Rx, awaiting pharmacist verification
ipd_pharmacy_verified handleRxVerified Verified, awaiting physical dispense
ipd_pharmacy_dispensed handleRxDispensed Audit row (status=COMPLETED)
ipd_pharmacy_hold_alert handleMedicationAutoHeld Auto-hold notification

Priority mapping in handlers:

Condition Priority
is_urgent = true URGENT
is_out_of_formulary = true HIGH
Default NORMAL
Hold alert HIGH

6. Orchestrator Handlers & Side Effects

All handlers live in infrastructure/medbase/functions/inpatient-handlers/ and are wired into encounter-orchestrator/index.ts.

6.1 handleRxPrescribed

Event: rx.prescribed

Side Effect Table Action
1 department_queues INSERT dept_type='ipd_pharmacy_pending', status=WAITING
2 encounter_journey_cache UPDATE has_active_medications=true, increment active_rx_count
3 acknowledgement_requests INSERT (if is_urgent) — pharmacist must verify in 15 min, reminder every 5 min x3, escalate after 15 min

6.2 handleRxVerified

Event: rx.verified

Side Effect Table Action
1 department_queues UPDATE ipd_pharmacy_pending → status=COMPLETED
2 department_queues INSERT dept_type='ipd_pharmacy_verified', status=WAITING
3 acknowledgement_requests UPDATE status=‘fulfilled’ (close urgent ack)

6.3 handleRxDispensed

Event: rx.dispensed

Side Effect Table Action
1 department_queues UPDATE ipd_pharmacy_verified → status=COMPLETED
2 department_queues INSERT dept_type='ipd_pharmacy_dispensed', status=COMPLETED (audit)

6.4 handleRxCycleMaterialization

Event: manifest.rx.cycles_requested

Side Effect Table/Function Action
1 medication_requests RPC upsert_medication_request() — idempotent
2 Edge function POST /functions/v1/dispense-cycle-runner (non-fatal)
3 encounter_journey_cache UPDATE pending_cycle_count, last_cycle_materialized_at

6.5 handleMarAdministered

Event: mar.administered

Side Effect Table Action
1 mar_audit INSERT (append-only, no UPDATE/DELETE allowed)

No department_queues write — purely audit. The MongoDB MedicationAdministration entity is the canonical write (handled by NestJS medicationAdministration module).

6.6 handleMedicationAutoHeld

Event: manifest.medication.auto_held

Side Effect Table Action
1 encounter_journey_cache UPDATE has_held_medications=true, hold_reason
2 department_queues INSERT dept_type='ipd_pharmacy_hold_alert', priority=HIGH

6.7 handleMedicationAutoResumed

Event: manifest.medication.auto_resumed

Side Effect Table/Function Action
1 medication_holds READ — count active holds for encounter
2 encounter_journey_cache UPDATE has_held_medications (false if no more active holds)
3 department_queues UPDATE ipd_pharmacy_hold_alert → status=COMPLETED
4 Edge function POST /functions/v1/dispense-cycle-runner (re-materialize unblocked cycles)

7. Dispense Cycle Engine

Migration: 20260514_ipd_dispense_cycles.sql Activation: 20260518c_activate_dispense_cycle.sql Edge Function: infrastructure/medbase/functions/dispense-cycle-runner/index.ts

7.1 dispense_cycle_configs

Field Type Notes
id UUID PK
name TEXT e.g., “default-ipd-cycle”
description TEXT
status TEXT ‘draft’, ‘active’, ‘inactive’ — only ‘active’ picked up
priority INTEGER Higher wins on scope conflict
organization_id UUID Nullable (multi-tenant forward-compat)
scope_json JSONB { ward_ids[], patient_classes[], med_categories[], encounter_types[] }
schedule_json JSONB { timezone, lookahead_hours, generation_mode, rounds[], default_frequency }
hold_json JSONB { auto_hold_on_npo, auto_hold_on_discharge_pending, auto_hold_on_transfer, hold_reason_default }
cart_json JSONB { group_by, require_pharmacist_ack }

Default seed: patient_classes=['IMP'], timezone=‘Asia/Bangkok’, lookahead_hours=24, generation_mode=‘on_demand’, rounds=[morning 06:00/noon 12:00/evening 18:00/night 22:00].

7.2 Three Invocation Paths

Path Trigger triggered_by
On-demand Postgres trigger on medication_requests → orchestrator → edge fn 'trigger'
Scheduled pg_cron */30 * * * *SELECT dispense_cycle_run() 'cron'
Manual Super-admin UI buttons at /super-admin/dispense-cycles 'manual' / 'preview' / 'reconcile'

7.3 Three Modes

Mode Writes? Purpose
Materialize Yes Expand frequencies → time slots → INSERT medication_administration_cycles
Preview No Dry-run, same logic, triggered_by='preview'
Reconcile No (reads both) Diff Supabase projection vs MongoDB canonical → report drift

7.4 Fixed Frequency Expansion

Frequency Scheduled Times
OD [‘08:00’]
BID [‘08:00’, ‘20:00’]
TID [‘08:00’, ‘14:00’, ‘20:00’]
QID [‘06:00’, ‘12:00’, ‘18:00’, ‘22:00’]
Q4H [‘02:00’, ‘06:00’, ‘10:00’, ‘14:00’, ‘18:00’, ‘22:00’]
Q6H [‘06:00’, ‘12:00’, ‘18:00’, ‘00:00’]
Q8H [‘06:00’, ‘14:00’, ‘22:00’]
Q12H [‘08:00’, ‘20:00’]

7.5 dispense_cycle_runs (Execution Log)

Field Type Notes
id UUID PK
config_id UUID FK → dispense_cycle_configs
triggered_by TEXT cron/manual/trigger/preview/reconcile
triggered_by_user_id UUID
started_at, completed_at TIMESTAMPTZ
status TEXT running/success/partial/failed
cycles_materialized INTEGER
cycles_skipped INTEGER
cycles_held INTEGER
orders_scanned INTEGER
summary_json JSONB Per-config breakdown, per-order decisions
error_payload JSONB Error list

8. Order Bus

Migration: 20260515h_order_bus.sql

Real-time, append-only, cross-department order status stream for all order types.

8.1 order_bus Schema

Column Type Notes
id UUID PK
created_at TIMESTAMPTZ
order_type TEXT pathology/blood_bank/imaging/or_request/labour_room/admission/er_request
order_id TEXT MongoDB _id of specialized order
order_request_id TEXT Parent orderRequest _id (billing hub)
encounter_id TEXT
patient_id TEXT
event_kind TEXT created/status_changed/cancelled/completed/acknowledged/financial_updated
status_before TEXT
status_after TEXT
dept_target TEXT[] GIN indexed — e.g., {‘cashier’,‘lab’,‘pharmacy’}
priority TEXT ROUTINE/NORMAL/HIGH/URGENT
financial JSONB {salesOrderId, total, netPay, currency, paymentStatus}
actor_user_id, actor_name TEXT Who triggered the change
source TEXT backend/frontend/fhir/hl7v2
patient_hn, patient_name, encounter_vn, doctor_name TEXT Denormalized display
metadata JSONB Order-type-specific

8.2 Default Department Routing

order_type dept_targets
pathology lab, cashier, pharmacy
blood_bank blood_bank, cashier, lab
imaging imaging, cashier, radiology
or_request or, cashier, anesthesia, nursing
labour_room labour, cashier, anesthesia, nursing
admission ipd, cashier, nursing, bed_management
er_request er, cashier, triage

Realtime filter: dept_target=cs.{dept} (array contains) or order_type=eq.blood_bank.


9. Policy Gates & Safety

9.1 Order Dispatch Policies

Migration: 008_order_dispatch_policies.sql

Controls whether orders auto-dispatch or require nurse acknowledgment.

Column Type Notes
dept_type TEXT medication, lab, imaging, blood, procedure
scope_type TEXT location, sub_clinic, clinic, global
scope_id TEXT NULL for global
requires_nurse_ack BOOLEAN
auto_dispatch BOOLEAN
priority INTEGER Higher = more specific (location > clinic > global)

9.2 Medication Safety Policy Gates

Migration: 065_phase2_policy_gates_seed.sql

Gate ID Trigger Action Description
O.17 medication.high_alert.ordered warn Independent verification at order entry
O.19 medication.high_alert.dispense warn Second pharmacist verification at dispense
M.60 medication.high_alert.admin warn Second nurse verification at bedside
M.61 medication.high_alert.admin + badge.count<2 block Both nurse + witness must scan badges
M.62 medication.double_check.completed warn Record decision into MAR + audit
M.95 medication.antimicrobial.ordered + duration>3d warn 72h review required; auto-stop enforced

9.3 e-MAR Safety Tables

Migration: 055_medication_administration_tracking.sql

Table Purpose
med_admin_vital_gates Per-drug vital sign thresholds (e.g., hold if HR < 60)
med_admin_observation_periods Post-injection observation windows
med_admin_prn_justifications PRN justification + effectiveness scoring

10. REST API Endpoints

10.1 OrderRequest

Method Path Action
GET /api/v2/orderRequests List all
GET /api/v2/orderRequests/:_id Get one
GET /api/v2/orderRequests/getLastDraftOrderByEncounterId Current draft
GET /api/v2/orderRequests/getByPatient/:patientId By patient
GET /api/v2/orderRequests/getByPatientAndEncounter By patient+encounter
GET /api/v2/orderRequests/getOrderRequestByEncounter/:encounterId By encounter
GET /api/v2/orderRequests/getMedicationItemHistoryByPatient/:patientId Medication history
GET /api/v2/orderRequests/getServiceByEncounterId/:encounterId Services for encounter
GET /api/v2/orderRequests/getOrderRequestTodayByPatient Today’s orders
POST /api/v2/orderRequests Create
POST /api/v2/orderRequests/update/:_id Update
POST /api/v2/orderRequests/updateStatus/:_id Status change
POST /api/v2/orderRequests/cancel/:_id Cancel
POST /api/v2/orderRequests/updateAcknowledge/:_id Single acknowledge
POST /api/v2/orderRequests/updateAcknowledgeAllOrderRequest Batch acknowledge
PUT /api/v2/orderRequests/updateLabWorklistResultEntry/:_id Lab result entry

10.2 MedicationRequest

Method Path Action
GET /api/v2/medicationRequests/:_id Get one
GET /api/v2/medicationRequests/listIPD IPD-only queue
GET /api/v2/medicationRequests/listByEncounter/:encounterRef By encounter
GET /api/v2/medicationRequests/listMedicalSupplyWorklist Supply worklist
GET /api/v2/medicationRequests/getAmountPharmacy Queue counts
GET /api/v2/medicationRequests/getMedicationRequestHomeMedDoctor Home med (doctor)
GET /api/v2/medicationRequests/getMedicationReconcile Reconciliation list
POST /api/v2/medicationRequests/cancel/:_id Cancel single
POST /api/v2/medicationRequests/cancelAll/:orderRequestId Cancel all in order
POST /api/v2/medicationRequests/dailyGenerateMedicationRequest Daily batch generation
PUT /api/v2/medicationRequests/:_id Update
PUT /api/v2/medicationRequests/:_id/updateMedicationRequestStatus Status change
PUT /api/v2/medicationRequests/updatescreened/:_id Mark screened
PUT /api/v2/medicationRequests/qcVerification/:_id QC verify
PUT /api/v2/medicationRequests/medicationReceivedBy/:_id Mark received
PUT /api/v2/medicationRequests/:_id/medicationRequestItem Update line item
PUT /api/v2/medicationRequests/updateManyMedicationRequestItem Batch update items
PUT /api/v2/medicationRequests/medicationRequestItemOffMed/:_id Off medication

10.3 MedicationAdministration

Method Path Action
GET /api/v2/medicationAdministrations/:_id Get one
GET /api/v2/medicationAdministrations List
POST /api/v2/medicationAdministrations Create MAR record
PUT /api/v2/medicationAdministrations/:_id Update
PUT /api/v2/medicationAdministrations/:_id/updateMedicationAdministrationStatus Status change

10.4 Supporting Endpoints

Resource Base Path
MedicationCart /api/v2/medicationCart
MedicationReturnSystem /api/v2/medicationReturnSystem
OrderRequestProductDispense /api/v2/orderRequestProductDispense
MedicationAdministrationEvent /api/v2/medicationAdministrationEvent

11. Frontend Component Map

11.0 IPD Medication Hub (Unified 5-Tab Flow)

Sandbox: http://localhost:5179/?target=IpdMedicationHub

Tab Thai Label Component Data Source
1 คำสั่งแพทย์ (Doctor Order) DoctorOrderTarget REST: /api/v2/medicationRequests/listByEncounter
2 รับทราบคำสั่ง (Nurse Ack) NurseAcknowledgeTarget / DialogNurseAcknowledge REST: /api/v2/orderRequests/updateAcknowledge
3 สถานะรับยา (Pharmacy) MedicationReceiveStatusTarget REST: /api/v2/medicationRequests/listIPD
4 วางแผนรอบยา (Dispense Rounds) OrderDetailsPageTarget Supabase: medication_administration_cycles
5 e-MAR (Administration) MarSystemPageTarget Supabase: medication_administrations + MongoDB

Key files:

  • Hub: web/sandbox/targets/IpdMedicationHubTarget.tsx
  • Registry: web/sandbox/registry.tsIpdMedicationHub

11.0a Nurse Acknowledgement

Component Path Purpose
DialogNurseAcknowledge medical-kit/src/medical-record/components/dialogs/DialogNurseAcknowledge.tsx 11-section checklist dialog
NurseAcknowledgementService src/services/nurse-acknowledgement.service.ts acknowledgeAndPushToQueues() — API + queue push
QueueGenerationRegistry src/services/queue-generation-registry.ts productType → queue config mapping
WorkflowActionHandler src/setup/dynamic/central-table/handlers/workflowActionHandler.ts ack-order action routing (3 paths: modal / explicit / legacy)
workflowState.ts medical-kit/src/medical-worklist/workflowState.ts wait-acknowledgement node definition

11.1 Order Dialog

Component Path Purpose
DialogNewEditOrder2026 medical-kit/src/order/components/dialogs/dialog-edit-order/DialogNewEditOrder2026.tsx Primary drug order dialog (Formik)
DynamicScheduler ui-kit/src/components/dynamic-scheduler-2/DynamicScheduler.tsx Dose pattern builder
SummaryCard ui-kit/src/components/dynamic-scheduler-2/summary-container/SummaryCard.tsx Formatted medication summary
TimePerDay ui-kit/src/components/dynamic-scheduler-2/summary-container/TimePerDay.tsx 12-pattern frequency visualization
Priority ui-kit/src/components/dynamic-scheduler-2/components/Priority.tsx Priority selector (2-button OPD / 6-button IPD)
useOrderManagement medical-kit/src/order/components/hooks/useOrderManagement.ts Order CRUD + allergy/interaction checks

11.2 Pharmacy Worklist (IPD Pharmacy — Screen/Prepare/Verify/Dispense)

This is the pharmacist’s own workspace — not a nurse view. Pharmacy receives acknowledged drug orders (after nurse ack) and processes them through their internal pipeline: screening → preparation → QC verification → acceptance → dispensing. The nurse’s “สถานะรับยา” view (Hub tab 3) shows the pharmacy status from the ward side.

Pharmacy internal pipeline (§3.2b):

  ORDERED ──▶ SCREENED ──▶ PREPARED ──▶ VERIFIED ──▶ ACCEPTED ──▶ DONE
   (รอคัดกรอง) (คัดกรองแล้ว) (จัดยาแล้ว)  (ตรวจสอบแล้ว)  (พร้อมจ่าย)   (จ่ายยาแล้ว)
Component Path Purpose
TableRowPharmacy medical-kit/src/pharmacy/components/pharmacy-worklist/TableRowPharmacy.tsx Pharmacy worklist row
DialogPharmacyOrder medical-kit/src/pharmacy/components/pharmacy-worklist/dialog-order-drug/DialogPharmacyOrder.tsx Drug order details
DialogScreeningDrugLeaves medical-kit/src/pharmacy/components/pharmacy-worklist/dialog-screening-drug-leaves/ Screening + dispense workflow
RowTabbleDispense ...dialog-screening-drug-leaves/RowTabbleDispense.tsx Dispense confirmation per drug
DialogPrintDrug medical-kit/src/pharmacy/components/pharmacy-worklist/dialog-print-drug/DialogPrintDrug.tsx Medication label printing

11.3 IPD Command Center

Component Path Step
Step1AdmitPanel medical-kit/src/ipd-system/command-center/Step1AdmitPanel.tsx Admission
Step2AssessmentPanel ...Step2AssessmentPanel.tsx Nursing assessment
Step3CarePanel ...Step3CarePanel.tsx Care + medication orders
Step4ProcedurePanel ...Step4ProcedurePanel.tsx OR procedures
Step5DischargePanel ...Step5DischargePanel.tsx Discharge prep
Step6CloseoutPanel ...Step6CloseoutPanel.tsx Financial settlement

11.4 e-MAR

Component Path Purpose
EmarDialog medical-kit/src/ipd-system/command-center/dialogs/EmarDialog.tsx 3-step MAR (verify → select → outcome)
MarSystemEnhanced miniapps/e-mar/MarSystemEnhanced.tsx Production e-MAR system
MarSystemProvider miniapps/e-mar/MarSystemProvider.tsx REST backbone for e-MAR
useSupabaseEmarSync miniapps/e-mar/useSupabaseEmarSync.ts Supabase realtime sync

11.5 IPD Nurse Worklist

Component Path Purpose
usePatientOrderStatus medical-kit/src/ipd-system/hooks/usePatientOrderStatus.ts Per-patient order status badges
MainTab medical-kit/src/ipd-system/nurse-ipd-work-list/components/MainTab.tsx Nurse worklist tabs
WardViewPanel medical-kit/src/ipd-system/ipd-management/components/dashboard/ Ward floor plan

11.6 IPD Encounter Step Status

File: medical-kit/src/ipd-system/command-center/stepStatus.ts

pending → admit-requested → ipd-admitted → ipd-nursing-assessment
    → ipd-nurse-rounds → ipd-medication-administration
    → ipd-nurse-handover → ipd-nurse-discharge-prep → finished

Step status per step: 'todo' | 'active' | 'done' | 'skipped' | 'blocked'


12. Dose Pattern System

File: ui-kit/src/components/dynamic-scheduler-2/summary-container/dosePatternKind.ts

12.1 DosePatternKind (14 types)

Kind TH Name Detection Signal
fixed ตารางคงที่ Standard frequency (OD/BID/TID/etc.)
prn เมื่อจำเป็น priority = ‘prn’ or frequency contains ‘prn’
one_time ครั้งเดียว priority = STAT or frequency = ONCE
continuous หยดต่อเนื่อง infusionRate present + route = IV
taper ลดขนาดยา taperSteps[] present
titration ไตเตรท method = ‘titration’
sliding_scale Sliding Scale slidingScaleTable[] present
cyclic รอบ/พัลส์ cyclic on/off days pattern
loading_maintenance โหลด+บำรุงรักษา loadingDose present
bolus_infusion โบลัส+หยด bolus + continuous infusion
pca PCA pcaConfig present
range ช่วงขนาดยา min/max dose range
protocol_lookup Protocol Lookup-based
bsa_based / weight_based / renal_adjusted / age_based Derivation Calculation methods

12.2 Detection Priority

detectDosePattern(order) runs a 19-step priority chain (first match wins):

  1. pcaConfig → pca
  2. slidingScaleTable → sliding_scale
  3. taperSteps → taper
  4. loadingDose + maintenanceDose → loading_maintenance
  5. bolus + infusion → bolus_infusion
  6. cyclic pattern → cyclic
  7. titration method → titration
  8. infusionRate + IV route → continuous
  9. dose range → range
  10. PRN flag → prn
  11. STAT/ONCE → one_time
  12. Standard frequency → fixed (default)

12.3 Specialized Protocol Row Types

Type Fields
SlidingScaleRow glucose range → dose lookup
TaperStepRow day range → dose step-down
PcaProtocolRow basal rate, demand dose, lockout minutes
CyclicProtocolRow days on/off, cycle count, rest days
LoadingMaintenanceRow loading dose → maintenance dose
ContinuousInfusionRow rate range, duration, titration
RangeOrderRow min-max dose, nurse instructions
FrequencyPolicyRow per-drug/category frequency restrictions

Doc Path Covers
Central Order System docs/architecture/central-order-system.md Hub-and-spoke order model, order bus, verification flows
IPD Dispense Cycles docs/architecture/ipd-dispense-cycles.md Dispense cycle engine design, two-layer model
Order Dialog Drug Subtypes docs/architecture/order-dialog-2026-drug-subtypes.md Injection/taper panels, duration toggle, IPD priority
Dose Pattern Visualization docs/architecture/dose-pattern-visualization-system.md 12-pattern rendering engine
Frequency RRule Overhaul docs/architecture/frequency-rrule-overhaul-plan.md 5-phase frequency + RRule cleanup
Standing Orders RRule docs/architecture/standing-orders-rrule-system.md Continue vs oneday semantics
Medication Per-Drug Defaults docs/architecture/medication-per-drug-default-usage.md Per-drug frequency locking
Injection Timeline MAR docs/architecture/injection-timeline-mar-integration.md Injection/infusion → MAR integration
CDS Vital Signs Rules docs/architecture/cds-vital-signs-rules.md CDS triggers on observations from orders
Pharmacy Gap Analysis docs/architecture/pharmacy-module-gap-analysis.md Gap analysis for pharmacy module
Encounter Orchestrator Triggers docs/architecture/encounter-orchestrator-triggers.md Master trigger inventory
Dose Pattern Master Setup docs/architecture/dose-pattern-master-setup-checklist.md Setup checklist
Department Command Center docs/architecture/department-command-center-tabs.md Timeline + Main + Order System tabs
Ask Anything