```html

Creating a Dynamic Proposal Template System: Deploying Ash-Scattering Charter Proposals to S3 + CloudFront

What Was Done

We identified and resolved a missing static asset in the Queen of San Diego proposal system: the charter proposal for ash-scattering ceremonies had never been published to production, despite existing as a template. The solution involved:

  • Creating the production HTML file from an existing template pattern
  • Implementing a two-tier pricing model with decision-fatigue reduction (two options instead of four)
  • Including regulatory compliance information (USCG/EPA/MPRSA requirements)
  • Deploying to S3 with CloudFront cache invalidation
  • Verifying deployment across the CDN edge network

Technical Details: File Structure and Template Pattern

The Queen of San Diego site uses a static-site-generation pattern with a centralized template library. The proposal system lives at:

/Users/cb/Documents/repos/sites/queenofsandiego.com/proposals/

The missing file was created at:

jada-charter-proposal-sue.html

Discovery process revealed the file had never been written to disk despite being referenced in documentation. The template pattern used by other proposals in the same directory follows this structure:

  • HTML5 semantic markup with microdata for pricing and schema.org compliance
  • Inline CSS for proposal styling (no external stylesheets to reduce HTTP requests)
  • Embedded image references using relative paths to /assets/images/ directory
  • Form submission endpoints wired to bookings@queenofsandiego.com
  • Hollywood history context sections (thematic branding)

The file was created with approximately 15 iterations to achieve:

  • Correct pricing data (Option A: $750 for 2-hr Captain-only; Option B: $1,575 for 3-hr full crew)
  • Legal compliance language for ash scattering under EPA/MPRSA and USCG regulations
  • Recommendation bias toward Option A (reduced decision fatigue for the end user)
  • Removal of personal identifiers (sister-in-law name and email replaced with general booking address)

Infrastructure: S3 Deployment and CloudFront Distribution

The site uses a multi-stage deployment pipeline:

Local Git repo → S3 bucket → CloudFront distribution → DNS (Route53)

S3 Bucket Configuration:

  • Bucket name: queenofsandiego.com (derived from domain, follows naming convention)
  • Object path: proposals/jada-charter-proposal-sue.html
  • Deployment command uses AWS CLI with environment variables sourced from secrets file:
set -a; source /Users/cb/Documents/repos/.secrets/repos.env; set +a && \
aws s3 cp proposals/jada-charter-proposal-sue.html \
  s3://queenofsandiego.com/proposals/jada-charter-proposal-sue.html \
  --content-type text/html

CloudFront Distribution Setup:

After S3 upload, cache invalidation was required to ensure edge nodes served the new content immediately:

aws cloudfront create-invalidation \
  --distribution-id [DISTRIBUTION_ID] \
  --paths "/proposals/jada-charter-proposal-sue.html" \
  --region us-east-1

The distribution ID is stored in the environment secrets file and resolved at deploy time. Invalidation status was verified using:

aws cloudfront get-invalidation \
  --distribution-id [DISTRIBUTION_ID] \
  --id [INVALIDATION_ID]

This returns status tracking to confirm the invalidation completed across CloudFront's edge locations before URL went live.

DNS / Route53:

No Route53 changes were required; queenofsandiego.com already resolves to the CloudFront distribution. The proposed URL (https://queenofsandiego.com/proposals/jada-charter-proposal-sue.html) was immediately accessible after invalidation cleared.

Key Architectural Decisions

Why Static HTML Instead of Dynamic Generation?

The proposal system uses pre-generated static HTML for several reasons:

  • Performance: CloudFront serves cached HTML with zero server-side rendering latency
  • Simplicity: No database queries, no runtime dependencies, reduced attack surface
  • Version control: Every proposal version is tracked in Git with full history
  • Offline preview: Developers can open files locally to verify before deployment

Pricing Model: Two Options vs. Four

The original card referenced four pricing tiers with truncated values. We consolidated to two because:

  • Decision fatigue: Research shows three to four options is the cognitive load threshold; two reduces paralysis
  • Clear recommendation: Option A ($750) is marked as recommended, guiding users toward a faster closing path
  • Business logic: The two options correspond to actual service tiers (Captain-only vs. full crew), not arbitrary price points

Regulatory Compliance Inline

Ash-scattering charter proposals must include USCG and EPA compliance language. Rather than linking to external documents, we embedded a brief legal notice directly in the HTML. This ensures:

  • Users see compliance info without additional clicks
  • The proposal is self-contained and can be printed as a single document
  • No broken links if external compliance pages move or change

Deployment Verification

Post-deployment validation included:

  • S3 object metadata check: Verified file exists and is readable via aws s3api head-object
  • HTTP response test: curl request to the live URL confirmed 200 status and correct HTML content
  • CloudFront cache status: Checked x-cache and x-amz-cf-* headers to confirm edge serving

All checks passed; the proposal is live and cached globally.

What's Next

Pending items for the proposal:

  • Asset integration: A hi-resolution photo of the vessel interior is ready to be added; awaiting file path confirmation
  • Contact info update: Remove sister-in-law personal details; replace with generic booking email (completed in current version)
  • Form backend: Proposal form submissions currently route to email; consider migrating to a webhook-based CRM integration for better tracking
  • Analytics: Add UTM parameters or event tracking to measure proposal view-through and conversion rates

The proposal template is now production-ready and can serve as a reference pattern for future charter offerings