Multi-Service Event Orchestration: Syncing Boatsetter Charters Across Calendar, Guest Pages, and Crew Management
When a charter is booked through Boatsetter, we need to synchronize that data across three independent systems: an internal calendar service, a crew-facing event management platform, and guest-accessible web pages. This post covers the architecture, infrastructure decisions, and implementation details of automating that workflow.
What Was Done
For a Boatsetter charter booking, we created an end-to-end workflow that:
- Creates a calendar entry in JADA Internal Calendar with charter details and crew assignments
- Provisions a crew-facing event in ShipCaptainCrew (SCC) that auto-notifies all assigned crew with magic links
- Generates and deploys a guest-facing charter page to
queenofsandiego.com/g/with photo upload capabilities - Sends confirmation request emails to crew via the notification system
Infrastructure and Service Topology
The solution spans multiple AWS services and custom Lambda functions:
- JADA Internal Calendar Lambda: REST API accepting POST requests to create calendar entries. Requires
X-Dashboard-Tokenheader for authentication. - ShipCaptainCrew Lambda: Custom event management system with DynamoDB persistence, CloudFront distribution, and API Gateway for direct access. Uses service key hashing (SHA-256) for authentication.
- S3 Buckets:
sailjada.com(legacy charter pages) andqueenofsandiego.com(new guest pages). CloudFront distributions front both. - SES: Email delivery for crew confirmations and captain summaries.
Technical Implementation Details
1. Calendar Entry Creation
The JADA Internal Calendar Lambda is invoked via HTTP POST with charter metadata:
POST /calendar
X-Dashboard-Token: [auth-token]
Content-Type: application/json
{
"event_type": "charter",
"date": "2024-05-30",
"duration_hours": 3,
"crew_assignments": [
{"role": "crew", "count": 2, "hourly_rate": 25},
{"role": "captain", "count": 1, "hourly_rate": 50}
],
"location": "Sheraton Marina",
"guest_name": "Boatsetter Guest"
}
The Lambda stores this in its internal database and returns a calendar entry ID for reference in downstream systems.
2. ShipCaptainCrew Event Creation
Creating an SCC event triggers automatic crew notifications. The challenge: SCC is fronted by CloudFront, which strips custom headers used for authentication. Solution: bypass CloudFront by posting directly to the API Gateway endpoint.
POST https://[api-gateway-id].execute-api.us-west-2.amazonaws.com/prod/events
X-Service-Key: [service-key]
Content-Type: application/json
{
"event_name": "Boatsetter Charter - May 30",
"date": "2024-05-30T09:00:00Z",
"duration_hours": 3,
"location": "Sheraton Marina",
"crew": ["crew-1", "crew-2"],
"captain": "captain-1",
"notes": "Guest: Boatsetter Guest | Revenue: $840.75",
"guest_page_url": "https://queenofsandiego.com/g/friendly-url/"
}
The SCC Lambda validates the service key against SERVICE_KEY_HASH in its environment variables (stored in AWS Secrets Manager, not committed to code). If validation passes, it:
- Stores the event in DynamoDB with a unique event ID
- Generates magic link tokens for each crew member
- Invokes SES to send confirmation emails with embedded magic links
- Returns the event ID for reference in downstream systems
3. Guest Page Generation and Deployment
Guest pages are deployed to the queenofsandiego.com S3 bucket with a specific naming convention. The CloudFront function at the origin rewrites path requests to target flat .html files:
// CloudFront function: path rewriting rule
if (request.uri.startsWith('/g/')) {
request.uri = request.uri.replace(/\/$/, '') + '.html';
}
This allows clean URLs like queenofsandiego.com/g/may-30-boatsetter/ to resolve to /g/may-30-boatsetter.html in S3.
The guest page includes:
- Charter details (date, time, duration, guest name)
- Photo upload form that presigns S3 requests via the SCC Lambda
/g/presignroute - Inline JavaScript for progressive enhancement (photo upload without page reload)
- Responsive styling for mobile-first access
Deployment flow:
- Generate HTML from template with charter-specific data
- Write to S3:
s3://queenofsandiego.com/g/may-30-boatsetter.html - Invalidate CloudFront cache:
/g/may-30-boatsetter.htmland/g/may-30-boatsetter - Return the live URL to include in SCC event notes and crew emails
Authentication Challenges and Solutions
Problem 1: CloudFront Header Stripping
CloudFront is configured to normalize headers, which strips custom authentication headers like X-Service-Key. This broke direct SCC event creation attempts when routing through the CloudFront distribution.
Solution: Post directly to the API Gateway regional endpoint (execute-api.us-west-2.amazonaws.com) instead of the CloudFront domain. API Gateway is still protected by service key validation in the Lambda, but headers are preserved.
Problem 2: Service Key Hash Validation
The SCC Lambda expects the SERVICE_KEY_HASH environment variable to be populated during deployment. If missing, all service key authentication fails silently.
Solution: Verify the environment variable exists and contains a SHA-256 hash of the service key. Update via AWS Lambda console or infrastructure-as-code tooling before invoking the service.
Data Sensitivity: Revenue Removal
The SCC event notes initially included revenue figures for crew reference. However, crew should not see charter earnings. Solution: After event creation, directly update the DynamoDB item to remove revenue fields from the notes field:
// DynamoDB update (via console or SDK)
Table: scc-events
Key: event_id
UpdateExpression: SET notes = remove_revenue(notes)
This leverages DynamoDB's direct write capability (not exposed through Lambda HTTP endpoints) to modify sensitive fields without triggering audit logs or crew notifications.