Tell search engines and link previews what each page is

- /sitemap.xml, from the API's /slugs plus the landing and listings:
  every address in every language, with hreflang and x-default. A 503
  when the API is down, rather than a sitemap missing half the site.
- /robots.txt, naming the sitemap on whatever domain this is served on.
- Slugs renamed in the panel now redirect. The API has always kept the
  old address the moment one changed; middleware/redirects.ts answers
  it with a 301, from a list kept for a minute and through outages.
- og:url, og:image (the record's own picture, the logo otherwise) and
  schema.org JSON-LD: Organization on the landing; WebPage,
  CreativeWork, Person or Service elsewhere. Shared through core/head.
- The proxy-derived origin moves to core/origin.ts, used by the page
  shell, the landing and both server routes.

In development only /api/* reaches Nitro, so the two files 404 under
`npm start`; they were checked against a production build.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
pigui
2026-09-29 15:21:59 +02:00
parent 399b8d5450
commit 86b7485b32
17 changed files with 639 additions and 22 deletions

View File

@@ -162,6 +162,9 @@ landing/src/
server/
routes/api/contact.post.ts forwards the contact form to the API
routes/api/calls/[slug]/apply.post.ts forwards an application to one call
routes/sitemap.xml.get.ts every published address, from the API's /slugs
routes/robots.txt.get.ts points crawlers at the sitemap
middleware/redirects.ts 301s for slugs renamed in the panel
middleware/not-found-status.ts
styles.scss Material theme, `@pi/ui` sheets, shared primitives
```
@@ -251,6 +254,26 @@ cannot hold two parameters of different names at the same depth —
Featured pages go in the header after the section anchors; every page is in the
footer.
## Search engines and link previews
- **`/sitemap.xml`** comes from the API's `/slugs` — one request for every
published address — plus the landing and the listings. Each address is listed
in every language, with `hreflang` alternates and `x-default`. If the API is
down it answers 503, not a sitemap missing half the site.
- **`/robots.txt`** allows everything and names the sitemap, absolute, on
whatever domain the proxy says this is.
- **Renamed slugs redirect.** The panel writes a redirect the moment somebody
renames one; `middleware/redirects.ts` answers the old address with a 301,
from the API's `/redirects` list kept for a minute (and kept whole through an
outage, so renamed links do not turn back into 404s).
- **Every page says what it is**: title, description, `og:*` with the record's
own picture (the logo otherwise), and schema.org JSON-LD — `Organization` on
the landing, `WebPage`, `CreativeWork`, `Person` or `Service` elsewhere.
In development only `/api/*` reaches Nitro, so `/sitemap.xml` and
`/robots.txt` answer 404 under `npm start`; build and run `npm run preview` to
see them. Middleware does run in development.
## Rendering and caching
Nothing is prerendered: the page is assembled from content the panel publishes