Automating Charter Provisioning: A Complete End-to-End Workflow for Sailing Operations
What Was Done
This session executed a complete charter provisioning workflow for a July 24, 2026 event (Adam Zehner's Comic-Con charter). The workflow demonstrates a multi-system integration pattern used to convert a booking into a fully operational charter: ledger entries, crew dispatch, guest page generation, and automated client communication—all coordinated through a deterministic provisioning tool and canonical workflow documentation.
The Provisioning Workflow
The charter provisioning system is defined in /Users/cb/icloud-jada-ops/CHARTER-WORKFLOW.md, which serves as the source of truth for the exact sequence and validation checks. The implementation is split across several components:
- Ledger System:
ledger.jsonstores all charter financials. For Adam's charter, the entryadam-zehner-comicconwas created with: total price ($2,368 honoring Carole's 2025 quote), deposit received ($500 Venmo on 7/3), and balance due ($1,868 at boarding). The ledger uses a slug-based key structure; existing entries are updated directly rather than recreated. - Contacts Register:
/Users/cb/icloud-jada-ops/passengers/contacts.csvis the persistent contact and booking status register. Adam's row was marked asbookedfor July 24 to prevent double-booking and track historical charters. - Calendar & Dispatch: Two integrated systems ensure crew coordination. A calendar event is created in the JADA Internal Google Calendar (accessible via OAuth scope
calendar), and a DynamoDB dispatch record is created with the charter identifier as the primary key. The crew muster time is calculated from the event time minus one hour (default rule:charter_provisioner.pyapplies this rule automatically). - Guest Page Generation: A dynamic HTML guest page is generated from the latest live template (stored in S3), customized with charter-specific data, and deployed to
https://queenofsandiego.com/g/2026-07-24-adam-zehner.html. This page is the public-facing interface for guests to upload their USCG names and photos. - Photo Code Management: A unique photo upload code (in this case,
2UEJ2J) is generated and stored in the DynamoDB dispatch record. This code is shared with the captain and used by the photo API to authenticate uploads without exposing credentials.
Infrastructure & Integration Points
The workflow touches multiple cloud and local services:
- Google Workspace: Gmail and Google Calendar APIs (via
jada_google.py) handle client communication and crew scheduling. The calendar event creation required reading the canonical JADA Internal calendar ID from memory/rules storage. - DynamoDB Dispatch Table: The
2026-07-24-adam-zehnerrecord stores all operational metadata: event date/time, crew assignments, guest count, photo code, and waiver/manifest status flags. The dispatch table is the system of record for real-time ops. - S3 & CloudFront: Guest pages are stored in S3 and served via CloudFront to ensure fast global delivery and HTTPS support. The URL pattern
queenofsandiego.com/g/{charter-slug}.htmlis routed through Route53 DNS to the CloudFront distribution. - Local Ledger & CSV:
ledger.jsonandcontacts.csvare version-controlled in the ops repository and serve as local audit trails. The ledger supports thequotecommand to pull prior pricing (used here to honor Carole's 2025 $2,368 quote for Adam's charter).
Key Decisions & Constraints
Why honor a prior-year quote? The 2025 quote ($2,368) was treated as a commitment. When Adam re-booked under similar circumstances (same captain, same event type), applying the prior quote preserved customer trust and simplified pricing negotiation. The quote was extracted from Carole's email attachments and converted from .docx to text for parsing.
Why separate crew muster from event start? The −1 hour rule (muster at 16:00 for a 17:00 event start) accounts for pre-event briefing and safety checks. This is coded into the provisioner's default behavior rather than manual calculation, reducing error.
Why a unique photo code per charter? The photo code (2UEJ2J) decouples photo uploads from crew identity, allowing guests to upload candids without exposing authentication. The code is validated server-side against the DynamoDB record before any upload proceeds.
Why two parallel SMS messages? Adam received separate texts: one with the guest page link and photo code, another with operational details (USCG name list due date, 28-guest capacity limit from the vessel, balance due). This splits concerns—guest-facing URLs from operational constraints—and matches the communication pattern documented in CHARTER-WORKFLOW.md.
Conflict Detection & Validation
Before provisioning, the system checked for scheduling conflicts. The provision tool verified that July 24 was clear in the dispatch table and that the designated crew (Darrell) had no blackout dates overlapping the charter date (his blackout begins July 25). This prevents overbooking and crew unavailability, two common operational failures.
Remaining Work
Post-provisioning tasks are documented in /Users/cb/icloud-jada-ops/2026-07-24-adam-zehner/NOTES.md and include:
- Crew dispatch confirmation (once Darrell confirms availability)
- Trip sheet and liability waiver generation
- Final manifest once Adam's guest list arrives (capped at 28 passengers)
This separation of concerns—provisioning the infrastructure separately from finalizing crew assignments and manifests—allows the system to operate in parallel and surfaces missing data early rather than blocking the entire workflow.
What's Next
The guest page is live and Adam has been texted the link and code. From here, the workflow enters the confirmation phase: Adam submits his guest list, crew responds with final availability, and the trip sheet/waiver are generated. The dispatch record in DynamoDB will be updated with waiver signatures and final manifest count before the charter date.