# 10. Frontend Architecture ## State Management Strategy ``` ┌─────────────────────────────────────────────────────────────────┐ │ STATE MANAGEMENT │ ├─────────────────────────────────────────────────────────────────┤ │ │ │ ┌─────────────────────────────────────────────────────────┐ │ │ │ TanStack Query │ │ │ │ (Server State / Cache) │ │ │ │ │ │ │ │ • Characters list │ │ │ │ • Accounts data │ │ │ │ • Teams & members │ │ │ │ • Progressions │ │ │ │ • DofusDB reference data │ │ │ └─────────────────────────────────────────────────────────┘ │ │ │ │ ┌─────────────────────────────────────────────────────────┐ │ │ │ Zustand │ │ │ │ (Client/UI State) │ │ │ │ │ │ │ │ • Selected items (multi-select) │ │ │ │ • UI preferences (sidebar collapsed, etc.) │ │ │ │ • Filter states │ │ │ │ • Modal open/close states │ │ │ │ • Theme preference │ │ │ └─────────────────────────────────────────────────────────┘ │ │ │ │ ┌─────────────────────────────────────────────────────────┐ │ │ │ React State │ │ │ │ (Component-local State) │ │ │ │ │ │ │ │ • Form inputs │ │ │ │ • Hover/focus states │ │ │ │ • Animation states │ │ │ │ • Temporary UI states │ │ │ └─────────────────────────────────────────────────────────┘ │ │ │ └─────────────────────────────────────────────────────────────────┘ ``` ## TanStack Query Setup ```typescript // src/lib/client/query-client.ts import { QueryClient } from '@tanstack/react-query'; export const queryClient = new QueryClient({ defaultOptions: { queries: { staleTime: 1000 * 60 * 5, // 5 minutes gcTime: 1000 * 60 * 30, // 30 minutes retry: 1, refetchOnWindowFocus: false, }, mutations: { onError: (error) => { console.error('Mutation error:', error); }, }, }, }); // Query keys factory export const queryKeys = { characters: { all: ['characters'] as const, list: (filters: CharacterFilters) => [...queryKeys.characters.all, 'list', filters] as const, detail: (id: string) => [...queryKeys.characters.all, 'detail', id] as const, }, accounts: { all: ['accounts'] as const, list: () => [...queryKeys.accounts.all, 'list'] as const, detail: (id: string) => [...queryKeys.accounts.all, 'detail', id] as const, }, teams: { all: ['teams'] as const, list: () => [...queryKeys.teams.all, 'list'] as const, detail: (id: string) => [...queryKeys.teams.all, 'detail', id] as const, }, progressions: { all: ['progressions'] as const, list: (type?: ProgressionType) => [...queryKeys.progressions.all, 'list', type] as const, byCharacter: (characterId: string) => [...queryKeys.progressions.all, 'character', characterId] as const, }, } as const; ``` ## Zustand Store ```typescript // src/lib/client/stores/ui-store.ts import { create } from 'zustand'; import { persist } from 'zustand/middleware'; interface UIState { // Sidebar sidebarCollapsed: boolean; toggleSidebar: () => void; // Theme theme: 'light' | 'dark'; setTheme: (theme: 'light' | 'dark') => void; // Selection (for bulk actions) selectedCharacterIds: string[]; selectCharacter: (id: string) => void; deselectCharacter: (id: string) => void; selectAllCharacters: (ids: string[]) => void; clearSelection: () => void; } export const useUIStore = create()( persist( (set) => ({ // Sidebar sidebarCollapsed: false, toggleSidebar: () => set((state) => ({ sidebarCollapsed: !state.sidebarCollapsed })), // Theme theme: 'dark', setTheme: (theme) => set({ theme }), // Selection selectedCharacterIds: [], selectCharacter: (id) => set((state) => ({ selectedCharacterIds: [...state.selectedCharacterIds, id] })), deselectCharacter: (id) => set((state) => ({ selectedCharacterIds: state.selectedCharacterIds.filter((i) => i !== id) })), selectAllCharacters: (ids) => set({ selectedCharacterIds: ids }), clearSelection: () => set({ selectedCharacterIds: [] }), }), { name: 'dofus-manager-ui', partialize: (state) => ({ sidebarCollapsed: state.sidebarCollapsed, theme: state.theme, }), } ) ); ``` ## Routing Structure ```typescript // src/routes/__root.tsx import { createRootRoute, Outlet } from '@tanstack/react-router'; import { AppShell } from '@/components/layout/app-shell'; export const Route = createRootRoute({ component: () => ( ), }); // Route tree /* src/routes/ ├── __root.tsx # Root layout with AppShell ├── index.tsx # / → Dashboard ├── characters/ │ ├── index.tsx # /characters → List │ └── $id.tsx # /characters/:id → Detail ├── accounts/ │ ├── index.tsx # /accounts → List │ └── $id.tsx # /accounts/:id → Detail ├── teams/ │ ├── index.tsx # /teams → List │ └── $id.tsx # /teams/:id → Detail ├── progressions/ │ └── index.tsx # /progressions → Tracker └── settings/ └── index.tsx # /settings → Settings */ ``` ---