Add React Router v7 routing
Add $route to the Vite SPA using React Router v7 Data Mode:
createBrowserRouter + RouterProvider, imported from react-router.
TanStack Query keeps server-state ownership. Do not adopt Framework/SSR or bare
Declarative Mode; Express remains the backend.
Step 1 — Detect the toolchain and ensure the dep
source "${CLAUDE_PROJECT_DIR}/.claude/lib/detect-toolchain.sh"
If missing, add react-router with the detected package manager. Do not add
react-router-dom; v7 uses one package. Confirm major version 7.
Step 2 — Place routing inside the feature slices
Keep frontend routing in vertical slices, never in backend routes/.
- One composition root, e.g.
app/router.tsx, callscreateBrowserRouterand is rendered by<RouterProvider>at the app entry. - Each feature exports its own route objects (e.g.
features/invoice/invoice.routes.tsx) that the root composes. A feature owns its routes like it owns its components and hooks.
Step 3 — Define routes with lazy code-splitting
Apply ${CLAUDE_SKILL_DIR}/references/patterns.md sections "Router setup" and
"Lazy routes".
- Use route objects with
Component, nestedchildren,index, and layout routes that render<Outlet/>. - Split each feature's route with
lazyso its bundle loads on navigation.
Step 4 — Keep TanStack Query the source of truth for server data
Apply the reference section "TanStack Query integration".
- Components keep fetching through their
useQuery/useMutationhooks. Do not re-fetch the same server data inside aloaderand return it as a parallel source of truth. - If a route needs to prefetch, have its
loadercallqueryClient.ensureQueryData(...)for the feature's existing query key, then let the component read it via the sameuseQuery(warm cache). - Use
actiononly for non-Query mutations or progressive-enhancement forms; otherwise mutate via the existing TanStack Query mutation hook and invalidate keys.
Step 5 — Parse URL and search params at the boundary
Apply the reference section "Typed params". Parse untrusted params and
useSearchParams with zod. Reuse an existing feature contract when it fits.
Step 6 — Pending and error states
Surface pending state with useNavigation. Give routes an ErrorBoundary
(ErrorBoundary/errorElement) using useRouteError.
Step 7 — Verify
source "${CLAUDE_PROJECT_DIR}/.claude/lib/detect-toolchain.sh"
run_typecheck
Checklist
- Data Mode only:
createBrowserRouter+RouterProvider, imports fromreact-router(v7). - No Framework/SSR adoption; Express stays the backend.
- Routes live in feature slices on the frontend, composed by one root; not under backend
routes/. - Server state still owned by TanStack Query; loaders at most prefetch into the query client.
-
params/search params parsed with zod into typed values. - Routes are lazy-split and have pending + error states.
-
run_typecheckpasses.