<!-- BEGIN:nextjs-agent-rules -->
# This is NOT the Next.js you know

This version has breaking changes — APIs, conventions, and file structure may all differ from your training data. Read the relevant guide in `node_modules/next/dist/docs/` before writing any code. Heed deprecation notices.
<!-- END:nextjs-agent-rules -->

---

## Stack

| Layer | Technology | Version |
|-------|-----------|---------|
| Framework | Next.js | 16.2.3 |
| UI | React | 19.2.4 |
| Styles | Tailwind CSS | v4 |
| Components | shadcn/ui | latest via `shadcn` CLI |
| Data fetching | TanStack Query | v5 |
| Forms | react-hook-form + zod | v7 / v4 |
| Language | TypeScript | 5 |
| Direction | Hebrew RTL | `dir="rtl"` throughout |

---

## Commands

```bash
# Regenerate API types from the live FastAPI schema — RUN AFTER EVERY BACKEND CHANGE
npm run api:types

# Validate before every push
npm run lint
npm run build

# Local dev (rare — prod runs inside Docker; no local Python env exists)
npm run dev          # requires NEXT_PUBLIC_API_ORIGIN=http://127.0.0.1:8000 or similar
```

**`npm run api:types` is mandatory** any time a FastAPI endpoint is added, removed, or its request/response shape changes. It fetches `https://legal-ai.nautilus.marcusgroup.org/openapi.json` and writes `src/lib/api/types.ts`.

---

## Backend Proxy — `/api/*`

`next.config.ts` transparently rewrites all `/api/*` requests to the FastAPI backend:

- In Docker (production): `http://127.0.0.1:8000`
- Override via env var: `NEXT_PUBLIC_API_ORIGIN`

**Never hardcode the backend origin in component code.** Always use relative paths like `/api/cases`.

The typed fetch wrapper lives in `src/lib/api/client.ts` — use `apiRequest<T>(path, options)`. It throws `ApiError` on non-2xx responses with the parsed body and status code.

---

## API Types — Never Edit by Hand

`src/lib/api/types.ts` is **auto-generated** by `openapi-typescript` from the live FastAPI OpenAPI schema.

- **Do NOT edit `src/lib/api/types.ts` manually** — changes will be overwritten on the next `npm run api:types` run.
- The typed helper modules in `src/lib/api/` (e.g. `cases.ts`, `documents.ts`, `precedents.ts`) ARE hand-written and import from `types.ts`. These are safe to edit.
- When adding a new API domain, create a new typed module in `src/lib/api/<domain>.ts` following the existing pattern.

---

## Tailwind CSS v4 — Breaking Changes from v3

Tailwind v4 has a completely different configuration model.

**What does NOT exist in v4:**
- `tailwind.config.ts` / `tailwind.config.js` — there is no config file
- `@tailwind base;` / `@tailwind components;` / `@tailwind utilities;` directives
- `tailwind.config.theme.extend` object

**What v4 uses instead:**
```css
/* globals.css — already set up, do not change */
@import "tailwindcss";
@import "tw-animate-css";
@import "shadcn/tailwind.css";

@theme {
  /* Design tokens defined here as CSS custom properties */
  --color-navy: #0f172a;
  /* ... */
}
```

- Custom tokens go inside `@theme {}` in `globals.css`.
- Custom variants use `@custom-variant`.
- Class names are the same (e.g. `bg-navy`, `text-gold`), but the config source is CSS, not JS.
- PostCSS is configured via `@tailwindcss/postcss` (devDependency).

---

## shadcn/ui Components

Adding a new component:
```bash
npx shadcn add <component-name>
# e.g. npx shadcn add table
```

Installed components live in `src/components/ui/`. They are editable (shadcn copies the source, not a package import). The `radix-ui` package (v1.4) is the underlying primitive.

- Do NOT `npm install @radix-ui/react-*` directly — use `npx shadcn add` which installs the correct Radix version and generates the shadcn wrapper.
- Design tokens in `globals.css` (`--color-navy`, `--color-gold`, etc.) are already mapped to the shadcn semantic tokens (`background`, `foreground`, `primary`, etc.), so shadcn components inherit the editorial/judicial aesthetic automatically.

---

## TanStack Query v5

**v5 has breaking API changes from v4.** Key patterns used in this codebase:

