PagesStatic site, no build step
Every push to main becomes a new release on the global network. No build, no pipeline: the HTML, CSS and JavaScript sit in the repo exactly as served. _headers sets the Content-Security-Policy, Permissions-Policy and cache rules; a root wrangler.toml holds the bindings.
Pages FunctionsServer logic next to the files
The guestbook (/api/sager), the counters and the shareable cases (/sag/980-0007 with link previews) are small functions in functions/. They run in the same request as the page, in the data centre nearest you.
Workers KVGuestbook and counters
A globally replicated key-value store holds the cases raised, the attempts to decide the case and today’s visitors, the last as daily hashes that expire after two days. No cookies for that; the session for the machine park is the only cookie, and it holds nothing about the person.
Workers + Service BindingThe thing’s machines behind /api/ting-ai/
The thing's machine park lives in a separate Worker. Pages calls it through a service binding, a direct call between two Workers that never touches the public internet. The Worker has no address of its own.
Workers AIThree models, one budget
Courtroom, Brian, newspaper and provenance: Llama 3.3 70B in JSON mode, so replies are validated against a schema before they are shown. The image evidence: Llama 3.2 Vision describes, the text model translates. The forge: FLUX.1 schnell. Daily quotas are reserved in the database before the model is called.
D1SQLite at the edge
Newspaper editions, cases, quotas, idempotency keys and rate limits live in a D1 database in Western Europe. Reservations carry a lease, so a crash mid-call never locks the day’s allowance forever.
Durable ObjectsOne truth about seven seats
The Great Vote is one Durable Object per ford with WebSocket Hibernation: every connection talks to the same instance, seats are assigned atomically, and the object sleeps between messages without losing the round. A reconnect gives you the same seat, not a new vote.
WorkflowsThe bureaucracy sleeps durably
A stool application starts a Workflow instance that sleeps a minute, two hours and a day between its steps. It runs while your browser is closed, and every step is idempotent: a repeated step never moves the case two places.
Cron TriggersThe paper is printed once a day
An hourly schedule in UTC with a date guard in Europe/Copenhagen, so daylight saving never yields two editions. A job lock in D1 ensures two simultaneous triggers still print one paper per language. Page views never generate anything.
R2Media without egress fees
Fictional finds and the radio’s audio files are stored in an R2 bucket under a key of choices, language, prompt version and model. The same combination is therefore fetched from the model only once; every guest shares the file.
AI GatewayOne gate in front of every model
Every AI call passes through AI Gateway, which logs model, latency and tokens, caches identical calls (the same sample picture is described only once) and can set its own ceiling. The site’s own daily quotas still apply; the gateway is the safety net around them.
Rate Limiting + TurnstileOne vote at a time, preferably from a human
Workers’ built-in rate limiting binding counts calls per session and endpoint inside Cloudflare’s own network. The guestbook and the stool application are protected by Turnstile, an invisible bot check with no picture puzzles; the token is validated server-side and can be used only once.
VectorizeBrian’s archive as a vector index
The editorial corpus (characters, case files, the real facts with sources) is indexed as embeddings from bge-m3. Brian finds the nearest excerpts to a question and may only quote them. The puzzle’s solutions are not in the index; the server still selects them by spoiler level.
Browser Run + ImagesA browser at the edge
Link previews of a shared case (/sag/980-0007) are drawn as a real image by a headless browser and stored in R2. The minutes can be fetched as a PDF from the same browser. The Images binding normalises uploads in the image evidence: orientation, metadata and size, before the model sees the file.
Network and securityHTTP/3, HSTS, CSP and no third parties
Everything is served over HTTP/3 from Cloudflare’s network with HSTS. The Content-Security-Policy allows only the site’s own scripts and Turnstile; AI text is always escaped and never becomes HTML. Sessions are a signed, HttpOnly cookie with no personal data. Web Analytics counts without cookies.
DNS and domainThe name lives on Cloudflare's name servers
tingsvad.dk has been the family's since the 90s. Today Cloudflare's anycast DNS (sid and val) answers for the name from hundreds of cities at once, so the lookup happens close to whoever asks. The zone is signed with DNSSEC (ECDSA P-256) and the DS record sits with Punktum.dk, so a validating resolver can reject forged answers. Traffic to the site is proxied through Cloudflare, so the real IP addresses behind Pages are never shown. Mail goes around it: the MX records point to the family's ordinary mail provider, and the site never touches it.
DDoS, WAF and analyticsA guard that is on before anyone asks
Cloudflare's DDoS protection stands in front of all traffic with no setup, and the managed WAF ruleset stops known attack patterns before they reach Pages Functions and the Worker. Web Analytics counts visits with a small script from Cloudflare's own domain, with no cookies, fingerprinting or third parties. The thing's own visitor counter at the bottom of the page is a daily hash in KV (see the Workers KV card) and knows nothing about who you are. Network Error Logging (NEL) reports connection failures back to Cloudflare, so the site can see when something does not arrive.
Pages Functions + HTMLRewriterOne navigation, no build step
The pages are plain HTML files with placeholders. A middleware (functions/_middleware.js) streams each page through HTMLRewriter and inserts the top bar, navigation and footer from /partials/, fills in the language switch from the page’s hreflang and marks the page you are on. _routes.json keeps images and scripts out of Functions, and because _headers does not apply to Functions responses, the middleware sets CSP and HSTS on HTML itself. Old links such as /#gaestebog are forwarded by a small script to the sub-page where the element now lives.
Server-TimingShow the machinery
Every panel in the machine park can unfold its machinery: the products behind it, the actual call, the response time measured in your browser and the Worker’s own measurements of D1, Workers AI, R2, KV and Vectorize, sent as a Server-Timing header. Bindings are wrapped in a small proxy (worker/src/lib/timing.js), so the measuring happens in one place. Stored results are labelled Stored result, so it is always clear whether something is live.
One canonDates and rulings in one place
assets/kanon.json holds the universe’s fixed figures: the thing convened in 980, the three rulings with the latest in the 1990s, foggy days and summer. The page reads the file, and Wrangler bundles the same file into the Worker on deploy, so the newspaper’s FACTS and the front-page counters cannot drift apart. A number guard removes sentences with figures the model made up.
QueuesThe raven’s mailbag
Orders to the raven exchange go into the queue tingsvad-ravn. The queue delivers at least once, with retries and a dead-letter queue; because every Workflow instance has a fixed name (ravn-<job>-<attempt>), a duplicate delivery does no harm. Queues are free on Workers Free.
Workflows + Browser RunDocuments and audits, step by step
The raven exchange’s Workflow goes from received via the raven is flying to the document is being written (a PDF from a fixed, escaped template in Browser Run, filed in R2) and delivered; every step is an idempotent transition in D1, and the writing is retried. The audit is another Workflow that each morning takes one page at a time with a pause in between, staying within Browser Run’s free allowance.
Outside CloudflareWhat the browser does itself
A service worker for offline and “add to home screen”, Web Audio for the river and the wind, canvas for the excavation and the certificate, the Intl API for Danish dates and seasons, localStorage for your finds. The family’s e-mail goes via MX records to an ordinary mail provider; Pages never touches it.