# Project Setup — Routing, Auth, Sidebar

Read once during Phase 2b (Code Orientation). Not needed per-page.

## File-Based Routing (Vite Plugin)

app-shell uses file-based routing via `@tailor-platform/app-shell-vite-plugin`. No `defineModule`/`defineResource` needed.

### Vite Config

```ts
// vite.config.ts
import { appShellRoutes } from "@tailor-platform/app-shell-vite-plugin";

export default defineConfig({
  plugins: [
    react(),
    appShellRoutes({
      entrypoint: "src/App.tsx", // recommended — avoids TDZ errors in page imports
      generateTypedRoutes: true, // generates src/routes.generated.ts
    }),
  ],
});
```

### Path Conventions

| Directory Name | Converts To | Description                    |
| -------------- | ----------- | ------------------------------ |
| `orders`       | `orders`    | Static segment                 |
| `[id]`         | `:id`       | Dynamic parameter              |
| `[...slug]`    | `*slug`     | Catch-all                      |
| `(group)`      | (excluded)  | Grouping only (not in path)    |
| `_lib`         | (ignored)   | Not routed (shared logic)      |

### Page Component

```tsx
import type { AppShellPageProps } from "@tailor-platform/app-shell";

const OrdersPage = () => <div>Orders</div>;

OrdersPage.appShellPageProps = {
  meta: { title: "Orders", icon: <PackageIcon /> },
  guards: [authGuard],
} satisfies AppShellPageProps;

export default OrdersPage;
```

- Every `page.tsx` must be a **default export** with `appShellPageProps`
- Guards are **not inherited** — each page must declare its own
- Directories without `page.tsx` return 404 (children remain accessible)

### Typed Routes (Highly Recommended)

When `generateTypedRoutes: true`, use the generated `paths` helper:

```tsx
import { paths } from "@/routes.generated";

navigate(paths.for("/orders/:id", { id: orderId }));
// TypeScript catches missing params and invalid paths
```

## Authentication

### App.tsx Pattern

```tsx
import { createAuthClient, AuthProvider, AppShell, SidebarLayout, DefaultSidebar } from "@tailor-platform/app-shell";
import { createClient, Provider } from "urql";

const authClient = createAuthClient({
  clientId: import.meta.env.VITE_TAILOR_CLIENT_ID,
  appUri: import.meta.env.VITE_TAILOR_APP_URL,
});

const urqlClient = createClient({
  url: `${authClient.getAppUri()}/query`,
  fetch: authClient.fetch, // DPoP proof + token refresh handled automatically
});

const App = () => (
  <AuthProvider client={authClient} autoLogin guardComponent={() => <LoadingScreen />}>
    <Provider value={urqlClient}>
      <AppShell title="My App">
        <SidebarLayout sidebar={<DefaultSidebar />} />
      </AppShell>
    </Provider>
  </AuthProvider>
);
```

- `authClient.fetch` — pass directly to urql; handles DPoP and token refresh
- `autoLogin` — redirects unauthenticated users to the login screen automatically (default: `false`). For typical business applications, enable this so users are sent to Tailor's built-in login screen directly. Set `autoLogin={false}` when the app needs a branded landing or login page — in that case, call `login()` from `useAuth()` explicitly when the user clicks a sign-in button.
- `guardComponent` — rendered while loading or when not authenticated
- OAuth callback params (`code`, `state`) are automatically cleaned from the URL after login — no dedicated callback page needed
- Required env vars: `VITE_TAILOR_APP_URL`, `VITE_TAILOR_CLIENT_ID`

### AuthProvider Props

| Prop | Type | Required | Description |
| --- | --- | --- | --- |
| `client` | `EnhancedAuthClient` | Yes | Auth client created with `createAuthClient` |
| `autoLogin` | `boolean` | No | Automatically redirect unauthenticated users to login |
| `guardComponent` | `() => React.ReactNode` | No | Rendered while loading or when not authenticated |

### useAuth Hook

Access authentication state and methods in any component:

```tsx
import { useAuth, Button } from "@tailor-platform/app-shell";

const UserProfile = () => {
  const { isReady, isAuthenticated, login, logout } = useAuth();

  if (!isReady) return <div>Loading...</div>;
  if (!isAuthenticated) return <button onClick={login}>Sign In</button>;
  return <Button onClick={logout}>Sign Out</Button>;
};
```

Returns: `isAuthenticated`, `isReady`, `error`, `login()`, `logout()`, `checkAuthStatus()`

### useAuthSuspense Hook

Use `useAuthSuspense` when React Suspense handles the loading state — `isReady` is guaranteed `true`:

```tsx
import { Suspense } from "react";
import { useAuthSuspense, Button } from "@tailor-platform/app-shell";

function ProtectedContent() {
  const { isAuthenticated, login, logout } = useAuthSuspense();
  if (!isAuthenticated) return <button onClick={login}>Log In</button>;
  return <Button onClick={logout}>Log Out</Button>;
}
```

## Sidebar Navigation

Two modes — use **composition mode** for explicit control:

```tsx
<DefaultSidebar>
  <SidebarItem to="/dashboard" />
  <SidebarSeparator />
  <SidebarGroup title="Purchasing" icon={<Package />}>
    <SidebarItem to="/purchasing/orders" />
    <SidebarItem to="/purchasing/invoices" />
  </SidebarGroup>
</DefaultSidebar>
```

- `SidebarItem` auto-resolves `title` and `icon` from page's `appShellPageProps.meta`
- Use `WithGuard` for access-controlled visibility (does not prevent navigation)
- `DefaultSidebar` accepts `header` and `footer` props for branding
