Add a "Not found" template target for designed 404 pages#52
Merged
Conversation
A page can now be marked as the site's 404 page via a third template
target kind, `{ kind: 'notFound' }` — "Not found (404)" in the Template
settings "Applies to" select.
- Core: new target kind in TemplateTargetSchema + parsePageTemplate;
resolveNotFoundTemplate(site) picks the winner (priority, then
document order). A notFound template never enters route chains.
- Publish: full publish bakes the template (wrapped in the everywhere
layout chain, like any page) to 404.html in the slot — the
static-hosting convention, so raw static exports keep a working
error page on Netlify/GH Pages.
- Serve: new last dispatcher route catches every GET no other route
claimed and serves the baked artefact (one disk read, no DB) — or a
live render through the Layer B LRU under the reserved /404 key —
always with status 404. No notFound template → JSON 404 as before.
- Editor: third "Applies to" option; "Open live page" resolves to
/404; canvas wraps the template in the everywhere layout.
- AI: setPageTemplate accepts the new kind; prompts updated.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
DavidBabinec
added a commit
that referenced
this pull request
Jun 13, 2026
…ifier SITE_DEFAULTS_ID is only used within MetaTab — make it a private const. The design spec now lives on main (landed via #52), so drop the "(local)" qualifier in the feature doc. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Adds a third template target kind — Not found (404) — so a designed page can be served for every public 404, replacing the bare
{ "error": "Not found" }JSON response.How it works
Core (
src/core)TemplateTargetSchemagains{ kind: 'notFound' }(+ tolerantparseTargetbranch). No DB migration — template config lives incells_json.resolveNotFoundTemplate(site)picks the winner (highest priority, document order breaks ties). A notFound template never entersresolveTemplateChain— it isn't a breadth level; route matching never "matches" a 404.Publish (
server/publish)renderPublishedNotFoundcomposes the template like a regular page — wrapped by theeverywherelayout chain, so the 404 page carries the site chrome.404.htmlin the slot — deliberately the static-hosting convention, so a raw static export keeps a working error page on Netlify / GitHub Pages. Baked first, so a literal page with slug404would overwrite it and stay authoritative.Serve (
server/router.ts,publicRouter.ts)tryServeNotFoundPage: any GET no other route claimed serves the baked artefact (one disk read, no DB — the path bot probes hit) with status 404; falls back to a live render through the Layer B LRU under the reserved/404key (stored once per publish version, shared by every missed URL). No notFound template → today's JSON 404, unchanged./admin/api/*,/_instatic/*,/uploads/*) keep their own 404s; the fresh-install setup redirect still wins (it runs earlier).Editor / AI
/404.setPageTemplateAI tool accepts the new kind.Known trade-off
A direct GET of
/404serves the baked artefact with status 200 — the same convention as GitHub Pages. Documented indocs/features/templates.md.Testing
bun test— 5385 pass (new:notFoundResponse.test.tscovering Layer A artefact serving incl. a DB-free proof, live-render fallback + caching, and the no-template null path; matching/parse/label/dialog tests extended).bun run build,bun run lint— clean.🤖 Generated with Claude Code