Saathora System map

Appointment business rules & edge cases

50 shipped patient scenarios, grouped into 30 categories. This is how appointments work when something goes wrong — not a table list.

Design around patient problems first: what can go wrong at this step, and what should Saathora do? Then convert the answer into Business Rule → Status → Database → API → Permission → Notification → UI → Audit → Test. Do not design only around database tables. Never auto-shift appointment_time. Never leave the patient at a dead end.

Business Rule Status Database API Permission Notification UI Audit Test

1 Normal booking shipped

What can go wrong: The patient cannot find a doctor, pick a real slot, or tell request from confirmed.

What Saathora does: Keep appointment_time as the official schedule. Disease → specialization → doctor → hospital → slot → payment → pending → staff confirm. Early arrivals wait in the published order. A Saathora Agent can book the same saathora visit by phone (pay at hospital in v1).

Scenario 1 Scenario 6 Scenario 20 Scenario 34
Statuspending, then confirmed
Databaseappointments.appointment_time, slot_lock, status
APIpublic.doctor-slots, book schedule/patient/pay
PermissionGuests book; auth:patient only at Razorpay pay
NotificationRequest received; then confirmed
UIBooking steps + After you book
AuditCreated and status history
TestBooking and confirmation feature tests

2 Doctor delay shipped

What can go wrong: The 10:00 AM slot arrives but the doctor is running late. The patient thinks the booking is broken.

What Saathora does: Show scheduled time, delay minutes, and estimated consultation. Continue Waiting / Reschedule / Cancel. Do not rewrite appointment_time.

Scenario 2 Scenario 44
Statusclinic delayed overlay; appointment stays confirmed
Databasedoctor_clinic_sessions.clinic_status, delay_minutes
APIliveBoard JSON poll
PermissionHospital/doctor set delay; patient cannot
Notificationclinic delayed / running late
UILive card: delay + ETA + actions
Auditclinic activity log
TestClinicQueueTest delay cases

3 Surgery shipped

What can go wrong: The doctor enters surgery. Remaining patients see an empty clinic or a shifted time.

What Saathora does: Blocking clinic status. Booked time unchanged. Show reason, expected return, ETA. Continue Waiting / Reschedule / Cancel.

Scenario 3 Scenario 4 Scenario 5
Statusclinic_status surgery; appointment confirmed
Databasedoctor_clinic_sessions.clinic_status, expected_return_at
APIclinic queue status + liveBoard
PermissionHospital/doctor only
NotificationDoctor in surgery
UILive card reason + ETA
Auditstatus change log
TestClinicQueueTest surgery / return-early

4 Emergency shipped

What can go wrong: A hospital emergency or 108 situation is treated like a normal booking.

What Saathora does: Clinic emergency blocks the board like surgery. Symptom routing sends true emergencies to Emergency Guidance (108), not the calendar.

Scenario 21
Statusclinic_status emergency; care_pathway emergency
Databasedoctor_clinic_sessions.clinic_status; appointments.care_pathway
APIfrontend.care.pathway, clinic status
PermissionPublic guidance; staff set clinic emergency
NotificationDoctor attending an emergency
UIEmergency Guidance page; live card reason
Auditclinic status + care pathway
TestClinicQueueTest emergency; care pathway tests

5 Doctor unavailable shipped

What can go wrong: The calendar is empty or says Appointment unavailable. The patient stops.

What Saathora does: Print Dr. {name} is unavailable today. Suggest similar doctors. Offer Find Another Doctor / Hospital, Choose Another Date, Contact Hospital. Never show only an error.

Scenario 9 Scenario 22 Scenario 49 Scenario 50
Statusunavailable / offline overlay
Databaseclinic_status; blocked exceptions
APIpublic.doctor-slots alternatives.recovery
PermissionPublic discovery; staff set unavailable
NotificationUnavailable reason on live card
UIProfile, booking, live card recovery actions
Auditclinic status
TestBookingRecoveryActionsTest, BookingSlotAlternativesTest

6 Doctor leave shipped

What can go wrong: Leave is taken after patients already booked that day.

What Saathora does: Blocked exception hides slots. Offer replacement or reschedule/cancel. Keep original appointment_time until the patient chooses.

Scenario 23
Statusdoctor_on_leave on live board
Databasedoctor_availability_exceptions type blocked
APIleave + liveBoard
PermissionHospital/doctor record leave
NotificationLeave / replacement notice
UILive card + similar doctors
Auditleave exception row
TestDoctorLeaveAfterBookingTest

7 Doctor replacement shipped

What can go wrong: The hospital silently swaps Dr. Ravi for someone else.

What Saathora does: Never silently change appointment.doctor_id. Store original vs replacement. Patient Accept / Reschedule / Cancel. Time unchanged.

