# Frontend Architecture ## Framework Next.js 15 App Router with TypeScript and CSS Modules. All pages under `src/app/(dashboard)/` are protected by `AuthGuard` and wrapped in the dashboard layout (sidebar + header). ## Route Map | Route | Page | |---|---| | `/` | Redirects to `/overview` | | `/overview` | Dashboard overview | | `/videos` | Video list — paginated, sortable, filterable, with tabs | | `/videos/[id]` | Video editor — metadata + description config | | `/blocks` | Description block management | | `/templates` | Template management | | `/variables` | Team global variables | | `/collaborators` | Collaborator management | | `/settings` | Team members + connected channels | | `/saved-views` | Saved filter preset management | | `/linting` | Lint results browser — filter by severity/rule | | `/bulk-jobs` | Bulk operation history + rollback | | `/calendar` | Scheduled video calendar (month/week/agenda) | | `/audit` | Change history / audit log | | `/quota-history` | YouTube API quota usage history | | `/io` | CSV / JSON import and export | | `/login` | Google OAuth login | | `/auth/callback` | OAuth callback handler | ## Key Files | File | Role | |---|---| | `src/lib/api.ts` | All API call functions + TypeScript interfaces for every API response | | `src/lib/api-client.ts` | Axios instance — sets `baseURL`, attaches JWT, handles 401 refresh | | `src/store/useAuthStore.ts` | Zustand — `user`, `teamId`, `token`, `clearAuth` | | `src/store/useUIStore.ts` | Zustand (persisted) — `sidebarCollapsed`, `toggleSidebar` | | `src/middleware.ts` | Route protection — redirects unauthenticated users to `/login` | | `src/styles/globals.css` | Design tokens (CSS variables), global utility classes | | `src/hooks/useTheme.ts` | Dark/light theme toggle with localStorage persistence | ## State Management | Concern | Tool | |---|---| | Server data (videos, blocks, etc.) | TanStack Query v5 `useQuery` / `useMutation` | | Auth state | Zustand `useAuthStore` | | UI state (sidebar) | Zustand `useUIStore` (localStorage-persisted) | | Page-level UI state | `useState` / `useReducer` | ## TanStack Query Patterns - `useQueryClient()` must be called at component level, never inside callbacks - After mutations, invalidate related queries in `onSuccess`: - After saving a video: invalidate `['video', id]` and `['videos']` - After changing blocks: invalidate `['blocks']` and affected video queries - Use `placeholderData: (prev) => prev` to keep stale data visible during page transitions - Query keys are arrays: `['videos']`, `['video', id]`, `['preferences']` ## API Layer All API calls are in `src/lib/api.ts`. The file exports: - TypeScript interfaces for all API response shapes - Named functions for each endpoint (`fetchVideos`, `updateVideo`, `lintVideo`, etc.) The Axios client (`api-client.ts`) handles: - Base URL from `NEXT_PUBLIC_API_URL` - JWT `Authorization: Bearer` header injection - 401 → automatic token refresh → retry ## Component Structure ``` src/components/ video-table/ VideoTable.tsx TanStack Table — video list with sorting, pagination VideoTable.module.css video-config/ VideoConfigEditor.tsx forwardRef component — exposes save() and isDirty() VideoConfigEditor.module.css shared/ Sidebar.tsx Collapsible navigation sidebar Header.tsx Top bar — search, sync status, bulk change, theme, user Modal.tsx Generic modal wrapper FormField.module.css Shared form field utility classes Providers.tsx TanStack Query provider wrapper AuthGuard.tsx Redirects unauthenticated users SortableSection.tsx DnD-kit sortable wrapper for video editor sections ``` ## Video Editor Layout The video editor (`/videos/[id]`) uses a combined horizontal header card (thumbnail + meta + actions) above a two-column sortable editing area. Sections (Basic Info, Language, Audience, Playlists, Description) can be dragged between the two columns. Column layout is persisted to `User.preferences` via `PATCH /users/me/preferences`. ## Related - [[01 - System Overview]] - [[01 - Visual Design]] (design guidelines) - [[02 - CSS Conventions]] (design guidelines)