flowingkhaosSign inBrowse the marketplace
New here? flowingkhaos is a build-in-public workshop. This is one part of one of two production failures.What this site is

openFix 02 · part four of five

Repair — Astro trailing slash on Cloudflare: fix the 307 and sitemap duplicates

Updated

Repair

Four changes. Two are settings on the Cloudflare zone, which answer before any code runs; two are code.

1. The trailing slash: 301, at the zone

A Redirect Rule on the zone, beside the existing www → apex rule:

  • When: the request path ends with / and is not / itself.
  • Then: a dynamic redirect to https://flowingkhaos.com + the path with its trailing slashes removed, status 301, query string preserved.

Check: curl -sI https://flowingkhaos.com/column/ → HTTP/2 301, location: https://flowingkhaos.com/column. / stays 200.

2. http → https, and HSTS

Zone settings: Always Use HTTPS on; HSTS on, six months, includeSubDomains off (the API host and others are not all on this zone’s TLS), preload off. Belt and braces in code: a public/_headers file that sets Strict-Transport-Security: max-age=15552000 on every path. The adapter copies it into the built assets the same way it copies _redirects, and appends its own cache rule for hashed assets.

Check: curl -sI http://flowingkhaos.com/ → 301 to https; the https response carries the HSTS header.

3. A sitemap with a true lastmod

The integration is removed. The site now writes sitemap-0.xml itself from the four content collections, and keeps sitemap-index.xml as a second endpoint listing the one file, so robots.txt, the /sitemap.xml 301 and the sitemap registered in Search Console all stay valid.

The date per URL: the CMS row’s updatedAt for a page with a row; the parent row’s for a fix’s stage pages and a workshop’s steps; the newest row’s for an index page (a list changes when its newest entry does); none for the three markdown pages that live in the repo. Every URL is the apex host with no trailing slash. The rules are one function, tested against the fixtures: every URL slashless, every URL dated except the three, nothing from /account, and one entry per node the site’s page tree declares.

One honest caveat, written beside the code so nobody “fixes” it later: Payload’s updatedAt moves on any save, including a save with no text change. Acceptable today, with few saves and all of them editorial. The trigger to revisit: lastmod moving on more than two pages a week without a text change. Then a contentUpdatedAt field set by a CMS hook that compares the body, and the sitemap reads that instead.

4. One schema.org graph on every page

The base layout prints one <script type="application/ld+json"> with a graph: the WebSite, the Brand at https://flowingkhaos.com/#brand (an id the clevrstart home page has pointed at for two weeks, which resolved to nothing until now), the Person at https://lukesidney.me/#person with the same profile list clevrstart publishes, the WebPage with its dateModified, and then the page’s own node:

Page Node
a fix, and each of its stages TechArticle — headline, datePublished = opened, dateModified, author, about = the measured impact; a stage is isPartOf the fix
a workshop Course with hasPart = its steps as LearningResource
a workshop step LearningResource, isPartOf the course, dates from the parent
a column piece BlogPosting
a listing Product + Offer with the price Polar lists and the licence terms already on the page
everything else the WebPage alone

Every content node names the author and both dates. The same dates are printed as text in a <time> on fix, workshop and column pages, because a visible date is on the checklist for being cited.

In the same pass

  • A description of its own on every page: fix stages and workshop steps take the first paragraph of their body, cut at a word under 160 characters; the index pages one sentence each; the legal pages their lede.
  • The four stage pages of a fix get their own H1: the stage name, then the fix title.
  • The sign-in links on a step page carry rel="nofollow", so the crawl budget stays on the lesson.

Gates

astro check 0 errors. 265 tests pass. A build against the live CMS: 26 URLs in the sitemap, 23 dated. Under a local wrangler preview: the HSTS header on /, the sitemap index 200, /sitemap.xml 301, a fix stage with its canonical, its own description, its own H1 and a dated TechArticle with an author. /column/ still answers 307 locally, as expected: the 301 is the zone rule, and the zone is not in the preview.

The column · weekly · free

The next fix, in your inbox the week it happens.

One written column a week. The email service holds the list.

The marketplacePay once

Skip the build. Start from code that ships

Production-ready code under a one-time licence. Buy it, and start building with the code you bought.

  • Pay once
  • Resell what you build
  • No subscription

Luke Sidney writes and builds everything here, alone, in the open. lukesidney.me

Next part · 05 of 05Aftermath