Scenario 11
Statusreplacement_status offered/accepted
Databaseappointments.original_doctor_id, replacement_doctor_id
APIaccept-replacement
PermissionStaff propose; patient accepts
Notificationclinic_doctor_replaced
UIOriginal / Updated doctor on live card
Auditreplacement timestamps
TestClinicQueueTest replacement

8 Patient late shipped

What can go wrong: Traffic or a late arrival is treated as an instant no-show.

What Saathora does: Late arrival: Join Current Queue or Request Reschedule. I'm running late notifies the desk and extends auto no-show. Do not auto-shift appointment_time.

Scenario 7 Scenario 47
Statusvisit overlay late / running_late
Databaseappointments.running_late_minutes, running_late_notified_at
APIarrive, join-queue, running-late
PermissionOwning patient only
NotificationDesk sees delayed-by-N-minutes
UILate arrival detected; I'm running late
Auditrunning_late_notified_at
TestClinicQueueTest late arrival; running-late tests

9 Patient no-show shipped

What can go wrong: The clock passing 10:00 marks them absent even if the doctor is in surgery.

What Saathora does: Auto no-show only after grace, and never while the clinic is blocking or delayed. Staff may still mark no-show by policy.

Scenario 8
Statusno-show overlay; appointments.status not a fifth enum
Databasequeue visit_status / no-show flags
APIclinic:mark-no-shows, staff mark
PermissionStaff; system scheduler
Notificationclinic_no_show
UIAttendance trail labels no-show separately
Auditno-show event
TestClinicQueueTest auto no-show skips delay

10 Patient cancellation shipped

What can go wrong: Cancel deletes the row, or clinic cancel silently drops paid visits.

What Saathora does: Never delete. Patient cancel pending/confirmed. Paid → refund_pending. Clinic cancel keeps bookings and offers Reschedule / Cancel.

Scenario 10 Scenario 24
Statuscancelled; payment refund_pending / refund_requested
Databaseappointments.status cancelled; payments.payment_status
APIpatient cancel; cancelClinic
PermissionOwning patient; hospital cancel clinic
Notificationcancelled / clinic_cancelled
UICancel / request refund
Auditrow retained
TestPatientCancellationWorkflowTest

11 Rescheduling shipped

What can go wrong: Completed visits can still be moved, or delay patients cannot move.

What Saathora does: Reschedule pending, or confirmed only while the live clinic is delayed/blocking. Choose Another Date from recovery. Time changes only when the patient picks a new slot.

Scenario 50
Statusstays pending unless staff re-confirm
Databaseappointments.appointment_date, appointment_time
APIportal reschedule
PermissionOwning patient when canBeRescheduledByPatient
Notificationrescheduled
UIReschedule / Request Reschedule / Choose Another Date
Auditold vs new slot
Testreschedule + recovery-action tests

12 Payment failure shipped

What can go wrong: A failed charge still holds the 10:00 slot forever.

What Saathora does: Temporary hold (10 min). Failed or expired hold releases the slot. Do not confirm.

Scenario 26
Statushold then released; no confirmed appointment
Databaseappointments.slot_lock until expiry
APIpay / verify / hold release
Permissionauth:patient at pay
Notificationpayment failed if a row exists
UISlot held 10 min
Audithold created/released
TestSlotHoldTest

13 Payment success but booking failure shipped

What can go wrong: Razorpay succeeded, then create appointment failed, so the patient pays again.

What Saathora does: Reconcile the payment to the booking. Never charge twice for the same idempotency key.

Scenario 25
Statuspayment captured; appointment created on recon
Databasepayments + appointments link
APIwebhook + PaymentReconciliationService
Permissionwebhook signature; patient verify
Notificationbooking notice after recon
UIDo not pay again
Auditrecon log
TestPaymentReconciliationTest

14 Duplicate booking shipped

What can go wrong: Refresh or a second Book click creates two visits. Same doctor twice in one day.

What Saathora does: Idempotency key / booking reference. Warn on a second same-doctor day. Overlapping other doctors need an explicit continue.

Scenario 18 Scenario 19 Scenario 27
Statusone pending row
Databaseappointments.idempotency_key unique
APIbook with idempotency
Permissionsame patient session
Notificationone request-received
UIDuplicate / overlap continue screens
Auditsingle appointment_no
TestBookingIdempotencyTest, DuplicateDoctorDayBookingTest

15 Concurrent booking shipped

What can go wrong: Two patients or two assistants take the same seat.

What Saathora does: Occupancy is doctor+date+time+seat. Database unique slot_lock. Second request: Selected time slot is no longer available. Please choose another slot.

