Interview Scheduling System Low-Level Design: Availability Matching, Calendar Integration, and Reminder Pipeline

Interview Scheduling System Low-Level Design

An interview scheduling system matches candidate time preferences against interviewer availability, handles calendar integration, prevents double-booking, and drives an automated reminder pipeline. This LLD covers the core data model and algorithms.

Slot Model

Interviewer availability is stored as discrete slots:

availability_slots:
  id, interviewer_id, start_time (UTC), end_time (UTC),
  timezone, status: AVAILABLE|BOOKED|BLOCKED,
  candidate_id (nullable), interview_id (nullable)

Slots are generated in advance from recurring availability rules (e.g., every Tuesday/Thursday 10am-5pm in 30-min increments). Interviewers can also add or remove individual slots.

Candidate Preferences

When a candidate is invited to schedule, they submit a preference object: preferred date range, list of acceptable time windows per weekday, and their IANA timezone. The system stores these and uses them in the matching algorithm.

Matching Algorithm

  1. Convert candidate's preferred windows to UTC ranges for the date range.
  2. Query availability_slots where interviewer_id IN (panel_ids), status = AVAILABLE, and start_time falls within the UTC ranges.
  3. For panel interviews: compute set intersection — only slots where all required interviewers are simultaneously available.
  4. Score each candidate slot by alignment with the candidate's stated preference (morning preference, specific days) and interviewer preference weight.
  5. Return top 3 scored options to the candidate for selection.

Calendar Integration

Each interviewer connects their calendar via OAuth2 (Google Calendar or Outlook). The system stores the access_token and refresh_token encrypted in the DB. On slot generation and conflict detection, the system calls the calendar API to read the interviewer's existing events. On booking, it writes the interview as a calendar event for all participants. Calendar webhooks or periodic polling keep the system aware of events added outside the tool.

Conflict Detection

When the candidate selects a slot, before confirming:

  1. Fetch all calendar events for each interviewer in the selected time window.
  2. Check for any overlap with the proposed interview time.
  3. If conflict detected, invalidate that slot and re-run matching to find an alternative.

Double-Booking Prevention

The slot is atomically claimed using a conditional SQL update:

UPDATE availability_slots
SET status = 'BOOKED', candidate_id = ?, interview_id = ?
WHERE id = ? AND status = 'AVAILABLE';

If the affected row count is 0, another candidate claimed the slot concurrently. The UI presents the next available option. This is a compare-and-swap without a separate lock, avoiding deadlocks.

Timezone Handling

All start_time and end_time values are stored in UTC. Display converts to the user's timezone using the IANA timezone database (e.g., America/New_York). The system never stores local times — only UTC plus an IANA timezone label for human display and recurring rule expansion.

Reminder Pipeline

A scheduler job runs every minute and checks upcoming interviews. Reminders are sent at T-24h, T-1h, and T-15min. Before sending each reminder, the system checks the interview's current status — if cancelled or rescheduled, the reminder is skipped. Reminder delivery uses an async queue (SQS/Kafka) feeding an email/SMS service to decouple scheduling from delivery.

Rescheduling Flow

  1. Candidate or interviewer requests reschedule via link in confirmation email.
  2. Current slot is released: status → AVAILABLE, candidate_id → NULL.
  3. Booked calendar event is deleted via calendar API.
  4. Matching algorithm re-runs with the same panel and candidate preferences.
  5. Candidate selects a new slot; booking and calendar write repeat.

Cancellation Handling

On cancellation: slot is released, all parties receive a cancellation email, the calendar event is deleted, and a reschedule prompt is sent to the recruiter. Cancellations within 1 hour of the interview are flagged for reporting (interviewer reliability metrics).

Interviewer Panel Coordination

For a panel interview with N interviewers, the available slots are computed as a set intersection of each interviewer's available slots for the given time window. This is implemented as a SQL query with N JOINs or as an in-memory intersection of slot ID sets, depending on panel size. Typically panels are 2-4 people, making the in-memory approach practical.

