System Design Interview: Design a Healthcare Appointment Booking System

What Is a Healthcare Appointment Booking System?

A healthcare appointment booking system allows patients to schedule, reschedule, and cancel appointments with doctors, clinics, and hospitals. It must handle complex scheduling constraints (doctor availability, appointment duration, room availability), prevent double-booking, notify patients and providers, and integrate with electronic health records (EHR). Systems like Zocdoc, MyChart, and NHS Online serve millions of appointments daily.

  • DoorDash Interview Guide
  • LinkedIn Interview Guide
  • Shopify Interview Guide
  • Airbnb Interview Guide
  • Uber Interview Guide
  • Stripe Interview Guide
  • System Requirements

    Functional

    • Search for available appointment slots by specialty, location, insurance, and date
    • Book, reschedule, and cancel appointments
    • Prevent double-booking: one patient per slot, one slot per provider time window
    • Send reminders (email, SMS, push) 24 hours and 1 hour before appointments
    • Handle waitlists: notify waitlisted patients when slots open
    • Support telehealth appointments with video call link generation

    Non-Functional

    • No double-booking — correctness over latency
    • Search must be fast: available slots returned in <500ms
    • HIPAA compliance: all patient data encrypted at rest and in transit, audit logs
    • High availability: 99.9% — patients need to access their appointments 24/7

    Core Data Model

    providers: id, name, specialty, location_id, timezone
    provider_schedules: id, provider_id, day_of_week, start_time, end_time, slot_duration_min
    appointments: id, provider_id, patient_id, start_time, end_time, status,
                  type (in-person/telehealth), created_at
    slot_locks: id, provider_id, slot_start, locked_by_session, locked_until
    waitlist: id, provider_id, patient_id, specialty, preferred_dates, created_at
    

    Slot Generation and Availability

    Rather than storing every possible slot as a database row (which would be billions of rows), generate slots on-the-fly from provider schedules:

    1. Fetch provider’s schedule (e.g., Mon-Fri 9am-5pm, 30-min slots)
    2. Generate all theoretical slots in the requested date range
    3. Query booked appointments for that provider in the same range
    4. Subtract booked slots from theoretical slots → available slots

    Cache the available slots in Redis with a 60-second TTL per provider per date. This serves the high-frequency search traffic without repeated database calculations.

    Preventing Double-Booking — The Critical Problem

    Two patients could simultaneously view the same available slot and both attempt to book it. Without coordination, both bookings succeed — double-booking.

    Optimistic Locking Approach

    -- Attempt to insert appointment with uniqueness check
    INSERT INTO appointments (provider_id, start_time, patient_id, status)
    SELECT ?, ?, ?, 'confirmed'
    WHERE NOT EXISTS (
        SELECT 1 FROM appointments
        WHERE provider_id = ? AND start_time = ?
        AND status NOT IN ('cancelled')
    );
    -- If 0 rows inserted: slot taken, return error to patient
    

    The atomic SELECT + INSERT (or equivalent upsert with unique constraint on provider_id + start_time) prevents double-booking at the database level. Add a unique index on (provider_id, start_time, status != ‘cancelled’).

    Slot Locking for Better UX

    To prevent users from going through the entire booking flow only to fail at the end: temporarily lock the slot when the patient clicks “Book” and starts filling in details. Lock for 5 minutes with the patient’s session ID. On final confirmation, verify the lock still belongs to this session before committing the booking. On timeout or page close: release the lock. Redis is ideal for slot locks (TTL-based auto-release).

    Search Architecture

    Patients search: “cardiologist in NYC available next Tuesday, takes Blue Cross.” This involves filtering by:

    • Specialty and subspecialty
    • Geographic proximity (geohash-based radius search)
    • Insurance network (provider’s accepted insurances)
    • Date/time preference

    Use Elasticsearch for provider search (full-text specialty search + geolocation + insurance filtering). Pre-index provider profiles with their geohash, specialty tags, and insurance lists. The slot availability check runs against the PostgreSQL database for accurate real-time results — Elasticsearch only narrows the candidate provider set.

    Reminders and Notifications

    • When an appointment is booked: send immediate confirmation (email + SMS)
    • 24 hours before: reminder with appointment details and directions
    • 1 hour before: final reminder; include video call link for telehealth
    • Implementation: schedule reminder jobs in a delayed queue (Kafka with delayed delivery or a dedicated job scheduler). On appointment creation, enqueue two reminder tasks with fire times = appointment_time – 24h and appointment_time – 1h. If the appointment is cancelled, dequeue or mark the tasks as cancelled.

    Waitlist Management

    When a patient can’t find an available slot, add them to the waitlist. When an appointment is cancelled:

    1. Query waitlist for that provider and date range
    2. Rank waitlisted patients by priority (earliest request, severity)
    3. Send offer to top-ranked patient with a 30-minute claim window
    4. If not claimed, offer to the next patient

    Use a Kafka consumer for cancellation events → waitlist processor → notification service.

    HIPAA Compliance

    • Encrypt all PHI (Protected Health Information) at rest: AES-256 for database fields, S3 server-side encryption for files
    • Encrypt in transit: TLS 1.3 for all connections
    • Audit logging: every read/write of patient data logged to an immutable audit trail (write-once S3 or append-only Postgres table)
    • Access control: RBAC — patients see only their own records; providers see only their patients; admins have audit-only access
    • Data retention: appointment records retained per regulatory requirements (typically 7-10 years)

    Telehealth Integration

    For telehealth appointments: generate a unique video room when the appointment is confirmed. Use Twilio Video, Zoom SDK, or Daily.co API. The room link is valid from 5 minutes before to 1 hour after the appointment. Include the link in reminder notifications. No client software needed — browser-based WebRTC.

    Interview Tips

    • Double-booking prevention is the core problem — lead with the unique constraint approach.
    • Slot generation on-the-fly (vs. pre-materialized slots) is a key design decision — explain the trade-offs.
    • HIPAA mentions show domain awareness. You don’t need deep HIPAA knowledge — just encryption at rest/transit and audit logs.
    • Waitlist management is a differentiator that shows you think about edge cases and user experience.

    {
    “@context”: “https://schema.org”,
    “@type”: “FAQPage”,
    “mainEntity”: [
    {
    “@type”: “Question”,
    “name”: “How do you prevent double-booking in a medical appointment system?”,
    “acceptedAnswer”: { “@type”: “Answer”, “text”: “Double-booking prevention requires an atomic check-and-insert at the database level. Add a unique constraint on (provider_id, start_time) with a partial index excluding cancelled appointments. On booking, use: INSERT INTO appointments (…) SELECT … WHERE NOT EXISTS (SELECT 1 FROM appointments WHERE provider_id=? AND start_time=? AND status!='cancelled'). If 0 rows are inserted, the slot was already taken — return an error. For better user experience, add a slot locking layer: when a patient clicks "Book," temporarily lock the slot in Redis with their session ID and a 5-minute TTL. Show the slot as "hold" to other users during this window. On final confirmation, verify the Redis lock belongs to this session before committing the database insert. On timeout or navigation away, the TTL auto-releases the lock.” }
    },
    {
    “@type”: “Question”,
    “name”: “How do you efficiently generate and serve available appointment slots?”,
    “acceptedAnswer”: { “@type”: “Answer”, “text”: “Pre-materializing every possible slot as a database row is impractical — a single doctor with 30-minute slots working 5 days a week for a year generates ~2600 rows, and with thousands of doctors this scales poorly. Instead, generate slots on-the-fly: (1) Fetch the provider's weekly schedule (e.g., Mon-Fri 9am-5pm, 30-min slots from the provider_schedules table), (2) Generate all theoretical slots in the requested date range in memory, (3) Query booked appointments for that provider in the same range, (4) Subtract booked from theoretical to get available. Cache the result in Redis with a 60-second TTL, keyed by provider_id + date. This serves search traffic from cache without repeated calculations. Invalidate the cache key when an appointment is booked or cancelled for that provider and date.” }
    },
    {
    “@type”: “Question”,
    “name”: “What are the key HIPAA technical safeguards for a healthcare system?”,
    “acceptedAnswer”: { “@type”: “Answer”, “text”: “HIPAA Technical Safeguards require: (1) Access controls — role-based access control (RBAC) where patients see only their own records, providers see only their patients, no cross-patient data leakage. Implement with row-level security in PostgreSQL or application-level filtering. (2) Encryption at rest — AES-256 for all PHI in databases, S3 server-side encryption for files and attachments. Store encryption keys in a KMS (AWS KMS, HashiCorp Vault), never hardcoded. (3) Encryption in transit — TLS 1.3 for all connections, including internal service-to-service calls. (4) Audit controls — immutable audit log of every PHI access (who read or wrote what, and when). Use an append-only audit table or write-once S3 bucket. (5) Automatic logoff — session tokens expire after inactivity. For interviews, mentioning these four pillars (access control, encryption at rest, encryption in transit, audit logging) demonstrates sufficient HIPAA awareness.” }
    }
    ]
    }

    Scroll to Top