Building a Real-Time Job Dispatch System: CloudFront Rewrites, S3 State Management, and Multi-Stage Deployments

We recently pushed a complete job dispatch and tracking system to production for quickdumpnow.com, handling the full lifecycle from job creation through customer tracking. This post details the infrastructure decisions, deployment patterns, and state management approach that made this work.

The Problem We Solved

The dispatch tool needed to:

  • Create jobs with unique tracking tokens that customers could use to monitor status in real-time
  • Route requests intelligently: /track/ endpoints to the tracking page, /book/ endpoints to booking pages, and everything else to the dashboard
  • Maintain authoritative job state in S3 while serving it through a web interface
  • Support multiple deployment stages (staging → production) with cache invalidation

Architecture Overview

The system uses a three-layer architecture:

  • CloudFront Layer: URL rewriting with CloudFront Functions for intelligent request routing
  • S3 State Layer: s3://qdn-jobs-bucket/jobs.json as the single source of truth for all job data
  • Web Layer: Static HTML/JS pages that fetch and render job state in real-time

This approach avoids the complexity of a database while maintaining consistency through atomic S3 updates.

CloudFront Function Routing

The core routing logic lives in /Users/cb/Documents/repos/sites/quickdumpnow.com/cf/qdn-track-rewrite.js. This CloudFront Function handles all incoming requests before they reach S3:

// Rewrite /track/{token} → /track/index.html?token={token}
if (request.uri.startsWith('/track/')) {
  const token = request.uri.split('/')[2];
  request.uri = '/track/index.html';
  request.querystring.token = { value: token };
}

// Rewrite /book/{page} → /book/{page}/index.html
if (request.uri.startsWith('/book/')) {
  request.uri += request.uri.endsWith('/') ? 'index.html' : '/index.html';
}

Why CloudFront Functions instead of Lambda@Edge? CloudFront Functions execute at edge locations with sub-millisecond latency and no cold starts. They're perfect for URL rewrites. We reserve Lambda@Edge for more complex transformations that need computational power.

Job Creation and State Management

When creating a job for Mark on Soderblom Ave with a $600 all-in deal, the system:

  1. Generates a unique tracking token: A cryptographically random identifier that becomes part of the tracking URL
  2. Builds the job object: Including location, amount, status (initially pending_confirmation), and timestamps
  3. Appends to jobs.json: The S3 object at s3://qdn-jobs-bucket/jobs.json is fetched, Mark's job is added, and it's uploaded back atomically

The job structure follows this shape:

{
  "job_id": "mark_soderblom_20240523",
  "tracking_token": "fcdc1c82cb284dbe",
  "customer_name": "Mark",
  "location": "Soderblom Ave",
  "amount_paid": 600,
  "status": "pending_confirmation",
  "status_flow": [
    "pending_confirmation",
    "ready_for_pickup",
    "in_transit",
    "dumped",
    "complete"
  ],
  "created_at": "2024-05-23T14:30:00Z",
  "phone": "+1XXXXXXXXXX"
}

Why S3 instead of DynamoDB? For this use case, S3 is simpler and cheaper. The entire jobs collection is small enough to fit comfortably in memory. Read-after-write consistency is acceptable since customer tracking queries are asynchronous. If job volume grows to millions, we'd migrate to DynamoDB with partition keys on location and date ranges.

Deployment Pipeline: Staging → Production

The deployment follows a staged approach with parallel promotions:

  1. Update CloudFront Function: Fetch current ETag from the function at ARN arn:aws:cloudfront:us-east-1:ACCOUNT:function/qdn-rewrite, update with new routing logic, and publish to LIVE stage
  2. Deploy Web Pages: Upload /track/index.html and /book/*/index.html to S3 staging paths
  3. Promote to Production: Copy from staging to production paths in S3
  4. Invalidate CloudFront: Create cache invalidation patterns for /track/* and /book/* paths

The commands executed in parallel look like:

aws s3 cp /tmp/track-index.html s3://qdn-staging/track/index.html
aws s3 cp /tmp/book-index.html s3://qdn-staging/book/index.html
aws cloudfront publish-function --name qdn-rewrite --if-match [ETAG]
aws s3 cp s3://qdn-staging/track/index.html s3://qdn-prod/track/index.html
aws cloudfront create-invalidation --distribution-id [DIST-ID] --paths "/track/*" "/book/*"

Real-Time Tracking Page Implementation

The tracking page at /track/index.html implements status flow visualization:

  • Extracts the tracking token from query parameters (passed by CloudFront Function rewrite)
  • Fetches jobs.json from S3 and finds the matching job record
  • Renders a visual status pipeline showing: pending_confirmation → ready_for_pickup → in_transit → dumped → complete
  • Uses color-coded pills (amber for pending, blue for ready, orange for in_transit, green for complete)
  • Polls S3 every 30 seconds to detect status changes

When the tracking link https://quickdumpnow.com/track/fcdc1c82cb284dbe initially returned "Job not found," the root cause was a timing issue: the job hadn't been created in S3 yet, or the CloudFront cache was serving a stale jobs.json. After creating the job and invalidating the CloudFront cache distribution (ID: E[DISTRIBUTION-ID]), the link resolved correctly.

Key Infrastructure Decisions

Static-first architecture: By using S3 + CloudFront instead of a traditional web server, we get automatic scaling, CDN distribution, and 99.99% availability with no operational overhead.

Client-side rendering: The tracking and dashboard pages use vanilla JavaScript to fetch and render jobs.json. This keeps deployment simple—no server-side templates or build process—while enabling real-time status updates via polling.

URL rewriting at edge: CloudFront Functions rewrite clean URLs into S3 object paths without exposing