# Frontend Architecture

Next.js React application providing UI for Open Notebook research assistant. Three-layer architecture: **pages** (Next.js App Router), **components** (feature-specific UI), and **lib** (data fetching, state management, utilities).

## High-Level Data Flow

```
Pages (Next.js) → Components (feature-specific) → Hooks (queries/mutations)
                                                       ↓
                          Stores (auth/modal state) → API module → Backend
```

User interactions trigger mutations/queries via hooks, which communicate with the backend through the API module. Store state (auth, modals) flows back to components via hooks. Child CLAUDE.md files document specific modules in detail:

- **`lib/api/CLAUDE.md`**: Axios client, FormData handling, interceptors
- **`lib/hooks/CLAUDE.md`**: TanStack Query wrappers, SSE streaming, context building
- **`lib/stores/CLAUDE.md`**: Zustand auth/modal state, localStorage persistence
- **`lib/locales/CLAUDE.md`**: Internationalization (i18n) system, translation files
- **`components/ui/CLAUDE.md`**: Radix UI primitives, CVA styling, accessibility

## Architectural Layers

### Pages (`src/app/`) — Next.js App Router
- `(auth)/login`: Authentication entry point
- `(dashboard)/`: Protected routes (notebooks, sources, search, models, etc.)
- Directory-based routing; each `page.tsx` is a route endpoint
- **Key pattern**: Pages call hooks to fetch data, render components with state
- **Router groups** `(auth)`, `(dashboard)` organize routes by feature without affecting URL

### Components (`src/components/`) — Feature-Specific UI
- **layout**: `AppShell.tsx`, `AppSidebar.tsx` — main layout wrapper used by all pages
- **providers**: `ThemeProvider`, `QueryProvider`, `ModalProvider` — app-wide context setup
- **auth**: `LoginForm.tsx` — authentication UI
- **common**: `CommandPalette`, `ErrorBoundary`, `ContextToggle`, `ModelSelector` — shared across pages
- **ui**: Reusable Radix UI building blocks (see child CLAUDE.md)
- **source**, **notebooks**, **search**, **podcasts**: Feature-specific components consuming hooks

**Component composition pattern**: Pages → Feature components → UI components. Feature components handle page-level state (loading, error), UI components remain stateless and styled.

### Lib (`src/lib/`) — Data & State Layer

#### `lib/api/` — Backend Communication
- **`client.ts`**: Central Axios instance with auth interceptor, FormData handling, 10-min timeout
- **`query-client.ts`**: TanStack Query configuration
- **Resource modules** (`sources.ts`, `chat.ts`, `notebooks.ts`, etc.): Endpoint-specific functions returning typed responses
- **Pattern**: All requests go through `apiClient`; auth token auto-added from localStorage

#### `lib/hooks/` — React Query + Custom Logic
- **Query hooks**: `useNotebookSources`, `useSources`, `useSource` — TanStack Query wrappers with cache keys
- **Mutation hooks**: `useCreateSource`, `useUpdateSource`, `useDeleteSource` — mutations with toast feedback + cache invalidation
- **Complex hooks**: `useNotebookChat`, `useSourceChat` — session management, message streaming, context building
- **SSE streaming**: `useAsk` — parses newline-delimited JSON from backend for multi-stage workflows
- **Pattern**: Hooks return `{ data, isLoading, error, refetch }` + action functions; cache invalidation on mutations

#### `lib/stores/` — Application State
- **`auth-store.ts`**: Authentication state (token, isAuthenticated) with 30-second check caching
- **Zustand + persist middleware**: Auto-syncs sensitive state to localStorage
- **Pattern**: Store actions (`login()`, `logout()`, `checkAuth()`) update state; consumed via hooks in components

#### `lib/types/` — TypeScript Definitions
- API request/response shapes, domain models (Notebook, Source, Note, etc.)
- Ensures type safety across API calls and store mutations

#### `lib/locales/` — Internationalization (i18n)
- **Locale files** (`en-US/`, `pt-BR/`, `zh-CN/`, `zh-TW/`, `ja-JP/`): Translation strings organized by feature
- **`i18n.ts`**: i18next configuration with language detection
- **`use-translation.ts`**: Custom hook with Proxy-based `t.section.key` access pattern
- **Pattern**: Components call `useTranslation()` hook; access strings via `t.common.save`, `t.notebooks.title`

## Data & Control Flow Walkthrough

### Example: Notebook Chat
1. **Page** (`notebooks/[id]/page.tsx`) fetches initial data, passes `notebookId` to `ChatColumn` component
2. **Hook call** (`useNotebookChat()`):
   - Queries sessions for notebook via TanStack Query
   - Sets up message state + context building logic
   - Returns `{ messages, sendMessage(), setModelOverride() }`
3. **Component renders**: `ChatColumn` displays messages, text input
4. **User sends message**: Component calls `sendMessage()` hook
5. **Hook execution**:
   - Builds context from selected sources/notes via `buildContext()` helper
   - Calls `chatApi.sendMessage()` (from API module)
   - Client-side optimistic update: adds message to local state before response
