```html

Multi-Domain Event Infrastructure: Coordinating Charter Bookings Across SCC, JADA Calendar, and Guest-Facing Pages

When a charter booking comes through Boatsetter, it needs to exist in at least four places simultaneously: the internal JADA calendar system, the ShipCaptainCrew (SCC) crew management platform, a guest-facing confirmation page, and a crew-facing logistics checklist. This post walks through the infrastructure decisions and implementation details for automating this multi-system synchronization.

The Problem: Four Systems, One Event

A typical booking creates a chain reaction:

  • Captain needs to confirm availability and see earnings
  • Crew (2 × 5-hour shifts at $25/hr) need crew-facing checklists and confirmation links
  • Internal calendar must reflect the booking with financial projections
  • Guest must receive a confirmation page with logistics details
  • Each system has different authentication, different required fields, and different data models

Building this manually takes ~30 minutes per booking. Automating it is worth the infrastructure investment.

Technical Architecture

System Integration Points

SCC Lambda (Source of Truth for Events)

The ShipCaptainCrew Lambda function at /tmp/scc-lambda-src/lambda_function.py is the primary event creation endpoint. It handles:

  • Event CRUD operations (routes POST /events, PATCH /events/{id})
  • Authentication via SERVICE_KEY_HASH environment variable (bcrypt-verified)
  • DynamoDB persistence to scc-events table
  • Automatic crew notification via magic links (handled by Lambda's handle_event_create)

The key insight: SCC Lambda automatically emails all assigned crew when an event is created. This is handled by the event creation handler, which queries the crew list and generates time-limited confirmation links. No separate notification system needed.

JADA Calendar Lambda

A separate Lambda (identified via secrets lookup) handles internal calendar entries. It requires:

  • X-Dashboard-Token header (API key authentication)
  • POST body with date, revenue, expenses, notes
  • Endpoint accessible via API Gateway URL (not CloudFront, to avoid header stripping)

Guest-Facing Page Infrastructure

Guest pages are hosted on queenofsandiego.com (CloudFront distribution) with S3 origin queenofsandiego-static. The CloudFront function (Viewer Request) rewrites paths:

  • /g/{GUID}.html → serves from S3 key /g/{GUID}.html
  • Pages are flat HTML files (not directory-based) per the CF function's uri.endsWith('.html') pattern
  • CloudFront distribution ID: (retrieved from secrets, not repeated here)

Crew-Facing Logistics Page

The crew page is served directly through SCC's existing guest presign route (GET /g/{event_id} in SCC Lambda). This endpoint:

  • Validates the crew member's magic link token
  • Returns time-aware HTML with photo upload capability
  • Presigns S3 URLs for crew to upload charter photos
  • Reads from the same SCC events table as the calendar system

Implementation Details

Event Creation Workflow

The automation runs these steps in sequence:

  1. Calculate financials
    Gross Revenue:        $840.75
    Crew (2 × 5hr × $25):  -$250.00
    Captain (3hr × $50):   -$150.00
    Port/Tax (18%):        -$151.34
    ────────────────────────────
    Net to Captain:        $289.41
  2. Create SCC Event
    POST /events (via direct API Gateway URL, not CloudFront)
    {
      "event_id": "XHQGMDH",
      "date": "2025-05-30T14:00:00Z",
      "duration_hours": 3,
      "crew_ids": ["crew-1", "crew-2"],
      "captain_id": "captain-1",
      "notes": "Boatsetter booking ref: [BOOKING_ID]",
      "status": "pending_confirmation"
    }
    

    SCC Lambda automatically hashes the SERVICE_KEY, compares to SERVICE_KEY_HASH env var, then creates the event and triggers crew notifications.

  3. Create JADA Calendar Entry
    POST /calendar (to Lambda endpoint, bypasses CloudFront)
    Headers: X-Dashboard-Token: [TOKEN]
    {
      "date": "2025-05-30",
      "revenue": 840.75,
      "expenses": {
        "crew": 250.00,
        "captain": 150.00,
        "port_tax": 151.34
      },
      "notes": "Boatsetter charter + SCC event XHQGMDH"
    }
    
  4. Generate Guest Page
    • Build static HTML file with guest's name, date, time, and logistics
    • Write to /tmp/jada-guest-XHQGMDH.html locally
    • Upload to S3: s3://queenofsandiego-static/g/XHQGMDH.html
    • Invalidate CloudFront cache: /g/XHQGMDH.html
  5. Crew Receives Confirmation Links

    SCC Lambda's event creation handler has already sent magic link emails. Each crew member receives a unique token that grants access to /g/XHQGMDH?token=[CREW_TOKEN], which displays the crew logistics page with photo upload.

Key Technical Decision: Bypassing CloudFront for API Calls

During implementation, we discovered that CloudFront was stripping the X-Dashboard-Token header when routing to Lambda origins. The solution: use the direct API Gateway URL instead of the CloudFront distribution URL for programmatic API calls.

This required identifying the actual API Gateway endpoint URL from the Lambda configuration, then using it as an alternate route for cross-system integration calls. Guest-facing requests continue to use CloudFront (with caching benefits), but system-to-system calls use the direct endpoint.

Why No Separate Captain/Hostess Fields in SCC

The booking request indicated "no hostess, no host, just bare minimum." The SCC event is created with only crew_ids and captain_id arrays—no additional host fields. This keeps the DynamoDB schema lean and reflects the actual staffing model.

Infrastructure Resources