---
name: routing
description: "Use when adding or changing a page, route file, navigation entry, search params, or route-level access control. Covers createFileRoute, beforeLoad requireAuth, loader preloads, validateSearch, useSearch, src/routes/ naming and colocation, __root.tsx navigation, the auth and login routes, and the RouterLink/RouterButton link components."
metadata:
  type: convention
  library: wcz-layout
---

> Mechanics (route definitions, loaders, context, guards, navigation, search params,
> route-tree fundamentals) are covered by TanStack's own skills. List the skills shipped by
> `@tanstack/router-core` and `@tanstack/react-router` and load whichever cover the task at
> hand. This skill adds the wcz-layout conventions.

## Rules

- Include `requireAuth(<permissionKey>)` in the route's `beforeLoad` to enforce access
  control — pass a key defined in your app's `src/lib/auth/permissions.ts`. Use bare
  `requireAuth()` when any signed-in user may enter, and omit it entirely only for
  intentionally public routes.
- Route-level `requireAuth` only hides the UI. Every server function or server route that
  accesses protected data still needs `authMiddleware`; see the `server-functions` skill.
- Use `Route.useRouteContext()` to access the authenticated user. `user` can be `null` if
  the route doesn't include `requireAuth`.
- Preload the route's live queries in the loader and return the promise:
  `loader: ({ context }) => context.dbClient.preloadLiveQuery(<x>QueryOptions)`.
- Literal URL segments and feature folders use kebab-case. Entity feature names are plural;
  TanStack special route tokens retain their required syntax.
- If a feature contains only one route, create a single file route: `src/routes/<feature>s.tsx`
- If a feature contains multiple related routes, create a folder: `src/routes/<feature>s/index.tsx`
- Colocate route-specific components/hooks inside `routes/<feature>s/-components` or `-hooks`.
- When a route needs its own components/hooks that no sibling route uses, wrap it in a route
  group folder named after the route and colocate them there: `routes/<feature>s/(index)/index.tsx` with `(index)/-components` and `(index)/-hooks`.
- Root-level `components/` and `hooks/` are only for code shared across multiple routes.
- After creating a new route, add a navigation item with a unique icon from
  `@mui/icons-material` in `src/routes/__root.tsx`.
- For user-clickable in-app navigation, use the type-safe router components from
  `wcz-layout/components` (`RouterButton`, `RouterIconButton`, `RouterLink`, `RouterFab`,
  `RouterTab`, `RouterListItemButton`) rather than raw MUI with a manual `href` — they wrap
  `createLink`, so `to`/`params`/`search` are type-checked.

## Examples

```ts
// imports
import AccountTree from "@mui/icons-material/AccountTree";
import Code from "@mui/icons-material/Code";
import Home from "@mui/icons-material/Home";
import Widgets from "@mui/icons-material/Widgets";
import { createFileRoute } from "@tanstack/react-router";
import { z } from "zod";
import type { Navigation } from "wcz-layout";
import { useDialogs, useTranslation } from "wcz-layout/hooks";
import { hasPermission, requireAuth } from "wcz-layout/utils";

// src/routes/<feature>s/index.tsx
export const Route = createFileRoute("/<feature>s/")({
  component: RouteComponent,
  beforeLoad: requireAuth("admin"),
  loader: ({ context }) => context.dbClient.preloadLiveQuery(featuresQueryOptions),
});

function RouteComponent() {
  const { t } = useTranslation();
  const { alert, confirm } = useDialogs();
  const { user } = Route.useRouteContext();
  // route component code...
}

// __root.tsx navigation
const navigation: Navigation = [
  { kind: "item", to: "/", title: t("Home"), icon: <Home />, hidden: !hasPermission(user, "admin") },
  { kind: "header", title: t("Documentation") },
  {
    kind: "group",
    title: t("Components"),
    icon: <Widgets />,
    children: [
      { kind: "item", to: "/components/navigation", title: t("Navigation"), icon: <AccountTree /> },
      { kind: "divider" },
      { kind: "item", to: "/components/forms", title: t("Forms"), icon: <Code /> },
    ],
  },
];
```
