```html

Multi-Service Charter Booking Pipeline: Integrating Boatsetter, ShipCaptainCrew, and Guest Portal

This post covers the architecture and implementation of a unified charter booking workflow that bridges three separate systems: Boatsetter (customer-facing marketplace), ShipCaptainCrew (crew scheduling and logistics), and a custom guest portal. The challenge was orchestrating data flow across these systems while maintaining authentication boundaries, managing CloudFront caching layers, and ensuring crew notifications propagate automatically.

What Was Done

We implemented an end-to-end booking pipeline triggered by a new Boatsetter charter. The system creates four synchronized artifacts:

  • JADA Internal Calendar entry — internal scheduling visibility
  • ShipCaptainCrew event — crew-facing booking with auto-notification
  • Guest-facing portal page — static HTML at /g/{SESSION_ID} on queenofsandiego.com
  • Crew-facing checklist page — integrated within SCC event details

Technical Architecture

Service Integration Points

The three independent systems required careful authentication handling at each integration boundary:

  • JADA Calendar (internal Lambda) — requires X-Dashboard-Token header; calls the dashboard Lambda via standard HTTPS endpoint
  • ShipCaptainCrew API — uses service key authentication, but CloudFront headers are stripped by the distribution's origin request function; solution was to hit the API Gateway endpoint directly, bypassing CloudFront entirely
  • Guest Portal (S3 + CloudFront) — files served from S3 bucket queenofsandiego.com, distributed via CloudFront with path rewriting logic

S3 and CloudFront Configuration

Guest pages are uploaded to S3 as flat HTML files (e.g., /tmp/jada-guest-xhqgmdh.html) with a specific naming convention. The CloudFront distribution for queenofsandiego.com includes an origin request function that rewrites incoming requests to /g/{SESSION_ID} into the corresponding flat file in S3. This avoids directory-based routing and simplifies cache invalidation.

S3 Bucket: queenofsandiego.com

CloudFront Distribution: Configured with an origin request Lambda@Edge function that handles path rewriting. When a request arrives for /g/XHQGMDH, the function rewrites it to fetch /jada-guest-XHQGMDH.html from the S3 origin.

Cache Invalidation: After upload, we invalidate the CloudFront path pattern to ensure fresh content is served immediately.

ShipCaptainCrew Authentication Deep Dive

The SCC service presented an authentication challenge. The Lambda function environment includes a SERVICE_KEY_HASH variable. On initial requests, this hash was missing from the environment, causing authentication failures. The solution involved:

  1. Downloading the SCC Lambda deployment package from the provided URL
  2. Examining the hash_password function to understand the hashing algorithm
  3. Verifying the actual service key against the expected hash
  4. Updating the Lambda environment to include the correct SERVICE_KEY_HASH

Additionally, CloudFront was stripping custom headers (including the service key). The workaround was to invoke the API Gateway endpoint directly instead of routing through the CloudFront distribution. This requires knowing the API Gateway endpoint URL (stored in secrets, not the CloudFront domain).

Example request pattern:

POST https://api-gateway-endpoint.execute-api.region.amazonaws.com/prod/events
Authorization: Bearer {SERVICE_KEY}
Content-Type: application/json

Data Pipeline and Event Flow

The booking creation follows this sequence:

  1. Trigger: New charter booked on Boatsetter; webhook or manual entry provides booking details (guest name, date, duration, rate)
  2. Financial Calculation: Compute crew costs (e.g., 2 crew × $25/hr × 5 hrs = $250), captain costs ($50/hr × 3 hrs = $150), port fees (18% of gross), and net revenue to operator
  3. Calendar Entry: POST to dashboard Lambda at /calendar endpoint with X-Dashboard-Token header; includes charter date, crew assignments, and internal notes
  4. SCC Event: POST to ShipCaptainCrew API Gateway endpoint to create event; payload includes guest details, crew roster, event description, and checklist items
  5. Guest Portal: Generate static HTML with guest-specific information (check-in time, safety briefing, emergency contact); upload to queenofsandiego.com S3 bucket with session-based naming
  6. Crew Notification: SCC event creation triggers automatic notification emails to all assigned crew with magic links for quick confirmation

Key Decision: Why Direct API Gateway for SCC

CloudFront distributions, when configured with origin request functions, may strip certain headers for security reasons. Custom authorization headers were being removed before the request reached the SCC Lambda. Rather than reconfigure CloudFront (which serves many other routes), we determined that SCC API calls should route directly to the API Gateway endpoint. This trades off the caching benefits of CloudFront for reliable, header-preserving authentication.

Key Decision: Flat HTML Files vs. Dynamic Routing

Guest portal pages could be served dynamically from a Lambda function, but instead we chose flat HTML files uploaded to S3. This decision was driven by:

  • Simplicity: No additional Lambda cold starts; S3 serves static content immediately
  • Caching: CloudFront can aggressively cache without worrying about query strings or dynamic state
  • Rewriting: The CloudFront origin request function handles path rewriting transparently
  • Cost: S3 + CloudFront is cheaper than Lambda invocations for every guest portal access

Security Considerations

  • Revenue Hiding: SCC events should not expose captain fees or revenue calculations to crew. After initial event creation, a follow-up DynamoDB update removes these fields from the notes field, ensuring crew sees only operational details
  • Token Scope: The X-Dashboard-Token is scoped to dashboard operations; SCC uses a separate service key, maintaining separation of concerns
  • CloudFront Bypass: Direct API Gateway access bypasses rate limiting and WAF rules that may be configured at CloudFront; ensure API Gateway has its own protections

Implementation Commands (Abstracted)

# List files in JADA site directory
aws s3 ls s3://sailjada.com/

# Upload guest page to queenofsandiego.com
aws s3 cp /tmp/jada-guest-xhqgmdh.html s3://queenofsandiego.com/j