CASE STUDY

Calendar Service (Google Calendar)

6 min read·1,070 words·Intermediate

How to use this case study

SDE-2 / Mid

Explain the event and attendee tables, how recurring events are stored as rules, and how a week view is loaded.

SDE-3 / Senior

Go deeper on expanding recurrences with exceptions, time zones, finding free slots and conflicts, invitation fan-out, and the reminder scheduler.

Staff / Principal

Discuss multi-device sync, very large meetings, room booking without double booking, and global deployment with users in many time zones.


0) Problem Restatement

Design a calendar service like Google Calendar. Users create events, invite others, and see their schedule in day, week and month views. Events can repeat ("every Monday at 10 AM"), attendees can accept or decline, and users get reminders before events start. People live in different time zones, and they use the calendar on several devices that must stay in sync. A common variant asks for a meeting scheduler that finds free times and prevents double-booking of rooms.

Asked at: Flipkart, Google, LinkedIn, OpenAI, Snowflake, Uber — 8 candidate reports between Nov 2025 and Aug 2026.

1) Requirements

1.1 Functional

  • Create, edit and delete events (one-time and recurring).
  • Invite attendees. They receive invites and can respond (accept, decline, maybe).
  • View a date range (a week, a month) quickly.
  • Detect conflicts and suggest free slots for a group.
  • Reminders (e.g., 10 minutes before).
  • Share calendars (view or edit access).

1.2 Non-Functional

  • Read-heavy: people open the calendar far more often than they change it.
  • Correct times across time zones and daylight saving changes.
  • Sync across devices within a few seconds.
  • Reliable reminders: they should fire on time and only once.

1.3 Scale Estimates

  • 500 million users, 100M daily active.
  • Each user creates ~2 events/day → 200M events/day ≈ 2,300 writes/sec.
  • Views: 10 opens per user per day → 1B range queries/day ≈ 12K/sec.
  • Storage: ~1 KB per event → 200 GB/day before replication.

1.4 API Design

  • POST /v1/events with { title, start, end, timezone, rrule?, attendees[], reminders[] }
  • GET /v1/calendars/{id}/events?from=2026-09-21&to=2026-09-28
  • PATCH /v1/events/{id}?scope=this|following|all (edit one occurrence of a recurring event, or all of them)
  • POST /v1/events/{id}/respond with { status: accepted }
  • POST /v1/freebusy with { users[], from, to } → busy blocks for each user


2) High-Level Architecture

2.1 Overview

  • Event Service: create, edit, delete and view events.
  • Event DB: stores events and attendees (sharded by calendar ID).
  • Invite Service: when an event has attendees, it adds the event to each attendee's calendar and sends emails or notifications.
  • Free/Busy Service: answers "when are these people busy?" from a compact busy-time index.
  • Reminder Scheduler: fires reminders at the right time (a delayed job queue).
  • Sync Service: pushes changes to the user's other devices.

2.2 Architecture Diagram

Architecture Diagram

flowchart LR
    C["Web / Mobile clients"] --> API["API Gateway"]
    API --> ES["Event Service"]
    ES --> DB[("Event DB - sharded by calendar")]
    ES --> K[("Change events - Kafka")]
    K --> INV["Invite Service"]
    K --> FB["Free/Busy indexer"]
    K --> REM["Reminder Scheduler"]
    K --> SYNC["Sync / Push Service"]
    INV --> DB
    FB --> FBS[("Busy-time index")]
    REM --> N["Notifications"]
    SYNC --> C

3) Data Model

