Low-Level Design: Healthcare Appointment Booking — Scheduling, Reminders, EMR Integration

Core Entities

Provider: provider_id, name, specialty, clinic_id, npi_number, languages[], accepts_new_patients. ProviderSchedule: schedule_id, provider_id, day_of_week, start_time, end_time, slot_duration_minutes, is_active. Appointment: appointment_id, patient_id, provider_id, appointment_type (NEW_PATIENT, FOLLOW_UP, URGENT_CARE, TELEHEALTH), scheduled_start, scheduled_end, status (SCHEDULED, CONFIRMED, COMPLETED, CANCELLED, NO_SHOW), reason_for_visit, notes. Patient: patient_id, name, dob, insurance_member_id, insurance_plan_id, primary_care_provider_id. TimeOff: provider_id, start_datetime, end_datetime, reason (VACATION, CME, SICK).

Slot Availability Computation

Computing available slots: (1) Load the provider recurring schedule for the requested week. (2) Generate all possible slots: for each working day, iterate from start_time to end_time in slot_duration_minutes increments. (3) Remove slots blocked by TimeOff entries that overlap the slot window. (4) Remove slots occupied by existing SCHEDULED or CONFIRMED appointments. (5) Return remaining slots. Caching: cache slot availability per provider per day with a short TTL (30-60 seconds). Invalidate on new booking or cancellation. For high-traffic scenarios, pre-compute slot availability for the next 30 days and cache in Redis as a bitmap (each bit = one slot, 1=available, 0=taken).

Booking with Conflict Prevention

Race condition: two patients simultaneously book the last available slot. Prevention: optimistic locking or database-level serialization. Preferred approach: when inserting an appointment, check for conflicts with a conditional INSERT: INSERT INTO appointments (…) SELECT … WHERE NOT EXISTS (SELECT 1 FROM appointments WHERE provider_id=X AND scheduled_start=T AND status NOT IN (“CANCELLED”)). If the INSERT fails (conflict exists), return “slot no longer available.” This works because the database serializes concurrent INSERTs to the same provider/time slot. Alternative: use a slot_reservations table with a unique constraint on (provider_id, slot_datetime) as a mutex. Reserve the slot, then create the appointment, then release the slot reservation atomically.

Appointment Reminders

Automated reminders reduce no-show rates by 20-30%. Reminder schedule: 72 hours before (email), 24 hours before (SMS + email), 2 hours before (push notification for telehealth). Implementation: a scheduled job runs every 15 minutes, querying appointments in the upcoming reminder window. For each appointment in the window: check if the reminder was already sent (store reminder_sent_at per reminder type). Send via notification service. Mark as sent. Pre-confirmation: send a confirmation request 72 hours before. If the patient does not confirm within 24 hours: release the slot and notify the patient. This allows filling cancelled slots. Patient preferences: respect preferred reminder channel and opt-out settings.

Waitlist Management

When no slots are available, add the patient to a waitlist: (provider_id, patient_id, appointment_type, earliest_desired_date, created_at). When a cancellation occurs: query the waitlist for patients who want to see this provider, with appointment_type matching, and earliest_desired_date on or before the newly available slot date. Notify the first eligible patient by push notification with a time-limited claim window (2 hours). If they do not claim within 2 hours, notify the next patient. Continue until the slot is filled or the waitlist is exhausted. Priority: existing patients over new patients; urgent over routine; FIFO within the same priority tier.

EMR Integration

Electronic Medical Records (EMR) integration syncs appointment data with clinical systems (Epic, Cerner). Standards: HL7 FHIR (modern REST-based) and HL7 v2 (older message-based). On appointment creation: POST /fhir/Appointment to the EMR. On completion: update appointment status and trigger clinical note creation workflow. Patient demographics sync: on new patient registration, search the EMR for existing records (match on name + DOB + insurance ID). If found: link patient_id to EMR patient_id to avoid duplicate records. FHIR resources: Appointment, Patient, Practitioner, Slot, Schedule. Authentication: OAuth 2.0 SMART on FHIR standard. All PHI (protected health information) data must be encrypted in transit (TLS 1.2+) and at rest (AES-256) per HIPAA requirements.

