# Frontend Architecture Documentation **Project**: Next.js + FastAPI Template **Version**: 1.0 **Last Updated**: 2025-10-31 **Status**: Living Document --- ## Table of Contents 1. [System Overview](#1-system-overview) 2. [Technology Stack](#2-technology-stack) 3. [Architecture Patterns](#3-architecture-patterns) 4. [Data Flow](#4-data-flow) 5. [State Management Strategy](#5-state-management-strategy) 6. [Authentication Architecture](#6-authentication-architecture) 7. [API Integration](#7-api-integration) 8. [Routing Strategy](#8-routing-strategy) 9. [Component Organization](#9-component-organization) 10. [Testing Strategy](#10-testing-strategy) 11. [Performance Considerations](#11-performance-considerations) 12. [Security Architecture](#12-security-architecture) 13. [Design Decisions & Rationale](#13-design-decisions--rationale) 14. [Deployment Architecture](#14-deployment-architecture) --- ## 1. System Overview ### 1.1 Purpose This frontend template provides a production-ready foundation for building modern web applications with Next.js 15 and FastAPI backend integration. It implements comprehensive authentication, admin dashboards, user management, and organization management out of the box. ### 1.2 High-Level Architecture ``` ┌─────────────────────────────────────────────────────────────┐ │ Next.js Frontend │ ├─────────────────────────────────────────────────────────────┤ │ App Router (RSC) │ Client Components │ API Routes │ ├────────────────────┼────────────────────┼──────────────────┤ │ Pages & Layouts │ Interactive UI │ Middleware │ │ (Server-side) │ (Client-side) │ (Auth Guards) │ └─────────────────────────────────────────────────────────────┘ ↓ ↑ ┌──────────────────────┐ │ State Management │ ├──────────────────────┤ │ TanStack Query │ ← Server State │ (React Query v5) │ ├──────────────────────┤ │ Zustand Stores │ ← Client State │ (Auth, UI) │ └──────────────────────┘ ↓ ↑ ┌──────────────────────┐ │ API Client Layer │ ├──────────────────────┤ │ Axios Instance │ │ + Interceptors │ ├──────────────────────┤ │ Generated Client │ │ (OpenAPI → TS) │ └──────────────────────┘ ↓ ↑ ┌──────────────────────┐ │ FastAPI Backend │ │ /api/v1/* │ └──────────────────────┘ ``` ### 1.3 Key Features - **Authentication**: JWT-based with token rotation, per-device session tracking - **Admin Dashboard**: User management, organization management, analytics - **State Management**: TanStack Query for server state, Zustand for auth/UI - **Type Safety**: Full TypeScript with generated types from OpenAPI spec - **Component Library**: shadcn/ui with Radix UI primitives - **Testing**: 90%+ coverage target with Jest, React Testing Library, Playwright - **Accessibility**: WCAG 2.1 Level AA compliance - **Dark Mode**: Full theme support with Tailwind CSS --- ## 2. Technology Stack ### 2.1 Core Framework **Next.js 15.x (App Router)** - **Why**: Modern React framework with RSC, excellent DX, optimized performance - **App Router**: Preferred over Pages Router for better data fetching, layouts, and streaming - **Server Components**: Default for better performance, client components for interactivity - **TypeScript**: Strict mode enabled for maximum type safety ### 2.2 State Management **TanStack Query (React Query v5)** - **Purpose**: Server state management (all API data) - **Why**: Automatic caching, background refetching, request deduplication, optimistic updates - **Usage**: All data fetching goes through React Query hooks **Zustand 4.x** - **Purpose**: Client-only state (authentication, UI preferences) - **Why**: Minimal boilerplate, no Context API overhead, simple API - **Usage**: Auth store, UI store (sidebar, theme, modals) - **Philosophy**: Use sparingly, prefer server state via React Query ### 2.3 UI Layer **shadcn/ui** - **Why**: Accessible components (Radix UI), customizable, copy-paste (not npm dependency) - **Components**: Button, Card, Dialog, Form, Input, Table, Toast, etc. - **Customization**: Tailwind-based, easy to adapt to design system **Tailwind CSS 4.x** - **Why**: Utility-first, excellent DX, small bundle size, dark mode support - **Strategy**: Class-based dark mode, mobile-first responsive design - **Customization**: Custom theme colors, design tokens **Recharts 2.x** - **Purpose**: Charts for admin dashboard - **Why**: React-native, composable, responsive, themed with Tailwind colors ### 2.4 API Layer **@hey-api/openapi-ts** - **Purpose**: Generate TypeScript client from backend OpenAPI spec - **Why**: Type-safe API calls, auto-generated types matching backend - **Alternative**: Considered `openapi-typescript-codegen` but this is more actively maintained **Axios 1.x** - **Purpose**: HTTP client for API calls - **Why**: Interceptor support for auth, better error handling than fetch - **Usage**: Wrapped in generated API client, configured with auth interceptors ### 2.5 Forms & Validation **react-hook-form 7.x** - **Purpose**: Form state management - **Why**: Excellent performance, minimal re-renders, great DX **Zod 3.x** - **Purpose**: Runtime type validation and schema definition - **Why**: Type inference, composable schemas, integrates with react-hook-form - **Usage**: All forms use Zod schemas with `zodResolver` ### 2.6 Testing **Jest + React Testing Library** - **Purpose**: Unit and component tests - **Why**: Industry standard, excellent React support, accessibility-focused **Playwright** - **Purpose**: End-to-end testing - **Why**: Fast, reliable, multi-browser, great debugging tools - **Coverage Target**: 90%+ for template robustness ### 2.7 Additional Libraries - **date-fns**: Date manipulation and formatting (lighter than moment.js) - **clsx** + **tailwind-merge**: Conditional class names with conflict resolution - **lucide-react**: Icon system (tree-shakeable, consistent design) --- ## 3. Architecture Patterns ### 3.1 Layered Architecture Inspired by backend's 5-layer architecture, frontend follows similar separation of concerns: ``` ┌────────────────────────────────────────────────────────────┐ │ Layer 1: Pages & Layouts (app/*) │ │ - Route definitions, page components, layouts │ │ - Mostly Server Components, minimal logic │ │ - Delegates to hooks and components │ └────────────────────────────────────────────────────────────┘ ↓ ┌────────────────────────────────────────────────────────────┐ │ Layer 2: React Hooks (hooks/, lib/api/hooks/) │ │ - Custom hooks for component logic │ │ - React Query hooks for data fetching │ │ - Reusable logic extraction │ └────────────────────────────────────────────────────────────┘ ↓ ┌────────────────────────────────────────────────────────────┐ │ Layer 3: Services (services/) │ │ - Business logic (if complex) │ │ - Multi-step operations │ │ - Data transformations │ └────────────────────────────────────────────────────────────┘ ↓ ┌────────────────────────────────────────────────────────────┐ │ Layer 4: API Client (lib/api/*) │ │ - Axios instance with interceptors │ │ - Generated API client from OpenAPI │ │ - Error handling │ └────────────────────────────────────────────────────────────┘ ↓ ┌────────────────────────────────────────────────────────────┐ │ Layer 5: Types & Models (types/, lib/api/generated/) │ │ - TypeScript interfaces │ │ - Generated types from OpenAPI │ │ - Validation schemas (Zod) │ └────────────────────────────────────────────────────────────┘ ``` **Key Rules:** - Pages/Layouts should NOT contain business logic - Components should NOT call API client directly (use hooks) - Hooks should NOT contain display logic - API client should NOT contain business logic - Types should NOT import from upper layers ### 3.2 Component Patterns **Server Components by Default:** ```typescript // app/(authenticated)/admin/users/page.tsx // Server Component - can fetch data directly export default async function UsersPage() { // Could fetch data here, but we delegate to client components with React Query return (
{/* Client Component with data fetching */}
); } ``` **Client Components for Interactivity:** ```typescript // components/admin/UserTable.tsx 'use client'; import { useUsers } from '@/lib/api/hooks/useUsers'; export function UserTable() { const { data, isLoading, error } = useUsers(); // ... render logic } ``` **Composition Over Prop Drilling:** ```typescript // Good: Use composition Users // Avoid: Deep prop drilling } /> ``` ### 3.3 Single Responsibility Principle Each module has one clear responsibility: - **Pages**: Routing and layout structure - **Components**: UI rendering and user interaction - **Hooks**: Data fetching and reusable logic - **Services**: Complex business logic (multi-step operations) - **API Client**: HTTP communication - **Stores**: Global client state - **Types**: Type definitions --- ## 4. Data Flow ### 4.1 Request Flow (API Call) ``` ┌──────────────┐ │ User Action │ (e.g., Click "Save User") └──────┬───────┘ ↓ ┌──────────────────┐ │ Component │ Calls hook: updateUser.mutate(data) └──────┬───────────┘ ↓ ┌──────────────────┐ │ React Query Hook │ useMutation with API client call │ (useUpdateUser) │ └──────┬───────────┘ ↓ ┌──────────────────┐ │ API Client │ Axios PUT request with interceptors │ (Axios) │ └──────┬───────────┘ ↓ ┌──────────────────┐ │ Request │ Add Authorization header │ Interceptor │ token = authStore.accessToken └──────┬───────────┘ ↓ ┌──────────────────┐ │ FastAPI Backend │ PUT /api/v1/users/{id} └──────┬───────────┘ ↓ ┌──────────────────┐ │ Response │ Check status code │ Interceptor │ - 401: Refresh token → retry │ │ - 200: Parse success │ │ - 4xx/5xx: Parse error └──────┬───────────┘ ↓ ┌──────────────────┐ │ React Query │ Cache invalidation │ │ queryClient.invalidateQueries(['users']) └──────┬───────────┘ ↓ ┌──────────────────┐ │ Component │ Re-renders with updated data │ (via useUsers) │ Shows success toast └──────────────────┘ ``` ### 4.2 Authentication Flow ``` ┌──────────────┐ │ Login Form │ User enters email + password └──────┬───────┘ ↓ ┌──────────────────────┐ │ authStore.login() │ Zustand action └──────┬───────────────┘ ↓ ┌──────────────────────┐ │ API: POST /auth/login│ Backend validates credentials └──────┬───────────────┘ ↓ ┌──────────────────────┐ │ Backend Response │ { access_token, refresh_token, user } └──────┬───────────────┘ ↓ ┌──────────────────────┐ │ authStore.setTokens()│ Store tokens (sessionStorage + localStorage/cookie) │ authStore.setUser() │ Store user object └──────┬───────────────┘ ↓ ┌──────────────────────┐ │ Axios Interceptor │ Now adds Authorization header to all requests └──────┬───────────────┘ ↓ ┌──────────────────────┐ │ Redirect to Home │ User is authenticated └──────────────────────┘ ``` **Token Refresh Flow (Automatic):** ``` API Request → 401 Response → Check if refresh token exists ↓ Yes ↓ No POST /auth/refresh Redirect to Login ↓ New Tokens → Update Store → Retry Original Request ``` ### 4.3 State Updates **Server State (React Query):** - Automatic background refetch - Cache invalidation on mutations - Optimistic updates where appropriate **Client State (Zustand):** - Direct store updates - No actions/reducers boilerplate - Subscriptions for components --- ## 5. State Management Strategy ### 5.1 Philosophy **Use the Right Tool for the Right Job:** - Server data → TanStack Query - Auth & tokens → Zustand - UI state → Zustand (minimal) - Form state → react-hook-form - Component state → useState/useReducer **Avoid Redundancy:** - DON'T duplicate server data in Zustand - DON'T store API responses in global state - DO keep state as local as possible ### 5.2 TanStack Query Configuration **Global Config** (`src/config/queryClient.ts`): ```typescript export const queryClient = new QueryClient({ defaultOptions: { queries: { staleTime: 60000, // 1 minute cacheTime: 300000, // 5 minutes retry: 3, // Retry failed requests refetchOnWindowFocus: true, // Refetch on tab focus refetchOnReconnect: true, // Refetch on network reconnect }, mutations: { retry: 1, // Retry mutations once }, }, }); ``` **Query Key Structure:** ```typescript ['users'] // List all users ['users', userId] // Single user ['users', { page: 1, search: 'john' }] // Filtered list ['organizations', orgId, 'members'] // Nested resource ``` ### 5.3 Zustand Stores **Auth Store** (`src/stores/authStore.ts`): ```typescript interface AuthStore { user: User | null; accessToken: string | null; refreshToken: string | null; isAuthenticated: boolean; isLoading: boolean; login: (credentials) => Promise; logout: () => Promise; logoutAll: () => Promise; setTokens: (access, refresh) => void; clearAuth: () => void; } ``` **UI Store** (`src/stores/uiStore.ts`): ```typescript interface UIStore { sidebarOpen: boolean; theme: 'light' | 'dark' | 'system'; setSidebarOpen: (open: boolean) => void; toggleSidebar: () => void; setTheme: (theme) => void; } ``` **Store Guidelines:** - Keep stores small and focused - Use selectors for computed values - Persist to localStorage where appropriate - Document why Zustand over alternatives --- ## 6. Authentication Architecture ### 6.1 Token Management Strategy **Two-Token System:** - **Access Token**: Short-lived (15 min), stored in memory/sessionStorage - **Refresh Token**: Long-lived (7 days), stored in httpOnly cookie (preferred) or localStorage **Token Storage Decision:** - **Primary**: httpOnly cookies (most secure, prevents XSS) - **Fallback**: localStorage with encryption wrapper (if cookies not feasible) - **Access Token**: sessionStorage or React state (short-lived, acceptable risk) **Token Rotation:** - On refresh, both tokens are rotated - Old refresh token is invalidated immediately - Prevents token replay attacks ### 6.2 Per-Device Session Tracking Backend tracks sessions per device: - Each login creates a unique session with device info - Users can view all active sessions - Users can revoke individual sessions - Logout only affects current device - "Logout All" deactivates all sessions Frontend Implementation: - Session list page at `/settings/sessions` - Display device name, IP, location, last used - Highlight current session - Revoke button for non-current sessions ### 6.3 Auth Guard Implementation **Layout-Based Protection:** ```typescript // app/(authenticated)/layout.tsx export default function AuthenticatedLayout({ children }) { return (
{children}