```html

Fixing Payment Term Inconsistencies Across Proposal Templates Using S3-Based Deployment Pipeline

What Was Done

During this development session, we identified and corrected payment term mismatches across two charter proposal templates stored in S3, then validated the fixes through a pull-and-redeploy cycle. The issue: two nearly-identical HTML proposal files (jada-charter-proposal-ewing.html and jada-charter-proposal-sue.html) contained contradictory payment language that could create confusion during client negotiations.

The Problem

The Ewing proposal on S3 specified a 50% deposit payment structure, while the Sue proposal contained conflicting terms on line 525: it stated "Deposit held in all cases" but also referenced weather-related refund conditions that contradicted the deposit language. This type of inconsistency in contract templates poses significant legal and operational risk—clients receive different terms, and internal teams can't maintain a single source of truth.

Technical Details and Process

Retrieving Proposals from S3

We used the AWS CLI to pull the proposal directly from the S3 bucket:

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

This approach allowed us to inspect the live deployed version before making changes. The S3 bucket queenofsandiego.com serves as the canonical storage for all proposal templates, with each file named using a consistent pattern: jada-charter-proposal-{clientname}.html.

Identifying Inconsistencies with grep

Rather than manually reading through HTML, we used targeted grep searches to locate payment-related language:

grep -n "deposit\|payment\|50%\|refund\|weather\|balance" /path/to/proposals/

This command searched for common payment-term keywords across all proposals in the directory, surfacing lines where terminology differed. Line numbers allowed us to navigate directly to problem areas in the files. The grep approach scales well when you have dozens of templates and need consistency auditing.

Local Editing and Validation

We edited the proposals in place on the local filesystem at /Users/cb/Documents/repos/sites/queenofsandiego.com/proposals/jada-charter-proposal-sue.html and the temporary copy of the Ewing proposal. The editing workflow was:

  • Pull from S3 to local temp storage
  • Edit HTML directly, preserving all formatting and structure
  • Validate the corrected payment terms match across both files
  • Push corrected version back to S3

By editing locally first, we avoid partial uploads and can batch changes before deployment.

Redeploying via S3 Upload

After corrections, we pushed the fixed version back to S3:

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

Note the explicit --content-type text/html flag. This ensures CloudFront and browsers treat the file as HTML rather than a generic binary object, enabling proper rendering. Without this, the browser may attempt to download rather than display the proposal.

Infrastructure and Caching Considerations

S3 as Source of Truth: All proposals live in s3://queenofsandiego.com/proposals/. This centralized bucket serves multiple purposes:

  • Single source of truth for all client-facing templates
  • Version history via S3 object metadata and optional versioning
  • Direct URL access for clients (via CloudFront CDN distribution)
  • Easy backup and disaster recovery

CloudFront Distribution: S3 bucket contents are likely served through a CloudFront distribution (typical setup for queenofsandiego.com). This means:

  • Proposal URLs are cached at edge locations globally
  • After uploading corrections, a CloudFront cache invalidation may be needed to serve fresh content immediately
  • Without invalidation, clients might see the old version for up to 24 hours (depending on TTL settings)

For time-sensitive proposal corrections, the invalidation command would be:

aws cloudfront create-invalidation --distribution-id [DIST_ID] --paths "/proposals/*"

This invalidates all proposal paths, ensuring clients receive the corrected versions on next request.

Dashboard Integration and Audit Trail

After fixing the proposals, we updated the project dashboard with status notes using the internal update_dashboard.py tool:

python3 /Users/cb/Documents/repos/tools/update_dashboard.py add-note t-f20bc5a4 "Payment terms fixed on both proposals."

This creates an audit trail linking the task ID (t-f20bc5a4) to the corrected proposals. Team members reviewing the task can see exactly what was changed and when. The tool posts notes to the progress tracking system at https://progress.queenofsandiego.com/state.json, which we validated by querying the JSON API:

curl -s 'https://progress.queenofsandiego.com/state.json' | python3 -c "import json,sys; data = json.load(sys.stdin); [print(t['id'], t.get('status')) for t in data.get('tasks', [])]"

This approach ensures the fix is documented in the team's task management system, not just in commit messages or file systems.

Key Architectural Decisions

1. Why S3 for Proposal Storage: Proposals are client-facing documents that need to be version-controlled, cached globally, and easily shared via URLs. S3 with CloudFront provides all of this without managing a separate web server or database.

2. Why Local Editing Before Upload: Editing locally allows us to test changes, use version control (git), and batch multiple corrections before deployment. This reduces the risk of partial uploads or syntax errors reaching clients.

3. Why grep for Validation: Searching for keywords like "deposit," "refund," and "weather" scales better than manual inspection, especially as the number of proposal templates grows. Regex patterns can catch even subtle variations.

4. Why Dashboard Integration: Linking infrastructure changes to task IDs creates traceability. Future team members (or future you) can see exactly which proposals were touched and why, without digging through S3 bucket metadata or git logs.

What's Next

Future improvements to this workflow could include:

  • Automated Proposal Validation: Add a pre-deployment linting step that checks all proposals for consistent payment language using a regex ruleset.
  • Version Control for Templates: Store proposal HTML in git alongside the source repository, with S3 sync triggered on commits. This gives us full git history for proposals.
  • Templating Engine: Instead of hand-editing HTML, use a templating engine (Jinja2, Handlebars) to generate proposals from a shared payment-terms config file. This eliminates duplication.