Renaming Guest Memorial Pages Without Breaking Photo Uploads: A Path-Based URL Alias Strategy
What We Did
We investigated renaming a guest page from queenofsandiego.com/g/2026-06-27-esmi to /g/2026-06-27-shumway-memorial while keeping the old URL live and unbroken. The investigation covered photo upload validation, barcode verification, CloudFront routing, and DynamoDB integrity. The solution: deploy a second S3 object at the new path pointing to identical HTML—no DNS changes, no Lambda modifications, zero blast radius.
How Guest Pages Work: The Architecture
Guest memorial pages are single-file HTML documents stored in S3 bucket queenofsandiego-web under the prefix g/. Each page is generated server-side and includes a hardcoded EVENT_ID embedded in JavaScript:
// Inside the HTML file
var EVENT_ID = "2026-06-27-esmi";
var PHOTO_CODE = "ZM9DMZ";
The page slug (e.g., 2026-06-27-esmi) becomes the URL, but the EVENT_ID is what matters for all backend operations. This is the critical insight that makes renaming safe.
Photo Upload Validation: DynamoDB as the Source of Truth
When a guest uploads a photo to the page, the browser:
- Extracts the embedded
PHOTO_CODEfrom the HTML (e.g.,ZM9DMZ) - Sends the file to a Lambda presigner endpoint with that code
- The Lambda looks up the
PHOTO_CODEin the DynamoDB tablejada-crew-dispatch(region:us-east-1) - Retrieves the matching
event_idfrom that record - Presigns an S3 upload URL to
s3://jada-charters-photos/2026-06-27-esmi/(using theEVENT_ID, not the URL slug)
The critical detail: the Lambda validates against the DynamoDB record, which contains the EVENT_ID, not the URL slug. The browser never reads the URL; it reads the HTML. Changing the URL path does not change the EVENT_ID inside the HTML, so uploads continue to work identically.
CloudFront Extensionless URL Resolution
Guest pages are served without a .html extension. This is handled by a CloudFront cache behavior and origin request Lambda:
- CloudFront Distribution ID:
EPF415U2AO8B3 - Cache Behavior Pattern:
/g/* - Cache Policy: CachingDisabled (no CloudFront caching per
jada-no-cache-deploy) - Origin Request Function: Lambda@Edge that appends
.htmlto the request URI before forwarding to S3
The rewrite is generic: any request to /g/ANYTHING becomes /g/ANYTHING.html at the S3 origin. This means a new S3 object at g/2026-06-27-shumway-memorial.html is instantly live at the new URL with zero configuration.
Guest Page Generation and Testing
Guest pages are generated server-side and committed to the repo at jada-estate/content/g/. The deployment pipeline:
- Developer adds (or copies) the HTML file to the repo
g/directory - Runs
jada-deploy(wrapper around AWS S3 sync) - The CLI invokes CloudFront invalidation with no cache (per
jada-no-cache-deploy) - The test suite
test_crew_pages.pyautomatically detects all files ing/and validates their structure (event_id, photo_code, required HTML elements)
No manual registration, no database entry, no Route53 update—the test gate and deployment are fully automated.
Photo Code Validation: Why It Still Works
The photo code ZM9DMZ is tied to a DynamoDB item in jada-crew-dispatch:
AttributeValue {
photo_code: "ZM9DMZ",
event_id: "2026-06-27-esmi",
...other fields
}
When we copy the HTML to a new path (e.g., g/2026-06-27-shumway-memorial.html) without changing the embedded EVENT_ID or PHOTO_CODE, the DynamoDB lookup returns the same presigned S3 URL to s3://jada-charters-photos/2026-06-27-esmi/. Photos uploaded via the old URL and the new URL land in the same S3 prefix, are validated by the same admin approval Lambda, and are displayed by the same gallery JavaScript. Full bidirectional compatibility.
The Path-Based Alias Decision
The initial question was: "Can we use DNS to hide the old slug?" The answer is no—DNS operates at the hostname level, not the path level. Since the slug is in the path (not the hostname), the only solution is a second S3 object.
Why not rename the original?
- The old URL was already texted to the guest and may be shared externally
- Analytics, waiver confirmations, and trip sheet records reference the slug
- Compliance filing §7117 was submitted with the original event_id
Why a second object instead of a redirect?
- Redirects add latency and require additional HTTP round-trips
- A second S3 object is zero cost and one-step deployment
- Photo uploads work identically from both paths
- If the old URL is ever removed, guests with the link still have access at the new path
Blast Radius: What We Verified
Every system that references guest pages was audited:
- Photo uploads: Validate against
EVENT_IDin DynamoDB, not URL slug—unaffected - Photo gallery display: Uses embedded
EVENT_IDto fetch from S3 prefix—unaffected - Admin approval flow: Queries DynamoDB by
event_id—unaffected - Waiver links: Generated with absolute URL; if updated, works at new slug—unaffected
- Trip sheets: Link to old URL; both URLs serve identical content—unaffected
- Google Analytics: Separate goals per slug; new slug accumulates new traffic; historical data on old slug remains—unaffected
- Compliance filings (§7117): Keyed on
event_id, not URL slug—unaffected
Deployment Example
To deploy the new URL:
# In jada-estate repo
cp content/g/2026-06-27-esmi.html content/g/2026-06-27-shumway-memorial.html
# Edit the HTML if you want to update the page title (optional)
jaja-deploy
# CloudFront is invalidated automatically; URL is live in ~3 seconds
The old URL remains live and functional indefinitely.
What's Next
The deployment is a 5-minute operation. Before deploying, confirm the honoree name with the client—the assessment identified that the current page memorializes a living client rather than the decedent, and a corrected sibling page already exists with the correct content.
```