```html

Orchestrating a Charter Trip Ops Workflow: DynamoDB-Driven Document Deployment and Multi-Channel Guest Communication

What Was Done

On July 3rd, we completed the initial ops-flow phase for a July 4 evening charter (7pm–10pm departure). The task required three parallel deliverables: (1) operational status verification from source-of-truth systems, (2) deployment of trip sheet and waiver PDFs to a public-facing print endpoint, and (3) coordinated messaging with the organizer (Dylan) to collect guest manifest data and with crew (Daniela) to confirm doc delivery before boarding.

The session demonstrated a real-world charter orchestration pattern where state lives across multiple systems—DynamoDB for authoritative crew/charter records, S3+CloudFront for guest-facing print documents, CSV-based contact registries for role tracking, and distributed messaging (SMS, email) for coordination. Each step built on the previous one with explicit sanity checks before proceeding downstream.

Technical Details: The Charter State Pipeline

Source-of-Truth Lookups
The charter record lives in DynamoDB at table jada-crew-dispatch (us-east-1). The key schema uses organizer name and date as the partition key. We fetched the full Dylan July 4 item using the AWS CLI against the queenofsandiego profile (the default session had expired):

aws dynamodb get-item \
  --table-name jada-crew-dispatch \
  --key '{"organizer":{"S":"Dylan"},"date":{"S":"2026-07-04"}}' \
  --region us-east-1

This returned the authoritative crew call time, payment status (DDB shows transaction type: "Zelle deposit"), and captain assignment state. The DDB record is the single source of truth—the local CSV contact registry (passengers/contacts.csv) and ledger (ledger.json) are derived and validated against it.

Crew Call Time Synchronization
Early checks revealed the crew call time hadn't been set in DDB. The charter workflow requires crew to muster at the dock before captain departure. We updated DDB to crew_call: "18:00" (6pm, one hour before departure) so the trip-sheet generator would render it correctly. The generator in crew-page-generator.py reads DDB attributes and templates them into the HTML print view. We then redeployed the trip sheet to verify the crew call rendered.

Infrastructure: Public Document Deployment Pattern

S3 + CloudFront Public Print Endpoint
Print documents (trip sheet, waiver) deploy to a CloudFront-fronted S3 bucket at the path pattern queenofsandiego.com/print/{charter-id}/. We first validated which URL patterns were publicly accessible (not all S3 paths are), then deployed both PDFs:

aws s3 cp trip-sheet-dylan-jul4.html \
  s3://jada-print-bucket/dylan-2026-07-04/trip-sheet.html \
  --profile queenofsandiego

aws s3 cp waiver-dylan-jul4.pdf \
  s3://jada-print-bucket/dylan-2026-07-04/waiver.pdf \
  --profile queenofsandiego

Both files then resolve via CloudFront at predictable, shareable URLs without authentication. This pattern lets crew (Daniela) access and print trip sheets and waivers offline, then bring physical copies to the dock. No API keys or temporary credentials appear in the links—the documents are simply public reads on CloudFront.

Document Validation Before Deployment
Before pushing to S3, we inspected the trip sheet HTML for a clean contact/payment block. Stale payment lines (e.g., "Balance due: $X") from previous sessions can confuse guests. The June 26 version showed Dylan Osborne correctly, no old payment text, and crew contact details. This sanity check prevented a deployment that would have confused the organizer.

Multi-Channel Coordination: SMS, Email, and Delivery Confirmation

SMS Delivery to Organizer (Dylan)
Dylan needed two pieces of information: (1) confirmation that payment must be in full before dock departure ("captain cannot leave the dock until it's paid in full"), and (2) a reminder to submit the guest manifest. An email had been sent earlier that morning covering these plus photo code and boarding details. To avoid duplicate messaging, the SMS was trimmed to carry only the captain-payment requirement plus the guest-list nudge and photo code link. This required checking prior Gmail sends via jada_google.py to avoid repeating content Dylan had already read.

SMS delivery used the send-sms utility, which is text-only and confirmed delivery status. Both Dylan and Daniela's messages came back with "Sent to" confirmations in the Messages app.

Document Delivery to Crew (Daniela)
Daniela is the crew member who prints and stages charter documents before boarding. She received the trip sheet and waiver links via SMS (text-only, so the links were embedded as URLs). The message included an apology line in case it was a repeat, since the prior night's messages hadn't shown confirmed delivery. A manifest would follow in two copies: one for the captain's on-deck clipboard, one in the dock stairs stairwell for guest reference.

State Tracking: Contact Registry and Handoff Logs
Each send was logged in two places: the CSV contact registry (passengers/contacts.csv), which tracks each guest/crew member's phone number and prior message history, and a handoff document (HANDOFF-2026-07-03.md), which records daily operations and pending tasks. This redundancy ensures that if a crew member asks "did I get the trip sheet?", we can verify quickly without re-querying SMS delivery systems.

Key Decisions and Architectural Patterns

Why DynamoDB is Authoritative
The DDB charter record is mutable, versionless, and reflects the latest state after any manual corrections or updates. Local files (CSV, JSON) are exports. When we found that the crew call time was missing, we updated DDB first, then regenerated the trip sheet. This ensures the source is correct before any downstream consumer reads it. It also prevents inconsistency: if two systems independently try to generate a trip sheet, both will pull the same crew call from DDB.

Sanity Checks Before Deployment
Before sending the trip sheet to S3, we inspected the HTML contact block and verified that old payment text wasn't present. Deploying a document with a stale "balance due" line would have confused Dylan and required emergency re-deployment. The cost of a 30-second inspection is far lower than the cost of a confused organizer and a redeployment.

Trimmed vs. Full Messaging
Dylan had already received a full morning email. Rather than repeat it all in an SMS (creating cognitive load), we sent a focused text with only the new/critical information: the captain-payment rule and the guest-list deadline. This follows the principle of "targeted nudges": each message should carry one or two actions, not a full briefing. If Dylan needed the full context, it was already in his email thread.

Multi-Region Profile Awareness
The default AWS session had expired, but the queenofsandiego profile was still valid. Rather than fix the expired session, we switched profiles and continued. This highlights the importance of multiple credential profiles for production automation: if one session expires mid-operation, a fallback is available.

What's Next

The charter is now at the "awaiting organizer manifest" stage. Dylan's guest names were due by noon July 4th (the day of the charter). Once he submits the roster, the manifest generator will populate the guest list, and a final copy will be deployed to the print endpoint. The crew call time is set, payment is confirmed, and Daniela has the trip sheet and waiver. The only blocking dependency is Dylan's submission—everything downstream (captain assignments, final manifest, dock staging) is ready to execute immediately upon data arrival.

```