```html

Automating Boat Cleaning Dispatch and Calendar Sync for Event Operations

This session focused on solving a critical operational gap: how to reliably manage boat cleaning services for events when third-party vendors like FancyHands become unavailable. The solution involved building a dispatch automation system and integrating it with our Google Calendar infrastructure.

The Problem

FancyHands, our contracted cleaning service platform, was cancelled mid-cycle. With events scheduled and no immediate replacement vendor, we needed a system to:

  • Dispatch cleaning tasks to team members reliably
  • Integrate with our existing calendar system
  • Provide audit trails for task completion
  • Allow easy scheduling of future cleaning needs

Architecture: Three-Layer Automation

We implemented a three-component system that integrates with existing infrastructure:

Layer 1: Task Dispatch System

Created /Users/cb/Documents/repos/tools/dispatch_boat_cleaner.py as the core dispatch engine. This Python script:

  • Reads cleaning task specifications from a structured format
  • Sends dispatch notifications via AWS SES to designated team members
  • Logs dispatch events with timestamps for audit purposes
  • Validates that team member email addresses are available before dispatch

The script loads environment variables for SES configuration from repos.env, allowing credential-free execution in CI/CD pipelines and Lambda functions.

Layer 2: Deployment Pipeline

Created /Users/cb/Documents/repos/tools/deploy_boat_cleaner.sh to handle:

  • Validating the dispatch script syntax
  • Testing SES connectivity with a canary email
  • Deploying to Lambda as a scheduled function
  • Setting CloudWatch logs for monitoring

This shell script ensures the dispatch system can run on a schedule independent of manual intervention, with failure notifications sent to operations.

Layer 3: Calendar Integration

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

  • Trigger dispatch events when calendar entries meet specific criteria
  • Synchronize with external boat platform calendars (GetMyBoat, Boatsetter)
  • Parse iCalendar feeds from boat booking platforms
  • Create internal calendar holds for scheduled cleaning tasks

The CalendarSync.gs file is deployed via Google Apps Script using Clasp. We identified the project ID from .clasp.json in the apps-script-replacement directory, which maps to a specific GAS project in our Google Workspace environment.

Technical Implementation Details

SES Integration

The dispatch system uses AWS SES (Simple Email Service) rather than SMTP because:

  • Scalability: SES handles burst email volume without rate-limiting
  • Deliverability: AWS maintains sender reputation and DKIM/SPF records
  • Audit trail: CloudWatch logs provide compliance records
  • No credentials in code: IAM roles on Lambda functions authenticate SES calls

Dispatch calls use the boto3 SES client with templates stored in /Users/cb/Documents/repos/tools/templates/. Two templates were created for different event types:

  • rady_shell_blast1.html — Standard cleaning dispatch
  • rady_shell_blast2.html — Urgent same-day requests

Templates are rendered with Jinja2, allowing dynamic insertion of event details, dates, and team member assignments without hardcoding data.

Google Calendar Sync

The CalendarSync.gs replacement project handles bidirectional synchronization:

  • Inbound: Polls external boat platform calendars via iCalendar feeds every 15 minutes
  • Processing: Parses VEVENT entries and normalizes event times to Pacific timezone
  • Outbound: Creates Google Calendar events with custom metadata tags
  • Cleanup: Removes stale events after 30 days

The polling interval and sendEmail calls were updated to reduce API quota usage while maintaining real-time synchronization for critical events (boat rentals, events).

Infrastructure Changes

Lambda Functions

Deployed dispatch_boat_cleaner as a Lambda function (4096 MB memory, 60-second timeout) with:

  • CloudWatch Events trigger for daily 8 AM execution
  • SES send email permission in execution role policy
  • S3 read access to s3://queenofsandiego-ops/dispatch-configs/

The Lambda reads dispatch tasks from S3 JSON files, allowing non-technical team members to update cleaning schedules via a web interface.

API Gateway Routes

Added two new routes to the existing API Gateway v2 endpoint:

  • POST /calendar/add-event — Allows dashboard to add calendar events programmatically
  • GET /calendar/list-events — Returns upcoming events in JSON format

Both routes authenticate using a Bearer token stored in repos.env and verified in the Lambda authorizer. This prevents unauthorized calendar modifications while allowing the dashboard and automation systems to coexist.

CloudWatch Monitoring

Set up log groups for:

  • /aws/lambda/dispatch_boat_cleaner — Dispatch execution logs
  • /aws/lambda/calendar-api — Calendar event API calls
  • /aws/events/dispatch-schedule — CloudWatch Events triggers

Alarms are configured to alert operations if dispatch tasks fail or if SES bounce rates exceed 5%.

Integration with Existing Systems

Dashboard Card System

The dashboard at /tmp/dashboard_index.html was updated to:

  • Display pending cleaning tasks from the dispatch queue
  • Allow manual task creation with one-click SES dispatch
  • Show task completion status via team member replies
  • Provide audit logs of all dispatches and completions

Campaign Scheduler

Created /Users/cb/Documents/repos/tools/campaign_scheduler.py to schedule recurring cleaning tasks using the same infrastructure. Configuration is stored in campaign_schedule.json with entries like:

{
  "cleaning_events": [
    {
      "boat_name": "Queen of San Diego",
      "frequency": "weekly",
      "day_of_week": "Wednesday",