Page Routing and SEO — SPEC

Start here → AGENTS.md · SPEC_INDEX.md · ARCHITECTURE.md.

Metadata

FieldValue
Module idpage-routing-and-seo
Source path(s)src/pages/, src/layouts/, src/lib/seo.ts, src/lib/sitemap*.ts
Doc kindModule spec
Coverage score100% assessed 2026-07-24; 14/14 mandatory fields PRESENT, focused ASP route evidence added
Generated frommodule-spec @ 0.2.1
generated_by / approved_by / updated_atcodex (gpt-5.6) / repository owner MODIFIED-delta append approval / 2026-08-19
Validation statuspass-with-warnings; validator claude-opus-4-8-1m (runtime independent of codex), target HEAD b9c7321ee3642bdb0137734e187a102a7f5de9be, assessed 2026-07-24; 0 Blocking, 0 Important, 0 Medium, 2 Minor; full suite environment-blocked (Node 24 + registry pending)

Evidence Rules

Behavioral claims cite current route/config/test files. Preserved migration specs supplied route intent and acceptance cases, but do not override the Astro file tree.

Source Material Register

Source materialScopeDecisionDisposition
Existing ASP listing specificationpage behaviorverified/correctedCurrent /asp-apps behavior is represented in requirements and routing flow
Current route tree and SEO testsimplementation/testsauthoritativeRequirements, public surface, error handling, test strategy

Overview

Astro file-based routing under src/pages/ owns public pages, same-origin APIs, operational endpoints, authentication callbacks, media proxies, robots policy, and sitemap output. Shared layouts apply metadata and page chrome; src/lib/seo.ts centralizes title, description, canonical URL, and social-image construction.

Purpose / Responsibility

Owns URL-to-handler mapping and indexable metadata for the current Astro application; it does not own external data normalization or browser interaction state.

Stack

Astro 6 SSR routes, TypeScript endpoint handlers, Astro layouts, Vitest route/SEO tests, Playwright higher-tier checks.

Folder / Package Structure

src/pages/
├── *.astro                 # public SSR pages
├── applications/[appId]   # dynamic app detail
├── category/[category]     # category listing
├── api/                    # same-origin JSON/action routes
├── auth/                   # App Hub OAuth
├── integration/            # native integration OAuth
└── sitemap*.ts, robots.txt.ts, ping.ts, getImage.ts

Key Files (source of truth)

FileHolds
src/pages/Actual route existence and method handlers
astro.config.mjsSSR output, site origin, static sitemap and redirects
src/lib/seo.tsMetadata defaults and normalization
src/pages/sitemap.xml.tsDynamic sitemap generation/cache/compression
src/lib/sitemap-config.tsStatic page catalog
src/lib/middleware/permanent-redirects.tsCanonical 301 redirects

Public Surface

Contract IDTypeSurfacePurposeCompatibilityDetailRoot index
page.catalogHTTPGET Astro page routesBrowse/search catalogURL and redirect stabilitysrc/pages/CONTRACTS.md
seo.robotsHTTPGET /robots.txtCrawler policyText/status stabilitysrc/pages/robots.txt.tsCONTRACTS.md
seo.sitemapHTTPGET /sitemap.xmlDiscover public URLsXML/gzip compatibilitysrc/pages/sitemap.xml.tsCONTRACTS.md
catalog.searchHTTPGET /api/searchServer-side catalog searchQuery/result compatibilitysrc/pages/api/search.tsCONTRACTS.md

Compatibility notes:

Requires (dependencies)

Synchronized catalog/category data, Redis, page layouts/components, SEO helpers, middleware redirects/security, and configured site host.

Requirements

