the URL says which page, not which row

`?page=about` instead of `?page=2`. A URL that names the page can be read, sent to somebody, and still
means the right thing after a database is restored from a dump with different ids — which happened
once in this project already, earlier today.

Home needs a word, because its slug is empty by design: that is the check constraint, and it is what
makes `/` fall out of joining a slug to the root. An empty string is no use in a query parameter that
has to name a page unambiguously, so the admin says `home` — and the site's API now REFUSES that slug,
which is what makes the mapping total in both directions rather than merely usual.

One reserved address costs nothing. Anybody who wanted /home wanted the front page, which they have.

One place maps a page to its URL value and back — pageParam and pageFromParam — so the nav, the detail
panel and the builder cannot disagree about what `?page=` means.

`record` is deleted on every navigation. It belonged to the per-page record panels, which are
unreachable now; nothing reads it, so it was not a bug, but every URL anybody copied carried a
parameter naming a row in a section that no longer exists.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-08-31 04:42:16 +01:00
co-authored by Claude Opus 5
parent b7c887a9e8
commit 5b1c5a2590
4 changed files with 38 additions and 9 deletions
+3 -3
View File
@@ -7,7 +7,7 @@ import { usePreviewable, useViewMode } from '../ViewMode';
import { paintCanvas, type CanvasComponent, type CanvasSection } from '../canvas';
import { AddSectionDialog, type SectionLayout } from './AddSectionDialog';
import { FreeTextDialog } from './FreeTextDialog';
import { usePages, type Page } from '../usePages';
import { pageFromParam, usePages, type Page } from '../usePages';
/**
* One page, being built.
@@ -30,7 +30,7 @@ export const PageBuilderPanel = () => {
clientRef.current = client;
const [params] = useSearchParams();
const id = Number(params.get('page')) || null;
const slug = params.get('page');
const devPort = useDevPort();
const { pages, announce } = usePages();
@@ -157,7 +157,7 @@ export const PageBuilderPanel = () => {
.catch((failure: unknown) => setError(readableError(failure)));
}, [pages, announce]);
const page = pages?.find((row) => row.id === id) ?? null;
const page = pageFromParam(pages, slug);
/*
The page's sections, which the canvas needs to name and outline what it finds in the document.