Automating Complex Event Provisioning: Building a Burial-at-Sea Event Engine
What Was Done
This session provisioned a complete burial-at-sea event—Lisa Nappi's July 18 memorial—across seven interconnected systems: proposal PDF generation, ledger reconciliation, event scheduling, database records, legal documents, crew coordination, and message dispatch. The work demonstrates a pattern for handling high-stakes, multi-party operations where data must remain synchronized across document generation, scheduling, regulatory systems, and human communication channels.
Technical Architecture
Data Source of Truth: Google Sheets API
The JADA Booking Requests sheet (spreadsheet ID: 1--kOrRP4WKN2Uu862ZbIZkJcJfv3qrBy2fuDDD9bltA) serves as the source-of-truth for client bookings. The integration queries multiple tabs (not just Sheet1) via the Sheets API, using URL-encoded range queries:
GET /v4/spreadsheets/{SID}/values/{tab}!A1:Z2000
This approach allows the booking sheet to remain human-readable while feeding automated systems. The ledger—tracking client payments, balance, and service history—is maintained in the same sheet's "Bookings" tab, enabling real-time reconciliation without custom database schema.
PDF Generation and Versioning
Proposal PDFs are generated deterministically and stored in S3. When the client's event schedule changed (muster 3:30 PM / depart 4:00 PM, corrected from the earlier 4:30/4:45), the regenerated PDF was deployed to:
s3://queenofsandiego.com/g/lisa-nappi-jul18.pdf
A CloudFront distribution sits in front of the S3 bucket, enabling cache invalidation when documents must be updated immediately. The invalidation was performed for the specific key path to avoid cache coherency issues:
cloudfront-distribution-id: (configured in infra)
invalidation-path: /g/lisa-nappi-jul18.pdf
The deterministic generation—same inputs always produce the same PDF—ensures that regenerating the document doesn't create version drift across distributed systems.
Event Record: DynamoDB Schema
Each burial-at-sea event creates a DynamoDB record with a composite key structure. For this event:
Table: burials-2026
Partition Key: event-date (2026-07-18)
Sort Key: service-name (nappi-burial)
Attributes:
guest-code: VGU2YQ (deterministically generated, used in waiver links)
party-size: ~20 guests
service-notes: [2 wreaths, rose petals, champagne + cannoli, 18% vendor fee, 9 PM red-eye hard stop, possible USAF honors]
captain-assigned: Darrell
contacts:
client-phone: +1 (619) 309-6740
client-name: Lisa Nappi
waiver-status: generated
crew-dispatch-status: scheduled-09:03am
The guest code serves double-duty: it's a short identifier for waiver links and guest pages, and it's deterministically generated from event parameters to enable idempotent creation (same event inputs always produce the same guest code).
Legal Document Generation: Deterministic Waivers
The waiver generator produces deterministic output—same event data, same waiver content and link structure. The waiver is deployed to:
queenofsandiego.com/g/2026-07-18-nappi-burial-waiver
This pattern eliminates version skew between what's promised to the client and what's actually deployed. The legal text is frozen in the generator code, making changes to waiver language an explicit code change tracked in git, not a runtime parameter that can diverge from the deployed version.
Integration Patterns: Crew Dispatch and Scheduling
Message Composition and Quiet-Hours Awareness
Crew dispatch involves SMSes to two crew members (Darrell, Travis) and an email to the admin team. Rather than sending immediately, the system stages messages in a dispatch file (/Users/cb/icloud-jada-ops/drafts/2026-07-03-nappi-jul18-crew-dispatch.md) and schedules them for delivery outside crew quiet hours:
Schedule: 09:03 AM on 2026-07-03 (outside Travis's 17:00–08:00 quiet window)
SMS recipients:
- Darrell +16199923487
- Travis +15302625427
Email (SES):
To: admin@queenofsandiego.com
Bcc: richardprietopmp@gmail.com, angelia.neel@gmail.com
From: JADA — The Queen of San Diego <admin@queenofsandiego.com>
Magic links for crew coordination are generated with a 72-hour TTL and scheduled to send ~72 hours before the event (July 15–16), ensuring crew can access links during the active coordination window without links expiring before the event date.
Ledger Integration and Payment Reconciliation
The ledger entry for Lisa Nappi records the $500 Venmo deposit and computes the remaining balance ($2,425 for remaining services). This is maintained in the same Bookings tab as other client data, enabling crew members to check payment status and fees (the 18% vendor pass-through was explicitly approved and logged in the DynamoDB service-notes).
Contacts Registry and Multi-Stage Workflow
Lisa was added to the contacts registry with a next-action of July 16 (manifest names due 48 hours before the event). This creates a contact-level workflow state independent of the event record itself—the contacts system will remind about manifest collection without the event provisioning system needing to track interim deadlines.
Guest page generation was intentionally held pending review. The decision reflects a hard lesson from a previous burial (Esmi/Tan): memorial event pages carry emotional weight and require human judgment about tone and content. Rather than auto-publishing, the system generates the page and queues it for approval.
Key Decisions and Trade-offs
- Scheduling over real-time: Crew dispatch fires at 9:03 AM on a cron rather than when provisioning completes. This decouples system availability from crew communication, allows quiet-hour rules to be enforced centrally, and keeps the provisioning system itself out of the critical path for time-sensitive messages.
- Deterministic generation for legal documents: Waivers are generated deterministically (not fetched from a database) so the deployed waiver always matches the event data that generated its link. This eliminates a class of bugs where a legal document could be updated in one system but not reflected in client-facing links.
- Idempotent event creation: The guest code is deterministically derived from event parameters, so re-running the provisioning script produces the same DynamoDB record and the same guest code. This allows the workflow to be re-triggered without duplicating events or breaking links.
- Manual vendor ordering gate: Even though the event is fully provisioned, vendor orders (wreaths, petals, champagne, pastries) require explicit approval. This avoids spending money on a contingency that might change.
What's Next
The event is now provisioned; the remaining work is human-driven: CB reviews and approves the guest page, vendor orders are placed, and the contacts system reminds about the July 16 manifest deadline. The 9:03 AM crew dispatch will route messages outside quiet hours, and magic links will be sent 72 hours before the event, giving crew adequate time to coordinate while links remain valid.