IDWHATWHYSource EvidenceTest / Example EvidenceGapsConfidence
PAGE-R-001Astro MUST derive routes from src/pages/; dynamic parameters MUST be validated before data lookup.Prevents invented routes and unsafe identifiers.src/pages/applications/[appId].astro, src/pages/category/[category].astrotests/unit/lib/listing-app.test.tsnonePRESENT
PAGE-R-002/asp-apps MUST render the ASP/agentic listing using current synchronized data and the shared listing layout.Preserves the shipped listing contract without reviving legacy routing.src/pages/asp-apps.astro, src/lib/fetch-synced-data.tsplaywright/tests/functional/navigation/collection-routes.spec.tsnonePRESENT
PAGE-R-003Page metadata MUST use centralized SEO defaults, bounded descriptions, absolute canonical/social URLs, and route-specific values.Prevents inconsistent or invalid index metadata.src/lib/seo.ts, src/layouts/BaseLayout.astrotests/unit/lib/seo.test.ts, tests/unit/lib/seo-spec-constants-drift.test.tsnonePRESENT
PAGE-R-004Robots and sitemap output MUST exclude non-indexable auth/API/error/search surfaces and include current public static/dynamic URLs.Keeps crawler output aligned with user-facing content.astro.config.mjs, src/pages/robots.txt.ts, src/pages/sitemap.xml.tstests/unit/pages/robots-txt.test.ts, tests/unit/pages/sitemap-generation.test.tsnonePRESENT
PAGE-R-005Permanent legacy URLs MUST resolve through the centralized redirect definitions before normal route handling.Maintains inbound-link compatibility.src/lib/middleware/permanent-redirects.ts, src/middleware.tstests/unit/config/permanent-redirects.test.tsnonePRESENT
PAGE-R-006 [MODIFIED 2026-08-19, 2026-09-15]/prebuilt-actions MUST render approved synchronized records and redirect to the current not-found route when none exist; sitemap output MUST include the listing and action detail URLs only while approved records exist. Legacy snapshot type aliases MUST pass through the same approval boundary before route or sitemap exposure, and the static fallback catalog MUST include /prebuilt-actions.Keeps browsable and crawler-visible routes aligned with publishable upstream state, including during rolling deployments and degraded sitemap loading.src/pages/prebuilt-actions.astro, src/pages/sitemap.xml.ts, src/lib/sitemap-config.ts, src/lib/prebuilt-actions.ts, src/lib/fetch-synced-data.tstests/unit/lib/prebuilt-actions.test.ts, tests/unit/lib/fetch-synced-data.test.ts, tests/unit/pages/sitemap-generation.test.tsfull route behavior covered by build/higher-tier navigation checksPRESENT

Design Overview

Routes are declarative files. Pages obtain server data before rendering and pass serializable initial state to islands. Static sitemap discovery is configured in Astro; the custom sitemap merges static pages with synchronized app/category URLs, normalizes/escapes them, caches the result, and serves compressed bytes when supported.

Data Flow

flowchart LR
  Request --> Middleware --> Route["Astro route"]
  Route --> Data["sync/SEO helpers"]
  Data --> Render["layout + components"]
  Render --> Response
  Data --> Sitemap["XML generation/cache"]

Sequence Diagram(s)

Operation groupDiagramFailure coverage
SSR pagePage renderMissing data selects empty/404 behavior
SitemapSitemap generationCache miss and unavailable data remain valid output paths
sequenceDiagram
  participant B as Browser
  participant M as Middleware
  participant P as Astro page
  participant R as Redis/sync helpers
  B->>M: GET page
  M->>P: next()
  P->>R: read normalized data
  alt route entity exists
    R-->>P: data
    P-->>B: SSR HTML + metadata
  else missing/invalid
    R-->>P: null
    P-->>B: 404/empty contract
  end
sequenceDiagram
  participant C as Crawler
  participant S as Sitemap route
  participant R as Redis/sync readers
  C->>S: GET /sitemap.xml
  S->>S: check process cache
  alt cache miss
    S->>R: read apps and categories
    R-->>S: current snapshot or unavailable subset
    S->>S: merge static/dynamic, normalize, escape, compress
  end
  S-->>C: XML or gzip XML

Class / Component Relationships

classDiagram
  class AstroRoute
  class Layout
  class SeoHelpers
  class SyncReaders
  AstroRoute --> Layout
  AstroRoute --> SeoHelpers
  AstroRoute --> SyncReaders

Use Cases

Business Rules & Invariants

Concurrency & Reactive Flow

UI Flow

Error Handling & Failure Modes

ConditionSignalRecovery
Invalid/missing dynamic ID404 or route-specific empty resultCorrect URL; do not call upstream with unchecked ID
Search/index unavailableAPI error/fallback resultRetry after sync; inspect sync health
Sitemap source unavailableValid response from available dataRegenerate after sync
Unknown route/probe404 from middleware/AstroNo retry unless URL corrected

Pitfalls

Module Do’s / Don’ts

Key Design Trade-off

File-based routing keeps route ownership visible and build-checked, while custom sitemap generation accepts extra runtime complexity to include Redis-backed dynamic catalog URLs.

Test-Case Strategy (module)

Unit-test SEO normalization, redirects, robots, sitemap escaping/deduplication/compression, and route helpers. Use build and visual/E2E suites for representative SSR routes and navigation.

BehaviorExisting test evidenceGap
PAGE-R-003tests/unit/lib/seo.test.tsnone
PAGE-R-004robots/sitemap unit suitesnone
PAGE-R-005permanent redirect testsnone
ASP listing SSRplaywright/tests/functional/navigation/collection-routes.spec.tsnone

Traceability