PUBLISHING.md carries the house style with the posts, so the standard survives without the design doc to hand — including the rule that a post states what a metric does not show, which is the strongest signal a human wrote it. CLAUDE.md gains the two constraints that are invisible from the code and expensive to rediscover: metadata file conventions break if moved into a route group, and the build must keep succeeding with DATABASE_URL unset. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017YmbBhr8s7GusjDE12hrZM
3.4 KiB
Publishing to the blog
The blog is Payload CMS, running inside the Next.js app. There is no separate service and no second deploy — writing a post is done in the browser and takes effect on the live site within seconds.
Signing in
https://www.schoolcompare.co.uk/admin — one account, no registration. If you
need the account seeded on a fresh environment, run against the container:
npx payload create-first-user
Staging has its own admin panel, its own database and its own credentials at
https://stx.schoolcompare.co.uk/admin. Never reuse production's secret or
password there.
Writing a post
Posts → Create New. The fields:
| Field | Notes |
|---|---|
| Title | The <h1> and the browser tab. |
| Slug | The URL segment, in the sidebar. Never change it after publishing — it is the canonical URL, and changing it breaks every existing link and discards the page's accumulated search signal. |
| Published at | The date shown on the post and in the feed. |
| Excerpt | Max 200 characters. Shown on the index and used as the meta description, so write it as a standalone sentence rather than a teaser. |
| Hero image | Optional. Becomes the social share image; without one, the site's generated card is used. |
| Content | Rich text. / inserts a block. |
Save as draft while you're working — drafts are not public. Publish when it's ready.
The callout block
One custom block, Callout, with two tones:
- Caveat — what a number does not show. This is the one that matters: it is how a post states a limitation in context rather than burying it in a closing paragraph.
- Note — a useful aside.
Images
Every image requires alt text; the editor will not let you save without it. Uploads go to a Docker volume on the host, which is backed up separately from Postgres — an image is not reproducible from the pipeline the way school data is.
How publishing reaches the live site
/blog,/blog/rss.xmland/content-sitemap.xmlare rendered per request, so a new post appears immediately./blog/[slug]is cached after its first request. Publishing or editing fires arevalidatePathfrom the collection'safterChangehook, which drops that cached copy — so edits appear immediately too.
If a change doesn't show, it is far more likely the post is still a draft than that the cache is stale.
House style
These rules are why the blog exists. A post that ignores them makes the site read more machine-generated, not less.
- First person singular. "I built", "I found" — never "we provide".
- Concrete over general. "When we were looking at schools in Wandsworth" beats any amount of stated warmth.
- State limits before someone else finds them. Every post that presents a metric says what it does not show. This is the single strongest signal that a human wrote it: generated content does not volunteer its own weaknesses.
- No mission statements, no "passionate about", no invented team. There is one person here.
- Short sentences.
- Never publish a surname, an employer, or a child's name. The site's author
is "Tudor". See
/about. - Never invent a figure, even illustratively. On a site whose whole proposition is official data, a made-up number attached to a real school is the one thing it cannot do — and no illustrative intent survives being screenshotted.