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 dispatchrady_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 programmaticallyGET /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",