Spaces:
Paused
Paused
| # 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`**: Thin wrapper around react-i18next's `useTranslation` with language change events | |
| - **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. | |