Overview
A scheduling system that lets a distributed services team take bookings across many practitioners without ever double-booking, mis-handling a timezone, or duplicating an appointment on a retry — with Google Calendar as the single source of truth.
What was built
A booking platform layered directly on Google Workspace. Clients pick a slot from computed availability; the platform reserves, verifies and confirms the appointment as a single idempotent transaction, writing the event to the practitioner's Google Calendar and notifying both sides. There is no separate database of record — the calendar the team already lives in stays authoritative.
Who it's for
A services business running several practitioners, each with their own working hours, buffers and time off, taking bookings from a web form, email, and the occasional phone call entered after the fact.
Business context
The manual process it replaced was losing roughly a slot a week to double-books and timezone slips — small in count, expensive in trust. The platform's job was to make the calendar authoritative and booking safe, without adding a second system that would drift out of sync.
Architecture
A thin, stateless coordinator in front of Google Calendar. A booking is a short, idempotent transaction — reserve, verify, confirm — routed through a per-practitioner queue so the race that causes double-booking cannot occur.
Why a queue per practitioner
Double-booking is a race between concurrent writers for one resource. Rather than reach for distributed locks, every request for a given practitioner runs through a single-consumer FIFO queue — a boring, debuggable primitive that makes the race impossible instead of merely recoverable. Concurrency across practitioners stays high; within one practitioner it drops to one.
Components
The platform is built from nine components. Each is documented as its own engineering section — why it exists, its architecture, the constraints and edge cases it handles, the tradeoffs taken, and the final implementation. Expand any to read it.
›C1Multi-step booking flow
- Why it exists
- Turns "find a time" into a guided, resumable sequence — service → practitioner → date → slot → details → confirm — that never presents a slot it can't honor.
- Architecture
- A stateless client driven by the availability engine; each step re-validates against live free/busy so a slot that fills mid-flow is caught before submission.
- Constraints
- Must work from a web form, an email link, and a manually-keyed phone booking; no step may rely on the client's device clock.
- Edge cases
- Slot taken between display and submit; back-button re-submission; a practitioner going on leave mid-session.
- Tradeoffs
- Re-validating each step costs an extra free/busy read but eliminates the "the slot you picked is gone" failure at confirm.
›C2Availability engine
- Why it exists
- Computes bookable windows per practitioner from working hours, buffers, existing events and time off — the read model the whole flow renders from.
- Architecture
- Precomputes windows on a schedule and on calendar-change webhooks, caching them in Firestore; the flow reads the cache, not the Calendar API, on the hot path.
- Constraints
- Must stay correct as practitioners edit their own calendars directly; must not exceed Calendar read quota under load.
- Edge cases
- Overlapping events, all-day blocks, recurring holds, and DST boundaries where a "9am" window shifts.
- Tradeoffs
- A short cache TTL trades a few seconds of staleness for a large drop in API calls; the confirm step is the authority, so brief staleness is safe.
›C3Booking API (reserve · verify · confirm)
- Why it exists
- The transactional core: turns a request into exactly one calendar event, safely, even under concurrency and retries.
- Architecture
- Every request for a practitioner runs through that practitioner's single-consumer FIFO queue;
confirm()checks free/busy inside that window and writes with a content-addressed idempotency key. - API contract
POST /booking → 201 {eventId} | 409 SlotTaken // idempotent: same intent ⇒ same eventId key = sha256(practitionerId, startUTC, clientId)
- Edge cases
- Concurrent requests for one slot (serialized away); form/network retries (collapse to one event via the ledger); partial failure after insert (ledger commit makes it replay-safe).
- Tradeoffs
- Per-practitioner serialization adds a few ms of latency and removes the race by construction — chosen over distributed locks.
›C4Google Calendar integration
- Why it exists
- Keeps Google Calendar as the source of truth — reading free/busy and writing events — so the team never leaves the tool they already use.
- Architecture
- Uses the aggregate
freebusyquery for availability (no event detail) andevents.insertfor writes, tagging each event with its booking key in private extended properties. - Constraints
- Per-minute read quotas; least-privilege scopes; must survive practitioners editing events by hand.
- Edge cases
- Manually-deleted events, external calendar shares, and reconciliation when the calendar and ledger disagree.
›C5Time-zone handling
- Why it exists
- Guarantees a slot means the same instant to client, practitioner and server across daylight-saving changes.
- Architecture
- Stores the instant in UTC and the user's intended IANA zone as a separate field; the two recombine only at render.
- Edge cases
- Spring-forward/fall-back gaps, zones that observe DST on different dates, and clients changing their device zone after booking.
- Tradeoffs
- Carrying an explicit zone is more to store than a bare timestamp, but it is the only way to preserve the promise "9am in Lisbon."
›C6Authentication & permissions
- Why it exists
- Lets the platform act on the domain's calendars with the least authority a security team will sign off on.
- Architecture
- A dedicated service account with narrowly-scoped domain-wide delegation; every account traces to an owner and a decision record.
- Constraints
- No broad scopes; keys rotated on a schedule; access reviewed on a calendar, not on memory.
- Tradeoffs
- Least-privilege means more configuration up front in exchange for a model that passes review without exceptions.
›C7Notifications
- Why it exists
- Confirms, reminds and cancels for both client and practitioner without ever sending twice.
- Architecture
- At-least-once delivery via Cloud Tasks with idempotency keys and a dead-letter queue, so a retry never double-sends.
- Edge cases
- Provider throttling, bounced addresses, and a booking cancelled before its reminder fires.
›C8Google Meet generation
- Why it exists
- Attaches a working video link to every remote booking at the moment the event is created.
- Architecture
- Requests conference data on
events.insertso the Meet link is part of the same atomic write as the booking. - Edge cases
- Conference-creation failures (the booking must still succeed) and rescheduled events keeping their link.
›C9Google Sheets reporting
- Why it exists
- Gives the operator a familiar, live view of bookings and load without a bespoke dashboard.
- Architecture
- Append-only sync from the ledger into a Sheet, treated as a read replica — never a source of truth.
- Tradeoffs
- A Sheet is limited and slightly delayed, but it is instantly legible to a non-engineer, which is the point.
Visual Output
What the system actually produces for the customer and the operator. These are exhibits from the running system — each captioned and cross-linked to the component that creates it. Drop the real screenshots into the frames.
The booking flow
The three-step customer journey: service & timing → contact details → date and time → confirmation. Each step re-validates against live availability.

