Pages — Thin Routing Wrappers

Every .astro file here is a thin routing wrapper: imports a template, passes slug + locale. Zero user-facing text. Enforced by pnpm check:text.

STRUCTURE

pages/
├── index.astro              # German homepage (/)
├── [locale]/index.astro    # English homepage (/en/)
├── [slug].astro             # CMS catch-all (pages + legal) — EXCEPTION
├── [locale]/[slug].astro    # English CMS catch-all — EXCEPTION
├── preview/[...path].astro  # SSR Directus preview — EXCEPTION (prerender = false)
├── robots.txt.ts            # API route, non-prerendered
├── 404.astro 500.astro     # Error pages
├── blog/ news/ podcast/ glossar/ webinare/ autoren/ bayern/  # German dynamic routes
├── [locale]/blog/ [locale]/news/ ...  # English dynamic routes
└── *.astro                  # ~40 German static pages (platform, chatbot, faq, etc.)

ROUTING MODEL

THREE EXCEPTIONS TO THIN-WRAPPER RULE

  1. [slug].astro / [locale]/[slug].astro — CMS catch-all. Fetches Directus pages collection directly, renders through PageShell/PageMain. Not a thin wrapper.
  2. preview/[...path].astro — SSR preview route (prerender = false). Validates DIRECTUS_PREVIEW_TOKEN, resolves collection/locale from path, renders inline.
  3. robots.txt.ts — API route, non-prerendered, generates robots.txt based on hostname.

WHERE TO LOOK

Task Location
Add a static page (code-owned) Create <slug>.astro + [locale]/<slug>.astro (thin wrappers) + template + .i18n.ts
Add a CMS page Add row in Directus pages collection — catch-all resolves it automatically
Dynamic route static paths src/utils/paths.tsgetStaticPathsDe / getStaticPathsEn / multi-collection variants
Change segment mapping src/utils/i18n.ts PATH_SEGMENT_MAP (glossar→glossary, autoren→authors, etc.)

CONVENTIONS