Automating Boat Cleaning Dispatch and Calendar Synchronization for Event Operations
This session focused on solving a critical operational problem: how to systematically manage boat cleaning services for the Queen of San Diego's charter events. With FancyHands no longer viable as a vendor solution, we built an automated dispatch system integrated with Google Calendar and external booking platforms.
The Problem: Manual Coordination at Scale
Previously, boat cleaning was handled through FancyHands, a third-party task management service. When that vendor relationship ended, we needed a replacement that would:
- Pull event data from Google Calendar (authoritative source)
- Query multiple boat platform APIs (GetMyBoat, Boatsetter) for booking details
- Generate structured dispatch tasks with vessel, location, and timing data
- Integrate with existing notification systems
Architecture: Multi-Source Event Aggregation
The solution combines three data sources into a single dispatch workflow:
- Google Calendar API: Event timing, attendee counts, and metadata
- CalendarSync.gs: Google Apps Script that normalizes calendar data and handles authentication
- Boat Platform APIs: GetMyBoat and Boatsetter credentials stored in environment configuration
- Python Dispatch Script: Lambda-compatible script that orchestrates the entire workflow
Implementation: Core Components
1. Calendar Data Layer
The CalendarSync.gs file (located at /repos/sites/queenofsandiego.com/rady-shell-events/apps-script-replacement/CalendarSync.gs) serves as the Google Apps Script that:
- Authenticates with Google Calendar API using OAuth tokens
- Queries events within configurable date ranges
- Extracts vessel identifiers from event descriptions or custom fields
- Handles rate limiting and retry logic for reliability
- Exposes data via HTTP endpoints for downstream consumers
The script was updated to support both direct Lambda invocation and scheduled polling. Key polling intervals and email notification settings were consolidated into configuration blocks at the top of the file for easy maintenance.
2. Dispatch Logic: Python Implementation
The primary dispatch script lives at:
/Users/cb/Documents/repos/tools/dispatch_boat_cleaner.py
This script performs the following operations:
- Loads boat platform credentials from environment configuration (no hardcoded secrets)
- Calls CalendarSync endpoints to retrieve upcoming events
- Filters for events requiring cleaning (based on event type tags)
- Queries GetMyBoat and Boatsetter APIs for current booking status
- Generates a structured dispatch manifest with cleaning requirements
- Integrates with SES for email notifications to cleaning contractors
The design uses environment variable injection rather than credential files, enabling safe deployment across local development and Lambda environments without configuration changes.
3. Deployment and Orchestration
Two deployment scripts handle different operational contexts:
/Users/cb/Documents/repos/tools/deploy_boat_cleaner.sh
/Users/cb/Documents/repos/tools/deploy_inbox_scraper.sh
These shell scripts:
- Package Python dependencies using pip requirements files
- Validate credential loading before deployment
- Push updates to Lambda via AWS CLI
- Trigger test invocations to verify functionality
- Log deployment metadata for audit trails
Campaign Scheduling Infrastructure
Beyond boat cleaning, this session introduced a flexible campaign scheduling system used for marketing outreach:
/Users/cb/Documents/repos/tools/campaign_scheduler.py
/Users/cb/Documents/repos/tools/campaign_schedule.json
/Users/cb/Documents/repos/tools/deploy_campaign_scheduler.sh
The JSON file defines scheduling rules in a declarative format:
{
"campaigns": [
{
"id": "rady_shell_blast_1",
"template_path": "templates/rady_shell_blast1.html",
"schedule": "0 9 * * 1",
"recipients_source": "platform_inbox",
"tracking_enabled": true
}
]
}
The Python scheduler parses this configuration and triggers campaigns via SES, with email template variables substituted from recipient data. This approach decouples campaign definition from code deployment, allowing marketing teams to modify schedules without developer involvement.
Multi-Domain Integration Pattern
The infrastructure serves multiple independent domains:
queenofsandiego.com: Primary charter operations site with event managementcarole.dangerouscentaur.com: Content delivery site managed via S3 + CloudFrontquickdumpnow.com: Secondary brand with independent campaign infrastructure
Each domain maintains separate tool directories and credential namespaces. This isolation prevents credential leakage between operational contexts while allowing code patterns to be reused and parameterized.
Key Technical Decisions
Why Calendar API Over Manual Entry?
Google Calendar serves as the single source of truth because:
- Event metadata is already entered by staff for other purposes (attendee management, resource booking)
- API querying eliminates manual synchronization burden
- Calendar sharing enables non-technical stakeholders to view event impact on cleaning schedules
Why Multiple Boat Platform APIs?
Querying both GetMyBoat and Boatsetter allows the system to handle vessels registered on either platform without requiring staff to normalize platform differences. The dispatch script queries both and merges results, presenting a unified view to contractors.
Why Python + Lambda Over Google Apps Script Alone?
While CalendarSync.gs handles authentication and calendar queries well, the dispatch logic requires:
- Complex conditional logic (filtering, validation, deduplication)
- Multiple API integrations with different authentication schemes
- Dependency management for libraries like requests, dateutil, boto3
- Long-running operations that benefit from Lambda's managed execution
Python provides better testability and dependency management for this complexity, while Lambda handles scaling and scheduling automatically.
Operational Workflow
The integrated system works as follows:
- Staff creates calendar events for charters with vessel metadata
- Scheduler invokes
dispatch_boat_cleaner.pydaily via CloudWatch Events - Script queries CalendarSync endpoints for events in the next 7 days
- Dispatch logic checks boat platforms for booking details
- Email template (located at
templates/rady_shell_blast*.html) is populated with vessel, time, and location info - SES sends dispatch emails to cleaning contractors with clear instructions
- Contractor confirmation responses are captured and logged to CloudWatch
What's Next
Future enhancements under consideration: