```html

Multi-Tenant Proposal Management: Dynamic Payment Terms Correction & S3 Deployment Pipeline

Overview

This session involved debugging and correcting payment term inconsistencies across two charter proposal documents stored in S3, then implementing a systematic approach to validate proposal state before deployment. The work highlights the challenges of maintaining consistency in template-driven document generation across multiple clients and the importance of validation layering in static site hosting architectures.

The Problem: Inconsistent Payment Terms

Two separate charter proposals—one for the Ewing family and one for Sue—contained conflicting or incorrect payment terms that didn't match the agreed-upon contract language. Specifically:

  • jada-charter-proposal-ewing.html: Listed "50% deposit" when the correct terms should have been a different structure
  • jada-charter-proposal-sue.html: Had contradictory language on line 525 (refund conditions vs. deposit handling) that created ambiguity for clients

The root cause was manual edits to HTML templates without validation against a canonical terms document, and proposals being generated/edited at different times with different assumptions about what "standard terms" meant.

Technical Approach: Multi-Layer Validation

Step 1: Retrieve and Analyze Proposal State

We pulled the proposals from their S3 location and analyzed them locally before making changes:

aws s3 cp s3://queenofsandiego.com/proposals/jada-charter-proposal-ewing.html /tmp/ewing-proposal.html

grep -n "deposit\|payment\|refund\|weather\|500\|balance" /tmp/ewing-proposal.html

This grep-based search identified all payment-related language in the document, allowing us to spot inconsistencies without manual reading of the full HTML. The search terms were chosen to catch:

  • deposit: Upfront payment mentions
  • payment: General payment references
  • refund: Refund policy language
  • weather: Weather cancellation clause (often tied to refund logic)
  • 500: Numeric reference (deposit amounts, balance due)
  • balance: Outstanding balance language

Step 2: Edit and Validate Locally

Rather than editing directly in S3, we:

  1. Created a working copy at /tmp/ewing-proposal.html
  2. Made corrections to payment term language to align with the canonical contract structure
  3. Verified the corrected terms didn't introduce new conflicts (re-ran grep validation)
  4. Only then deployed to S3

This local-first workflow prevents partial uploads or corruption mid-edit, since S3 operations are atomic at the object level but not at the content level if interrupted.

Step 3: S3 Deployment with Content-Type Headers

Deployed the corrected proposal back to S3 with explicit content-type specification:

aws s3 cp /tmp/ewing-proposal.html s3://queenofsandiego.com/proposals/jada-charter-proposal-ewing.html \
  --content-type text/html

The --content-type flag is critical for CloudFront caching and browser rendering. Without it, S3 may infer the MIME type incorrectly, causing browsers to download the HTML as an attachment rather than render it. This is especially important for proposal previews that need to be viewed in-browser.

Infrastructure: The S3 → CloudFront → Route53 Chain

Proposals are served through a standard AWS content delivery pipeline:

  • S3 bucket: s3://queenofsandiego.com/proposals/ — stores all proposal HTML documents
  • CloudFront distribution: Caches proposals with configurable TTL to reduce origin hits and improve client-side load times
  • Route53: DNS records point progress.queenofsandiego.com and similar subdomains to the CloudFront distribution

A key insight: because proposals are static HTML documents, they're ideal CloudFront candidates. However, after making corrections, the CloudFront cache must either be invalidated or allowed to expire. In this case, we relied on the default cache TTL (typically 24 hours for HTML objects), which is acceptable for internal-facing proposal updates since clients view them shortly after generation.

Dashboard Integration: Tracking Changes

After deploying the corrected proposals, we updated the internal dashboard via Python script calls:

python3 /Users/cb/Documents/repos/tools/update_dashboard.py add-note t-33502227 \
  --text "Payment terms corrected — both proposals now aligned with contract language"

This dashboard integration serves two purposes:

  1. Audit trail: Records what was changed and when, enabling future debugging if discrepancies arise again
  2. Client notification: Notes can be automatically surfaced to relevant team members or even clients via email/API hooks

The dashboard also maintains task state, allowing us to mark related work items (like follow-up emails to Pat Steigerwald) as needing attention without losing context.

Why This Matters: Template Fragility

The core issue this session exposed is that HTML proposal templates are brittle when edited manually. Without a source-of-truth document (like a JSON schema or YAML config defining payment terms), each edit risks introducing inconsistencies.

Better solutions for future improvements:

  • Template-driven generation: Generate proposals from a base template + client data JSON, rather than editing HTML directly
  • Schema validation: Define proposal structure in JSON Schema; validate each generated/edited proposal against it before S3 upload
  • Canonical terms document: Maintain payment terms in a single source file (e.g., /Users/cb/Documents/repos/policies/charter-payment-terms.md); reference it in all proposals to prevent drift
  • Pre-deploy checks: Run grep/regex validation as part of CI/CD pipeline before S3 upload, catching payment term discrepancies automatically

Key Decisions

  • Local-first edits: We edited proposals locally before S3 deployment to avoid partial uploads and enable easier rollback if needed.
  • Explicit MIME types: We specified --content-type text/html on S3 upload to ensure CloudFront and browsers handle the content correctly.
  • Grep-based validation: Rather than manual reading, we used grep to identify all payment-related language, reducing human error.
  • Dashboard logging: We recorded the changes in the dashboard system, creating an audit trail and enabling team visibility into proposal corrections.

What's Next

Short term: Monitor for similar inconsistencies in other proposals by running the same grep validation across all proposals in the bucket:

for file