‹ Back to the site

The stack & how it works

The operating manual for traveller.org — kept current with every publish that changes a process. Sits with the CMS portal behind the admin door.

What this is

traveller.org is a static website: every page is pre-built into HTML from plain content files whenever the content changes, then served from Cloudflare’s edge. There is no database and no application server. Around that static core sit a handful of small programs — a Pages Function in front of every request, four Cloudflare Workers, and a set of GitHub Actions workflows — each doing one job. This page is the reference for all of it: the map of what connects to what, then every service and what is inside it, then the flows a request, an upload or an email takes through them, then what is true of the domain right now.

Three rules that hold the whole thing together. Content never contains design: photographs, letters and banknotes are plain records; the look lives in layouts and one stylesheet. Nothing goes live until you say “publish it”: every change lands on the test site first, and the live site moves only when the Publish button (or the phrase, in a session) fast-forwards the production branch. The manual moves with the machinery: a feature, a service or a change to what the domain is doing lands with its page here in the same push; a repository check (Docs guard) warns when it does not.

The stack at a glance

Every box is a real service or a real program, named as its console names it; the fine print under each is what lives inside it. Arrows are the connections that carry traffic, data or credentials. Click any box for its entry below. On a phone the map scrolls sideways.

Map of the traveller.org stack: who asks, the Cloudflare zone and its Pages project, Workers and R2 bucket, the GitHub repository and workflows, and the outside services. WHO ASKS CLOUDFLARE — one account, the traveller.org zone in it Workers — code in the repository, deployed on every push GITHUB — brarob100/traveller.org OUTSIDE SERVICES — reached by the Functions, the Workers and the workflows (see the flows below) A visitor reads the public site A friend password, or an emailed button;the unlisted albums open You (owner) admin pages · uploaders ·the Publish button iPhone Shortcut · phone page workers.dev + /albums.txtupload.traveller.org/m Search & answer engines Googlebot, Bingbot, GPTBot, ClaudeBot…read robots.txt · sitemap.xml · llms.txt Zone & DNS — traveller.org nameservers here since 2026-08-19www · apex · albums → Pages projectimages → R2 · upload → WorkerInMotion records removed 2026-09-25MX → Email Routing · SPF · DMARC · Resend Crawler controls decides BEFORE robots.txtSearch · Agent · Trainingper-crawler Block switchestraining tier still refused(as of 2026-09-16) Turnstile widget "traveller.org contact"site key rides in the buildsecret: contact Worker + the Pages projectgates both forms Access Zero Trustapp 1: /admin*app 2: /guides*one-time PINallow-lists Email Routing (receiving) the apex MXnine addresses → Gmailtheboys@ → traveller-emaildmarc@ → traveller-dmarcswitched on at cutover step 15 Pages project "traveller-org" — the site takes the site Publish builds and uploads; serves www.traveller.org,traveller.org (301 → www) and albums.traveller.orgFUNCTIONS, in front of every request: _middleware — true 301s for every old URL · the friends gate · the albums host friends/login · admin-login · share-link · request · approve · entervariables: SITE_URL · SITE_BASE · PUBLIC_R2_BASE · PUBLIC_TURNSTILE_KEY …secrets: FRIEND_KEY · TURNSTILE_SECRET · RESEND_API_KEY traveller-upload upload.traveller.org (custom domain)www.traveller.org/api/* (route)traveller-upload.brarob.workers.devdesktop + phone (/m) uploaders, album builder,iCloud intake, Publish, /albums.txtsecrets UPLOAD_KEY · GITHUB_TOKENR2 binding · rate limit on the passphrase traveller-dmarc reads the DMARC reports, alerts you traveller-email theboys@ → two inboxes traveller-contact contact form → your inbox (Resend) R2 bucket "traveller-images" every photograph, film and scan · zero egressserved at images.traveller.org (since 2026-09-25);the old pub-…r2.dev address off since 2026-09-25<country>/<album>/ larges · thumbs/ · films/ · currency/ · journal/intake: films-in/ journal-in/ currency-in/ · hashes/ · near-dupes/ Repository trunk (= the test site): claude/…-approach-945vehproduction branch (= the live site): moves only by Publishsrc/data/*.json · functions/ · cloudflare/ · migration/ GitHub Pages — the test site brarob100.github.io/traveller.orgevery trunk push · plain files: no Functions, no door Actions — the workflows Deploy test site (push) · Deploy upload Worker (push: all four Workers)R2 gallery import (dispatch: 33 modes — import, sync, films, rotate, delete-album, move-album, currency, note-writeups…)Publish to production (dispatch) · Sync app guides (nightly + ping)Crawler probe (Mondays) · Cutover checks (push) · Docs guard (push) · iCloud probesecrets: the three R2 keys · RESEND_API_KEY · CLOUDFLARE_API_TOKEN ANTHROPIC_API_KEY · CENTRAL_DOCS_GIT_TOKEN · variable ANTHROPIC_MODEL The other app repos paprika, amapas353, …docs/guides/*.mdping → Sync app guides Resend sends every email the domain sendsfour API keys + one SMTP key Gmail receives the forwardssends as @traveller.org via Resend Anthropic API drafts banknote write-upsin the currency run Google Search ConsoleAnalytics G-80N129L5BJ Apple iCloud Copy iCloud Link→ the pipeline fetches Porkbun · InMotion registrar only ·InMotion cancelled 2026-09-25

Legend: purple — the people and devices that make requests; cream — Cloudflare, where the site is served; blue-grey — GitHub, where it is stored, built and operated; green-grey — the services outside both. The dashed box is the four Workers, which are code in this repository deployed by a workflow, not things configured by hand.

Every service, what it is for, and what is inside it

Grouped by where the console is. Each row: the item as its console names it, what it does and what lives inside it, and the one link that opens it. Cloudflare links land on the account picker if more than one account is signed in; pick the traveller.org account once and they go direct thereafter. Where a credential lives and how to roll it is the credentials table on the pipeline page.

Cloudflare (one account; the zone traveller.org inside it)

ItemWhat it does · what is inside itCostOpen it
Zone & DNSThe domain lives here since 2026-08-19 (nameservers moved from Porkbun, which remains the registrar and nothing more). The records: www and the apex point at the Pages project (the apex answers with a 301 to www), albums at the same project, images at the R2 bucket, upload at the upload Worker; mail, cpanel and ftp were grey-clouded A records at InMotion’s IP until the plan was cancelled on 2026-09-25, and were removed with it on your word (a session cannot read DNS to confirm); the apex MX belongs to Email Routing; SPF, DMARC (p=none) and Resend’s send.traveller.org records are TXT. TTL is still the cutover’s 600 seconds. Never create a record at Porkbun: it would not be read.$0DNS records
Pages project traveller-orgThe site itself. Since 2026-11-11 it no longer builds on its own: automatic production branch deployments are off, and Publish builds the production commit on GitHub and uploads the finished dist folder to it (how; before that date Cloudflare built every push to production itself, usually in minutes, once in 27). It serves the site on three custom domains: www.traveller.org, traveller.org and albums.traveller.org, plus its own traveller-org.pages.dev. Inside it: the Functions in functions/, which run in front of every request — _middleware.js answers every old URL with a true 301 (the 2532-row table), guards the unlisted albums and everything under /friends/ with the friend cookie, and serves the albums host from the /albums/ tree behind that door; friends/login and admin-login set the cookie, share-link mints the one-tap link, request / approve / enter are the ask-for-access flow. Its settings (Production): the build variables SITE_URL, SITE_BASE, PUBLIC_R2_BASE, PUBLIC_LEGACY_IMAGES, PUBLIC_TURNSTILE_KEY, PUBLIC_CONTACT_URL, PUBLIC_UPLOAD_URL, and the secrets FRIEND_KEY, TURNSTILE_SECRET, RESEND_API_KEY. Pages is in maintenance mode at Cloudflare (2026-09-09): still built, still served, no shutdown announced; a move to Workers is on the runbook’s open list for when there is a reason.$0 (500 builds/month, 5 custom domains)Deployments · Custom domains · Variables & secrets
The friends door (inside the Pages project)One shared password (FRIEND_KEY) opens every unlisted album for a year per device; friends sign in at /friends/ on www or on the albums site (one cookie covers both, scoped to the zone). Since 2026-09-22 the same page lets a friend without the password ask: a name and an email behind the Turnstile check, an email to you with an Approve button, an email back to them with a button that signs them in — three Functions, no storage, every link a signed token that expires. The albums site, albums.traveller.org, is every unlisted album on its own hostname, served by the same Function from the same build with the door in front of everything. Deliberately not Cloudflare Access (that door is an email allow-list for you) and not the upload passphrase (that key starts machinery).$0FRIEND_KEY and the two door secrets · What to send a friend
Worker traveller-uploadThe admin door for machinery. Source cloudflare/upload-worker.js, deployed by the Deploy upload Worker workflow on every push that touches it (dashboard edits are overwritten). Reachable at three addresses, all declared in wrangler.toml: upload.traveller.org (a Worker custom domain — the one to type), www.traveller.org/api/* (a route — what the admin pages call, being same-origin) and traveller-upload.brarob.workers.dev (what the iPhone Shortcut carries). Inside it: the desktop upload page and the phone page at /m, the album builder, the iCloud-link intake, the gallery lists every admin picker reads (/galleries, /albums.txt), photo rotate/remove/move/reorder, the buttons that dispatch the import workflow and the Publish, and (since 2026-11-10) /runs, which tells a page what became of the job it started (how). Its settings: secrets UPLOAD_KEY (the passphrase everyone who uploads types) and GITHUB_TOKEN (a fine-grained PAT that starts workflows); an R2 binding to the bucket; a second R2 binding, DRAFTS, to the private traveller-drafts bucket (journal drafts, since 2026-10-27); a Workers AI binding, AI, for voice-memo transcription (since 2026-10-27); a rate limit on failed passphrases. Access must never cover /api/*.$0Upload page · Worker · Secrets
Worker traveller-contactThe contact form’s backend (cloudflare/contact-worker.js): verifies the Turnstile token, then emails the message to you through Resend with Reply-To the sender. A public endpoint, so it deliberately shares nothing with the upload Worker. Secrets: TURNSTILE_SECRET, its own RESEND_API_KEY. Deployed with the upload Worker.$0Worker · Secrets
Worker traveller-dmarcReceives dmarc@traveller.org (an Email Routing rule’s action since 2026-09-10), reads each daily aggregate report, and emails you only when something claimed the domain and failed to prove it, forwarding the report with the alert. Silence means checked and clean. Secret: its own RESEND_API_KEY. Deployed with the upload Worker.$0Worker · Secrets
Email Routing + Worker traveller-emailReceiving mail for the domain. Set up in cutover step 15: the apex MX is Cloudflare’s, and nine @traveller.org addresses forward to Gmail. Two rules have a Worker as their action instead of an inbox: theboys@ goes to traveller-email, which hands the message to two people (a rule forwards to exactly one verified destination), and dmarc@ goes to the DMARC Worker above. Destinations verify themselves by clicking a link; an unverified one silently drops mail. Sending is the other half — Gmail sends as @traveller.org through Resend SMTP (cutover step 16).$0Routing rules (select the zone first) · traveller-email
R2 bucket traveller-imagesEvery photograph, film and scan. Object storage on the same edge, zero egress. Inside: each album’s 2048 px larges under <country>/<album>/, its 460 px thumbnails under thumbs/, films under films/, banknote scans under currency/, a letter’s own photographs under journal/<entry>/; the intake folders films-in/, journal-in/, currency-in/; and the pipeline’s own hashes/ (fingerprints for the duplicate check) and near-dupes/ (photographs held back). Addressed by two hostnames: images.traveller.org, its custom domain (attached at step 14), which every page and tool asks for since 2026-09-25 (the live site switched with that day’s Publish), and the bucket’s original pub-…r2.dev address, switched off by you on 2026-09-25 (it answers 401 now).~$1/yr at today’s size (first 10 GB free, then $0.015/GB-month)Bucket · API tokens
R2 bucket traveller-draftsUnpublished journal letters, and nothing else (since 2026-10-27). One small JSON file per draft under journal/, written by the upload Worker as you type in the Journal editor, so a draft follows you between devices. It has no public address of any kind (no r2.dev URL, no custom domain), which is the whole point: a draft is readable only through the Worker, behind your sign-in or the passphrase. Publishing or discarding a letter deletes its file. Never attach a domain to it.$0 (a few KB)Bucket
Workers AI (Whisper speech-to-text)Turns a voice memo into words for the Journal editor (since 2026-10-27). The page sends the memo in pieces of about 30 seconds to the upload Worker’s /transcribe, which hands each to @cf/openai/whisper-large-v3-turbo and returns the text. Nothing is stored: the audio exists only for the length of each request. Billed to this Cloudflare account, no key of its own.about $0.0005 per audio minute (Cloudflare’s listed rate); the daily free allowance covers about 3½ hoursThe model and its price (it needs no setting of its own)
Zero Trust Access (two applications)The door on the admin and on the guides. Application 1 covers www.traveller.org/admin* — the tools and this manual — with an email allow-list verified by one-time PIN (2026-08-19; no longer optional; set up at runbook step 21). Application 2 covers www.traveller.org/guides* with its own allow-list (2026-09-14), so an app’s users can be let onto the shelf without being let into the admin. Neither covers /api/*, the albums host, or the Worker’s own addresses, whose door is the passphrase. Since 2026-10-08 the admin also reaches the Worker through /admin/api/, which is inside the admin application: the site checks the pass itself (functions/admin/api/[[path]].js), checks the address is one of the admins (brarob@gmail.com, reynaldh@gmail.com), and adds the passphrase on the way — so on www no page asks for it. It is switched on by ACCESS_AUD_ADMIN and UPLOAD_KEY on the Pages project, both set on 2026-10-09; without them it would answer “not switched on” and the pages would fall back to the passphrase. Both are also enforced by the site itself since 2026-10-01 (functions/_access.js, the design amapas353.com’s admin uses): Access stands on the hostname, and the Pages project answers on others too (traveller-org.pages.dev, a preview address per deployment), so the Function sends /guides* and /admin* on any other host to www, and — once an application’s audience tag is set on the Pages project (ACCESS_AUD_GUIDES, ACCESS_AUD_ADMIN) — refuses a request on www that does not carry that application’s signed pass. Each tag is its own switch: the guides tag is set (2026-10-03), the admin’s too (2026-10-09). /guides/door-check/ and /admin/door-check/ say, to a signed-in visitor, whether that area’s check is on and whose pass it verified.$0 (≤50 users)Zero Trust dashboard
Turnstile widget traveller.org contactThe “I’m not a robot” check, usually invisible. One widget serves two forms: the contact form and the friends door’s ask-for-access card. Its site key is public and rides in the build (PUBLIC_TURNSTILE_KEY on the Pages project and in deploy.yml for the test site); its secret lives in two places, the contact Worker and the Pages project. It draws only on hostnames listed under Hostname Management — as of 2026-09-22: traveller.org, www.traveller.org, albums.traveller.org. brarob100.github.io is not on that list, so the test site’s contact form draws no check.$0Turnstile widgets
Crawler controls (on the zone)Cloudflare decides which crawlers get in before robots.txt is read, by user agent: a policy sheet (Search / Agent / Training) and a per-crawler Block Crawler switch on every row. The site’s own files — robots.txt, sitemap.xml, llms.txt, llms-full.txt — are generated by the build and open to everything but the admin, the guides and the Worker’s verbs. The Monday Crawler probe workflow asks the edge as fifteen identities and goes red when one is refused.$0Security → Settings (select the zone first)
Claude’s Cloudflare connector Cloudflare Developer PlatformA session’s own view into the account, switched on by you on 2026-10-10 (“full access” on the connector). It is a connector on your Claude account, not a credential in this repository or in Cloudflare’s settings, and it reaches only what its tools cover, checked the day it was switched on: Workers — list them, read each one’s details and deployed code (it listed all twelve in the account, the four traveller ones among them); R2 — list, read, create and delete buckets, not the photographs inside one; KV, D1 and Hyperdrive; and Cloudflare’s documentation. It cannot see or change DNS, the Pages project (its deployments, variables and secrets — ACCESS_AUD_ADMIN, UPLOAD_KEY, FRIEND_KEY), Zero Trust Access, Email Routing or Turnstile, and it cannot deploy a Worker or set a Worker secret: those stay yours, and deploys stay with the workflows. One tool deletes a bucket outright, traveller-images included; nothing here calls it, and a session asks before any delete.$0Claude → Settings → Connectors (your Claude account)

GitHub (brarob100/traveller.org)

ItemWhat it does · what is inside itCostOpen it
The repositoryEverything, and the history of every change. Content as plain records in src/data/ (galleries, journal, currency, places, home, guides), the page templates and the one stylesheet, the Functions and the four Workers, the pipeline scripts, the redirect machinery (the crawl’s inventory and the generated table), the design boards, the decision log and this manual. Two branches matter: the trunk claude/traveller-redesign-approach-945veh, which is the test site and where every session and every pipeline run commits; and production, which is the live site and moves only when Publish fast-forwards it to the trunk. Collaborators on the repository are the people who can publish.GitHub ProRepository · Collaborators · Secrets
GitHub PagesThe test site, brarob100.github.io/traveller.org: whatever the last trunk push built. Plain files — no Functions, so no friends door, no 301 table and no albums host there; hidden pages are reachable by address and say so. Its admin pages are the master set: they act on the same storage and the same pipeline as the live ones.includedPages settings · Test site
Actions — the workflowsThe build robot and the pipeline. Nothing is built or imported by hand. Deploy test site builds every trunk push and publishes it to GitHub Pages. Deploy upload Worker ships all four Workers with wrangler when their files change (needs CLOUDFLARE_API_TOKEN). R2 gallery import is the pipeline: 33 modes (verify, import, icloud, sync, remove-photos, delete-zips, films, rotate, …), started by the uploaders’ buttons or by hand, each run committing only the records it changed and regenerating the redirect table. Publish to production fast-forwards the production branch (the Publish button). Retired-file sweep (daily, since 2026-09-24) deletes a removed, rotated or moved photograph from storage once neither live site names it any more — it asks each site which commit it is showing (/build.json) and deletes nothing when either cannot say. Sync app guides copies each app’s docs/guides onto the shelf nightly or when an app pings, and publishes itself when guides are the only thing waiting. Crawler probe asks the edge every Monday. Cutover checks rebuilds production-shaped on every push and fails if a redirect lands nowhere or a page still names the old host. Docs guard warns on feature code without a docs change. Design guard (since 2026-10-28) checks every push that touches the design against the Design system page: anything new in the stylesheet or the components with no description yet, or a breakpoint the page names that is gone. iCloud link probe tests Apple’s link recipe on demand. Secrets: the three R2 keys, RESEND_API_KEY (the pipeline’s), CLOUDFLARE_API_TOKEN, ANTHROPIC_API_KEY, CENTRAL_DOCS_GIT_TOKEN, optional ALERT_EMAIL / RESEND_FROM; one variable, ANTHROPIC_MODEL.includedAll runs · Photo import · Deploy · Worker deploy · Guides sync · Crawler probe
The other app repositoriesEach app on the guides shelf keeps its own guide pages under docs/guides/*.md in its own repository; src/data/guides.json lists the apps. The sync reads them with CENTRAL_DOCS_GIT_TOKEN; an app that carries the three-line dispatch step (with its own CENTRAL_DOCS_DISPATCH secret) pings this repository so a pushed guide reaches the shelf within a minute rather than overnight.includedThe shelf

Outside Cloudflare and GitHub

ItemWhat it does · what is inside itCostOpen it
ResendSends every email the domain sends. The domain is verified there (its records are the TXT and the send.traveller.org MX in DNS). Five credentials, deliberately separate so any one can be rolled alone: the pipeline’s API key (import notices and zip links; a GitHub secret), the contact Worker’s, the DMARC Worker’s, the Pages project’s (the friends door), and an SMTP key typed into Gmail’s Send-mail-as settings — cutover step 16 — so Gmail sends as brobinson@traveller.org and friends.$0 (100 emails/day)Sent emails · API keys · Domain
GmailWhere the forwards land, and what sends as the domain (through Resend). The DMARC reports used to land here too; since 2026-09-10 the Worker reads them instead.—Send mail as
Anthropic (Claude API)Drafts the banknote write-ups in the currency run: both faces of a scan go to Claude, which writes The artwork / In circulation / Details onto the note page for you to edit or regenerate at Banknote pages. Key ANTHROPIC_API_KEY and variable ANTHROPIC_MODEL on the repository.pennies per noteConsole · API keys · Usage
GoogleSearch Console reads the site and its sitemap (the property was told the site moved at step 22); the indexing report’s reading is on the pipeline page. Analytics 4, property G-80N129L5BJ, counts the public pages of the live site only — never the admin, the friends pages, the albums host, the test site or the old-URL forwarding pages, nor (since 2026-11-10) the contact page, which tells its visitor “no tracking”. A session reads both, read-only, through a Google Cloud service account (since 2026-10-14; the search-data row below). In Search Console that account sees the Domain property sc-domain:traveller.org, which covers every address on the domain, and http://www.traveller.org/. It sees no https://www.traveller.org/ property. Whether one exists without the account on it is not recorded. The sitemap is registered as http://www.traveller.org/sitemap.xml (read through the API, 2026-10-14; the same one entry under both properties), submitted 2009-05-25 — the old site’s registration, which the new sitemap kept its filename for. Google last read it on 2026-10-04: 793 URLs submitted, 2 warnings, no errors, and the report’s “indexed” figure read 0. There is no https entry and none is needed; Google follows the redirect. The sitemap report is where to see when Google next reads it.$0Search Console · Analytics
Microsoft ClarityHeatmaps and session recordings of the public pages (since 2026-10-31): where visitors click, how far they scroll, and replays of visits with what they typed masked. Project z62cj5f8a5. It loads under exactly the same rule as Analytics, one switch in src/layouts/Base.astro: the public pages of the live site only — never the admin, the friends pages, the albums host, the test site, the old-URL forwarding pages or (since 2026-11-10) the contact page — and tests/analytics.test.mjs checks both tags across the whole build. The project id is public and rides in every page; there is no key or secret. Signed in to Clarity with your Microsoft account.$0Clarity projects
Bing Webmaster Tools · IndexNowBing’s Search Console. It reads the site and the sitemap and lists SEO recommendations; on 2026-10-13 it asked for IndexNow, unique meta descriptions, longer ones, and more inbound links (only the first three are code). It holds the site as http://traveller.org/, verified, the only traveller.org entry on your Bing account (read through its API, 2026-10-14). That one entry also answers for https://www.traveller.org/, so no second one is needed. Who added it, and when, is not recorded here. A session reads it through the Webmaster API with your Bing API key (since 2026-10-14; the search-data row below). IndexNow, since 2026-10-13: after every Publish the IndexNow workflow tells Bing, and through it Yandex, Seznam, Naver and Yep, which pages that Publish added, changed or removed. Google does not take part and keeps reading the sitemap. Its key is public by design, served at /4261e9fd364ba523c66028934df59844.txt; Bing fetches it to check the site is ours. No account or secret is involved. Bing Webmaster Tools has an IndexNow page listing what it received. Its exact address is not recorded here; the portal link opens the site’s dashboard. What Bing held on 2026-10-14 (its API): the sitemap feed https://www.traveller.org/sitemap.xml, last read 2026-10-11; 2,764 traveller.org pages in its index on 2026-10-08 against 792 in the sitemap — the rest are the old site’s addresses, which it re-reads and gets 301 from, about 2,500 a day, and which age out on their own; two crawl issues, both the old feedback.php, which www answers 404 for now; 58–106 impressions a day and 0–3 clicks to 2026-10-11.$0Bing Webmaster Tools
The insights dashboards (inside the Pages project)Search & indexing and Traffic & AI, under Insights in the admin (since 2026-10-14): Google Search Console, Bing Webmaster Tools and Google Analytics read live into two admin pages, with a date range, by a Pages Function at /admin/insights behind the Cloudflare sign-in. It uses the same four credentials as the search-data row, copied onto the Pages project as settings (added by you, 2026-10-14). Answers are cached at the edge for an hour to a day by source; nothing secret reaches a browser. How it works and fails: the pipeline page; how to read it: the manual.$0 (a Function invocation per card load; Google and Bing APIs are free at this scale)Search & indexing · Traffic & AI
Search-data credentials for sessionsHow a session reads Bing’s and Google’s numbers about the site, set up by you on 2026-10-14 and shared with the amapas353.com sessions. A Bing Webmaster API key (BING_WEBMASTER_API_KEY), from Bing Webmaster Tools’ settings, under API access. It belongs to your Bing user, so it reaches every site on that account: on 2026-10-14 those were http://traveller.org/, https://amapas353.com/ and https://amapas.lodgify.com/, all verified. A Google Cloud service account (GOOGLE_SERVICE_ACCOUNT_JSON, its key file), with read access to both sites in Analytics and Search Console. The Google Analytics Data API and the Search Console API are switched on in its Cloud project; the Analytics Admin API is not, and nothing needs it. With them go four plain values naming each site’s Analytics property and Search Console property (GA4_PROPERTY_ID_TRAVELLER, GSC_SITE_URL_TRAVELLER and the two _AMAPAS). None of these is in this repository or in GitHub. They are variables in the Claude cloud environment the sessions run in, readable only inside a session. A session reports whether each is set, never its value. They are read-only: nothing here can change Bing, Analytics or Search Console with them.$0Claude cloud environments (your Claude account) · Bing Webmaster Tools · Google Cloud service accounts
Apple iCloudA Copy iCloud Link pasted on either uploader makes the pipeline fetch the originals from Apple straight into the album (2026-09-13). Rests on Apple’s undocumented web client; the iCloud link probe workflow says when the recipe moves.—Probe
Porkbun · InMotionPorkbun registers the domain and does nothing else; its nameservers point at Cloudflare. InMotion was the old host. It was left alone for a month (step 23, done 22 Sept); cancelling the plan was step 24, done 25 Sept after a full account backup, which you keep — its WordPress database is the one remaining copy of what the migration could not reach (runbook, the open list). Its cPanel, webmail and old .htaccess redirects ended with it; the new site answers every old address itself.$0 since 2026-09-25Porkbun · InMotion AMP

Two links that are not services but get used most: the photo import workflow (watch a batch process) and the Publish page. Prices were re-checked against Cloudflare’s published rates in August 2026.

How the pieces connect — the flows

A visitor opens a page

  1. DNS says www.traveller.org is the Pages project; the apex 301s to www.
  2. The zone’s crawler controls decide first if the visitor is a crawler.
  3. The Pages Function runs: an old address gets a true 301 from the table; a page under /friends/ or an unlisted album asks for the friend cookie; /albums/* is sent to the albums host; anything under /admin* or /guides* has already met Access.
  4. The built page is served from the edge, with its photographs fetched from the R2 bucket on images.traveller.org and its analytics tag reporting to Google only on the public pages.

You upload photographs, and they become an album

  1. You open upload.traveller.org (or the Shortcut posts to the workers.dev address) and type the passphrase; the Worker checks UPLOAD_KEY, rate-limited.
  2. Files land in the bucket under the album’s folder; the Worker writes the folder marker (unlisted? albums-only?).
  3. Start import makes the Worker dispatch R2 gallery import with GITHUB_TOKEN. The run develops RAW, resizes larges, makes thumbnails, fingerprints for duplicates, writes the gallery record, regenerates the redirect table, commits to the trunk (record-level merge, so concurrent runs do not clobber each other) and emails you the review notice through Resend.
  4. The trunk push builds the test site. The album is on staging; the phone said so.
  5. You press Publish (or say it): Publish to production fast-forwards the production branch, builds the site on GitHub and hands the finished folder to Cloudflare Pages (since 2026-11-11), and the album is live, usually inside two minutes.

A friend asks for access

  1. On the door (either host) they leave a name and email; the Turnstile widget draws a check.
  2. The request Function verifies the token with TURNSTILE_SECRET, seals an approve link under FRIEND_KEY, and emails you through Resend.
  3. You open the link and press Approve; the approve Function emails them a signed button.
  4. Their tap at enter sets the same cookie the password does, zone-wide, for a year.

Mail in and out

  1. In: the apex MX is Cloudflare Email Routing; each address forwards to Gmail, except theboys@ (the email Worker, two inboxes) and dmarc@ (the DMARC Worker).
  2. Out: Gmail sends as the domain through Resend’s SMTP; the pipeline, the contact Worker, the DMARC Worker and the friends door send through Resend’s API, each with its own key.
  3. Every large mailbox provider reports daily on what claimed the domain; the Worker reads the reports and speaks only when one fails.

An app’s guide reaches the shelf

  1. The app’s repository pushes to docs/guides/ and pings this repository (or the nightly sync finds it).
  2. Sync app guides reads it with the read token, builds the site to prove it still builds, commits to the trunk.
  3. If guides are the only thing waiting on the trunk, it publishes itself; otherwise it stops on staging and says so.

Where the domain stands today

The tables above say what each service is. This one says what is true right now, dated, because the two can differ and only one of them is what you need when something breaks. A session updates this section in the same push as any change to the domain or a service, and tests/docs-refs.test.mjs keeps its runbook step numbers honest. Cutover history is on Launch & cutover: as of 2026-08-20, steps 1–21 were done; steps 22, 23, 27 and 29 followed on 2026-09-22, and steps 25, 26 and 28 on 2026-09-24. Step 24, cancelling InMotion, followed on 2026-09-25, and with it the whole runbook.

WhatTodayBecomes
Films and journal entries can be deleted New 2026-11-10. The pipeline gained two modes, delete-film and delete-journal-entry, each started from the admin behind the item’s own title typed out. Storage is not emptied at once: files are retired and removed only when no published page can show them. How to · what it does. —
Publish: built on GitHub, uploaded to Cloudflare As of 2026-11-11: on. Publish moves the production branch, then the same run builds that commit on GitHub, checks it against www when www is on the same commit, and uploads the finished site to the Pages project (FAST_PUBLISH = on, a repository variable). Cloudflare no longer builds on its own: automatic production branch deployments are off in the Pages project, so a push to production by anything other than Publish changes nothing live. First fast Publish 04:53 UTC on 11 November, 80 seconds from button to live; the friends’ door, the Access sign-in and the contact form all checked on www afterwards. To undo it, the runbook’s part F. Publish in a minute or two. If a Publish run goes red at fast / deploy, the branch moved but nothing went live: re-run the failed job.
Staging builds, Publish and the live site’s request code Changed 2026-11-10. A test-site build in flight is no longer cancelled by the next push; a failed one emails you; Publish refuses when the test site’s last build failed. On the live site, /_astro/* and /fonts/* (stylesheets, scripts, fonts) are served without running the request code; every page, album and photograph still goes through it. The whole list. —
Public pages fetch pictures as they are reached Changed 2026-11-10. Listing pages (Photographs, Countries, Journal, Films, a country) draw their pictures as lazy-loaded images, not CSS backgrounds: opening Photographs on a phone asks images.traveller.org for about 80 thumbnails, not 927. The home page fetches one hero photograph, not five; the film grids use the 460px posters. Nothing moved in storage and no address changed. The measurements. —
Every build uses one Node version Changed 2026-11-11. A file at the top of the repository, .nvmrc, says 22. The test-site deploy, the faster Publish, the guides check, the design guard and the cutover checks all read it; they used to ask for 20 or 22 separately. The live site is built by the Publish run on GitHub since the faster Publish went on, so www moves to 22 with the next Publish. Why, and how to undo it. The first Publish after this is the first live build on 22; the two before it built on 20.
A third size of every photograph, for phones Changed 2026-11-11, at your word. The image bucket gains a folder, mid/, holding a 1200px copy of each high-resolution photograph beside its 2048px large and 460px thumbnail. On a phone the photo view asks for that copy; a desk and an iPad are unchanged. New photographs get theirs as they are imported, rotated or moved. Same bucket, same address (images.traveller.org), no new service or credential. How it is kept in step. The copies for photographs already on the site were made on 11 November: 30,846 of 30,932, 5.27 GB in all, 171 KB each on average. The other 86 have no full-size file in storage to copy (open item). Phones on www start using the copies when you Publish.
The admin says when a job is done Changed 2026-11-10. The upload Worker now names every pipeline run it starts and answers /runs; a status card on every admin page and both uploaders follows the job to “Done. It is on the test site now”. The Publish page watches www’s /build.json and says Live when the published commit is being served. No new service, credential or DNS record: the Worker’s existing GitHub token reads the runs. What you see · how it works. —
The upload Worker reads the repository and shows what was waiting Changed 2026-11-11. The Worker has five more routes, all behind the passphrase: it reads captions from the trunk as they are now (so Album cleanup marks a caption a minute after it is saved, with no rebuild), lists and brings back photographs an import held as near-duplicates, and lists, names or discards banknote photographs the reader could not name. Caption saves leave in batches, a few seconds apart, not one run each. The phone uploader can change Unlisted and “Publish to www too” on an album that already exists. No new service, credential or DNS record: the Worker’s existing GitHub token (its Contents: Read-only permission) does the reading. How it works · on the phone. The Worker deploys from the trunk on push; the manual pages that describe these go to www when you Publish.
Analytics and Clarity off the contact page Changed 2026-11-10, at your choice. The contact page says “no tracking”, and both Google Analytics and Clarity’s session recording were loading on it. Neither loads there now; both still run on every other public page. Visits to the contact page will no longer appear in either tool. —
Microsoft Clarity on the public pages Live 2026-10-31 (published at your word that day). Project z62cj5f8a5, loading on every public page of www.traveller.org next to Google Analytics, and on none of the admin, friends, albums or test-site pages. Recordings and heatmaps begin with the first visits after the Publish; Clarity’s dashboard usually shows them within a couple of hours. The site has no privacy page yet: deferred, open item on Launch & cutover. A privacy page saying what both tools collect, when you ask for it.
Journal drafts in your account; voice memos to words Built 2026-10-27, on staging. A second R2 bucket, traveller-drafts, was created that day by a session through the Cloudflare connector. It has no public address: no r2.dev URL and no custom domain. The upload Worker is bound to it as DRAFTS, and to Workers AI as AI (Whisper, for /transcribe), in wrangler.toml; both arrive with that push’s Deploy upload Worker run. That run is the proof the deploy token can bind them; if it went red, the run’s log names what was refused. No new secret or key. The editor that uses them reaches www on the next Publish; until then the live editor keeps drafts on the device as before. Live on the next Publish. The drafts bucket holds only unpublished letters, a few KB each, and empties itself as letters are published or discarded.
Search engines told of changes (IndexNow) Live since the Publish of 2026-10-13 (c05e9b97). www serves the key file and fingerprints for all 792 sitemap pages. The first IndexNow run laid the baseline and sent nothing, as designed; IndexNow asks for what changed since you started, not the back catalogue. The same push fixes Bing’s two description findings: every page in the sitemap now has its own description, 111–160 characters. Before, 395 of 792 shared the site-wide line, and gallery pages had a 75-character one. llms.txt now quotes those same descriptions for every section and all of the countries. Both are live, checked on www the same night. All 792 pages were announced once at 23:52 UTC by a hand run marked all, and IndexNow answered 200. A try two minutes earlier got 403 SiteVerificationNotCompleted: the key file had been live for three minutes and IndexNow had not finished checking it. Bing acted on it at once (checked through Bing’s Webmaster API, 2026-10-14): the home page, Australia and Cuba were re-read between 23:52:27 and 23:52:42 UTC, seconds after IndexNow’s 200. By 00:45, 6 of the 18 pages checked had been re-read; Bing allowed no more lookups that night. Publish 276, refused before it changed anything, made its IndexNow run send nothing, as it should. Second read, later on 2026-10-14: no Publish since, so no run and nothing to send; www still serves e464ae59, the key file and 792 fingerprints. Neither engine had read the sitemap since the Publish (Bing 2026-10-11 18:46 UTC, Google 2026-10-04), and Bing was still refusing page lookups (ThrottleHost) from the night’s burst, so 6 of 18 stands. From the next Publish on, each one sends its changed pages, at about 2–3 Actions minutes (it waits for Cloudflare’s build). Bing’s IndexNow page shows them arriving (open list on Launch & cutover).
Search and traffic insights in the admin Built 2026-10-14, on staging; live on the next Publish. Two admin pages read Google Search Console, Bing Webmaster Tools and Google Analytics through a Pages Function at /admin/insights, behind the Cloudflare sign-in. The four settings it needs (GOOGLE_SERVICE_ACCOUNT_JSON, GA4_PROPERTY_ID_TRAVELLER, GSC_SITE_URL_TRAVELLER, BING_WEBMASTER_API_KEY) were added to the Pages project by you the same day, so the first Publish that carries the pages deploys with them. A session cannot read Pages settings, so the dashboards’ own IndexNow card is the check: it prints each setting as set or missing. After that Publish, both pages fill in on www. If a card reads Not configured yet, it names the setting; if a Google card says the key file is not valid JSON, it was not pasted as one line.
Admin sign-in The Cloudflare sign-in, on www since 2026-10-09. The Pages project has ACCESS_AUD_ADMIN and UPLOAD_KEY, and you and Reynald (in the traveller admin access group, your confirmation) sign in with Cloudflare: no admin page on www asks for the passphrase, door-check says ON, and the upload pages answer at /admin/api/ and /admin/api/m/. The phone page’s first answer was “not found”; fixed and published the same day, and your check of it is open item 1 on the runbook. Since 2026-10-13 the admin menu’s Photo uploader and Phone uploader open those signed-in addresses on www; before, they opened the passphrase ones. On a phone the gold Connected band is the account control (tap it for the friends’ door and Sign out), and an iPad shows the side menu with the account block at its foot (2026-10-13). The passphrase still works on the old upload addresses and on the test site’s admin, until stage two. The iPhone Shortcut uses it, by your choice. Stage two, once you say the phone page works: the passphrase comes off the web pages entirely (the test site’s admin points to www, the old upload addresses forward); the Shortcut keeps it.
Claude’s access to Cloudflare A read-mostly connector since 2026-10-10, switched on by you: a session can now read the Workers and their deployed code, and list the R2 buckets, KV and D1, without asking you to look. It still cannot reach DNS, the Pages project’s settings, Access, Email Routing or Turnstile — the stack table’s connector row says exactly what it covers. Nothing further; turned off at Claude’s Connectors settings if ever wanted.
Sweeps Agent’s mail A ninth forwarding address since 2026-10-10. You created brarobsw@ in Email Routing that day, forwarding to Gmail: it is the address given to sweepstakes sponsors, so their mail, winner notices included, arrives with a label-able To. Sweeps Agent itself (a separate app on the account, repository brarob100/sweeps-agent, on the guides shelf) will send its 6 am digest and claim-deadline reminders from sweeps@traveller.org through Resend, with a Resend key of its own. As of 2026-10-10 its first deploy has not run, so it has sent nothing. Once it deploys: the Resend row counts its key, and this row says when the first digest went out.
Zip records Retired 2026-10-09 (your call): imports and film conversions make none, and the Zip records page and its nav entry are gone. The old zips in zips/ are deleted: the delete-zips run of 2026-10-09 emptied the folder, and the old zip addresses answer 404. Film originals are not kept either (“keep nothing”). Published 2026-10-09. Nothing further; nothing writes to zips/ again.
GitHub Actions minutes Near the plan’s 3,000 a month, 2026-09-24: 2,731 used by the 24th, 82% of them traveller.org’s, while development is heavy (August ran to 6,533 and $21.18). The $35 Actions budget alerts and does not stop anything. Two savings are written down and deliberately not made (Launch & cutover, the open list). Since 2026-10-13 each Publish also runs the IndexNow workflow, about 2–3 minutes while it waits for Cloudflare’s build. Falls on its own as development slows; the two savings wait until wanted.
Photographs you remove, rotate or move Retired, not deleted, since 2026-09-24. The file stays in storage, out of every list, so the live site — which changes only on Publish — keeps showing the album as it was instead of a broken frame. The daily Retired-file sweep deletes it once neither live site names it. Before this change the file went at once: 21 frames were broken on www.traveller.org on 2026-09-24 (Washington D.C. 1989, both Beijing albums), and the next Publish is what mends them. Nothing to do. The sweep deletes nothing until the live site has its own /build.json, which it gets with the first Publish after this change.
The live site Cloudflare Pages, since the cutover of 2026-08-19, built from the production branch and current with the last Publish. One address: the bare traveller.org 301s to www (2026-08-30). Pages has been in maintenance mode at Cloudflare since 2026-09-09 — nothing broken, nothing announced; you chose not to spend time on a move. Updates whenever Publish is pressed. One day, a move to Workers — when there is a reason.
DNS Cloudflare, zone Active since 2026-08-19; Porkbun is the registrar and nothing more. The grey-clouded mail, cpanel and ftp records at InMotion’s IP went with the plan on 2026-09-25, on your word. The TTL went back up on 2026-09-24 (step 25, done by you). Nothing: the three InMotion records went with the plan (step 24).
Photographs Served from images.traveller.org since 2026-09-25, finishing step 14: you changed PUBLIC_R2_BASE and published, and a session checked the live build that night — the home page, an album, the country index, a country, the journal, the banknotes, the films and both friends doors ask images.traveller.org and nothing asks r2.dev. The admin pages, the test site and the pipeline’s emails had moved the day before. The bucket’s original pub-…r2.dev address was switched off by you the same day and answers 401. Nothing. Old emails or image-search results that named r2.dev no longer load; the site never asks for it.
Email Cloudflare Email Routing receives, Resend sends. Set up for receiving (step 15) and Resend SMTP for sending (step 16), both on 2026-08-19. Nine addresses forward to Gmail; theboys@ goes through the email Worker to two inboxes; dmarc@ goes to the DMARC Worker (2026-09-10). InMotion no longer touches the domain’s mail, and its cPanel ended with the plan on 2026-09-25. Nothing further. Cancelling InMotion (step 24) ended the last of it.
The friends door and the albums site Live. The door since 2026-08-28; one sign-in covers both hosts since 2026-09-22, the day albums.traveller.org went live — you attached the hostname at runbook step 27 (Cloudflare wrote the record and the certificate itself; the Verifying sheet it showed was not a to-do) and published; the build took 27 minutes to land. Checked from outside: the albums host answers with the sign-in, www.traveller.org/albums/ forwards to it, the nav carries the item. The door’s Need access? Ask Bradley line is on both hosts; you set the two Pages secrets at runbook step 28 and added the albums hostname to the Turnstile widget the same day, and the flow went live with the Publish that followed. Photo controls on the albums site (2026-09-23, on staging until Publish): Unlock the live site now carries your passphrase to albums.traveller.org as well as www, so its photo pages show Rotate, Friends-only and Remove; a browser unlocked before then needs the button pressed once more. Nothing further. Rotating the friend password is one edit on the Pages project; it signs everyone out and voids every emailed button.
The admin pages Behind Cloudflare Access on www.traveller.org/admin* since 2026-08-19 — the admin door is locked (step 21) — with the upload Worker passphrase-gated and rate-limited behind them. The staging admin on github.io is the master set and carries the newest controls; a fussy browser is happier on the live domain, where the Worker is same-origin at /api/. The Worker answers at three addresses, all live, none replacing another. Nothing further.
Contact form Live on www.traveller.org since 2026-08-20 through the contact Worker. On the test site it draws no robot check: the widget’s hostname list holds the apex, www and albums (checked 2026-09-22) and not brarob100.github.io, so staging shows the box empty. Cosmetic there — nothing on staging sends. Add brarob100.github.io to the widget’s hostnames if the staging form should draw its check.
Search & answer engines Search tier open; training tier still refused at the edge (found 2026-09-16; the Monday probe re-asks). Every search and agent identity gets through; GPTBot, ClaudeBot, CCBot, Amazonbot and Bytespider meet a 403 from Cloudflare before robots.txt is read. You set the three policies to Allow on 2026-09-16 and the per-crawler switches would not release; the next thing to try is Cloudflare’s crawler-controls contact. Set the three controls to Allow at runbook step 26 and off every row’s switch, then run the probe. Search Console was told the site moved (step 22, done 2026-09-22); its indexing report is read on the pipeline page. The probe reading every identity is let in.
The guides shelf Live at www.traveller.org/guides/ since 2026-09-05, behind the second Access application since 2026-09-14 (allow-list: you and Reynald). Every app but the empty contacts repository has its guide; the nightly sync and the apps’ pings keep them current, and a guides-only change publishes itself (2026-09-07). A guide is held off the shelf only when you say so (Amapas 353 website, since 2026-09-10). 2026-10-01: the door had a side entrance. The site also answers at its own Pages address, traveller-org.pages.dev, where no Access application stands, and traveller-org.pages.dev/guides/ served the shelf to anyone — a production build, every app address on it. Closed in the site’s own Function (you asked for the amapas353.com design; the host check in front of it is the session’s addition): /guides and /admin on any address but www are sent to www, live from the first Publish after that date. The second layer — the site checking Access’s signed pass itself — is built and switches on with ACCESS_AUD_GUIDES. 2026-10-03: you set it (Production, then Retry deployment) with the guides application’s tag — checked from outside against the tag Cloudflare puts in that application’s own sign-in redirect — and the shelf opens for you signed in. Whether the lock is on is read at www.traveller.org/guides/door-check/ once it is published; the shelf looks the same either way. ACCESS_AUD_ADMIN was set on 2026-10-09, and /admin/door-check/ says ON for you. Set the guides audience tag; decide about old preview deployments; widen the allow-list app by app, as people need it. 2026-10-14: traveller’s own card gained The stack, and how it works, the shelf’s copy of this page’s stack table with a map; a service that joins or changes updates both in the same commit.
The uploaders Desktop page and phone page (/m) on the Worker, the iPhone Shortcut picking its album from /albums.txt, and iCloud links on both pages (2026-09-13). Every picker shows one site’s albums at a time (www or the albums site) and every album has its Publish-to-www switch (2026-09-22). A same-name upload never overwrites by accident (2026-09-13); every “started” message says staging, since that is where an import lands. Nothing further. The upload passphrase should be rotated whenever it has been seen in a screenshot or a chat.
Visitor statistics Google Analytics 4 on the public pages of the live site only, since 2026-08-26. Any figure dated before that is the old WordPress site. Nothing further.
DMARC reports Watched, not monitored, since 2026-09-10 — the switch is thrown. The policy published on 19 August 2026 is p=none — monitor only, nothing is blocked — and the daily reports had forwarded to Gmail since cutover step 15; on 2026-09-10 you re-pointed dmarc@traveller.org to the traveller-dmarc Worker and set its RESEND_API_KEY, so the Worker reads each one and writes only when something needs acting on, forwarding the original report with the alert. It spoke for the first time on 21 and 22 September 2026, and it was right to: mail claiming this domain that proved neither check — our own retired InMotion host, whose cPanel notifications had been going out as cpanel@traveller.org since 20 September. Stopped at source on 22 September (runbook step 29); the capability ended when the plan was cancelled on 2026-09-25 (step 24). The move off p=none is now the reports’ call, not InMotion’s: with our own failing sender gone, a session reads the reports and says when p=quarantine is safe (runbook, the open list). Cutover step 16 records that a Gmail send-mail-as entry was once routed through InMotion’s SMTP; if one still is, the reports will show it failing. The reasoning is on the Pipeline page.
The redirect table Follows the data since 2026-09-22: the import workflow regenerates it on every committing run, and a deleted or moved album’s address forwards to its country page or its new address instead of 404ing. 2532 rows today, every one landing on a page the build makes (Cutover checks proves it on every push). Since 2026-09-25 it also answers the old pages the crawl never saw but the InMotion backup held — Peru 2010’s highlights, Philippines 2016, Africa’s old “cool” pages — on the test site now and on the live one from the next Publish (Pipeline page). Nothing further.

How the site is put together

Content (the part you own)

  • src/data/galleries.json — every album (235 today): country, year, photo list, flags (base: "r2", unlisted, albums-only, friends-only photographs).
  • src/data/journal.json — every letter (165): title, city, date, country, body, images.
  • src/data/currency.json — the banknotes (270 notes from 52 currencies) with scans and write-ups.
  • src/data/places.json — photo→place tags per album. src/data/captions.json — photo captions, one per photograph, keyed by its full address (since 19 October 2026). src/data/home.json — the carousel, cards and covers. src/data/guides.json — the apps on the shelf.
  • public/thumbs/ — 460 px thumbnails for the legacy albums that still ship with the site; everything upgraded serves from the bucket.

Design (the part a future redesign replaces)

  • src/layouts/ + src/pages/ — the page templates. src/components/ — the pieces two pages share (the album page, the timeline row, the admin connect card).
  • src/styles/global.css — the whole "Darkroom Daylight" design system: colors, type, every component. Read it as a page at Design system (since 28 October 2026): the palette with contrast, the fonts and type scale measured live, the breakpoints, every component drawn with the site’s own markup, and the media limits — all read from the stylesheet and the pipeline when the site builds, so it cannot go out of date. Save as PDF on it makes a clean copy to send a content partner; the page itself stays behind the admin door. It keeps itself current: it is rebuilt from the code with every deploy, and the Design guard flags anything new that still needs a description (in src/data/design-system.json).
  • design/site-daylight.html — the approved design reference, every page type in one file, kept in sync with every visual change.

Design boards — the source of truth for UI projects (25 August 2026)

Every screen that was designed before it was built lives in the repo as a set of boards, and the boards are what to reopen — by you, or by Claude in a future session — before changing one of those screens or building a new one in the same idiom. They record the approved look and the decisions behind it (annotations on the boards say why a control is where it is), which the built page alone cannot.

  • design/ios-upload/ — 9 boards: the iPhone uploader at /m (unlock, album picker and search, new-album, currency, uploading, done and failure screens). traveller-uploader-iphone.html beside them is the whole set as one browsable file.
  • design/ios-admin/ — 17 boards: Album cleanup on the phone (Browse / Select / Arrange modes, the sheets, import, delete) and Cards & strips (hub, carousel, letters home, country covers, the pickers), plus the two flow maps. traveller-admin-iphone.html is the one-file render.
  • design/iphone-nav/ — 4 boards: the site’s own navigation on an iPhone in portrait. You chose the masthead on 30 August 2026 and it is what the site does below 700px; the other three boards stay as the record of what was weighed.
  • design/iphone-photo-view/ — 5 boards (2026-09-06): the public photo view on an iPhone. You chose Option A the same day (the slim bar, the full-width photograph, the caption below, the admin verbs behind one chip) and Option C (turn the phone to fill the window); Board B remains the record of what was weighed.
  • design/site-daylight.html (with its editable -source.html) — the public site, every page type; unlike the boards above it is kept in sync: any visual change to a public page updates it in the same push.
  • design/design-directions.html and design/home-variations.html — the exploration that preceded the approved design. History, not truth.

The two ios-* folders are design-canvas projects: each screen is its own .dc.html artboard (open it in any browser), canvas.json lays them out, and the single-file render beside them is the shareable copy. Where a built page and its board disagree, the decision log says which one moved and why (Addenda 249–250 for the uploader, 258–260 for the admin pages).

Computed, never typed

Country stats (albums, photographs, years, banknotes), region groupings, listing filters, counts on cards, llms.txt / llms-full.txt, the sitemap, every page’s structured data, the redirect table and the numbers on this page are all derived at build time from the data files. Add a photo and every number that should change, changes on the next publish.

Where documentation lives

  • This manual (/admin/docs/) — how to operate the site: this page for the stack, Updating the site for what you do, the pipeline for how the machinery behaves and where every credential lives, Launch & cutover for the runbook of what was set up, when, and by whom, and the iPhone recipe. Updated in the same push as any change it describes. Golden rule: any service added to or removed from the stack must appear on this page in the same push.
  • docs/ in the repo — dated decision logs: what was decided, when, and why, each with the alternatives rejected.
  • CMS.md and REDESIGN.md in the repo — the architecture summary and the original redesign analysis.
Access note. The live site’s admin pages have been behind Cloudflare Access since 19 August 2026 — every address under www.traveller.org/admin*, this manual included, answers a stranger with the one-time-PIN login rather than a page. The upload Worker’s own addresses are not covered by it and never can be: their door is the passphrase, which rate-limits failed guesses.