Deploying a Receipt Management System on quickdumpnow.com: S3, CloudFront, and Custom Error Handling

This post covers the deployment of a new receipts page for a trailer rental business operating under quickdumpnow.com, including S3 object management, CloudFront invalidation strategies, and debugging custom error responses that were masking missing content.

Project Context

The quickdumpnow.com domain needed a dedicated receipts/books section at /books to manage trailer rental payment records. The site is hosted on S3 with CloudFront distribution caching, requiring careful coordination of object uploads and cache invalidation to ensure the new page went live without serving stale content.

What Was Done

  • Created and deployed /books/index.html with a receipts intake form
  • Updated robots.txt to block the /books path from search indexing
  • Uploaded assets to S3 bucket quickdumpnow.com
  • Managed CloudFront cache invalidation for multiple object paths
  • Debugged and validated custom error response configuration
  • Updated the ExpenseTracker Google Apps Script to log a charter payment ($1,845.72) to the Port Log sheet

Technical Details: S3 Object Management

The critical decision here was understanding how S3 and CloudFront handle "pretty URLs" versus explicit index files. When deploying a directory-based page to S3:

# Local file structure
/Users/cb/Documents/repos/sites/quickdumpnow.com/books/index.html

# S3 upload strategy
s3://quickdumpnow.com/books/index.html  (traditional object path)
s3://quickdumpnow.com/books             (bare key for pretty URL routing)

The initial deployment only uploaded to /books/index.html, which caused CloudFront to return a 404—because S3 doesn't automatically redirect requests to /books to /books/index.html the way a traditional web server does. The solution was to upload the HTML content to both keys:

  • s3://quickdumpnow.com/books/index.html — for direct file requests
  • s3://quickdumpnow.com/books — for directory-level routing via CloudFront

This dual-key approach ensures that whether a user requests quickdumpnow.com/books or quickdumpnow.com/books/, CloudFront can serve the correct HTML object without relying on S3 redirect rules.

CloudFront Distribution Configuration

The CloudFront distribution for quickdumpnow.com was configured with a custom error response that was initially masking the real issue. The distribution had:

  • Origin: S3 bucket quickdumpnow.com
  • Default Root Object: index.html
  • Custom Error Response: 404 errors redirecting to /index.html (homepage)

This error response is appropriate for single-page applications, but it meant that when the /books object didn't exist in S3, CloudFront would silently serve the homepage instead of failing visibly. This made debugging harder—the HTTP response code was 200 (from the homepage), not 404.

After uploading the correct objects to S3, we invalidated the CloudFront cache for the affected paths:

# CloudFront invalidation commands (pseudocode)
Invalidate pattern: /books
Invalidate pattern: /books/*
Invalidate pattern: /robots.txt

CloudFront typically completes invalidations within 30–60 seconds for small batches. We issued separate invalidations for different path patterns to ensure comprehensive cache clearing without over-invalidating unrelated objects.

robots.txt Updates

The /robots.txt file was updated to block search engine crawling of the receipts page, since this is internal business data:

# /robots.txt
User-agent: *
Disallow: /books
Disallow: /admin

The robots.txt file itself is served as a top-level S3 object (s3://quickdumpnow.com/robots.txt) and required its own CloudFront invalidation to ensure search bots fetch the updated version.

Infrastructure Decision: Why Dual S3 Keys?

S3 is an object store, not a traditional filesystem. It doesn't support directory semantics natively. When CloudFront requests an object and receives a 404 from S3, it doesn't automatically try appending /index.html. The Default Root Object setting only applies to the root path (/), not to subdirectories.

The dual-key approach avoids adding complexity like:

  • Lambda@Edge functions to rewrite URLs
  • CloudFront origin request behaviors with path rewriting
  • S3 website hosting mode (which has limitations and doesn't integrate as cleanly with CloudFront origins)

By uploading identical content to both /books and /books/index.html, we keep the architecture simple and stateless.

Google Apps Script Integration: Port Log Update

In parallel, the ExpenseTracker Google Apps Script project was updated to log a charter payment. The workflow involved:

  1. Authenticating to the GAS project and retrieving the correct sheet ID for the Port Log tab
  2. Reading existing headers and entries to understand the data structure
  3. Appending a new row with the charter payment: Joseph Zurek, $1,845.72
  4. Cleaning up test entries that were used during validation

The GAS script uses the Sheets API via the clasp CLI and manifest configuration, allowing programmatic row appends without manual Google Sheets interaction. This ensures accurate, timestamped financial records.

Key Decisions Summary

  • S3 dual-key upload: Simplifies URL routing without Lambda@Edge
  • CloudFront invalidation strategy: Separate invalidations for /books and /robots.txt ensure cache coherency
  • robots.txt blocking: Protects internal business data from search indexing
  • GAS automation: Keeps financial logging accurate and audit-ready

What's Next

The receipts page is now live at https://quickdumpnow.com/books. Future work includes:

  • Building out the receipt submission form to POST data back to the Port Log sheet
  • Adding file upload capability (S3 signed URLs for client-side receipt PDF/image uploads)
  • Implementing authentication to restrict access to authorized business users
  • Monitoring CloudFront cache hit ratios and S3 request patterns to optimize costs