Real screenshot from the running systemComponent: Multi-step booking flow
The lead record
Where the contact step's answers land: a row appended to the Google Sheet — name, company, work email, source and submission timestamp. Use anonymized or sample data.

Real screenshot · sample / anonymized dataComponent: Google Sheets reporting
Calendar event created
The booking API writes directly to the practitioner's Google Calendar — title, time, timezone, both attendees, a Google Meet link, and the intake context in the description. Proof the system creates a native calendar artifact, not a private database row.

Customer invitation & confirmation
What the customer receives — the Google Calendar invitation and confirmation, with meeting details and the Meet link.

Real screenshot · redact recipient detailsComponent: Notifications · Google Meet generation
Internal notification
What the team sees when a booking lands — the internal notification with the captured qualification context and source workflow.
Real screenshot · anonymizedComponent: Notifications
Failure & recovery
The states that prove production thinking: a slot taken between display and submit, and the successful retry that follows. Left: conflict. Right: recovery.
Impact
Objective outcomes that resulted from putting the platform into production — evidence, not marketing.
- Business
- Replaced a Calendly-plus-Zapier scheduling stack with one owned system.
- Removed the recurring third-party subscription cost and the glue connecting the tools.
- Customer
- Immediate, reliable confirmation at the moment of booking.
- Fewer scheduling failures — no offered slot that can't be honored.
- Operations
- Duplicate bookings eliminated.
- Timezone handling automated end-to-end.
- Manual calendar entry removed from the team's day.
- Engineering
- A single source of truth — no parallel booking database to drift.
- Retry-safe, idempotent writes; fewer moving parts to operate.
- Scale
- ~4,000 bookings / month.
- Zero double-books since the v2 serialization landed.
Technical Documents
Chronological engineering records written while building the platform — the decisions, dead ends and incidents as they happened. Newest first.
Case Study
A retrospective on the platform from the business perspective — why it exists, the approach taken, and how it turned out.
- Problem
- A services team ran its calendar by hand and lost about one slot a week to double-books and timezone errors — cheap to count, expensive in client trust.
- Goal
- Make the calendar authoritative and booking safe, operable by one person, without a second system of record.
- Constraints
- Google Calendar stays the source of truth; least-privilege security; correct under concurrency and retries; within Calendar API quotas.
- Approach
- A thin, stateless coordinator in front of the Calendar API; per-practitioner serialization to remove the race; content-addressed idempotency to remove duplicates; UTC-plus-intent for time.
- Architecture
- Intake → edge validation → per-practitioner FIFO queue → reserve/verify/confirm coordinator → Google Calendar, with a small idempotency ledger. No parallel booking database.
- Tradeoffs
- Chose a boring, provably-correct queue over distributed locks; accepted seconds of availability staleness for a large quota saving; kept state in the platform that already owns it.
- Outcome
- In production since Feb 2024, ~4,000 bookings/month, zero double-books since the v2 serialization landed; "did my booking go through?" became a non-event because retries are safe.
- Lessons
- Serialize the contended resource; don't lock the world.
- Idempotency is a feature, not a safeguard.
- Let the platform keep the state it already owns.
- Future
- A self-serve reschedule flow, and moving the ledger's TTL cleanup off cron onto document expiry.
