Staff Schedule System
Overview + TOR mapping for the staff scheduling system, the existing-frontend audit and ultimate design.
4 min read diagramsUpdated 2026-04-29docs/architecture/staff-schedule-system/00-overview.md
Why this document exists
medOS-ultra already has a partially built staff scheduling system spread across:
web/packages/scheduling-kit/(frontend) — calendar UI, shift templates, leave worklistservices/foundation/(backend) —staffScheduleManagement,workTimeSetting,leaveRequestservices/administration/(backend) —appointment,holiday,device,doctorRoom,corporateEmployeesinfrastructure/medbase/(Supabase) —schedule_business_hoursonly; no shift/roster tables yetweb/src/containers/conference/+core-kit/conference/— separate conference scheduling system
The TOR (sections 2.2.2.1 – 2.2.2.18) requires a single integrated module that covers shift planning, resource booking, leave, swaps, appointment integration, and reporting. The existing pieces don’t meet the TOR alone — there are 5 critical gaps (resource booking integration, shift swap workflow, hour-cap tracking, RBAC enforcement at DB layer, audit log scoped to schedule events).
This documentation set is the blueprint to close those gaps.
Document set
| File | Topic |
|---|---|
00-overview.md |
This file — TOR mapping, gap analysis, glossary |
01-existing-frontend.md |
Existing staff-schedule miniapps, routes, key components |
02-conference-system.md |
Conference scheduling — separate architecture, why, integration points |
03-backend-apis.md |
Foundation + Administration service modules, REST endpoints, schemas |
04-database-schema.md |
Supabase tables (existing + gaps), MongoDB collections, RLS |
05-ultimate-design.md |
Target architecture: unified scheduler, user profile, resource booking, RBAC |
06-uat-flows-implementation.md |
All 4 UAT flows mapped to concrete implementation steps |
TOR coverage matrix
Status legend: ✅ implemented · 🟡 partial · ❌ missing
| TOR § | Requirement | Status | Where |
|---|---|---|---|
| 2.2.2.1 | Schedule CRUD with location, equipment, conditions, notes | 🟡 | staffScheduleManagement has CRUD; equipment binding is not enforced |
| 2.2.2.2 | Schedule staff in advance | ✅ | StaffScheduleManagement.date arbitrary future date |
| 2.2.2.3 | Shift cycles (เวรเช้า/บ่าย/ดึก) | ✅ | WorkTimeSetting.item[] |
| 2.2.2.4 | Manpower targets per slot | 🟡 | WorkTimeSetting.item.patientAmount exists; no per-shift headcount target table |
| 2.2.2.5 | Annual + ad-hoc holidays | ✅ | Holiday entity (administration service) |
| 2.2.2.6 | Edit by authorized role only | 🟡 | App-layer guard in NestJS controllers; no DB-level RLS on schedule rows |
| 2.2.2.7 | Shift swap with approval workflow | ❌ | No swap entity, no approval action |
| 2.2.2.8 | Replace assigned staff in pre-set schedules | 🟡 | Doable via PUT /staffScheduleManagements/:id but no swap-aware audit |
| 2.2.2.9 | Leave management | ✅ | LeaveRequest + updateTreatmentPlanAndStatus approval action |
| 2.2.2.10 | Bind to appointment system | 🟡 | scheduleCheck + eventScheduleCheck validate availability; no quota deduction loop |
| 2.2.2.11 | Show staff DB + contact | 🟡 | corporateEmployees exists; not wired to schedule UI directory |
| 2.2.2.12 | Reports (monthly schedule, hours, room utilization, daily/monthly headcount) | ❌ | No report endpoints, no print views |
| 2.2.2.13 | Live monthly hours summary (during & after planning) | ❌ | WorkTimeSetting has caps; no actual-vs-target rollup view |
| 2.2.2.14 | Cross-department visibility (find free slots) | 🟡 | Possible via getAllByStaffId but no aggregated cross-dept view |
| 2.2.2.15 | Manage locations (building/dept/room) + per-location shift cycles | 🟡 | room/department entities exist; room controller is a stub |
| 2.2.2.16 | Per-person monthly hour cap | 🟡 | WorkTimeSetting.hourHigh/otHourHigh static; no enforcement at create time |
| 2.2.2.17 | (TOR section likely covers training/certification — verify with user) | ❓ | Out of scope for this doc unless TOR text supplied |
| 2.2.2.18 | Mark hours as regular vs OT | 🟡 | WorkTimeSetting.isOt flag exists; not surfaced per-shift-row in staffScheduleManagement.item |
The 5 critical gaps
- Resource booking — rooms and equipment are first-class entities (
room,device) but not linked tostaffScheduleManagement. UAT Flow 1 fails: nothing prevents two doctors from booking the same Ultrasound at 09:00. - Shift swap workflow — UAT Flow 2 fails: there is no
ShiftSwapRequestentity, no notification fan-out, no auto-swap on approve, no audit log entry. - Appointment quota loop — UAT Flow 3 partial:
scheduleCheckexists but no atomic decrement ofpatientAmountwhen an appointment is created against a shift slot. - Leave → schedule sync — UAT Flow 4 partial:
LeaveRequestapproval doesn’t tag thestaffScheduleManagementrows or block downstream appointments on that day. - Audit trail scoped to schedule events —
fhir_audit_logexists in Supabase but is patient-scoped; schedule edits (who created/swapped/cancelled) have no dedicated immutable log surfaced in the admin UI.
Glossary
| Term | Meaning |
|---|---|
| Shift / กะ | Named time block (เวรเช้า 08-16, เวรบ่าย 16-24, เวรดึก 00-08) defined in WorkTimeSetting.item[] |
| Schedule entry | A single staff-on-a-shift-on-a-date row in StaffScheduleManagement |
| Roster | The aggregated view of all schedule entries per dept per month |
| Manpower target | Required min staff count per shift per dept per day |
| Hour cap | Per-person monthly ceiling (regular + OT) |
| Conference | Tumor-board / case-review event; uses leave_request.leaveType='conference', NOT shift tables |
| Resource | Physical asset — room, equipment, vehicle — that a shift may consume |