Design of Google Calendar
The design of a system akin to Google Calendar encompasses event management, sharing, synchronization, and reminders, with an AI assistant for scheduling. The architecture separates event persistence from synchronization, ensuring durable updates and asynchronous processing of invitations. Key components include an API gateway for request handling, a transactional outbox for reliable event publication, and a robust data model for managing events and recurrence rules. The system employs mechanisms like idempotency keys and version checks to maintain data integrity, while AI features facilitate natural language scheduling, ensuring user confirmation before event creation.
We'll cover the following...
In this lesson, we will design a system similar to Google Calendar that supports event management, calendar sharing, recurring events, synchronization, and reminders. We will also integrate an AI assistant that suggests available meeting times. This is a proposed architecture and does not represent Google’s actual internal implementation.
High-level design
The architecture separates event persistence from event synchronization and notification delivery. The system acknowledges an event update only after the change is durably persisted. Invitation emails and attendee synchronization are processed asynchronously after the write succeeds.
Client requests pass through a load balancer to an API gateway. The gateway authenticates callers, validates incoming requests, enforces rate limits, and routes requests to the appropriate services. The receiving service performs resource-level authorization to verify that the caller has permission to perform the requested operation.
Each event update writes the event record and a corresponding outbox entry within the same database transaction. An outbox relay publishes events from committed outbox entries to a publish-subscribe (pub/sub) system. Background workers consume these events to update attendee calendar views, generate synchronization updates, and schedule notifications. The notification service creates reminder jobs, which a task scheduler dispatches at their scheduled times.
If the service crashes right after the commit, the outbox entry is still there for the relay to publish, so no committed change is lost downstream. A successful response therefore means the event and its outbox entry are committed, while attendee updates and invitations continue asynchronously with retries.
Detailed design
Each type of state has exactly one owner. The event service owns events, recurrence rules, occurrence exceptions, attendees, and RSVPs. The calendar and sharing service owns calendars and access rules. Invitation, sync, and notification components only consume committed changes; they never become a separate source of truth.
These are logical boundaries. Several components can share a deployment until their workloads need to scale independently.
Service responsibilities
The following table summarizes each component’s responsibility. For example, an RSVP is committed by the event service; the invitation worker only updates projections and arranges delivery.
Component | Main Responsibility |
Event service | Manage events, recurring series, exceptions, attendee membership, RSVPs, and permitted availability queries |
Calendar and sharing service | Manage calendars, ACLs, sharing relationships, and visibility rules |
Invitation worker | Maintain attendee projections and request invitation or update delivery |
Sync service | Build and serve incremental changes, issue sync tokens, and support recovery |
Notification service | Maintain delivery state, schedule reminders, and send email and push notifications |
Task scheduler | Release reminder jobs when their due times are reached |
Conversational AI service | Interpret user input and produce validated scheduling intent |
Scheduling service | Compute feasible meeting intervals and rank candidate times |
API design
Clients call these APIs through the API gateway. Every mutating call carries an idempotency key so retries are safe, and every update or deletion carries the version the client last read, so concurrent edits are detected instead of overwritten.
Create event: Creates a one-time or recurring event on a calendar and returns the committed event, including its event_id and version.
createEvent(calendar_id, event_details, recurrence_rule, attendees, reminders, idempotency_key)
Update and delete event: Modify or cancel an event. For a recurring event, scope selects this occurrence, this and following occurrences, or the entire series, and original_start identifies the occurrence being changed.
updateEvent(event_id, changes, scope, original_start, base_version, idempotency_key)deleteEvent(event_id, scope, original_start, base_version, idempotency_key)
Respond to invitation: Records an attendee’s RSVP for an event or a single occurrence.
respondToEvent(event_id, original_start, response_status)
List events: Returns the events from the selected calendars that overlap a time window, with recurring series expanded and fields filtered by the caller’s permissions. The optional min_version lets a client that just wrote an event avoid reading an older cached result.
listEvents(calendar_ids, time_min, time_max, time_zone, page_token, min_version)
Sync changes: ...