```html

Automating Event Calendar Sync and Service Dispatch: Building a Lambda-Backed Calendar Integration System

Managing event calendars across multiple platforms is a persistent operational challenge, especially when coordinating bookings from third-party services like GetMyBoat and Boatsetter. This session focused on replacing a deprecated Google Apps Script-based calendar sync with a Lambda-backed system and implementing a dispatch automation pipeline for service coordination.

The Problem: Manual Calendar Management at Scale

The existing infrastructure relied on Google Apps Script (GAS) to manually poll external calendar feeds and sync events. This approach had several drawbacks:

  • GAS execution limits and unreliable polling intervals
  • No centralized event storage or audit trail
  • Manual email notifications for service dispatch
  • Tight coupling between calendar sync and email delivery
  • Difficulty scaling across multiple event sources

Architecture: Lambda + API Gateway + Google Calendar API

The new system decouples calendar synchronization from notification delivery by using AWS Lambda as the primary orchestration layer:


┌─────────────────────────────────────────────────┐
│ External Calendars (GetMyBoat, Boatsetter)     │
└──────────────┬──────────────────────────────────┘
               │ iCal feeds
               ▼
┌─────────────────────────────────────────────────┐
│ AWS Lambda: CalendarSync Handler                │
│ - Parse iCal feeds                              │
│ - Transform to Google Calendar events           │
│ - Deduplicate & conflict check                  │
│ - Dispatch service notifications                │
└──────────────┬──────────────────────────────────┘
               │ Google Calendar API
               ▼
┌─────────────────────────────────────────────────┐
│ Google Calendar (Primary Event Store)           │
└─────────────────────────────────────────────────┘

File Structure:

  • /Users/cb/Documents/repos/sites/queenofsandiego.com/rady-shell-events/apps-script-replacement/CalendarSync.gs — Primary Lambda handler function
  • /Users/cb/Documents/repos/tools/dispatch_boat_cleaner.py — Service dispatch script for cleaning coordination
  • /Users/cb/Documents/repos/tools/campaign_scheduler.py — Generic event scheduling engine

CalendarSync Lambda Function: Design & Implementation

The Lambda function implements a state machine pattern with the following action handlers:

  • add-calendar-event — Insert event into Google Calendar with conflict detection
  • list-calendar-events — Query events by date range and optional filters
  • dispatch-service — Trigger external service notifications (email, SMS, webhooks)
  • sync-external-feeds — Fetch and parse iCal feeds from GetMyBoat/Boatsetter

Key Implementation Details:


# Lambda handler entry point
def lambda_handler(event, context):
    action = event.get('action')
    params = event.get('params', {})
    
    if action == 'add-calendar-event':
        return add_event_to_calendar(params)
    elif action == 'list-calendar-events':
        return query_calendar(params)
    elif action == 'dispatch-service':
        return dispatch_notification(params)
    else:
        return {'status': 'error', 'message': f'Unknown action: {action}'}

The function uses the Google Calendar API client library to authenticate via a service account key stored in Lambda environment variables (never hardcoded). Events are added with:

  • Idempotency keys in the event description to prevent duplicate syncs
  • Source attribution (GetMyBoat, Boatsetter, manual entry) in event metadata
  • Conflict detection — before inserting, query for overlapping bookings on the same resource
  • Automatic color coding — different calendar colors by event type (booking, internal hold, service window)

Dispatch Automation: The dispatch_boat_cleaner.py Pipeline

Service dispatch is handled by a Python-based task scheduler that runs on a cron trigger:


File: /Users/cb/Documents/repos/tools/dispatch_boat_cleaner.py

Key functions:
- get_upcoming_events(calendar_id, days_ahead=3)
- determine_service_needs(event, resource_config)
- send_dispatch_email(service_provider, event_details)
- log_dispatch_to_dynamodb(event_id, dispatch_record)

Workflow:

  1. Lambda queries Google Calendar for all events in the next 3 days
  2. For each event, determine required services (cleaning, provisioning, crew assignments)
  3. Check service provider availability (stored in DynamoDB: ServiceProviders table)
  4. Send dispatch email via SES to assigned provider with event details, timing, special instructions
  5. Log dispatch record to DynamoDB with status and timestamp for audit trail

Integration with Campaign Scheduling

A separate campaign scheduler was implemented to handle bulk event operations and marketing blasts:


File: /Users/cb/Documents/repos/tools/campaign_scheduler.py
File: /Users/cb/Documents/repos/tools/campaign_schedule.json

campaign_schedule.json structure:
{
  "campaigns": [
    {
      "name": "rady_shell_weekly_blast",
      "event_source": "calendar",
      "filter": "event_type=promotional",
      "email_template": "rady_shell_blast1.html",
      "recipients": "marketing_list",
      "dispatch_window": "-7 days",
      "retry_policy": "exponential_backoff"
    }
  ]
}

This decouples event scheduling from marketing campaigns, allowing independent tuning of each pipeline.

Deployment Strategy: Layered Push Model

CalendarSync.gs Deployment:


# Via Google Apps Script CLI (clasp)
$ cd /Users/cb/Documents/repos/sites/queenofsandiego.com/rady-shell-events/apps-script-replacement/
$ clasp push

# Verifies .clasp.json project binding
Project ID: [from .clasp.json]
Deployed to: https://script.google.com/macros/d/[deployment-id]/usercallable

Python Scripts Deployment:


# Via deployment shell scripts
$ bash /Users/cb/Documents/repos/tools/deploy_campaign_scheduler.sh
$ bash /Users/cb/Documents/repos/tools/deploy_inbox_scraper.sh

# Creates zip archive, uploads to S3, updates Lambda function code
# S3 bucket: [deployment-bucket-name] (from env config)
# Lambda function: [calendar-sync-function-name] (from repos.env)

Infrastructure Components

AWS Resources: