Frontend Route Mapping
Frontend codebases are not fully knowable from a file-tree map alone. Routes, navigation, and the data dependencies of each page are the actual surface area an agent must reason about when proposing changes or authoring user-flow tests. This skill defines the artifact every frontend codebase gets: <codebase>/docs/ROUTE_MAP.md.
File location and format
- Path:
<codebase>/docs/ROUTE_MAP.md. - YAML frontmatter (required):
--- last_routed: 2026-05-16T10:30:00Z codebase: /abs/path/to/frontend framework: nextjs-15-app-router # or react+react-router-6, vue+vue-router-4, etc. --- - Markdown body following the schema below.
Schema (every section is required)
## Route Inventory
A table covering every route exposed by the app.
| Route | Type | Auth | Component | File | API calls | Outbound links |
|---|---|---|---|---|---|---|
/login |
public | none | LoginPage |
src/pages/Login.tsx |
POST /auth/login |
/, /signup |
/dashboard |
protected | user | Dashboard |
src/pages/Dashboard.tsx |
GET /api/me, GET /api/projects |
/projects/:id, /settings |
Columns:
- Route — exact path pattern as the framework defines it.
- Type —
public/protected/admin/system. - Auth —
none/user/<role>. - Component — top-level component name rendered.
- File — absolute or repo-relative path.
- API calls — every endpoint hit by the route's component tree (
METHOD /path). Empty =—. - Outbound links — every other route reachable from this route, via any navigation mechanism (link click, programmatic navigation, form-submit redirect).
## Dynamic Routes
For routes with URL params (/projects/:id, /users/:userId/posts/:postId):
- Route pattern.
- Each param: name, type/format (UUID, slug, integer), source (URL only / URL + query).
- Data fetched per param (e.g., "
GET /api/projects/:idreturns ProjectDetail").
## Navigation Web
A graph of route → outgoing edges. Use a code-block diagram or mermaid:
/login --[POST /auth/login 200]--> /dashboard
/dashboard --[ProjectCard click]--> /projects/:id
/projects/:id --[Edit button]--> /projects/:id/edit
/projects/:id/edit --[Save → PATCH /api/projects/:id 200]--> /projects/:id
/dashboard --[Settings link]--> /settings
Each edge labels the trigger ([<element/event> → <api or condition>]). Every navigation must appear here, including programmatic redirects from API success/failure.
## Entry Conditions
For every protected/conditional route, list the predicate:
/dashboard: requires session cookie; redirects to/loginif absent./admin: requiresuser.role === 'admin'; renders 403 page otherwise./projects/:id: requires the user has membership in the project (server-checked, 404 otherwise)./onboarding: requiresuser.onboarding_completed === false; redirects to/dashboardif true.
## Modal & Drawer Routes
Two kinds:
- URL-bound (modal/drawer state lives in the URL): list with selector. Example:
/projects/:id?modal=delete→DeleteProjectDialog. - State-bound (modal/drawer triggered programmatically): list the trigger component(s) → modal ID → component rendered.
## API Endpoint Catalog
Every endpoint hit by the frontend, grouped by route. For each:
- Method + path.
- Where it's called (
file:lineorfile:function). - Inferred request shape (from the call site: types, body composition).
- Inferred success response shape (from how the result is consumed).
- Observed error handling (which statuses surface what UI).
What "complete" means (for the codebase-map-reviewer)
A ROUTE_MAP.md is incomplete if ANY of the following:
- A route exists in the framework's routing config that is not in the Route Inventory.
- A
<Link>/<Navigate>/router.push()/redirect()/<Form action>exists in the code that has no outgoing edge in the Navigation Web. - A
fetch/axios/ query hook / RPC call exists in a route's component tree that is not in the API calls column or the API Endpoint Catalog. - A protected route has no entry in Entry Conditions.
- A modal/drawer trigger exists in the code that is not in Modal & Drawer Routes.
Reviewers must spot-check by sampling components and confirming claims.
Freshness
last_routedis set by the route-mapper at write time, ISO 8601 UTC.- The intake skill compares it against
git -C <codebase> log -1 --format=%cI. Doc older than the latest commit → re-run the route-mapper. The agent uses git diff to scope the update.
Companion artifact: DESIGN_MAP.md (conditional)
When design artifacts are present in $REQ_DIR (screenshots, Figma exports) OR design tokens / Storybook / assets exist in the codebase, the route-mapper additionally produces <codebase>/docs/DESIGN_MAP.md per the design-fidelity-mapping skill. ROUTE_MAP.md captures STRUCTURAL surface (routes, navigation, API calls, modals); DESIGN_MAP.md captures VISUAL surface (design tokens, asset registry, per-screen visual specs, detected drift). Both are produced in the same Phase −1B pass when applicable; DESIGN_MAP.md's absence is not a gap when no design inputs exist.
Downstream consumer: interaction-intuition (Phase −1D)
ROUTE_MAP.md is a Phase −1B output and a Phase −1D input. At Phase −1D the interaction-intuiter agent reads ROUTE_MAP.md (alongside DESIGN_MAP.md and INTEGRATION_MAP.md) per the interaction-intuition skill and produces <codebase>/docs/INTERACTION_INTUITION_MAP.md — a per-element intuition of "what action does this control take and which endpoint does it call" with confidence high / medium / low / unknown. Every interactive element in the route table feeds that cross-walk; route entries with awaiting_confirmation: true flags or no explicit target_link annotation become high-priority low or unknown items in the intuition map, surfacing them to the Phase −1D bulk-verify gate.
Anti-patterns to reject
| Rationalization | Rebuttal |
|---|---|
| "Routes are obvious from the file structure" | They're discoverable, not documented. Tests + reuse-first decisions need them in one place. |
| "I'll just list the top-level routes" | Dynamic and nested routes are where bugs live. List them all. |
| "API calls are scattered — too much work to map" | That's exactly why they need mapping. Future agents shouldn't re-discover them every time. |
| "Modals don't have routes" | URL-bound modals do. State-bound modals are still navigation surface — list them. |