Unified Procedure-Room Setup
One admin page to configure procedure rooms, presets, and per-procedure features.
Status: Phase 1 (sandbox prototype) in progress 2026-05-29. Goal: one admin page where you
add a procedure → assign it to a department’s procedure room → configure that room’s phases,
columns, actions/gates, and category — and the procedure then routes to that room’s
procedure_day_queue. Unifies config that’s currently split across three stores + a hardcoded TS file.
The mental model
A procedure room = a subDept UUID (department_id). Everything hangs off it:
Procedure Room (subDept UUID)
├─ Metadata category / title / color / workspace_style → specialty_clinic_modules [EXISTS]
├─ Procedures catalog assigned to this room → NEW (today: hardcoded dayProcedures)
├─ Phases/times sign_in(time-in) / time_out / sign_out(time-out) / intra_op(clock-in/out) /
│ recovery / par_score / surgical_team / surgical_type → procedure_workflow_config [EXISTS]
├─ Actions & gates allowed row actions + required-before-complete → procedure_workflow_config.gate + policy_gates [EXISTS]
└─ Queue columns which columns show / order / labels → NEW
Why “assign to room” just works for routing: the room’s subDept UUID is the
procedure_day_queue.department_id. Orders carry category:'procedure' + the room’s location;
the encounter-orchestrator routes category:'procedure' → the procedure queue for that room
(resolveDepartmentKeyFromOrderItem). So assigning a procedure to a room + ordering it lands it
in that room’s queue with no extra plumbing.
What already exists (reuse — do NOT rebuild)
| Concern | Store | Where |
|---|---|---|
| Phases / timestamps / gates | procedure_workflow_config (Supabase, mig 075) |
4-tier resolver procedureWorkflowConfig.service.ts (resolveConfig/saveConfig), admin page pages/admin/procedure-workflow-config.tsx, catalog ALL_PROCEDURE_FEATURES |
| Clinic metadata + category | specialty_clinic_modules (Supabase, mig 20260517c) |
useSpecialtyClinicModules.ts; columns incl. category (clinic/specialized_unit/other_service), title_*, color, icon, sub_dept_id, workspace_style, status, display_order |
| Procedure catalog (backend) | procedureItems (Mongo REST v2/medication/procedureItems) |
services/ever-medication/procedureItem.service.ts — list/create/update, fields name/product/unit/category/snomed/active |
| Department picker source | SEEDED_DEPARTMENTS (code) + custom UUID |
procedureWorkflowConfig.defaults.ts, screeningModalConfig.defaults.ts |
| Routing | category + location → department_queues.dept_type |
encounter-orchestrator/index.ts resolveDepartmentKeyFromOrderItem (case 'procedure') |
| Related admin pages | — | department-config-hub.tsx, subclinic-management.tsx, administration-setup.tsx, clinic-management.tsx, fee-schedule-management.tsx |
The genuinely-new pieces
- Procedure → room assignment — today
dayProceduresis hardcoded inclinic-configs.ts. Need a per-room, runtime-editable list. Phase 2 table:procedure_room_procedures(department_id, code, name_th, name_en, est_minutes, icd_code, addons jsonb, display_order, active). - Queue column config — per-room which columns show, order, labels. Phase 2: a
column_configJSONB on the room (or a small table). Column ids:hn, patient, procedure, priority, status, time_in, time_out, clock_in, clock_out, room, actions. - The unified page — one editor tying all axes together (below).
The page — ProcedureRoomSetup (5 tabs)
Pick a room (dropdown from specialty_clinic_modules + SEEDED_DEPARTMENTS + paste-UUID), then:
- Room & Category — category, title, color, workspace_style, subDept id (+ placeholder warning).
- Procedures — list the room’s procedures; add new (code, nameTh, nameEn, est minutes, ICD); remove; reorder. This is “add a procedure, assign it to this room.”
- Phases & Timestamps —
ALL_PROCEDURE_FEATURESrows with enabled/required toggles + presets (full-or / minor-ops / safety-only / basic-opd). Reuses the realprocedure_workflow_configservice. - Columns — enable/disable + reorder + relabel queue columns; live preview of the resulting queue header.
- Actions & Gates — allowed row actions (accept/start/complete/cancel/hold) + which phases are
required-before-complete (drives
blocked_actions). Reusesprocedure_workflow_config.gate.
Rollout
Phase 1 — sandbox prototype (this work)
- [ ]
docs/architecture/procedure-room-setup-unified.md(this file) - [x]
room-registry.ts+AddRoomDialog.tsx— runtime-added rooms persist to localStorageprocedure_rooms.v1;getAllRooms()merges built-in (SPECIALTY_CLINIC_CONFIGS) + custom. A custom room is a fullSpecialtyClinicConfig(placeholder subDept until a real UUID is pasted). - [x]
ProcedureRoomDirectory.tsx(“stores” page) — searchable card grid of all rooms; Add clinic; per-card code ID + category + proc count + built-in/custom badge; cards deep-link to?target=ProcedureRoomSetup&room=<key>and?target=ClinicOrderSystem&clinic=<key>; Remove (custom only). - [x] ProcedureRoomSetup picker surfaces the code ID per item + a
code <key>chip, an inline New button (AddRoomDialog), and?room=<key>deep-link preselect. - [ ]
ProcedureRoomSetup.tsx— 5-tab editor, localStorage-backed (procedure_room_setup.v1) so it’s try-able offline; Phases tab uses the realresolveConfig/saveConfig. Plain MUI (sandbox-safe). - [ ]
ProcedureRoomSetupTarget.tsx+ register (?target=ProcedureRoomSetup) + targetMeta (category ‘config’) - [ ] Verify in sandbox: pick room → add procedure → toggle phases → add/reorder columns → gates → preview
Phase 2 — real persistence + wiring (next)
- [ ] Migration:
procedure_room_procedures+ per-roomcolumn_config(Supabase) with RLS like 075/076 - [ ] Procedures tab → real
procedureItemsREST create + room assignment write - [ ] Room & Category tab → real
specialty_clinic_modulesupsert - [ ] Mount as a real admin route (design-kit components per style guide) — likely a tab in
department-config-hub.tsx - [ ] Wire
ClinicOrderSystemto READ the room config: procedures fromprocedure_room_procedures, columns fromcolumn_config, phase columns/actions fromprocedure_workflow_config - [ ] Confirm end-to-end: add procedure in setup → appears in that room’s Order System → orders route to
its
procedure_day_queue
Invariants
- Room identity = subDept UUID =
procedure_day_queue.department_id. Never invent a second id. - Reuse
procedure_workflow_configfor phases/gates; never fork it. - Frontend writes config to config stores only — never to read models (
procedure_day_queue,department_queues). - A procedure with no real subDept assignment can’t route (surface a placeholder warning).