Building a Multi-Tenant Job Dispatch System: CloudFront Rewrite Rules, Lambda Microservices, and Real-Time Status Tracking

This post details the architecture and deployment of a dispatch management system for QuickDumpNow.com, a small-scale waste hauling operation. We implemented a complete job tracking pipeline: from booking through dispatch to customer status updates, all running on AWS Lambda, CloudFront, and S3.

What Was Built

The system consists of three main components:

  • Booking Interface — A customer-facing form at /book/ that generates unique job IDs and tracking tokens
  • Dispatch Dashboard — An authenticated crew interface showing real-time job status, kanban-style columns, and role assignments
  • Customer Tracking Page — A public status page (protected by token) at /track/{token} showing job progress from booking through completion

The core challenge was managing URL routing across static S3 assets and Lambda-powered APIs without traditional server infrastructure.

Infrastructure Architecture

CloudFront URL Rewriting

We implemented intelligent path-based routing using a CloudFront Lambda@Edge function stored at:

/Users/cb/Documents/repos/sites/quickdumpnow.com/cf/qdn-track-rewrite.js

This function intercepts requests to:

  • /track/* — Routes to /tracking/index.html
  • /book/* — Routes to /booking/index.html
  • /api/* — Passes through to Lambda backend unchanged
  • Default paths — Serve root domain content normally

The rewrite avoids expensive ALB or API Gateway costs by leveraging CloudFront's viewer-request event, executing in milliseconds at edge locations:

if (uri.startsWith('/track/')) {
  request.uri = '/tracking/index.html';
} else if (uri.startsWith('/book/')) {
  request.uri = '/booking/index.html';
}
return request;

This pattern allows us to deploy a single-page application (SPA) architecture on S3 while maintaining clean URLs for customers. The function was published to the LIVE stage on the CloudFront distribution for quickdumpnow.com.

Lambda Microservice Backend

The core dispatch logic runs in a Python Lambda function:

/Users/cb/Documents/repos/sites/quickdumpnow.com/tools/shipcaptaincrew/lambda_function.py

This function handles:

  • Job Creation — Generates UUID-based job IDs and secure tracking tokens; persists to S3 jobs.json
  • Status Updates — Transitions jobs through states: booking_confirmedready_for_pickupin_progresscompleted
  • Role Assignment — Assigns crew members (driver, first_mate, supervisor) to jobs via DynamoDB lookups
  • Real-Time Queries — Returns filtered job lists for dashboard views (kanban columns by status)

The function authenticates requests using JWT tokens embedded in environment variables, preventing unauthorized status changes.

Data Persistence

Two storage layers support different access patterns:

  • S3 (jobs.json) — Stores complete job objects including customer info, status history, and assigned crew. Located in the site's data bucket. This design prioritizes simplicity for small job volumes (typically <50 active jobs).
  • DynamoDB (crew_roster table) — Maintains crew member profiles, role availability for specific dates, and contact information (phone, email). Indexed by date range for efficient May 23-31 event queries.

The Lambda function reads from jobs.json on each API call, calculates filtered views based on status, and writes back only on state changes. This avoids complex locking while maintaining data consistency for small teams.

Frontend Architecture

Two HTML5 applications handle the customer and crew interfaces:

Tracking Page

Located at /Users/cb/Documents/repos/sites/quickdumpnow.com/tools/shipcaptaincrew/frontend/charter/index.html (served via rewrite from /track/{token}):

  • Extracts tracking token from URL fragment (e.g., /track/abc123def456)
  • Calls Lambda endpoint to fetch job status without exposing the token in network logs
  • Renders a vertical timeline showing job progression with status pills (color-coded: blue for pending, yellow for in-progress, green for complete)
  • Displays customer-relevant info: estimated pickup time, assigned driver name, current location (when available)

Status definitions are hardcoded in the frontend to maintain consistency with Lambda definitions, reducing round-trips:

const STATUS_FLOW = {
  booking_confirmed: { label: 'Booking Confirmed', color: 'blue' },
  ready_for_pickup: { label: 'Ready for Pickup', color: 'yellow' },
  in_progress: { label: 'In Progress', color: 'orange' },
  completed: { label: 'Completed', color: 'green' }
};

Dispatch Dashboard

Located at /Users/cb/Documents/repos/sites/quickdumpnow.com/tools/shipcaptaincrew/frontend/index.html:

  • Requires authentication (crew password stored as salted hash in Lambda environment)
  • Displays kanban board with columns for each status (one column per job state)
  • Each job appears as a draggable card showing customer name, address, assigned crew, and a "Drawer" button
  • Clicking a job card opens a details panel showing full history, notes, and quick-action buttons to advance status

The dashboard queries the Lambda API endpoint /api/jobs?status=ready_for_pickup (filtered per column) every 5 seconds, enabling real-time updates when crew members change job states from other devices.

Key Technical Decisions

Why CloudFront Lambda@Edge for Routing?

We chose Lambda@Edge rewriting over API Gateway or ALB routing because:

  • Cost — CloudFront Lambda@Edge charges per-million requests; API Gateway charges per-request at higher unit cost
  • Latency — Rewrite happens at the viewer-request stage (before cache lookup), so cache hits on /tracking/index.html are instant
  • Simplicity — No need to manage route tables or conditional origins; logic is co-located with the distribution

Why S3 for Job Storage?

For a small dispatch operation, S3 with a single jobs.json file beats DynamoDB because:

  • Job volumes are small (under 100 concurrent jobs)
  • Read-heavy