# Frontend Documentation

> React Router v7 web application

## Overview

The Izri frontend is built with React Router v7 (formerly Remix), React 19, and Vite. It uses TanStack Query and tRPC for data, Tailwind v4 for styling, and shadcn/ui for components.

## Technology Stack

- Framework: React Router v7 + React 19
- Build Tool: Vite 5
- Styling: Tailwind CSS v4
- UI Components: shadcn/ui (Radix primitives)
- Data: tRPC + TanStack Query
- Type Safety: TypeScript 5

## Documentation Pages

- Setup & Configuration: ./setup.md
- Components & Forms: ./components-and-forms.md
- Testing: ./testing-frontend.md

## Application Structure

```
apps/web/
├── app/
│   ├── root.tsx                      # Root layout, providers
│   ├── routes.ts                     # Route configuration (authoritative)
│   ├── routes/
│   │   ├── home.tsx                  # Landing page (/)
│   │   ├── _auth.tsx                 # Auth layout
│   │   ├── _organizations.tsx        # Organizations layout (auth-protected)
│   │   ├── auth/
│   │   │   ├── login.tsx             # /auth/login
│   │   │   ├── register.tsx          # /auth/register
│   │   │   └── logout.tsx            # /auth/logout (outside auth layout)
│   │   └── organizations/
│   │       ├── index.tsx             # /organizations
│   │       ├── new.tsx               # /organizations/new
│   │       ├── $slug.tsx             # Layout for slugged routes
│   │       └── $slug/
│   │           ├── index.tsx         # /organizations/:slug
│   │           ├── dashboard.tsx     # /organizations/:slug/dashboard
│   │           ├── stats.tsx         # /organizations/:slug/stats
│   │           ├── projects/
│   │           │   ├── index.tsx     # /organizations/:slug/projects
│   │           │   ├── new.tsx       # /organizations/:slug/projects/new
│   │           │   └── $id.tsx       # /organizations/:slug/projects/:id
│   │           ├── settings.tsx      # /organizations/:slug/settings
│   │           ├── members.tsx       # /organizations/:slug/members
│   │           └── invite.tsx        # /organizations/:slug/invite
│   ├── providers/
│   │   └── trpc-provider.tsx         # tRPC client + QueryClient
│   ├── lib/
│   │   ├── trpc.ts                   # createTRPCContext React helpers
│   │   ├── trpc-server.ts            # SSR caller for loaders
│   │   ├── auth-client.ts            # Better Auth client
│   │   ├── auth-server.ts            # Better Auth session on server
│   │   ├── auth-loader.ts            # requireAuth, redirectIfAuthenticated
│   │   ├── organization-loader.ts    # requireOrganization, admin checks
│   │   └── contexts/
│   │       └── organization-context.tsx
│   └── components/
│       ├── common/
│       │   └── data-boundary.tsx
│       ├── errors/
│       │   └── layout-error-boundary.tsx
│       └── layout/
│           └── sidebar.tsx
```

## Root Providers

Mount providers in app/root.tsx:

```tsx
// app/root.tsx (excerpt)
import { TRPCProvider } from '@/providers/trpc-provider'
import { OrganizationProvider } from '@/lib/contexts/organization-context'

export default function Root() {
  return (
    <TRPCProvider>
      <OrganizationProvider>
        <Outlet />
      </OrganizationProvider>
    </TRPCProvider>
  )
}
```

## Data Fetching (tRPC + TanStack Query)

Use the typed helpers from createTRPCContext.

```tsx
import { useTRPC } from '@/lib/trpc'
import { useQuery } from '@tanstack/react-query'

export function OrgsList({ userEmail }: { userEmail: string }) {
  const trpc = useTRPC()
  const { data, isPending } = useQuery({
    ...trpc.organizations.list.queryOptions({ userEmail }),
    enabled: !!userEmail,
  })
  if (isPending) return <div>Loading...</div>
  return (
    <ul>{data?.organizations.map((o) => (<li key={o.id}>{o.name}</li>))}</ul>
  )
}
```

## Authentication Flow (server-first)

- Server validates session in loaders via Better Auth (auth.api.getSession)
- requireAuth() in layout loaders protects routes
- redirectIfAuthenticated() guards auth pages
- Organization access: requireOrganization(), requireOrganizationAdmin()

## tRPC Client

See ./setup.md for tRPC client setup, queries, mutations, and caching patterns.

## Troubleshooting

- 401/redirect loops: ensure cookies are sent (credentials: 'include') and APP_URL/domain match
- Type errors: verify @izri/trpc/routers import and provider mounting