{
“@context”: “https://schema.org”,
“@type”: “FAQPage”,
“mainEntity”: [
{
“@type”: “Question”,
“name”: “How do you prevent double-booking a provider slot?”,
“acceptedAnswer”: {
“@type”: “Answer”,
“text”: “The core protection is a conditional INSERT with a conflict check: INSERT INTO appointments (provider_id, scheduled_start, scheduled_end, …) SELECT … WHERE NOT EXISTS (SELECT 1 FROM appointments WHERE provider_id=X AND status NOT IN (‘CANCELLED’) AND scheduled_start start_time). The WHERE NOT EXISTS clause checks for any overlapping appointment. If two concurrent requests try to book the same slot, the database serializes them; the second INSERT sees the first appointment and fails. Return 409 Conflict to the second requester with the message ‘Slot no longer available.’ A unique partial index on (provider_id, scheduled_start) WHERE status != ‘CANCELLED’ enforces this at the database level more efficiently.”
}
},
{
“@type”: “Question”,
“name”: “How do appointment reminders reduce no-show rates?”,
“acceptedAnswer”: {
“@type”: “Answer”,
“text”: “Automated reminders reduce no-show rates by 20-30% in clinical settings. Multi-channel reminders at strategic intervals: 72 hours before (email — enough time to reschedule), 24 hours before (SMS — high open rate for day-before reminders), 2 hours before (push notification — especially for telehealth logins). Each reminder type is tracked separately (reminder_sent_at per type) to prevent duplicate sends. Confirmation requests: 72 hours before, ask the patient to confirm (reply YES to confirm, or click a link). If no confirmation within 48 hours: send a follow-up. If still unconfirmed 24 hours before: release the slot and move a waitlisted patient in. Tracking no-show rates by provider, appointment type, and reminder compliance enables continuous improvement.”
}
},
{
“@type”: “Question”,
“name”: “How do you compute available appointment slots efficiently?”,
“acceptedAnswer”: {
“@type”: “Answer”,
“text”: “Naive approach: generate all possible slots and subtract booked ones — correct but slow for high-traffic searches across many providers. Optimized approach: store provider schedules as recurring rules (day_of_week, start_time, end_time, slot_duration). Pre-compute slot availability for the next 30 days as a bitmap cached in Redis (one bit per slot, 1=available). On booking: flip the bit. On cancellation: flip it back. Cache TTL: 24 hours, rebuilt nightly by a batch job. For real-time accuracy: combine the bitmap (read from Redis) with a live DB query for slots modified in the last minute. Search UI: filter by specialty, insurance, date range, telehealth option — apply filters before computing slots to reduce the provider set.”
}
},
{
“@type”: “Question”,
“name”: “What HIPAA requirements apply to a healthcare appointment system?”,
“acceptedAnswer”: {
“@type”: “Answer”,
“text”: “HIPAA (Health Insurance Portability and Accountability Act) applies to any system storing or transmitting PHI (Protected Health Information). PHI includes: patient name, DOB, address, diagnosis, appointment reason, insurance information. Technical safeguards required: (1) Encryption in transit: TLS 1.2+ for all API calls and data transfers. (2) Encryption at rest: AES-256 for databases and backups. (3) Access controls: role-based access (RBAC) — receptionists see schedules, not clinical notes; providers see only their patients. (4) Audit logging: log every access to PHI with user_id, timestamp, action, and patient_id. (5) Minimum necessary: APIs return only the data needed for the task. Business Associate Agreements (BAAs) required with all third-party services handling PHI (AWS, Twilio, SendGrid).”
}
},
{
“@type”: “Question”,
“name”: “How does EMR integration work with FHIR standards?”,
“acceptedAnswer”: {
“@type”: “Answer”,
“text”: “FHIR (Fast Healthcare Interoperability Resources) is the modern standard for healthcare data exchange. FHIR resources relevant to scheduling: Patient, Practitioner, Schedule (provider working hours), Slot (individual bookable times), Appointment (booked slot). Integration flow: (1) When a new patient registers, search the EMR via GET /fhir/Patient?identifier=MRN-123 to check for existing records. (2) On appointment creation, POST /fhir/Appointment to the EMR to sync the booking. (3) On appointment status changes (COMPLETED, NO_SHOW), PATCH /fhir/Appointment/{id}. Authentication: OAuth 2.0 SMART on FHIR — the app registers with the EMR as an OAuth client and requests scopes like patient/*.read and appointment/*.write. FHIR subscriptions allow the EMR to push updates (lab results, new orders) back to the scheduling system.”
}
}
]
}

Asked at: Atlassian Interview Guide

Asked at: Shopify Interview Guide

Asked at: Stripe Interview Guide

Asked at: DoorDash Interview Guide

Scroll to Top