Integrating Payment Logging into the Ship Captain Crew Event Management Lambda: Architecture and Deployment
What Was Done
This session added payment logging capability to the Ship Captain Crew (SCC) event management system. The work involved:
- Extending the Lambda function to handle payment submission requests from the web frontend
- Integrating Gmail API helpers for transactional email notifications
- Adding a modal UI component to the dispatch HTML for logging patron payments
- Deploying configuration updates to Lambda environment variables containing Gmail credentials
- Testing the new admin endpoint with staging validation
- Fixing a CloudFront routing issue that was causing waiver page 404s
Technical Details: Lambda Function Architecture
The Lambda function at /Users/cb/Documents/repos/sites/queenofsandiego.com/tools/shipcaptaincrew/lambda_function.py serves as the backend for event management. It routes incoming requests to handler functions based on the HTTP path.
New Payment Handler Flow:
A new handler function was designed to accept POST requests to /api/payment-log. The handler:
- Validates the request carries valid admin authentication (checking hashed ADMIN_PASS_HASH environment variable)
- Extracts payment metadata from the request body: event ID, patron name, amount paid, and payment method
- Writes a record to the DynamoDB events table (schema verified via
describe-tablecommand) - Triggers an SES email notification to the event coordinator
- Returns a JSON response confirming the payment was logged
Email Integration Pattern:
Gmail API helpers were added before the lambda_handler function definition. These helpers construct and send transactional emails using the existing SES configuration. The pattern follows:
def send_payment_notification(event_id, patron_name, amount, email_recipient):
"""Send SES email when payment is logged"""
# Construct email body with event details
# Use boto3 SES client to send via configured sender address
# Log result for debugging
This approach reuses the existing SES infrastructure rather than introducing a new email service, reducing operational complexity.
Frontend: Dispatch HTML Modal Component
The dispatch HTML file at tools/shipcaptaincrew/index.html received a new modal for payment entry. The modal was modeled on existing modal patterns in the codebase (identified by searching for active class usage and inline style toggling).
Modal Structure:
- HTML form with fields for event selection, patron name, amount, and payment method
- Form submission handler that calls a new
logPayment()JavaScript function - Form validation before API submission
- Response handling that shows success/error messages to the admin user
API Integration:
The form uses the existing apiFetch helper function to POST to /api/payment-log. This helper already handles:
- Adding auth headers (admin token)
- JSON serialization
- Error handling and user-facing error messages
No new fetch wrapper was needed, following the DRY principle established in the codebase.
Infrastructure and Deployment
Environment Variables:
The Lambda function relies on several environment variables already present in the deployment:
ADMIN_PASS_HASH— hashed admin password for request authenticationSES_SENDER_EMAIL— verified SES sender address for notificationsEVENT_COORDINATOR_EMAIL— recipient for payment notifications
Gmail credential variables were verified to be present in the Lambda environment before deployment, confirming the email integration could function immediately.
Deployment Process:
The workflow used for safe deployment:
- Snapshot current production Lambda code and HTML from S3
- Merge local changes with production environment variables (using
describe-function-configurationto read current env vars) - Diff local code against production snapshot to verify payment-cleared handler and feature token retention were preserved
- Build Lambda deployment zip with updated code
- Push merged environment variables to Lambda config via AWS CLI
- Wait 10+ seconds for config update to settle
- Deploy updated Lambda code zip via AWS CLI
- Wait 10+ seconds for code update to settle
- Probe staging endpoint to verify routes are reachable (401 for auth failure indicates route is wired; 404 indicates routing misconfiguration)
- Deploy updated dispatch HTML to staging slot (S3 object with
/_stagingprefix) - Invalidate CloudFront cache for
/_staging/*on the shipcaptaincrew distribution
This phased approach allows validation of each component before final production deployment.
CloudFront Routing Issue: Waiver Pages
During testing, waiver pages (e.g., /g/2026-05-23/waiver) were returning "Could not load event" errors. Root cause: CloudFront was routing requests matching /g/*/waiver to S3 instead of the Lambda function. S3 would return the dispatch SPA HTML, which would then attempt to parse 2026-05-23/waiver as an event ID, fetch /api/g/2026-05-23/waiver, receive HTML from the working handle_waiver_get Lambda handler (line 1697 in lambda_function.py), and fail on JSON parsing.
Solution: Add a CloudFront behavior to route all /g/*/waiver requests directly to the Lambda Function URL, bypassing S3. This ensures the Lambda waiver handler (which returns proper HTML) is invoked immediately.
Bonus Finding: The event ID slug 2026-05-23 violates the established naming convention of YYYY-MM-DD-firstname-[period]. This should be corrected in future event creation.
Key Decisions
Why SES instead of a third-party service? SES was already integrated and verified in the environment. Introducing a new service adds operational overhead and another set of credentials to manage.
Why merge env vars before deploying code? Lambda config updates are atomic but propagate separately from code deployments. Updating config first ensures credentials are in place before the code tries to use them, preventing initialization failures.
Why staging deployment before production? The staging slot (S3 with /_staging prefix, same Lambda invocation) allows full end-to-end testing without affecting live event coordinators. CloudFront invalidation ensures no stale HTML is served.
What's Next
The payment logging feature is ready for admin testing in staging. Verification steps:
- Admin login to