Design Google Calendar — System Design Interview Practice
Design a calendar application that allows users to create, manage, and share events and appointments. Work through the requirements, architecture trade-offs, and an interactive design review.
Concepts and architecture decisions to consider
- productivityConcept to explore
- schedulingConcept to explore
- calendarConcept to explore
Interview prompt
Design events, recurring schedules, invitations, reminders, and shared calendars so users can create or update a calendar event reliably at scale.
- Define the source of truth for event versions and attendee responses and make retries idempotent.
- Use bounded, partitioned state to meet 100M users and 1B events with recurring expansions and p95 <=150ms event reads.
- Separate the critical request path from reminders, recurrence expansion, sync, and search indexing.
- Explain consistency, failure recovery, authorization, observability, and a degraded mode.
Requirements and scale assumptions
- Support the core workflow to create or update a calendar event.
- Expose status, results, and freshness appropriate to events, recurring schedules, invitations, reminders, and shared calendars.
- Support authorization, validation, updates, deletion, and recovery semantics.
- Meet p95 <=150ms event reads under normal load.
- Scale to 100M users and 1B events with recurring expansions without a single hot key or unbounded synchronous work.
- Do not lose committed state; make retries and duplicate events safe.
- Degrade safely when downstream workers, caches, or external dependencies fail.
- 100M users and 1B events with recurring expansions
- Partition by the primary tenant, user, item, or geographic key and isolate hot partitions.
- Keep serving state bounded; retain raw events or durable records for replay and auditing.
- Peak scale: 100M users — Capacity assumption that drives partitioning and backpressure.
- Latency target: p95 <=150ms event reads — User-facing budget for the primary request or read path.
- Durable boundary: Committed before async — The source of truth is event versions and attendee responses.
- Async boundary: At-least-once workers — Keep reminders, recurrence expansion, sync, and search indexing off the synchronous path.
Key entities
- CalendarEventeventId, calendarId, organizerId, startAt, endAt, timezone, version
Versioned event with recurrence, attendee, and timezone semantics for google calendar.
- RecurrenceRuleeventId, rrule, timezone, exceptions, effectiveAt
Expansion rule and exceptions used to derive recurring google calendar instances.
- AttendeeResponseeventId, attendeeId, response, sequence, updatedAt
Idempotent attendee invitation and RSVP state.
- SyncCursorprincipalId, calendarId, token, version, expiresAt
Incremental sync position for reconnecting clients.
Data flow
- 1. Validate timezone and calendar policyThe API checks google calendar ACLs, recurrence limits, attendee permissions, timezone rules, and idempotency before writing.
- 2. Commit an event versionThe calendar service conditionally writes the event, recurrence exceptions, attendee sequence, and tombstones.
- 3. Expand ranges and remindersWorkers materialize bounded google calendar instances, free/busy intervals, and reminder jobs from committed versions.
- 4. Fan out invitations and sync deltasInvitation, RSVP, and incremental sync consumers process the event with deduplication and cursor ordering.
- 5. Recover missed jobs and conflictsRepair workers replay events, report stale projections, and preserve conflict evidence rather than overwriting edits.
Deep dives and trade-offs
- Timezone, recurrence, and exceptionsStore UTC instants plus the original timezone and recurrence rule; expand with a pinned timezone database version. Model exception and cancellation instances explicitly so a single edit does not rewrite the series ambiguously. Bound expansion windows and schedule future reminders from durable recurrence state.
- Concurrent edits and invitationsUse event version and attendee sequence checks to reject or merge stale edits deterministically. Separate organizer truth from attendee response state and make notification jobs idempotent. Return conflicts and current version so offline clients can reconcile instead of silently losing changes.
- Sync and reminder reliabilityIssue versioned sync cursors with snapshot fallback when a client is too far behind. Track reminder schedule, delivery attempts, and provider receipt independently from event commit. Measure range freshness, conflict rate, missed reminders, and duplicate notifications.
- Materialized recurrence versus query-time expansionMaterialize bounded near-term instances and expand long-range views asynchronously from the rule. Expanding every recurring series on every read creates unpredictable latency and duplicate reminder risk.
- Strong range reads versus projection freshnessServe indexed ranges with a visible version and fall back to authoritative state for narrow critical reads. Hiding stale free/busy data can cause double booking or missed meeting conflicts.
- Push sync versus cursor pullUse push as a wake-up signal and cursor pull as the correctness path for offline and reconnect recovery. Push-only sync loses changes when a device sleeps or changes networks.