Files
ResumeSite/docs/spec/ROUTING_SPEC.md
T
2026-07-03 21:07:25 +02:00

3.7 KiB

ROUTING_SPEC.md

1. Canonical route table (the EN↔NO contract)

Page EN (default, root) NO (/no prefix, localised slugs)
Home / /no/
Projects index /projects/ /no/prosjekter/
JobTrack case study /projects/jobtrack/ /no/prosjekter/jobtrack/
InboxIntel case study /projects/inboxintel/ /no/prosjekter/inboxintel/
Homelab capability page /projects/homelab/ /no/prosjekter/hjemmelab/
Experience /experience/ /no/erfaring/
About /about/ /no/om-meg/
Contact /contact/ /no/kontakt/
CV hub /cv/ /no/cv/
Site meta ("how this site works") /colophon/ /no/kolofon/
404 /404 (bilingual page)

Rules: trailing-slash canonical (nginx redirects the bare form, 301). Product names (jobtrack, inboxintel) stay untranslated per CONTENT_STRATEGY glossary. This table lives in code as the single slug map module (i18n/slugMap.ts conceptually): pageId → {en: path, no: path}; consumed by the language switch, hreflang generation, sitemap, and nav. CI test asserts bijection (every EN path has exactly one NO twin and vice versa) and that every content entry maps to a route.

2. Non-page routes

Route Serves Notes
/cv/connor-babbington-cv-en.pdf English CV Stable, shareable, versioned in repo
/cv/connor-babbington-cv-no.pdf Norwegian CV Same
/api/contact POST → contact-relay container Only non-static route; nginx proxies. 405 on GET
/sitemap-index.xml, /robots.txt build artifacts SEO_SPEC
/og/*.png Pre-generated OG images per page per locale Build-time generated
/Linkedin 301 → LinkedIn profile Preserves the existing cesnimda.co.uk/Linkedin redirect used on the printed/PDF CV — must not break
Legacy WP URLs (/feed/, /wp-*, old anchors) 410 Gone (crawler cleanup) except any URL known to be shared → 301 to nearest new page Inventory old URLs before cutover (Phase 3 task)

3. Redirect & language behaviour

  • No automatic locale redirect. / is always EN. Rationale (Phase 1): shared links must be stable; recruiters forward URLs across languages; auto-redirects break back-button and SEO.
  • First-visit hint: if navigator.language starts with nb/nn/no, and no stored preference, and current locale is EN → show the dismissible hint bar (client-side only, one-time, stores dismissal). Never shown on NO pages, never a redirect.
  • Language switch: header control resolves current pageId via the slug map → navigates to the twin URL. Stores preference (used only for the hint logic and CV-button default — never for redirects).
  • Unknown /no/... path: bilingual 404 (NO strings first when under /no/).

4. URL quality rules

  • Lowercase, hyphenated, ASCII slugs (NO slugs transliterate: om-meg, not om-mæg — æøå avoided in URLs for shareability/encoding robustness).
  • No query parameters anywhere in canonical URLs; anchors (#architecture / #arkitektur) are localised to match section headings' explicit ids from the content model (stable across copy edits).
  • Case-study section anchors are part of the content schema (DATA_MODEL) so the mini-TOC, deep links, and language-switch section-mapping (J5) stay in sync.

5. Navigation state mapping

  • aria-current="page" from exact pageId match; Projects nav item also marked current on case-study pages (section-current, underline 60% per Phase 1).
  • Homepage scroll-spy: section ids #skills #projects #experience #about #contact (EN) / #kompetanse #prosjekter #erfaring #om-meg #kontakt (NO) — defined in the slug map's anchor table, not ad hoc.