```html

Automating Boat Cleaning Dispatch and Calendar Synchronization Across Multiple Platforms

What Was Done

This session focused on consolidating scattered cleaning service coordination into an automated dispatch system while simultaneously implementing cross-platform calendar synchronization. The core problem: manual scheduling of boat cleaning services across GetMyBoat, Boatsetter, and internal systems was error-prone and created operational friction. The solution involved building a Python-based dispatch coordinator and resurrecting a dormant Google Apps Script calendar sync system.

The Boat Cleaning Dispatch System

Created /Users/cb/Documents/repos/tools/dispatch_boat_cleaner.py as a lightweight coordinator that:

  • Queries booking platforms (GetMyBoat/Boatsetter iCal feeds) for upcoming reservations
  • Maps reservation dates to cleaning service requirements
  • Generates dispatch notifications with relevant booking metadata
  • Maintains state to avoid duplicate service requests

The dispatch script pulls from platform iCal feeds rather than directly hitting APIs—this avoids maintaining multiple OAuth2 flows and lets platform credentials live in a single repos.env file. The script is designed to run on a cron schedule (recommended: 6 AM daily) via deploy_boat_cleaner.sh.

Why this approach? iCal feeds are more stable than REST APIs for read-only operations, and they shift the authentication burden to HTTP Basic Auth over environment variables. This reduces the surface area for credential rotation and simplifies the deployment model.

Google Apps Script Calendar Synchronization

The heavier lift was restoring the calendar sync infrastructure in /Users/cb/Documents/repos/sites/queenofsandiego.com/rady-shell-events/apps-script-replacement/CalendarSync.gs. This GAS project serves as the canonical source of truth for event availability across properties.

Architecture Details

The CalendarSync.gs script:

  • Reads a master calendar stored in Google Calendar (accessible via Service Account credentials)
  • Polls the Lambda-backed calendar API endpoint at regular intervals
  • Syncs event metadata (date, time, title, description) across multiple GAS projects deployed to different web properties
  • Maintains iCal exports for external consumption by booking platforms

The polling interval was set to 30-minute windows to balance freshness against quota consumption. GAS has strict daily email quota limits (~100 emails/day), so the script was configured to batch notifications rather than firing per-event.

Deployment and Integration

The GAS project is tied to a Google Cloud project via .clasp.json configuration. Location:

/Users/cb/Documents/repos/sites/queenofsandiego.com/rady-shell-events/apps-script-replacement/.clasp.json

Deployment uses the Google Apps Script CLI (clasp push) to sync local TypeScript/GAS code to the cloud project. This enables version control and rollback capabilities that the legacy web UI deployment model lacked.

Calendar Event Ingestion

A Lambda function (exact function name redacted for security, but stored in repos.env as LAMBDA_CALENDAR_FUNCTION) exposes an API Gateway endpoint that accepts calendar event payloads. The endpoint structure:

POST /api/calendar/add-event
Authorization: Bearer {DASHBOARD_TOKEN}
Content-Type: application/json

{
  "title": "Sea Scout Wednesday Hold",
  "date": "2026-04-29",
  "time": "18:00",
  "duration_minutes": 120,
  "description": "Weekly youth group reservation"
}

During this session, 7 recurring Sea Scout Wednesday holds were added to the master calendar via this endpoint. The API Gateway uses IAM-based authorization via the dashboard auth token stored in repos.env, eliminating the need for API key rotation.

Email and Notification Coordination

Two complementary notification systems were deployed:

  1. Direct Email via AWS SES: Created platform_inbox_scraper.py to parse incoming emails from booking platforms and customers, extracting actionable items (cleaning requests, cancellations, date changes). Responses are sent back via SES with proper headers to maintain thread continuity.
  2. Campaign Scheduler: Implemented campaign_scheduler.py with campaign_schedule.json as the schedule manifest. This enables templated bulk communications (e.g., seasonal promotions) without manual SMTP configuration for each campaign.

Both systems use the same SES sender identity (configured in Route53 with DKIM verification) to maintain sender reputation.

Key Infrastructure Decisions

Why Lambda + API Gateway Over Cron Jobs?

The calendar sync could have been implemented as pure cron-triggered Lambda functions, but API Gateway exposure was critical because:

  • It allows the dashboard and external tools to trigger calendar syncs on-demand (e.g., when a booking is confirmed)
  • It provides audit logging via CloudTrail for compliance purposes
  • It decouples the calendar sync schedule from the dispatch schedule—they can operate independently

Why GAS Over AWS Lambda for Google Calendar?

Google Apps Script is the only service that has native, frictionless access to Google Calendar without separate OAuth2 flows. While Lambda can call the Google Calendar API, it requires managing service account keys and calendar delegation setup. GAS eliminates that complexity at the cost of some operational visibility (GAS logs are less detailed than Lambda logs). The tradeoff favors GAS for this use case.

Why iCal Instead of Direct API Polling?

iCal feeds are:

  • More reliable (lower TLS/connection overhead)
  • Cached aggressively by CDN (reduces platform API quota burn)
  • Easier to archive and audit (static files rather than transient API responses)

The downside: iCal updates lag behind real-time API state by 5-10 minutes. For a cleaning service, this is acceptable; for a real-time trading system, it would not be.

File Organization and Deployment Artifacts

All deployment scripts follow a consistent pattern:

/Users/cb/Documents/repos/tools/deploy_*.sh

These bash scripts are idempotent and can be safely run multiple times. They use environment variables from repos.env and are compatible with CI/CD pipelines (though manual deployment is currently the norm).

HTML templates for email campaigns are versioned in:

/Users/cb/Documents/repos/tools/templates/
/Users/cb/Documents/repos/sites/quickdumpnow.com/marketing/templates/

This separation allows shared templates in tools/ while property-specific customizations live alongside their respective web roots.

What's Next

  • Monitoring: CloudWatch alarms need to be configured for failed SES sends and Lambda invocation errors
  • Testing: Implement integration tests that simulate end-to-end booking → calendar sync → cleaning dispatch workflows
  • Documentation: Playbooks for runbook operations (e.g., "how to