```typescript
import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query";

// Reading data
const { data, isLoading, isError } = useQuery({
  queryKey: ["cases"],
  queryFn: () => apiRequest<CaseListResponse>("/api/cases"),
});

// Writing data
const queryClient = useQueryClient();
const mutation = useMutation({
  mutationFn: (body: CreateCaseRequest) =>
    apiRequest<Case>("/api/cases", { method: "POST", body }),
  onSuccess: () => {
    queryClient.invalidateQueries({ queryKey: ["cases"] });
  },
});
```

**v5 changes from v4:**
- `useQuery` no longer accepts positional arguments — always use the options object.
- `isLoading` is replaced by `isPending` for mutations (but `isLoading` still works for queries).
- `onSuccess`/`onError`/`onSettled` callbacks on `useQuery` are removed — use mutation callbacks or `useEffect` instead.
- `getQueryData` / `setQueryData` are unchanged.

The shared `QueryClient` is created in `src/lib/api/client.ts` via `makeQueryClient()` and provided by `src/lib/providers.tsx`.

---

## RTL — Hebrew UI Rules

**All UI is Hebrew, right-to-left.** The `<html>` element has `dir="rtl"` and `lang="he"`.

Use **logical CSS properties** instead of directional ones:

| Avoid (directional) | Use (logical) |
|---------------------|--------------|
| `ml-*` / `mr-*` | `ms-*` (start) / `me-*` (end) |
| `pl-*` / `pr-*` | `ps-*` (start) / `pe-*` (end) |
| `text-left` | `text-start` |
| `text-right` | `text-end` |
| `float-left` | `float-start` |
| `border-l-*` | `border-s-*` |

In RTL, "start" = right side, "end" = left side. Using logical properties means the layout works automatically without RTL overrides.

Flexbox direction: `flex-row` in RTL naturally flows right-to-left. Use `flex-row-reverse` only when you need LTR inside an RTL context.

---

## Project Structure

```
src/
├── app/                    # Next.js App Router pages
│   ├── layout.tsx          # Root layout — sets dir="rtl", applies fonts
│   ├── globals.css         # Tailwind v4 imports + design tokens + :root vars
│   ├── cases/              # Case management pages
│   ├── precedents/         # Precedent library pages
│   ├── methodology/        # Methodology browser
│   ├── training/           # Training document management
│   ├── settings/           # Application settings
│   └── skills/             # Skills management
├── components/
│   ├── ui/                 # shadcn primitives (editable copies)
│   ├── app-shell.tsx       # Top-level shell with nav
│   ├── cases/              # Case-domain components
│   ├── documents/          # Document viewer components
│   ├── precedents/         # Precedent components
│   └── compose/            # Decision drafting / block editor
├── lib/
│   ├── api/
│   │   ├── types.ts        # AUTO-GENERATED — never edit
│   │   ├── client.ts       # apiRequest<T> + QueryClient factory
│   │   ├── cases.ts        # Typed case API helpers
│   │   ├── documents.ts    # Typed document API helpers
│   │   └── ...             # One file per API domain
│   ├── providers.tsx       # TanStack Query + theme providers
│   ├── utils.ts            # cn() and other shared utilities
│   ├── doc-types.ts        # Document type constants
│   └── sse.ts              # Server-Sent Events helper for streaming
```

---

## Forms

Forms use **react-hook-form** (v7) with **zod** (v4) validation via `@hookform/resolvers`:

```typescript
import { useForm } from "react-hook-form";
import { zodResolver } from "@hookform/resolvers/zod";
import { z } from "zod";

const schema = z.object({ title: z.string().min(1) });
type FormValues = z.infer<typeof schema>;

const form = useForm<FormValues>({ resolver: zodResolver(schema) });
```

---

## Notifications / Toasts

Use **sonner** (`import { toast } from "sonner"`). The `<Toaster>` is mounted in `src/lib/providers.tsx`.

```typescript
toast.success("התיק נשמר בהצלחה");
toast.error("שגיאה בשמירה");
```

---

## Streaming (SSE)

Server-sent events are used for long-running AI operations (drafting, analysis). The helper is in `src/lib/sse.ts`. Use it instead of raw `EventSource`.

---

## Deploy

This frontend runs **inside Docker via Coolify** — not as a standalone Node process.

- **No `npm run dev` on the server** — there is no local Python environment for the backend.
- To see changes in production: `git commit` + `git push origin main` → Gitea Actions builds image → Coolify redeploys (~2-4 min).
- Prod URL: `https://legal-ai.nautilus.marcusgroup.org`
- The Next.js output is `standalone` (see `next.config.ts: output: "standalone"`).
