# Complete Documentation — Calendar Booking Platform

**Version:** 1.0  
**Last updated:** June 25, 2026  
**Product type:** Calendly-style scheduling with multi-calendar integration

---

## Table of Contents

1. [Executive Summary](#1-executive-summary)
2. [Goals and Non-Goals](#2-goals-and-non-goals)
3. [Personas and User Stories](#3-personas-and-user-stories)
4. [Core Features](#4-core-features)
5. [User Flows](#5-user-flows)
6. [System Architecture](#6-system-architecture)
7. [Availability Engine](#7-availability-engine)
8. [Calendar Integrations Overview](#8-calendar-integrations-overview)
9. [Data Model Summary](#9-data-model-summary)
10. [Security and Compliance](#10-security-and-compliance)
11. [Notifications](#11-notifications)
12. [Admin and Analytics](#12-admin-and-analytics)
13. [Deployment and Operations](#13-deployment-and-operations)
14. [Implementation Roadmap](#14-implementation-roadmap)
15. [Glossary](#15-glossary)

---

## 1. Executive Summary

This platform enables professionals to offer bookable time slots via a **public link**, similar to Calendly. Each host:

- Registers an account and claims a unique booking URL slug.
- Defines **working hours**, **timezone**, and optional date-specific overrides.
- Connects one or more external calendars (**Google Calendar**, **Microsoft Outlook/365**, **Apple iCloud Calendar**).
- Creates **event types** (e.g. 15 / 30 / 60 minutes) with optional buffers and booking rules.
- Shares a link; guests pick an open slot without creating an account.

When a guest books:

1. The system verifies the slot is still free (race-safe).
2. A booking record is created.
3. Events are created on connected calendars (primary write target + optional guest invite).
4. Confirmation and reminder emails are sent.

---

## 2. Goals and Non-Goals

### Goals

| ID | Goal |
|----|------|
| G1 | One-click public booking via shareable link |
| G2 | Accurate availability across multiple connected calendars |
| G3 | Timezone-safe scheduling for hosts and guests worldwide |
| G4 | OAuth-based calendar sync (Google, Microsoft, Apple/iCloud) |
| G5 | Conflict prevention and idempotent booking |
| G6 | Mobile-friendly booking experience |

### Non-Goals (v1)

- Payment collection (Stripe) — future phase
- Round-robin / team scheduling — future phase
- Video conferencing auto-provisioning (Zoom/Meet links) — optional v1.1
- Native mobile apps — web-first
- Two-way CRM sync — future phase

---

## 3. Personas and User Stories

### Personas

| Persona | Description |
|---------|-------------|
| **Host** | Professional who defines availability and receives bookings |
| **Guest** | Person booking time via public link; may not have an account |
| **Admin** | Platform operator managing users, abuse, and system health |

### User Stories

#### Host

| ID | Story | Acceptance Criteria |
|----|-------|---------------------|
| H1 | As a host, I register with email/password or SSO so I can manage my calendar | Email verification; unique username slug |
| H2 | As a host, I set my timezone so slots display correctly | IANA timezone stored; affects all availability |
| H3 | As a host, I define weekly working hours | Per-day start/end; can mark days unavailable |
| H4 | As a host, I connect Google/Microsoft/Apple calendars | OAuth or CalDAV; free/busy imported |
| H5 | As a host, I create event types with duration and buffers | Name, duration, pre/post buffer, max bookings/day |
| H6 | As a host, I share my public link | URL format: `/book/{username}/{event-slug}` |
| H7 | As a host, I receive email when someone books | Includes guest details and calendar attachment |
| H8 | As a host, I can cancel or reschedule a booking | Guest notified; external events updated |

#### Guest

| ID | Story | Acceptance Criteria |
|----|-------|---------------------|
| G1 | As a guest, I open a public link and see available times in my timezone | Timezone selector; no login required |
| G2 | As a guest, I book a slot with name and email | Form validation; confirmation page |
| G3 | As a guest, I receive calendar invite (.ics) | Compatible with Google, Outlook, Apple Mail |
| G4 | As a guest, I can cancel via link in email | Tokenized cancel URL; slot freed |

---

## 4. Core Features

### 4.1 Registration and Profile

| Field | Required | Notes |
|-------|----------|-------|
| Email | Yes | Unique; used for login and notifications |
| Password | Yes (or SSO) | Min 12 chars; bcrypt/argon2 hash |
| Full name | Yes | Shown on booking page |
| Username slug | Yes | URL-safe, unique, e.g. `jane-doe` |
| Timezone | Yes | IANA, e.g. `America/New_York` |
| Avatar | No | Optional upload or Gravatar |

**Public booking URL pattern:**

```
https://{APP_DOMAIN}/book/{username}/{event-slug}
```

Example: `https://book.example.com/alice/30min-consultation`

### 4.2 Working Hours

Hosts define **recurring weekly availability** in their profile timezone.

| Concept | Description |
|---------|-------------|
| Weekly schedule | Array of `{ dayOfWeek, startTime, endTime }` — e.g. Mon–Fri 09:00–17:00 |
| Unavailable days | Days with no intervals = fully blocked |
| Date overrides | Specific dates: custom hours or full day off (holidays) |
| Minimum notice | e.g. "Book at least 4 hours in advance" |
| Scheduling window | e.g. "Only show dates up to 60 days ahead" |

**Example weekly schedule (host timezone `Europe/London`):**

| Day | Available |
|-----|-----------|
| Monday | 09:00 – 12:00, 13:00 – 17:00 |
| Tuesday | 09:00 – 17:00 |
| Wednesday | Unavailable |
| Thursday | 10:00 – 16:00 |
| Friday | 09:00 – 12:00 |
| Sat–Sun | Unavailable |

### 4.3 Event Types

Each event type is a bookable offering tied to the host.

| Field | Example | Description |
|-------|---------|-------------|
| `slug` | `30min-call` | URL segment |
| `title` | 30 Minute Call | Display name |
| `durationMinutes` | 30 | Meeting length |
| `bufferBeforeMinutes` | 5 | Gap before event |
| `bufferAfterMinutes` | 5 | Gap after event |
| `location` | Google Meet / Phone / In person | Shown to guest |
| `description` | Optional intake text | Shown on booking page |
| `customQuestions` | JSON array | e.g. "Company name" |
| `isActive` | true | Hide without deleting |
| `color` | `#4F46E5` | Calendar display color |

### 4.4 Public Booking Page

The public page (no auth) displays:

1. Host name, avatar, event title and description
2. Timezone selector (defaults to guest browser timezone)
3. Calendar date picker (only dates with ≥1 free slot)
4. Time slot list for selected date
5. Guest form: name, email, optional phone, custom questions
6. Confirmation screen with `.ics` download and "Add to Google Calendar" link

### 4.5 Booking Rules

| Rule | Behavior |
|------|----------|
| Double-booking prevention | DB transaction + optimistic lock on slot |
| External calendar conflicts | Free/busy blocks slot before display and re-check on submit |
| Buffers | Applied around event duration when computing availability |
| Max per day | Optional cap on bookings per event type per day |
| Cancellation policy | Host-defined: min hours before start to allow guest cancel |

---

## 5. User Flows

### 5.1 Host Onboarding

```mermaid
sequenceDiagram
    participant H as Host
    participant App as Application
    participant Cal as Calendar Provider

    H->>App: Register (email, password, username)
    App->>H: Verify email
    H->>App: Set timezone + working hours
    H->>App: Connect Google / Microsoft / Apple calendar
    App->>Cal: OAuth or CalDAV auth
    Cal->>App: Access token + refresh token
    App->>Cal: Fetch calendar list + initial free/busy
    H->>App: Create event type
    App->>H: Public booking URL
```

### 5.2 Guest Booking

```mermaid
sequenceDiagram
    participant G as Guest
    participant App as Application
    participant DB as Database
    participant Cal as Host Calendars

    G->>App: Open /book/{user}/{event}
    App->>DB: Load host, event type, working hours
    App->>Cal: Fetch free/busy (cached)
    App->>G: Available slots (guest TZ)
    G->>App: Select slot + submit form
    App->>App: Re-validate slot (race check)
    App->>DB: Create booking (transaction)
    App->>Cal: Create calendar events
    App->>G: Confirmation + .ics email
    App->>Host: New booking notification
```

### 5.3 Cancellation

1. Guest clicks cancel link in email (`/cancel/{bookingToken}`).
2. System validates token and cancellation policy.
3. Booking status → `cancelled`.
4. External calendar events deleted or marked cancelled.
5. Host and guest receive cancellation emails.
6. Slot becomes available again.

---

## 6. System Architecture

### 6.1 High-Level Diagram

```mermaid
flowchart TB
    subgraph Client
        WEB[Web App - Host Dashboard]
        PUB[Public Booking Page]
    end

    subgraph API Layer
        GW[API Gateway / Load Balancer]
        AUTH[Auth Service]
        SCHED[Scheduling Service]
        CAL[Calendar Sync Service]
        NOTIFY[Notification Service]
    end

    subgraph Data
        PG[(PostgreSQL)]
        REDIS[(Redis Cache)]
        QUEUE[Job Queue]
    end

    subgraph External
        GOOGLE[Google Calendar API]
        MS[Microsoft Graph API]
        APPLE[Apple iCloud CalDAV]
        EMAIL[Email Provider]
    end

    WEB --> GW
    PUB --> GW
    GW --> AUTH
    GW --> SCHED
    GW --> CAL
    SCHED --> PG
    SCHED --> REDIS
    CAL --> QUEUE
    QUEUE --> GOOGLE
    QUEUE --> MS
    QUEUE --> APPLE
    NOTIFY --> EMAIL
    CAL --> PG
```

### 6.2 Service Responsibilities

| Service | Responsibility |
|---------|----------------|
| **Auth Service** | Registration, login, JWT/session, OAuth for calendar providers |
| **Scheduling Service** | Working hours, availability computation, booking CRUD |
| **Calendar Sync Service** | Token refresh, free/busy import, event create/update/delete |
| **Notification Service** | Email templates, .ics generation, reminders |
| **Web Frontend** | Host dashboard + public booking UI |

### 6.3 Key Technical Decisions

| Decision | Recommendation | Rationale |
|----------|----------------|-----------|
| Primary DB | PostgreSQL | ACID transactions for booking; JSON for custom questions |
| Time storage | UTC in DB; display in user TZ | Avoid DST bugs |
| Availability cache | Redis, TTL 2–5 min | Reduce calendar API calls |
| Background jobs | Queue for calendar writes | Retry on provider rate limits |
| Idempotency | `Idempotency-Key` header on POST /bookings | Prevent duplicate bookings on retry |

### 6.4 Environment Variables

| Variable | Description |
|----------|-------------|
| `DATABASE_URL` | PostgreSQL connection string |
| `REDIS_URL` | Redis for cache and queue |
| `JWT_SECRET` | Signing key for auth tokens |
| `APP_URL` | Public base URL, e.g. `https://book.example.com` |
| `GOOGLE_CLIENT_ID` / `GOOGLE_CLIENT_SECRET` | Google OAuth |
| `MICROSOFT_CLIENT_ID` / `MICROSOFT_CLIENT_SECRET` | Microsoft OAuth |
| `SMTP_*` or `SENDGRID_API_KEY` | Email delivery |
| `ENCRYPTION_KEY` | Encrypt stored OAuth refresh tokens at rest |

---

## 7. Availability Engine

### 7.1 Algorithm (Pseudocode)

```
function getAvailableSlots(host, eventType, dateRange, guestTimezone):
    hostTz = host.timezone
    duration = eventType.durationMinutes
    bufferBefore = eventType.bufferBeforeMinutes
    bufferAfter = eventType.bufferAfterMinutes
    slotInterval = 15  // minutes, configurable

    candidates = []

    for each date in dateRange:
        intervals = getWorkingIntervals(host, date, hostTz)
        // Merge weekly schedule + date overrides

        for each interval in intervals:
            slots = generateSlots(interval, slotInterval, duration, bufferBefore, bufferAfter)

            for each slot in slots:
                if slot.start < now + host.minNoticeHours: continue
                if slot.start > now + host.maxAdvanceDays: continue

                if conflictsWithExistingBookings(host, slot): continue
                if conflictsWithExternalBusy(host, slot): continue
                if exceedsDailyCap(host, eventType, slot): continue

                candidates.append(slot converted to guestTimezone)

    return candidates
```

### 7.2 Conflict Detection

A slot `[start, end]` (including buffers) is **blocked** if it overlaps any:

| Source | Overlap rule |
|--------|--------------|
| Existing booking | `booking.start - bufferBefore < end AND booking.end + bufferAfter > start` |
| External busy block | Same interval overlap |
| Outside working hours | Slot not fully contained in a working interval |

### 7.3 Timezone Rules

1. **Store** all timestamps in UTC (`timestamptz` in PostgreSQL).
2. **Working hours** are defined as local wall-clock times in the host timezone.
3. **Display** slots in the guest-selected timezone with clear label: *"Times shown in Pacific Time (PT)"*.
4. **DST transitions:** Use IANA timezone database (`tzdata` / `luxon` / `date-fns-tz`). Never use fixed UTC offsets for recurring rules.
5. **Ambiguous local times** (fall-back): Prefer the later occurrence or exclude ambiguous hour — document choice in config.

### 7.4 Performance

- Precompute busy blocks per host for a rolling 90-day window (background job every 5–15 min).
- Invalidate cache on: new booking, cancellation, calendar reconnect, working hours change.
- Paginate public API: return one month of slots per request.

---

## 8. Calendar Integrations Overview

Detailed setup: [CALENDAR_INTEGRATIONS.md](./CALENDAR_INTEGRATIONS.md)

| Provider | Protocol | Read (free/busy) | Write (create event) | Auth |
|----------|----------|------------------|----------------------|------|
| Google Calendar | REST API v3 | `freebusy.query` or Events list | `events.insert` | OAuth 2.0 |
| Microsoft 365 / Outlook | Microsoft Graph | `getSchedule` or `/me/calendarView` | `POST /me/events` | OAuth 2.0 |
| Apple iCloud | CalDAV | `REPORT calendar-query` (VFREEBUSY) | `PUT` VEVENT | App-specific password + CalDAV |

### Integration Principles

1. **Multiple calendars:** Host selects which calendars to check for conflicts and which calendar receives new bookings.
2. **Token lifecycle:** Store refresh tokens encrypted; background job refreshes before expiry.
3. **Write path:** On booking confirm, create event on primary calendar; include guest as attendee if provider supports it.
4. **Sync delay:** Treat external calendar as eventually consistent; always re-check on booking submit.
5. **Disconnect:** Revoke token at provider; delete stored credentials; stop sync jobs.

---

## 9. Data Model Summary

Full schema: [DATABASE_SCHEMA.md](./DATABASE_SCHEMA.md)

### Core Entities

```
User (host)
  ├── has many CalendarConnection
  ├── has one AvailabilitySchedule (+ overrides)
  ├── has many EventType
  └── has many Booking

EventType
  └── has many Booking

Booking
  ├── belongs to User (host)
  ├── belongs to EventType
  └── has many CalendarEventSync (external event IDs)
```

### Booking Statuses

| Status | Description |
|--------|-------------|
| `pending` | Created; calendar write in progress |
| `confirmed` | Calendar events created successfully |
| `cancelled` | Cancelled by host or guest |
| `failed` | Calendar write failed after retries |

---

## 10. Security and Compliance

### Authentication

- Host dashboard: email/password with bcrypt/argon2, or SSO (Google/Microsoft) in v1.1.
- Public booking: no account; rate limit by IP.
- Cancel/reschedule links: signed JWT or opaque token with expiry.

### Authorization

- Hosts can only access their own data (`userId` scope on all queries).
- Public endpoints expose only: host display name, event metadata, available slots — never other guests' data.

### Data Protection

| Measure | Implementation |
|---------|----------------|
| OAuth tokens | AES-256 encrypted at rest |
| HTTPS | TLS 1.2+ everywhere |
| CSRF | SameSite cookies + CSRF token on mutating host requests |
| Rate limiting | 60 req/min per IP on booking; 5 bookings/hour per email |
| Input validation | Sanitize all guest fields; validate email format |
| Audit log | Log booking create/cancel with timestamp and IP |

### Privacy (GDPR-oriented)

- Privacy policy and cookie consent on public pages.
- Data export and account deletion endpoints for hosts.
- Retain booking data per host-configurable retention or legal minimum.
- Guest email used only for booking communications.

---

## 11. Notifications

### Email Types

| Trigger | Recipient | Content |
|---------|-----------|---------|
| Booking confirmed | Guest + Host | Time, timezone, location, .ics attachment |
| Reminder (24h / 1h) | Guest + Host | Optional configurable |
| Cancelled | Guest + Host | Who cancelled, original time |
| Calendar sync failure | Host | Action required to reconnect |

### ICS File Fields

```
BEGIN:VCALENDAR
BEGIN:VEVENT
UID:{booking-uuid}@book.example.com
DTSTART:{UTC datetime}
DTEND:{UTC datetime}
SUMMARY:{event title} with {host name}
DESCRIPTION:{booking details + cancel link}
LOCATION:{location}
ORGANIZER:mailto:{host email}
ATTENDEE:mailto:{guest email}
END:VEVENT
END:VCALENDAR
```

---

## 12. Admin and Analytics

### Host Dashboard Metrics (v1)

- Total bookings (week / month)
- Upcoming bookings list
- Cancellation rate
- Most booked event type

### Platform Admin (optional v1)

- User search and suspend
- Failed sync queue monitoring
- API rate limit configuration

---

## 13. Deployment and Operations

### Recommended Infrastructure

| Component | Suggestion |
|-----------|------------|
| Compute | AWS ECS, Fly.io, or Railway |
| Database | Managed PostgreSQL (RDS, Supabase, Neon) |
| Cache/Queue | Managed Redis (ElastiCache, Upstash) |
| CDN | CloudFront or Cloudflare for static assets |
| Secrets | AWS Secrets Manager or Doppler |

### Health Checks

- `GET /health` — API alive
- `GET /health/db` — PostgreSQL connectivity
- `GET /health/redis` — Redis connectivity
- Background worker heartbeat for calendar sync queue

### Monitoring

- Error tracking: Sentry
- Metrics: Datadog or Prometheus (booking success rate, sync latency, API p95)
- Alerts: calendar token refresh failure rate > 5%, booking failure rate > 1%

### Backup

- Daily PostgreSQL snapshots; 30-day retention
- Test restore quarterly

---

## 14. Implementation Roadmap

### Phase 1 — MVP (6–8 weeks)

- [ ] User registration, login, profile (timezone, username)
- [ ] Weekly working hours + date overrides
- [ ] Event types CRUD
- [ ] Availability engine (bookings only, no external calendar)
- [ ] Public booking page + confirmation email + .ics
- [ ] Google Calendar OAuth (read free/busy + write events)

### Phase 2 — Multi-calendar (3–4 weeks)

- [ ] Microsoft Graph integration
- [ ] Apple iCloud CalDAV integration
- [ ] Calendar connection UI (select check vs write calendars)
- [ ] Background sync jobs + cache

### Phase 3 — Polish (2–3 weeks)

- [ ] Guest cancel/reschedule flows
- [ ] Reminder emails
- [ ] Host analytics dashboard
- [ ] Custom booking page branding

### Phase 4 — Growth (future)

- [ ] Team / round-robin scheduling
- [ ] Payments (Stripe)
- [ ] Zoom / Google Meet auto-link generation
- [ ] Webhooks for CRM integrations
- [ ] Embeddable booking widget

---

## 15. Glossary

| Term | Definition |
|------|------------|
| **Host** | User who owns the calendar and receives bookings |
| **Guest** | Person who books via public link |
| **Event type** | Template for a bookable meeting (duration, rules) |
| **Slot** | A specific start/end time offered for booking |
| **Buffer** | Padding time before/after a meeting |
| **Free/busy** | External calendar data indicating busy periods without event details |
| **Slug** | URL-safe identifier for username or event type |
| **IANA timezone** | Standard timezone ID, e.g. `America/Los_Angeles` |

---

## Related Documents

- [User Guide](./USER_GUIDE.md)
- [Use Cases](./USE_CASES.md)
- [API Reference](./API_REFERENCE.md)
- [Calendar Integrations](./CALENDAR_INTEGRATIONS.md)
- [Database Schema](./DATABASE_SCHEMA.md)
