Deploying a Static Receipt Upload Interface for quickdumpnow.com/books with CloudFront Cache Invalidation

This post covers the technical work to establish a dedicated receipt management endpoint for a trailer rental business, including S3 deployment patterns, CloudFront distribution configuration troubleshooting, and cache invalidation strategy.

What Was Done

The goal was to create a functional receipt upload interface at https://quickdumpnow.com/books that would serve as a distinct landing page from the main domain. The project required:

  • Deploying a new static HTML page to S3 with proper URL structure
  • Updating robots.txt to block search engine indexing of the receipt area
  • Diagnosing and working around CloudFront custom error response configuration
  • Invalidating CloudFront cache to surface the new endpoint

Technical Details: File Structure and Deployment

The quickdumpnow site is deployed to an S3 bucket with CloudFront distribution in front. The local repository structure mirrors this:

/Users/cb/Documents/repos/sites/quickdumpnow.com/
├── index.html
├── robots.txt
└── books/
    └── index.html

The books/index.html file existed locally but hadn't been uploaded to S3. Initial attempts to access /books returned the homepage, indicating a CloudFront configuration issue rather than a missing file problem.

Infrastructure: S3 and CloudFront Configuration

The quickdumpnow S3 bucket uses a common static site hosting pattern: the CloudFront distribution has a custom error response configured that redirects all 4xx errors (including 404s) back to index.html. This is a typical SPA fallback pattern, but it masks deployment issues.

The deployment required uploading the books page to S3 using two keys to ensure both "pretty URLs" and direct file access work:

  • s3://quickdumpnow-static/books/index.html — traditional file path
  • s3://quickdumpnow-static/books — bare key for CloudFront path-based routing

The second key is necessary because CloudFront's origin (S3) doesn't automatically rewrite `/books` to `/books/index.html` the way traditional web servers do. By creating the bare books object, we ensure that requests to https://quickdumpnow.com/books resolve directly without relying on index document rewriting at the distribution level.

Command sequence for upload (executed with AWS CLI credentials configured):

aws s3 cp /Users/cb/Documents/repos/sites/quickdumpnow.com/books/index.html \
  s3://quickdumpnow-static/books/index.html \
  --content-type "text/html; charset=utf-8"

aws s3 cp /Users/cb/Documents/repos/sites/quickdumpnow.com/books/index.html \
  s3://quickdumpnow-static/books \
  --content-type "text/html; charset=utf-8"

aws s3 cp /Users/cb/Documents/repos/sites/quickdumpnow.com/robots.txt \
  s3://quickdumpnow-static/robots.txt \
  --content-type "text/plain"

Cache Invalidation Strategy

After uploading, the CloudFront distribution needed cache invalidation to surface the new content. The distribution ID for quickdumpnow.com is stored in the site's CloudFront configuration. We invalidated both the /books path and the updated /robots.txt file:

aws cloudfront create-invalidation \
  --distribution-id [DISTRIBUTION_ID] \
  --paths "/books*" "/robots.txt"

The wildcard pattern /books* invalidates /books, /books/, and any child paths. This ensures that both the bare path and any future subpaths are refreshed immediately.

CloudFront invalidations typically take 30–60 seconds to propagate globally. During this window, some edge locations may still serve cached content. Full propagation depends on geographic distribution and cache TTL settings.

robots.txt Configuration

The books section is internal-facing and should not be indexed by search engines. The updated robots.txt blocks crawlers from the /books path:

User-agent: *
Disallow: /books/

This directive is advisory—compliant search engines will respect it, but it doesn't prevent direct access. For true access control, authentication should be implemented in the application layer.

Why This Approach

Why two S3 keys for the same content? CloudFront's origin configuration doesn't rewrite URLs at the path level. Traditional web servers (nginx, Apache) have index document directives, but S3 doesn't. Creating both /books/index.html and /books ensures that CloudFront, which sits between the client and origin, can serve content regardless of whether the client requests the path with or without a trailing slash.

Why the custom error response was masking the issue: The 404-to-homepage redirect made it appear that the site was working correctly when it wasn't. The new content was never reaching S3; the redirect was covering up the gap. This is a common gotcha when debugging SPA deployments—error responses can hide real problems.

Why robots.txt needed redeployment: The original robots.txt didn't exclude /books. Updating and redeploying it ensures search engines respect the exclusion immediately (assuming they re-crawl within the next day or two).

Next Steps

The receipt upload functionality itself still needs to be implemented. The HTML page is now live, but the backend—form submission handling, file storage, and receipt tracking—remains to be built. This could involve:

  • A Lambda function or API Gateway endpoint to handle form submissions
  • S3 storage for uploaded receipt files with a separate bucket and IAM policy
  • A database (DynamoDB or similar) to track receipt metadata and associated charter entries

Additionally, the port sheet entry for the $1,845.72 charter payment needs to be recorded in the JADA Port Log spreadsheet. This is a separate operational task but flows from the same business process—capturing and organizing financial data for the sailing charter operation.