# Component Dependencies — CMS Frontend ## Dependency Overview ```mermaid graph TD subgraph Backend["Backend (Unit 0)"] CorsPolicy["CorsPolicy\n(ServiceCollectionExtensions)"] AuthCtrl["AuthController\n(updated)"] AuthSvc["AuthService\n(no changes)"] AuthCtrl --> AuthSvc end subgraph Infrastructure["Frontend Infrastructure Layer"] ApiClient["ApiClient\n(fetch wrapper)"] AuthContext["AuthContext\n(session state)"] Router["RouterConfig\n(TanStack Router)"] AuthContext --> ApiClient end subgraph Guards["Auth Guards"] ProtectedRoute["ProtectedRoute"] RoleGuard["RoleGuard"] InitGuard["InitGuard"] ProtectedRoute --> AuthContext RoleGuard --> AuthContext InitGuard --> ApiClient end subgraph Layout["Layout Components"] AppLayout["AppLayout"] Sidebar["Sidebar"] ThemeProvider["ThemeProvider"] AppLayout --> Sidebar Sidebar --> AuthContext end subgraph QueryHooks["TanStack Query Hooks"] useAvailability["useAvailabilityStatus"] useUsers["useUsers + useInviteUser"] useInvitation["useValidateInvitation\nuseCompleteSetup"] useSetup["useSetupStatus\nuseCreateOwner"] useAvailability --> ApiClient useUsers --> ApiClient useInvitation --> ApiClient useSetup --> ApiClient end subgraph Pages["Page Components"] LoginPage["LoginPage"] SetupPage["SetupPage"] InviteCompletePage["InviteCompletePage"] DashboardPage["DashboardPage"] UsersPage["UsersPage"] ProfilePage["ProfilePage"] SettingsPage["SettingsPage"] CmsPage["CmsPage"] LoginPage --> AuthContext SetupPage --> useSetup InviteCompletePage --> useInvitation DashboardPage --> useAvailability UsersPage --> useUsers ProfilePage --> AuthContext SettingsPage --> useAvailability end Router --> Guards Router --> AppLayout AppLayout --> Pages style CorsPolicy fill:#4CAF50,stroke:#2E7D32,color:#fff style AuthCtrl fill:#4CAF50,stroke:#2E7D32,color:#fff style AuthSvc fill:#FFC107,stroke:#F57F17,color:#000 style ApiClient fill:#FFC107,stroke:#F57F17,color:#000 style AuthContext fill:#FFC107,stroke:#F57F17,color:#000 style Router fill:#FFC107,stroke:#F57F17,color:#000 style ProtectedRoute fill:#FF5722,stroke:#BF360C,color:#fff style RoleGuard fill:#FF5722,stroke:#BF360C,color:#fff style InitGuard fill:#FF5722,stroke:#BF360C,color:#fff style AppLayout fill:#9C27B0,stroke:#4A148C,color:#fff style Sidebar fill:#9C27B0,stroke:#4A148C,color:#fff style ThemeProvider fill:#9C27B0,stroke:#4A148C,color:#fff style useAvailability fill:#009688,stroke:#004D40,color:#fff style useUsers fill:#009688,stroke:#004D40,color:#fff style useInvitation fill:#009688,stroke:#004D40,color:#fff style useSetup fill:#009688,stroke:#004D40,color:#fff style LoginPage fill:#2196F3,stroke:#0D47A1,color:#fff style SetupPage fill:#2196F3,stroke:#0D47A1,color:#fff style InviteCompletePage fill:#2196F3,stroke:#0D47A1,color:#fff style DashboardPage fill:#2196F3,stroke:#0D47A1,color:#fff style UsersPage fill:#2196F3,stroke:#0D47A1,color:#fff style ProfilePage fill:#2196F3,stroke:#0D47A1,color:#fff style SettingsPage fill:#2196F3,stroke:#0D47A1,color:#fff style CmsPage fill:#2196F3,stroke:#0D47A1,color:#fff ``` --- ## Dependency Matrix | Component | Depends On | Used By | |-----------|-----------|---------| | **ApiClient** | `import.meta.env.VITE_API_BASE_URL`, `AuthContext.accessToken` | All TanStack Query hooks, `InitGuard` | | **AuthContext** | `ApiClient` (for login/logout/refresh calls) | `ProtectedRoute`, `RoleGuard`, `Sidebar`, `ProfilePage`, `LoginPage` | | **RouterConfig** | `ProtectedRoute`, `RoleGuard`, `InitGuard`, `AppLayout` | App root | | **ProtectedRoute** | `AuthContext` | Router (wraps authenticated routes) | | **RoleGuard** | `AuthContext` | Router (wraps role-restricted routes) | | **InitGuard** | `useSetupStatus` → `ApiClient` | Router (root-level check) | | **AppLayout** | `Sidebar`, `ThemeProvider` | Authenticated routes | | **Sidebar** | `AuthContext` | `AppLayout` | | **useAvailabilityStatus** | `ApiClient` | `DashboardPage`, `SettingsPage` | | **useUsers / useInviteUser** | `ApiClient` | `UsersPage` | | **useValidateInvitation / useCompleteSetup** | `ApiClient` | `InviteCompletePage` | | **useSetupStatus / useCreateOwner** | `ApiClient` | `InitGuard`, `SetupPage` | | **DashboardPage** | `useAvailabilityStatus`, `AuthContext` | Router | | **UsersPage** | `useUsers`, `useInviteUser`, `InviteUserDialog` | Router | | **ProfilePage** | `AuthContext` (user data from context — no API call) | Router | | **SettingsPage** | `useAvailabilityStatus` | Router | | **InviteCompletePage** | `useValidateInvitation`, `useCompleteSetup` | Router | | **LoginPage** | `AuthContext.login()` | Router | | **SetupPage** | `useCreateOwner` | Router | --- ## Communication Patterns | Pattern | Where Used | |---------|-----------| | **React Context** | Auth state shared from `AuthContext` to guards, sidebar, profile, login page | | **TanStack Query** | Server state (availability, users, invitation, setup) — cached, auto-refetch | | **Cookie (httpOnly)** | Browser ↔ Backend: refresh token — set by backend, never read by JS | | **In-memory state** | Access token held in `AuthContext` — cleared on page refresh (intentional) | | **LocalStorage** | Theme preference only (`cms-theme`) — no auth data | --- ## Key Dependency Rules (Security Baseline) - `ApiClient` is the **only** module that makes HTTP calls — no direct `fetch` in pages/components - `accessToken` is accessed **only** through `AuthContext` — never passed as prop or stored elsewhere - `refreshToken` is **never accessible to JavaScript** — httpOnly cookie only - Role checks happen in `RoleGuard` (routing) and `Sidebar` (UX) — backend is authoritative