Scenario 16 Scenario 17
Statusone winner pending
Databaseunique doctor/date/slot_lock/seat
APIbook() inside lock
Permissionany booker; first write wins
Notificationonly the saved booking
UIchoose another slot
Auditone slot_lock row
TestSlotDoubleBookingTest

16 Multiple hospitals shipped

What can go wrong: The doctor is treated as one queue across campuses, or the patient is sent to a sister branch.

What Saathora does: Each hospital is one campus. Never silently change appointment.hospital_id. Live queue is doctor + hospital + session.

Scenario 13 Scenario 14 Scenario 46
Statusbooked hospital_id frozen
Databaseappointments.hospital_id; doctor_hospital_specialization
APIslots?hospital_id, clinic-queue?hospital_id
PermissionCMS users limited to their hospital_id
Notificationbranch on every notice
UIHospital vs Branch, Find us, maps
Audithospital_id unchanged
TestClinicQueueTest multi-hospital; wayfinding

17 Multiple doctor sessions shipped

What can go wrong: Morning and evening boards are mixed, or the UI defaults to the first session.

What Saathora does: Require session_id when more than one session exists that day. Chips use Morning/Evening hours.

Scenario 15
Statusper-session clinic_status
Databasedoctor_clinic_sessions start/end
APIclinic-queue?session_id
PermissionDoctor/hospital of that session
Notificationsession hours on notices
UISession chips before the board
Auditsession_id on queue entries
TestClinicQueueTest session chips

18 Hospital changes shipped

What can go wrong: Building, floor, or campus copy overwrites the booked hospital.

What Saathora does: Campus changes: Clinic location updated. Find us: …. Keep booked hospital_id and appointment_time.

Scenario 33
Statussession location overlay
Databaseconsultation_building, floor, department
APIupdate location on session
PermissionHospital/doctor
Notificationclinic location updated
UIFind us inside path
Auditprevious_* location columns
TestAppointmentWayfindingTest

19 Room/department changes shipped

What can go wrong: Room 305 becomes Room 201 and the booked time is rewritten.

What Saathora does: Session-level consultation_room. Notify remaining in-clinic visits. Do not change appointment_time.

Scenario 12
Statusroom overlay
Databaseconsultation_room + previous_consultation_room
APIupdateConsultationRoom
PermissionHospital/doctor
Notificationclinic_room_changed
UIConsultation room changed to Room 305.
Auditprevious room stored
TestClinicQueueTest room change

20 Notifications shipped

What can go wrong: The system treats Sent as Delivered. A new phone is saved without OTP.

What Saathora does: Track Pending/Sent/Delivered/Failed/Read. Show failures to staff. Phone change needs OTP purpose change_phone.

Scenario 28 Scenario 29
Statusnotification log status
Databaseappointment_notification_logs; patients.phone
APIotp change_phone; staff see failed
PermissionOwning patient for phone; public /otp rejects change_phone
Notificationemail + SMS; fail visible
UIStaff delivery state; profile OTP
Auditnotification history
TestAppointmentNotificationDeliveryTest; PatientProfilePhoneChangeTest

21 Family/dependent booking shipped

What can go wrong: A child is treated as an adult login. Elderly assistance silently jumps the queue.

What Saathora does: Myself or Family member. Child: parent account, child patient_id. Elderly: wheelchair/attendant/priority only if hospital policy.

Scenario 30 Scenario 31 Scenario 32
Statusappointment.patient_id is the person seen
Databasepatient_dependents; booked_by_patient_id; needs_wheelchair
APIbooking who-for + relation
Permissionauth:patient for minors
Notificationguardian when child has no contact
UIFather/Mother/Spouse/Child/Elderly chips
Auditbooked_by vs patient_id
TestPatientDependentBookingTest, ChildAppointmentTest, ElderlyAppointmentTest

22 Emergency pathway shipped

What can go wrong: Chest pain is booked like a routine ortho slot.

What Saathora does: Emergency Guidance is 108 and hospital emergency phones, not the booking calendar. Copy must not diagnose.

Scenario 21
Statuscare_pathway emergency vs normal
Databaseappointments.care_pathway
APIPOST frontend.care.pathway
PermissionPublic GET guidance
Notificationnone for 108 page
UIEmergency Guidance separate from calendar
Auditcare_pathway stored on urgent bookings
Testcare pathway feature tests

23 Follow-up shipped

What can go wrong: The visit ends and there is no next step. Tests have no home on the appointment.

What Saathora does: Consultation completed → Prescription → Tests → Follow-up date → Book follow-up. Ordered tests stay read-only for patients.