CREATE TABLE events (
  event_id     UUID PRIMARY KEY,
  calendar_id  UUID,            -- owner calendar
  title        TEXT,
  start_utc    TIMESTAMP,       -- first occurrence start, stored in UTC
  end_utc      TIMESTAMP,
  timezone     TEXT,            -- e.g. "America/New_York", needed for recurrence
  rrule        TEXT,            -- e.g. "FREQ=WEEKLY;BYDAY=MO", NULL if one-time
  recur_until  TIMESTAMP,       -- last possible occurrence (or far future)
  version      INT
);
CREATE TABLE event_exceptions (   -- one changed or cancelled occurrence
  event_id UUID, original_start_utc TIMESTAMP, new_start_utc TIMESTAMP,
  new_end_utc TIMESTAMP, cancelled BOOLEAN
);
CREATE TABLE attendees (
  event_id UUID, user_id UUID, response TEXT,  -- accepted, declined, tentative
  PRIMARY KEY (event_id, user_id)
);
CREATE INDEX ON events (calendar_id, start_utc);

4) Recurring Events (the key idea)

We do not create one row per occurrence. "Every Monday forever" would be infinite. Instead:

  • Store the rule (an RRULE, the standard iCalendar format) plus the time zone.
  • When someone views a week, load events whose range overlaps the week (start_utc <= week_end AND recur_until >= week_start), then expand each rule into concrete times for that week only.
  • Apply exceptions: "this Monday moved to Tuesday" or "cancelled on Dec 25".
  • Editing "this and following" splits the series: end the old rule at that date and create a new rule starting from it.

Why store the time zone? "10 AM every Monday in New York" must stay at 10 AM local time even when daylight saving time changes. Expanding in the event's own time zone (then converting to UTC) keeps it correct.

5) Key Flows

5.1 Creating a meeting with attendees

  1. Save the event in the organizer's calendar.
  2. Publish a change event. The Invite Service links the event into each attendee's calendar (a row pointing to the same event_id) and sends invites.
  3. The Free/Busy indexer updates each attendee's busy blocks.
  4. The Reminder Scheduler schedules reminders for the next occurrence.

5.2 Finding a free slot

  1. Get busy blocks for all attendees in the range from the Free/Busy index. It stores only start/end pairs, with no titles, which also protects privacy.
  2. Merge all busy intervals (sort by start and combine overlaps), then return the gaps that are long enough and fall inside working hours.


6) Deep Dive — Reminders, rooms and sync

  • Reminders: store the next reminder time per event and user in a delayed queue (a Redis sorted set by time, or a job scheduler). A worker fires due reminders. For recurring events, it then schedules the next occurrence's reminder. Use an idempotency key (event, occurrence, user) so a reminder never fires twice.
  • Room booking without double booking: treat each room as a calendar. Booking uses a transaction that checks for overlapping bookings of that room and inserts in the same step, e.g., a database exclusion constraint on the time range, or a lock on the room.
  • Multi-device sync: every change bumps a per-calendar sync token (a sequence number). Devices ask "what changed since token 5812?" and get only the differences. A push notification tells devices to sync right away.
  • Huge meetings (all-company events with 50K attendees): don't copy the event into 50K calendars. Store it once and have attendees reference it, then send invites asynchronously in batches.


7) Trade-offs & Alternatives

DecisionChoiceWhyAlternative
Recurring eventsStore rule + expand on readSmall storage, easy series editsStore every occurrence: simple queries, huge and hard to edit
Time storageUTC + original time zoneCorrect across DSTLocal time only: breaks for travelers and DST
Free/busySeparate busy-time indexFast group queries, privateScan full events: slower, leaks details
Device syncSync tokens + pushOnly sends changesFull reload: simple but wasteful

8) Common Follow-up Questions

  • "How do you show a month view fast?" Cache expanded occurrences per calendar per month, and invalidate when an event in that calendar changes.
  • "External invites (other providers)?" Send standard iCalendar (.ics) emails and accept replies by email.
  • "Privacy?" Shared calendars can be "free/busy only", "see details" or "edit". Check this on every read.


9) Wrap-Up

Store events in UTC with their time zone, keep recurring events as rules with exceptions, and expand them only for the range being viewed. Use change events to drive invites, a free/busy index, reminders and device sync. Prevent room double-booking with a transactional overlap check, and keep sync efficient with sync tokens.

More Case Studies

Practice with a Mock Interview

Apply what you learned in a live system design mock interview with our AI interviewer.

Start System Design Interview →