```html

Automating Event Logistics: Building a Distributed Calendar Sync and Service Dispatch System

This session tackled a critical operational challenge: how to coordinate event calendars across multiple platforms and automate service dispatch workflows. The result is a hybrid architecture combining Google Apps Script, AWS Lambda, and Python-based dispatch tools that eliminates manual calendar management and streamlines vendor coordination.

The Problem

Queen of San Diego operates multiple event venues and services, each with their own booking platforms (GetMyBoat, Boatsetter, Google Calendar). Manually syncing these calendars was error-prone and time-consuming. Additionally, ancillary services like boat cleaning needed to be coordinated based on calendar holds and bookings. The previous attempt to solve this used FancyHands, which proved insufficient.

Architecture Overview

The solution consists of four integrated components:

  • CalendarSync.gs — Google Apps Script that polls external booking platforms and syncs events to Google Calendar
  • Lambda API Gateway — Serverless endpoint for programmatic calendar operations
  • Dispatch Scripts — Python-based tools that respond to calendar changes and trigger service workflows
  • Campaign Scheduler — JSON-driven system for coordinating multi-platform event communications

Technical Details: Calendar Synchronization

File: /Users/cb/Documents/repos/sites/queenofsandiego.com/rady-shell-events/apps-script-replacement/CalendarSync.gs

The core synchronization engine is a Google Apps Script that runs on a timed trigger. Key functions:

  • syncGetMyBoatICalendar() — Fetches iCalendar data from GetMyBoat reservations, parses event properties, and creates Google Calendar events with proper metadata
  • syncBoatsetterCalendar() — Similar workflow for Boatsetter platform
  • pollExternalSources() — Master orchestrator that runs on a 30-minute interval, checking all configured platforms
  • sendSyncNotification() — Logs sync results and alerts on failures

The script stores credentials securely in Google Apps Script Properties (not in version control). The polling interval was set to 30 minutes after testing revealed that real-time sync via webhooks wasn't available from the booking platforms, making client-pull the most reliable approach.

Why this approach? Google Apps Script provides native Calendar API access and runs in Google's infrastructure, eliminating the need for separate authentication servers. The 30-minute interval balances freshness against API quota consumption.

Lambda-Based Calendar API

File: /Users/cb/Documents/repos/sites/queenofsandiego.com/tools/shipcaptaincrew/lambda_function.py

For programmatic event management, we deployed a Python Lambda function behind API Gateway. This allows services to add, modify, or query events without direct Google Calendar access.

Key Actions Implemented:

  • add-calendar-event — Accepts JSON payload with event title, start/end times, description, and attendees. Validates input, creates event, returns event ID.
  • list-calendar-events — Returns all events in a date range, filtered by calendar ID
  • update-calendar-event — Modifies existing events (title, time, description)
  • delete-calendar-event — Removes events by ID

Example invocation:

curl -X POST https://api.queenofsandiego.com/calendar \
  -H "Authorization: Bearer ${DASHBOARD_TOKEN}" \
  -H "Content-Type: application/json" \
  -d '{
    "action": "add-calendar-event",
    "title": "Sea Scout Wednesday Hold",
    "start_time": "2024-04-24T18:00:00Z",
    "end_time": "2024-04-24T21:00:00Z",
    "calendar_id": "scouts@queenofsandiego.com"
  }'

The Lambda function uses service account credentials (stored as encrypted environment variables) to authenticate to Google Calendar API. API Gateway enforces token-based authentication, preventing unauthorized calendar modifications.

Dispatch and Service Automation

Files:

  • /Users/cb/Documents/repos/tools/dispatch_boat_cleaner.py
  • /Users/cb/Documents/repos/tools/deploy_dispatch_boat_cleaner.sh

The boat cleaning dispatch system monitors calendar events and triggers cleaning scheduling. The workflow:

  1. CalendarSync detects a booking on a specific boat (event title contains boat ID)
  2. Dispatch script queries the Lambda calendar API for events matching that boat
  3. Script calculates cleaning window (typically 2 hours before next booking or end of day)
  4. Sends dispatch notification to cleaning service via SMS/email with boat location and required turnaround time

The dispatch script is deployed as a CloudWatch Events rule (triggers every 60 minutes) that invokes the Python script via Lambda. This eliminates the need for a permanently running server.

Campaign Scheduling System

Files:

  • /Users/cb/Documents/repos/tools/campaign_schedule.json — Configuration file defining all campaigns, timing, and templates
  • /Users/cb/Documents/repos/tools/campaign_scheduler.py — Event-driven scheduler
  • /Users/cb/Documents/repos/tools/deploy_campaign_scheduler.sh — Deployment script

For multi-platform event communications (emails about bookings, reminders, upsells), we built a JSON-driven campaign system. Example structure:

{
  "campaigns": [
    {
      "id": "rady_shell_pre_event",
      "trigger": "booking_confirmed",
      "delay_hours": 24,
      "templates": {
        "email": "templates/rady_shell_blast1.html",
        "sms": "templates/rady_shell_sms1.txt"
      },
      "recipients": "booking_email",
      "platforms": ["rady-shell-events", "quickdumpnow"]
    }
  ]
}

The scheduler runs as a Lambda function that:

  1. Queries the calendar API for recent bookings
  2. Checks which campaigns apply based on booking metadata
  3. Sends templated messages via SES (email) and Twilio (SMS)
  4. Logs delivery status to DynamoDB for audit trails

Infrastructure and Deployment

Key AWS Resources:

  • Lambda Functions: Two functions deployed in us-west-1 region
    • shipcaptaincrew-calendar-api — Calendar operations endpoint
    • campaign-scheduler-processor — Event communication orchestrator
  • API Gateway: REST API with token-based authorization, endpoint: /calendar,