```html

Building a Dynamic Charter Proposal System: Static HTML Generation with AWS S3 and CloudFront

What Was Done

Created a templated HTML proposal system for charter bookings on queenofsandiego.com. The core challenge was generating a static proposal document that could be customized per client while maintaining version control, fast CDN delivery, and zero runtime overhead. The solution involved:

  • Building a parameterized HTML proposal template with semantic markup
  • Establishing a proposals/ directory structure within the static site repo
  • Deploying to S3 with CloudFront cache invalidation for instant propagation
  • Integrating legal compliance language (USCG, EPA/MPRSA regulations) into the proposal flow
  • Removing personally identifiable information (PII) from templates in favor of generic contact addresses

Technical Details

File Structure and Version Control

The proposal lives at /Users/cb/Documents/repos/sites/queenofsandiego.com/proposals/jada-charter-proposal-sue.html in the local development repo. This path mirrors the live S3 object path:

s3://queenofsandiego.com/proposals/jada-charter-proposal-sue.html

The file is tracked in Git alongside the main site content, allowing proposals to be versioned alongside code changes and rolled back if needed. This is critical for audit trails on pricing and legal language revisions.

HTML Structure and Semantic Markup

The proposal uses semantic class names for easier testing and future JavaScript enhancement:

  • .greeting-sub — personalized greeting section
  • .proposal-title — main heading
  • .vessel-banner, .history-photo, .photo-strip — image containers for responsive layouts
  • .option-a, .option-b — pricing tiers with visual distinction (one marked recommended)
  • .legal-compliance — regulatory language (USCG licensing, EPA/MPRSA ash scattering)
  • .faq-form — client Q&A submission form at bottom

This semantic approach allows future developers (or JavaScript frameworks) to target specific sections without brittle string matching.

Pricing and Decision Architecture

The proposal presents exactly two pricing options to reduce decision fatigue:

  • Option A (Captain Sergio, 2-hour): $750 flat rate — recommended
  • Option B (Full crew, 3-hour): $1,575 flat rate

Both options include the same regulatory compliance language to ensure clients understand USCG licensing requirements and EPA/MPRSA regulations governing ash scattering at sea. This is legally necessary and builds trust.

PII Removal and Contact Consolidation

Original templates referenced individual names and personal email addresses. The revised version uses a generic contact email:

bookings@queenofsandiego.com

This change:

  • Protects individual privacy in version control
  • Allows team routing behind the scenes without changing the proposal
  • Prevents PII from being exposed in git logs or S3 version histories

Infrastructure and Deployment

S3 and CloudFront Configuration

The proposal file is deployed to the S3 bucket queenofsandiego.com (public website bucket). The deployment script at publish_static_site.sh handles:

aws s3 cp proposals/jada-charter-proposal-sue.html \
  s3://queenofsandiego.com/proposals/jada-charter-proposal-sue.html \
  --content-type "text/html; charset=utf-8"

After S3 upload, a CloudFront cache invalidation is triggered to purge the CDN edge cache:

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

This ensures:

  • Global users fetch the latest version within seconds (not hours)
  • No manual cache busting needed on the client side
  • Proposals update atomically — no race conditions between regions

DNS and URL Structure

The live URL is:

https://queenofsandiego.com/proposals/jada-charter-proposal-sue.html

This uses the bare domain (no subdomain). The DNS is managed via Route53, with an alias record pointing to the CloudFront distribution. This approach:

  • Allows free HTTPS via CloudFront's default certificate
  • Handles 301/302 redirects at the edge (CDN level) for SEO
  • Enables future A/B testing by swapping S3 objects or CloudFront behaviors

Key Design Decisions

Why Static HTML Over Dynamic Rendering

A static HTML proposal (not generated server-side or via Lambda@Edge) was chosen because:

  • No runtime cost: Once deployed, S3 serves it with zero compute overhead
  • Version control: Each proposal revision is tracked in Git with diffs
  • Simplicity: No database queries, environment variables, or template engines needed
  • Sharability: A single immutable URL works for email, SMS, and print (QR codes)

If per-client personalization becomes needed (e.g., client name, custom dates), the recommendation is to generate static files during CI/CD, not at request time.

Why Semantic Class Names Matter

Future requirements may include:

  • Email rendering (stripping JavaScript, optimizing images for Outlook)
  • PDF generation (CSS-paged media queries)
  • Form parsing (extracting structured data for admin dashboards)

Semantic class names make these transformations trivial. A script can target .option-a and extract pricing without string parsing.

Legal Compliance as Design Constraint

USCG licensing and EPA/MPRSA ash scattering regulations are prominently featured because:

  • They are legal requirements, not optional marketing
  • Clients need to understand they're hiring a licensed captain, not bareboat renting
  • Liability is reduced when clients acknowledge compliance language

What's Next

Image Asset Integration