Feedback Reminder

After end_time passes, a scheduler job detects completed interviews and sends a feedback form link to each interviewer. Feedback submission deadline is 24 hours post-interview. Non-submission triggers a follow-up reminder at T+24h and escalates to the recruiter at T+48h.

{
“@context”: “https://schema.org”,
“@type”: “FAQPage”,
“mainEntity”: [
{
“@type”: “Question”,
“name”: “How do you design an availability matching algorithm for interview scheduling across multiple time zones?”,
“acceptedAnswer”: {
“@type”: “Answer”,
“text”: “Store all availability windows in UTC internally and convert to local time only at the display layer. Model each participant's availability as a sorted list of UTC intervals. To find mutual free slots, run a merge-interval intersection across all participant lists in O(n log n) time. Use a segment tree or interval tree when you need to handle frequent availability updates without recomputing the full intersection. For cross-timezone UX, always surface times in the viewer's local timezone and show the interviewer's timezone as secondary context to avoid confusion.”
}
},
{
“@type”: “Question”,
“name”: “How would you integrate Google Calendar or Outlook Calendar into a scheduling service without creating tight coupling?”,
“acceptedAnswer”: {
“@type”: “Answer”,
“text”: “Introduce a CalendarProvider interface with methods like getFreeSlots(userId, range), createEvent(eventDetails), and deleteEvent(eventId). Implement a GoogleCalendarAdapter and OutlookCalendarAdapter behind this interface using their respective REST APIs (Google Calendar API v3, Microsoft Graph API). Use OAuth 2.0 with token refresh logic encapsulated inside each adapter. Store provider type and encrypted refresh tokens per user in your database. This lets you add new providers or swap implementations without touching scheduling business logic. Use an async job queue (e.g., Kafka or SQS) to sync calendar state rather than doing it inline on booking requests, improving reliability and decoupling write latency.”
}
},
{
“@type”: “Question”,
“name”: “How do you design the reminder pipeline for an interview scheduling system to ensure reliability and avoid duplicate notifications?”,
“acceptedAnswer”: {
“@type”: “Answer”,
“text”: “Model reminders as durable scheduled jobs stored in a database with columns: interview_id, reminder_type (24h, 1h, 15min), send_at (UTC), status (pending/sent/failed), and idempotency_key. A worker polls for jobs where send_at <= NOW() AND status = 'pending', claims them with an optimistic lock (UPDATE … WHERE status='pending' RETURNING id), then dispatches via email/SMS/push through a notification service. Use the idempotency_key when calling downstream providers to handle retries safely. For scale, partition the jobs table by send_at date and use a distributed scheduler (e.g., Quartz, Celery Beat, or a Temporal workflow) instead of polling, which eliminates thundering-herd problems around popular interview slots."
}
},
{
"@type": "Question",
"name": "How would you handle double-booking prevention in a high-concurrency interview scheduling system?",
"acceptedAnswer": {
"@type": "Answer",
"text": "Use optimistic locking with a version column on the interviewer's availability record. When a candidate books a slot, read the availability row and its version, then issue an UPDATE … WHERE version = :read_version AND slot_status = 'available'. If zero rows are affected, another request won the race and you return a conflict error to the client. For higher throughput, shard availability by interviewer_id and use Redis with a Lua script to atomically check-and-reserve a slot (GET + conditional SET in a single atomic operation), treating the database as the source of truth and Redis as a fast gate. Always include a slot expiry (e.g., 10-minute hold) so abandoned booking attempts release capacity automatically."
}
}
]
}

See also: Netflix Interview Guide 2026: Streaming Architecture, Recommendation Systems, and Engineering Excellence

See also: Atlassian Interview Guide

See also: LinkedIn Interview Guide 2026: Social Graph Engineering, Feed Ranking, and Professional Network Scale

Scroll to Top