Scenario 36 Scenario 37
Statuscompleted then follow-up booking pending
Databaseappointment_follow_ups; test orders; follow_up_from_appointment_id
APIbook-again?follow_up=1; doctor orders tests
PermissionPatient books follow-up; doctor orders tests
Notificationfollow-up recommendation
UIx-visit-follow-up, x-visit-ordered-tests
Auditfollow-up row
TestAppointmentFollowUpTest

24 Second opinion shipped

What can go wrong: Doctor B is nested under appointment A and 500s, or anyone can browse PHI.

What Saathora does: Current condition → Doctor A → Second opinion → Doctor B. withoutScopedBindings. Eligibility in the controller.

Scenario 38
Statusnew pending booking for Doctor B
Databasesecond_opinion_from_appointment_id
APIsecond-opinion/{doctor:slug}
PermissionOwning patient; :can-discover only on patient portal
Notificationsecond-opinion booking
UIx-visit-second-opinion
Auditlink to original visit
TestAppointmentSecondOpinionTest

25 Hospital/doctor alternatives shipped

What can go wrong: No slots today is a dead end. Ranking is a fake JS number.

What Saathora does: No slots today + next available + other doctors + nearby hospitals. Similar doctors when unavailable. Compare and directory ranking stay on GET /doctors and /hospitals/compare.

Scenario 39 Scenario 40 Scenario 48 Scenario 49 Scenario 50
Statusdiscovery only; no appointment rewrite
Databaseexisting doctors/hospitals graphs
APIslots alternatives; hospitals.compare; doctors?sort=
PermissionPublic
Notificationnone until they book
UIalternatives card + recovery actions
Auditnone (marketplace overlay)
TestHospitalComparisonTest, BookingSlotAlternativesTest, BookingRecoveryActionsTest

26 Complaints/escalation shipped

What can go wrong: Waiting too long has no desk task. A dispute has no evidence pack.

What Saathora does: Waiting too long? Request Assistance (one open desk task). Disputes collect booking reference, payment, check-in, notifications, audit.

Scenario 42 Scenario 45
Statuswait_assistance open; dispute pack read model
Databaseappointment_wait_assistance_requests; evidence queries
APIrequest-assistance; dispute show
PermissionOwning patient; staff mark seen; IDOR 404
Notificationdesk task; no extra patient spam on second click
UIRequest Assistance; dispute evidence
Auditassistance + dispute pack
Testwait-assistance + AppointmentDisputeEvidenceTest

27 Refunds shipped

What can go wrong: Cancel deletes a paid visit, or refund is assumed when Razorpay is not called.

What Saathora does: Paid cancel → refund_pending / refund_requested. Staff Mark refunded. Do not auto-call Razorpay on clinic cancel.

Scenario 24
Statuspayment refund_pending then refunded
Databasepayments.payment_status
APIpatient cancel; admin mark refunded
PermissionOwning patient request; staff complete
Notificationrefund pending / refunded
UICancel / request refund
Auditpayment status history
TestPatientCancellationWorkflowTest

28 Reviews shipped

What can go wrong: Anyone can review a hospital from a public form.

What Saathora does: Completed appointment → Eligible for review. Verified Patient Review vs General Review. Public POST needs appointment_no + owning email.

Scenario 41
Statuscompleted then reviewed
Databasereviews tied to appointment
APIportal review; public.review with appointment_no
PermissionOwning patient or owning email; not hospital_id alone
Notificationnone required
UIx-visit-review
Auditreview row + kind badge
TestAppointmentReviewTest

29 Audit/history shipped

What can go wrong: Staff argue from the current status enum. Offline patients have no pass.

What Saathora does: Attendance trail of eight steps. Dispute pack. Inline QR + booking reference. Notification history. Do not rely only on appointments.status.

Scenario 35 Scenario 43
Statusoverlay history beside pending/confirmed/completed/cancelled
Databasequeue timestamps; notification logs; clinic_activity_logs
APIpass page; show evidence
PermissionOwning patient; staff scan with hospital internet
Notificationhistory listed even if failed
UIVisit attendance; x-appointment-pass
Auditthe trail is the audit
TestAppointmentQrCheckInTest; attendance tests

30 Security/privacy shipped

What can go wrong: Documents leak via /storage. Patients hit admin login. Cross-appointment IDOR.

What Saathora does: Patient and admin URLs stay independent. Documents stream from private disk. Portal 404 unless owned. Login only before payment. OTP purposes stay scoped.

Scenario 29
Statusn/a
Databaseprivate local disk; no public appointment-documents
APIauth:patient /my; web /admin; abort 404 IDOR
Permissionguards, policies, isOwnedByPatient
Notificationnever email PII after a booking OTP lookup
UIDownload/View authenticated only
Auditaccess denied as 404
TestBookingAuthTest, document and IDOR tests
System map Booking walkthrough Home