```html

Automated Calendar Sync and Guest Management for Charter Operations: Lambda, DynamoDB, and CloudFront Integration

What Was Done

This session focused on synchronizing crew assignments across multiple systems for JADA charter operations, ensuring consistency between the Google Calendar source-of-truth, a DynamoDB event roster, guest boarding pages, and crew assignment endpoints. The core challenge: crew data lives in three places (Google Calendar, DynamoDB, S3 guest pages), and manual updates create race conditions and data inconsistency.

We implemented a multi-system sync workflow that:

  • Patched crew assignments in Google Calendar via the Calendar API
  • Updated corresponding DynamoDB event records
  • Regenerated and deployed S3 guest/crew pages via CloudFront invalidation
  • Validated waiver endpoints and Lambda handlers for minor passenger support
  • Tested end-to-end boarding email delivery with photo upload codes

Technical Details: Calendar and Crew Data Flow

Google Calendar as Source-of-Truth

The JADA Internal calendar (accessed via Google Calendar API) serves as the authoritative crew roster. Each event record contains:

  • Event metadata: date, time, location (e.g., "Quinn Male - May 30, 2:30 PM")
  • Captain assignment in event title or description
  • Crew members listed in attendees or description field

Commands used to validate and update:


# Fetch event list with iCal parsing (avoids OAuth token refresh issues)
curl -H "Authorization: Bearer ${GOOGLE_CALENDAR_TOKEN}" \
  "https://www.googleapis.com/calendar/v3/calendars/JADA_INTERNAL_CALENDAR_ID/events?timeMin=2026-05-28T00:00:00Z&timeMax=2026-06-16T23:59:59Z"

# Patch individual event via Calendar API
curl -X PATCH \
  -H "Authorization: Bearer ${GOOGLE_CALENDAR_TOKEN}" \
  -H "Content-Type: application/json" \
  -d '{"description":"Updated crew: Gene (Captain), Angelia removed"}' \
  "https://www.googleapis.com/calendar/v3/calendars/JADA_INTERNAL_CALENDAR_ID/events/EVENT_ID"

Why this approach: Google Calendar's real-time sync, permission model, and mobile accessibility make it ideal for crew scheduling. The API supports PATCH operations for incremental updates without overwriting the entire event.

DynamoDB as Operational State

Event records are mirrored in DynamoDB (table: jada-events, partition key: event_id) to enable fast queries by crew dispatch, Lambda functions, and the waiver endpoint. Structure:


{
  "event_id": "quinn-male-2026-05-30",
  "date": "2026-05-30",
  "time_start": "14:30",
  "time_end": "17:30",
  "captain": "Gene",
  "crew": ["Angelia"],
  "passengers": ["Quinn (M)"],
  "event_type": "charter",
  "waiver_required": true,
  "status": "confirmed"
}

Updates were applied via AWS CLI:


aws dynamodb update-item \
  --table-name jada-events \
  --key '{"event_id":{"S":"quinn-male-2026-05-30"}}' \
  --update-expression "SET captain = :captain, crew = :crew" \
  --expression-attribute-values '{":captain":{"S":"Gene"},":crew":{"L":[{"S":"Angelia"}]}}'

Why DynamoDB: Low-latency reads for real-time crew dispatch, built-in TTL for event archival, and tight integration with Lambda (synchronous updates without polling).

Infrastructure: S3, CloudFront, and Guest Pages

Guest Page Deployment Pipeline

Three guest pages were generated and deployed to S3 for this weekend's charters:

  • quinn-guest.htmls3://jada-public-assets/charters/quinn-male-2026-05-30/guest.html
  • danika-guest.htmls3://jada-public-assets/charters/danika-2026-05-31/guest.html
  • jonathan-afternoon.htmls3://jada-public-assets/charters/jonathan-afternoon-2026-05-30/guest.html

Each page includes:

  • Charter details (date, time, captain, crew roster)
  • Embedded waiver iframe linking to https://waiver.jada.internal/events/{event_id}
  • Photo upload code for boarding documentation
  • Arrival time ("Arrive by 2:15 PM" for Quinn Male, "3:00 PM" for Danika)

Deployment and cache invalidation:


# Upload files to S3
aws s3 cp quinn-guest.html s3://jada-public-assets/charters/quinn-male-2026-05-30/guest.html
aws s3 cp danika-guest.html s3://jada-public-assets/charters/danika-2026-05-31/guest.html
aws s3 cp jonathan-afternoon.html s3://jada-public-assets/charters/jonathan-afternoon-2026-05-30/guest.html

# Invalidate CloudFront cache (distribution: E2JFKL9M7XQPW)
aws cloudfront create-invalidation \
  --distribution-id E2JFKL9M7XQPW \
  --paths "/charters/quinn-male-2026-05-30/*" \
       "/charters/danika-2026-05-31/*" \
       "/charters/jonathan-afternoon-2026-05-30/*"

Why CloudFront: Edge caching reduces origin load; TTL=3600s balances freshness and performance. Invalidation propagates within 60 seconds, ensuring guests see updated crew rosters before receiving boarding emails.

Waiver Endpoint and Minor Passenger Support

The waiver system (Lambda function: jada-waiver-handler) was tested to verify:

  • Guardian data is captured for minor passengers
  • POST requests to /events/{event_id}/waiver store records in DynamoDB table jada-waivers
  • Photo upload codes are generated and returned in response

Test waiver submission for Quinn (minor):


curl -X POST https://waiver.jada.internal/events/quinn-male-2026-05-30/waiver \
  -H "Content-Type: application/json" \
  -d '{
    "passenger_name": "Quinn",
    "passenger_age": 12,
    "guardian_name": "Parent/Guardian Name",
    "guardian_email": "guardian@example.com",
    "guardian_phone": "+1-619-555