FLUX DOCUMENTATION SYSTEM Layer 11 — STARTER KIT | starter-kit-deployment flux.dantesisofo.com/wiki/starter-kit-deployment/
How a draft becomes live, and how the public surfaces stay consistent. Keys/consts from CONFIGURATION.
data/catalog.json # the index (no-cache)
<slug>/index.html # project page (no-cache)
<slug>/large/<photo_id>.jpg # web image (immutable)
<slug>/thumbs/<photo_id>.jpg # thumbnail (immutable)
<slug>/contact_sheet.png # immutable
<slug>/<slug>-project.zip # offline export (no-cache or immutable)
hub/index.html # master hub (no-cache)
hub/embed/index.html # iframe embed (no-cache)
catalog/index.html # non-collection listing (no-cache)
| Content | Content-Type | Cache-Control |
|---|---|---|
*.html, *.json |
text/html / application/json |
no-cache, no-store, must-revalidate |
images (large/,thumbs/,contact sheet) |
image/jpeg / image/png |
public, max-age=31536000, immutable |
export .zip |
application/zip |
no-cache (so re-publish updates the download) |
HTML/JSON are no-cache so updates appear immediately; images are content-addressed
(id = sha) so they can be cached forever.
publish(run_dir, slug)Idempotent / replace-in-place. Steps:
submission.json; load catalog.json (S3 authoritative, local fallback).walk_id+slug if the slug is already
published; else assign next walk_id. Add slug to reserved_slugs.large/,thumbs/) — skip keys already present
(immutable) for fast re-publish.metadata.json, project index.html, project ZIP.walk_id):
copy stats; set collections = walk.collections or default_for(location); set
route = downsample(stats.route, ROUTE_MAX_POINTS), bbox = bbox(stats.route);
cover_image = <slug>/large/<photos[0].id>.jpg (unless a cover was chosen).
Write catalog.json to S3 and local mirror.build_catalog_index(catalog) → upload LISTING_KEY.deploy_surfaces(s3, catalog) → upload HUB_KEY and EMBED_KEY
together (§5)./<slug>/*, /+CATALOG_KEY,
/+LISTING_KEY, and PHILLY_SURFACE_PATHS (hub+embed).Acceptance: after publish, GET FLUX_BASE_URL/<slug>/ is 200; the hub shows
the new project; catalog.json contains the WalkRecord.
SURFACE_PATHS = [HUB_URL, HUB_URL+"*", EMBED_URL, EMBED_URL+"*"].SURFACE_PATHS
plus /+CATALOG_KEY and /+LISTING_KEY.CreateInvalidation is the only CloudFront write the IAM user needs."/*" invalidation is acceptable after bulk changes.There must be exactly one function that uploads the hub, and it uploads the embed in the same call:
def deploy_surfaces(s3, catalog):
upload(s3, HUB_KEY, build_hub(catalog), "text/html", NO_CACHE)
upload(s3, EMBED_KEY, build_embed(catalog), "text/html", NO_CACHE)
return [HUB_KEY, EMBED_KEY]
Route every state change through it: publish, unpublish, set_cover, and
any future editing action. Audit rule: grep for build_hub(/HUB_KEY upload
sites — the only one allowed is inside deploy_surfaces. (This exact class of bug —
a regenerate path that updated the hub but not the embed — is the failure to guard
against.)
unpublish(slug)s3://YOUR_BUCKET/<slug>/* (or leave + redirect if external links exist).catalog.json; keep slug in reserved_slugs.build_catalog_index + deploy_surfaces + invalidate (/<slug>/* + surfaces +
catalog + listing).deploy.pyFor one-off pushes of shared/static assets (not per-publish), wrap
aws s3 sync LOCAL_SITE/ s3://YOUR_BUCKET/ --no-progress with correct
--cache-control per type, then a CloudFront invalidation.
Caution: a full sync deploys the local copy — keep local static sources in
sync, or a sync can overwrite live pages with stale local versions.
Cache-Control is no-cache and an
invalidation was created (the IAM user can't GetInvalidation, but Create
suffices). Hard-refresh.Next: PROJECT WORKFLOW.
FLUX_WIKI_v2.0 — flux.dantesisofo.com/wiki/starter-kit-deployment/