Appointment Lifecycle
Relevant source files
The following files were used as context for generating this wiki page:
- apps/api/src/modules/appointments/service.ts
- packages/contracts/src/appointments.ts
- apps/web/app/clinic/consultations/[id]/page.tsx
- packages/db/prisma/migrations/20261007150000_appointments/migration.sql
- apps/api/src/modules/appointments/routes.ts
- apps/api/test/appointments.int.test.ts
- apps/web/app/clinic/appointments/appointment-row.tsx
The Appointment Lifecycle manages the progression of a patient visit from initial booking or walk-in through to clinical completion or cancellation. It enforces business rules regarding scheduling, role-based access control for status updates, and data integrity via transaction-scoped advisory locks. The system tracks every state change in an append-only history table to maintain a full audit trail of the patient journey.
Appointment States and Transitions
Appointments move through a series of defined statuses. The AppointmentStatus enum defines eight possible states that represent the operational and clinical progress of a visit.
This diagram illustrates the primary clinical flow and terminal states like Cancelled or Completed.
Sources: packages/contracts/src/appointments.ts:9-18, apps/api/src/modules/appointments/service.ts:46-55
Status Definitions
| Status | Description |
|---|---|
pending | Initial state for bookings awaiting confirmation. |
confirmed | A scheduled slot that has been verified by staff. |
checked_in | The patient has arrived at the clinic. Required before starting a consultation. |
in_consultation | The doctor has started the clinical session with the patient. |
completed | The consultation is finished. This is a final state. |
cancelled | The appointment was aborted by staff or patient; requires a reason. |
no_show | The patient did not arrive; can only be marked after the slot starts. |
rescheduled | The booking was moved to a different slot; links to a new appointment record. |
Sources: packages/contracts/src/appointments.ts:9-18, apps/api/src/modules/appointments/service.ts:104-106, apps/api/test/appointments.int.test.ts:153-157
Booking and Placement Logic
The AppointmentService.place() method handles the creation of new appointments. It distinguishes between scheduled bookings and unscheduled walk-ins.
Concurrency and Locking
To prevent double-booking, the system uses a PostgreSQL advisory lock scoped to the doctor, clinic, and date: pg_advisory_xact_lock(hashtextextended(${'appt:doctorUserId:date'}, 0)). This ensures that only one booking request for a specific doctor's daily schedule is processed at a time.
Sources: apps/api/src/modules/appointments/service.ts:161-163, packages/db/prisma/migrations/20261007150000_appointments/migration.sql:103-108
Overbooking Rules
Staff can book into taken slots if the overbook flag is set, provided the count does not exceed the overbookPerDay limit defined in booking_rules.
- Walk-ins: Automatically set to
checked_instatus and do not require a free slot. - Bookings: Require a valid slot from the doctor's availability schedule.
Sources: apps/api/src/modules/appointments/service.ts:175-207, packages/db/prisma/migrations/20261007150000_appointments/migration.sql:11-12
Action Permissions
Transitions between states are restricted by user roles. The ACTIONS configuration in the API service defines valid source/target states and authorized roles.
| Action | Allowed Roles | Valid From States | Resulting State |
|---|---|---|---|
confirm | front_desk, doctor, clinic_admin | pending | confirmed |
check_in | front_desk, doctor | pending, confirmed | checked_in |
start | doctor | checked_in | in_consultation |
complete | doctor | in_consultation | completed |
cancel | front_desk, doctor, clinic_admin | pending, confirmed, checked_in | cancelled |
no_show | front_desk, doctor | pending, confirmed | no_show |
Sources: apps/api/src/modules/appointments/service.ts:46-55
Rescheduling and History
When an appointment is rescheduled, the system does not modify the original record's time. Instead, it performs the following sequence:
- Creates a new appointment record with the new time and
sourcecopied from the original. - Sets the original appointment's status to
rescheduled. - Links the two records via
rescheduledFromIdandrescheduledToId. - Records the transition in the
appointment_status_historytable.
Database Schema Relationships
The ER diagram shows how appointments relate to their history and the clinical consultation record.
Sources: packages/db/prisma/migrations/20261007150000_appointments/migration.sql:15-63, packages/contracts/src/appointments.ts:60-67
Clinical Integration and Locking
Once an appointment reaches in_consultation, the doctor can record vitals and consultation notes.
- Vitals Recording: Front desk or doctors can update vitals until the appointment is finalized.
- Prescription Signing: When a doctor signs a prescription, the consultation record's
lockedAtfield is populated. - Finality: After
lockedAtis set or the status becomescompleted,cancelled,no_show, orrescheduled, the record becomes read-only. API requests to update notes or vitals for locked appointments return a409 Conflict.
Sources: apps/web/app/clinic/consultations/[id]/page.tsx:165-172, apps/api/test/clinical.int.test.ts:133-149
Summary
The appointment lifecycle acts as the state machine for the entire clinic workflow. It coordinates administrative actions (booking, check-in) with clinical actions (consultation, vitals). By using strict role enforcement, transaction-level concurrency control, and immutable status history, the system ensures that patient flow is predictable and fully auditable.