6. **Backend response** arrives, TanStack Query updates cache
7. **Cache invalidation** on other source/note mutations ensures stale UI refreshes

### Example: File Upload with Source Creation
1. **Component** (`SourceDialog`) renders form with file picker
2. **Hook** (`useFileUpload`):
   - Converts file to FormData (JSON fields stringified)
   - Calls `sourcesApi.create()` with FormData
   - API client interceptor deletes Content-Type header (lets browser set multipart boundary)
3. **Toast notifications** show progress
4. **Cache invalidation** on success: `queryClient.invalidateQueries(['sources'])`
5. **Related queries** auto-refetch: notebooks, sources list, etc.

## Key Patterns & Cross-Layer Coordination

### Caching & Invalidation
- **Query keys**: `QUERY_KEYS.notebook(id)`, `QUERY_KEYS.sources(notebookId)` — hierarchical structure
- **Broad invalidation**: `['sources']` invalidates all source queries; trade-off between accuracy + performance
- **Auto-refetch**: `refetchOnWindowFocus: true` on frequently-changing data (sources, notebooks)

### Auth & Protected Routes
- **Proxy** (`src/proxy.ts`): Redirects root `/` to `/notebooks`
- **Auth store**: Validates token via `/notebooks` API call (actual validation, not JWT decode)
- **Interceptor**: Adds `Bearer {token}` to all requests; 401 response clears auth and redirects to login

### Modal State Management
- **Modal hooks**: Components query modal state from stores
- **Context**: Modals pass data (e.g., notebook ID) to child components
- **Pattern**: One store per modal type; triggered by button clicks + data passing via hook arguments

### Error Handling
- **API errors**: All request failures propagate to consuming code; components show toast notifications
- **Error message resolution** (`lib/utils/error-handler.ts`): `getApiErrorMessage()` tries i18n mapping first via `ERROR_MAP`, then falls back to displaying the backend's descriptive error message directly. This ensures user-friendly error messages from the error classification system are shown as-is.
- **Toast feedback**: Mutations show success/error toasts (from `sonner` library)
- **Error boundary**: App-level error boundary catches React render errors; shows fallback UI

### FormData Handling
- **JSON fields**: Nested objects (arrays, objects) must be JSON stringified before FormData
- **Content-Type header**: Removed by interceptor for FormData requests (lets browser set boundary)
- **Example**: `sources` array converted to string via `JSON.stringify()` before appending to FormData

## Component Organization Within Features

- **Feature folders** (`source/`, `notebooks/`, `podcasts/`): Group related components
- **Composition**: Larger components nest smaller ones; no deep prop drilling (state lifted to hooks)
- **Dialog patterns**: Features define dialog components for inline actions (edit, create, delete)
- **Props**: Components accept data + action callbacks from parent or hooks

## Providers & Context Setup

**Root layout** (`app/layout.tsx`) wraps app with (outermost → innermost):
1. `ErrorBoundary` — React error boundary (catches all render errors)
2. `ThemeProvider` — next-themes for light/dark mode
3. `QueryProvider` — TanStack Query client
4. `I18nProvider` — i18next initialization and language loading overlay
5. `ConnectionGuard` — checks backend connectivity on startup
6. `Toaster` — sonner toast notification system (inside ConnectionGuard)

## Important Gotchas & Design Decisions

- **Token storage**: Stored in localStorage under `auth-storage` key (Zustand persist); consumed by API interceptor
- **Base URL discovery**: API client fetches base URL from runtime config on first request (async; can be slow on startup)
- **Optimistic updates**: Chat messages added to state before server confirmation; removed on error
- **Modal lifecycle**: Dialogs not auto-reset; parent must clear form state after submit
- **Focus management**: Dialog auto-focuses first input; can cause layout shifts if inputs are conditional
- **Cache invalidation breadth**: Trade-off between precision + simplicity; broad invalidation simpler but may over-fetch

## How to Add a New Feature

1. **Create page**: `app/(dashboard)/feature/page.tsx` — calls hooks, renders components
2. **Create feature components**: `components/feature/` — compose UI + business logic
3. **Add hooks** (if data needed): `lib/hooks/useFeature.ts` — TanStack Query wrapper
4. **Add API module** (if backend call needed): `lib/api/feature.ts` — resource-specific functions
5. **Add types**: `lib/types/api.ts` — request/response shapes
6. **Use UI components**: Import from `components/ui/` for consistent styling
7. **Handle auth**: Middleware redirects unauthenticated users; no special handling needed in component

## Testing

- **Hooks**: Mock API functions, wrap in `QueryClientProvider`, assert query/mutation behavior
- **Components**: Mock hooks via `vi.fn()`, test rendering + user interactions
- **API calls**: Mock `axios` interceptors; test request/response shapes
- **Stores**: Mock store state, test mutations via `act()`, assert state changes

See child CLAUDE.md files for module-specific testing patterns.
