# ADR-005: Frontend State Management and Server Cache Strategy **Date**: 2025-12-12 **Implementation Date**: 2026-01-08 **Status**: Accepted and Fully Implemented (Phases 1-8 complete, 100% coverage) ## Context The frontend currently uses React's built-in hooks (`useState`, `useEffect`, `useContext`) for state management, as seen in `useAuth.tsx`. While effective for simple cases, this manual approach becomes complex and error-prone when fetching, caching, and synchronizing data with the server. It often leads to custom logic for loading states, errors, re-fetching, and optimistic updates. ## Decision We will adopt a dedicated library for managing server state, such as **TanStack Query (formerly React Query)** or **SWR**, for all server-side data fetching on the client. This will abstract away the complexities of caching, background re-validation, and request deduplication. ## Consequences **Positive**: Leads to a more performant, predictable, and simpler frontend codebase. Standardizes how the client-side communicates with the server and handles loading/error states. Improves user experience through intelligent caching. **Negative**: Introduces a new frontend dependency. Requires a learning curve for developers unfamiliar with the library. Requires refactoring of existing data-fetching logic. ## Implementation Status ### Phase 1: Infrastructure & Core Queries (✅ Complete - 2026-01-08) **Files Created:** - [src/config/queryClient.ts](../../src/config/queryClient.ts) - Global QueryClient configuration - [src/hooks/queries/useFlyersQuery.ts](../../src/hooks/queries/useFlyersQuery.ts) - Flyers data query - [src/hooks/queries/useWatchedItemsQuery.ts](../../src/hooks/queries/useWatchedItemsQuery.ts) - Watched items query - [src/hooks/queries/useShoppingListsQuery.ts](../../src/hooks/queries/useShoppingListsQuery.ts) - Shopping lists query **Files Modified:** - [src/providers/AppProviders.tsx](../../src/providers/AppProviders.tsx) - Added QueryClientProvider wrapper - [src/providers/FlyersProvider.tsx](../../src/providers/FlyersProvider.tsx) - Refactored to use TanStack Query - [src/providers/UserDataProvider.tsx](../../src/providers/UserDataProvider.tsx) - Refactored to use TanStack Query - [src/services/apiClient.ts](../../src/services/apiClient.ts) - Added pagination params to fetchFlyers **Benefits Achieved:** - ✅ Removed ~150 lines of custom state management code - ✅ Automatic caching of server data - ✅ Background refetching for stale data - ✅ React Query Devtools available in development - ✅ Automatic data invalidation on user logout - ✅ Better error handling and loading states ### Phase 2: Remaining Queries (✅ Complete - 2026-01-08) **Files Created:** - [src/hooks/queries/useMasterItemsQuery.ts](../../src/hooks/queries/useMasterItemsQuery.ts) - Master grocery items query - [src/hooks/queries/useFlyerItemsQuery.ts](../../src/hooks/queries/useFlyerItemsQuery.ts) - Flyer items query **Files Modified:** - [src/providers/MasterItemsProvider.tsx](../../src/providers/MasterItemsProvider.tsx) - Refactored to use TanStack Query - [src/hooks/useFlyerItems.ts](../../src/hooks/useFlyerItems.ts) - Refactored to use TanStack Query **Benefits Achieved:** - ✅ Removed additional ~50 lines of custom state management code - ✅ Per-flyer item caching (items cached separately for each flyer) - ✅ Longer cache times for infrequently changing data (master items) - ✅ Automatic query disabling when dependencies are not met ### Phase 3: Mutations (✅ Complete - 2026-01-08) **Files Created:** - [src/hooks/mutations/useAddWatchedItemMutation.ts](../../src/hooks/mutations/useAddWatchedItemMutation.ts) - Add watched item mutation - [src/hooks/mutations/useRemoveWatchedItemMutation.ts](../../src/hooks/mutations/useRemoveWatchedItemMutation.ts) - Remove watched item mutation - [src/hooks/mutations/useCreateShoppingListMutation.ts](../../src/hooks/mutations/useCreateShoppingListMutation.ts) - Create shopping list mutation - [src/hooks/mutations/useDeleteShoppingListMutation.ts](../../src/hooks/mutations/useDeleteShoppingListMutation.ts) - Delete shopping list mutation - [src/hooks/mutations/useAddShoppingListItemMutation.ts](../../src/hooks/mutations/useAddShoppingListItemMutation.ts) - Add shopping list item mutation - [src/hooks/mutations/useUpdateShoppingListItemMutation.ts](../../src/hooks/mutations/useUpdateShoppingListItemMutation.ts) - Update shopping list item mutation - [src/hooks/mutations/useRemoveShoppingListItemMutation.ts](../../src/hooks/mutations/useRemoveShoppingListItemMutation.ts) - Remove shopping list item mutation - [src/hooks/mutations/index.ts](../../src/hooks/mutations/index.ts) - Barrel export for all mutation hooks **Benefits Achieved:** - ✅ Standardized mutation pattern across all data modifications - ✅ Automatic cache invalidation after successful mutations - ✅ Built-in success/error notifications - ✅ Consistent error handling - ✅ Full TypeScript type safety - ✅ Comprehensive documentation with usage examples **See**: [plans/adr-0005-phase-3-summary.md](../../plans/adr-0005-phase-3-summary.md) for detailed documentation ### Phase 4: Hook Refactoring (✅ Complete) **Goal:** Refactor user-facing hooks to use TanStack Query mutation hooks. **Files Modified:** - [src/hooks/useWatchedItems.tsx](../../src/hooks/useWatchedItems.tsx) - Refactored to use mutation hooks - [src/hooks/useShoppingLists.tsx](../../src/hooks/useShoppingLists.tsx) - Refactored to use mutation hooks - [src/contexts/UserDataContext.ts](../../src/contexts/UserDataContext.ts) - Clean read-only interface (no setters) - [src/providers/UserDataProvider.tsx](../../src/providers/UserDataProvider.tsx) - Uses query hooks, no setter stubs **Benefits Achieved:** - ✅ Both hooks now use TanStack Query mutations - ✅ Automatic cache invalidation after mutations - ✅ Consistent error handling via mutation hooks - ✅ Clean context interface (read-only server state) - ✅ Backward compatible API for hook consumers ### Phase 5: Admin Features (✅ Complete) **Goal:** Create query hooks for admin features. **Files Created:** - [src/hooks/queries/useActivityLogQuery.ts](../../src/hooks/queries/useActivityLogQuery.ts) - Activity log with pagination - [src/hooks/queries/useApplicationStatsQuery.ts](../../src/hooks/queries/useApplicationStatsQuery.ts) - Application statistics - [src/hooks/queries/useSuggestedCorrectionsQuery.ts](../../src/hooks/queries/useSuggestedCorrectionsQuery.ts) - Corrections data - [src/hooks/queries/useCategoriesQuery.ts](../../src/hooks/queries/useCategoriesQuery.ts) - Categories (public endpoint) **Components Migrated:** - [src/pages/admin/ActivityLog.tsx](../../src/pages/admin/ActivityLog.tsx) - Uses useActivityLogQuery - [src/pages/admin/AdminStatsPage.tsx](../../src/pages/admin/AdminStatsPage.tsx) - Uses useApplicationStatsQuery - [src/pages/admin/CorrectionsPage.tsx](../../src/pages/admin/CorrectionsPage.tsx) - Uses useSuggestedCorrectionsQuery, useMasterItemsQuery, useCategoriesQuery **Benefits Achieved:** - ✅ Automatic caching of admin data - ✅ Parallel fetching (CorrectionsPage fetches 3 queries simultaneously) - ✅ Consistent stale times (30s to 2 min based on data volatility) - ✅ Shared cache across components (useMasterItemsQuery reused) ### Phase 6: Analytics Features (✅ Complete - 2026-01-10) **Goal:** Migrate analytics and deals features. **Files Created:** - [src/hooks/queries/useBestSalePricesQuery.ts](../../src/hooks/queries/useBestSalePricesQuery.ts) - Best sale prices for watched items - [src/hooks/queries/useFlyerItemsForFlyersQuery.ts](../../src/hooks/queries/useFlyerItemsForFlyersQuery.ts) - Batch fetch items for multiple flyers - [src/hooks/queries/useFlyerItemCountQuery.ts](../../src/hooks/queries/useFlyerItemCountQuery.ts) - Count items across flyers **Files Modified:** - [src/pages/MyDealsPage.tsx](../../src/pages/MyDealsPage.tsx) - Now uses useBestSalePricesQuery - [src/hooks/useActiveDeals.tsx](../../src/hooks/useActiveDeals.tsx) - Refactored to use TanStack Query hooks **Benefits Achieved:** - ✅ Removed useApi dependency from analytics features - ✅ Automatic caching of deal data (2-5 minute stale times) - ✅ Consistent error handling via TanStack Query - ✅ Batch fetching for flyer items (single query for multiple flyers) ### Phase 7: Cleanup (✅ Complete - 2026-01-10) **Goal:** Remove legacy hooks once migration is complete. **Files Created:** - [src/hooks/queries/useUserAddressQuery.ts](../../src/hooks/queries/useUserAddressQuery.ts) - User address fetching - [src/hooks/queries/useAuthProfileQuery.ts](../../src/hooks/queries/useAuthProfileQuery.ts) - Auth profile fetching - [src/hooks/mutations/useGeocodeMutation.ts](../../src/hooks/mutations/useGeocodeMutation.ts) - Address geocoding **Files Modified:** - [src/hooks/useProfileAddress.ts](../../src/hooks/useProfileAddress.ts) - Refactored to use TanStack Query - [src/providers/AuthProvider.tsx](../../src/providers/AuthProvider.tsx) - Refactored to use TanStack Query **Files Removed:** - ~~src/hooks/useApi.ts~~ - Legacy hook removed - ~~src/hooks/useApi.test.ts~~ - Test file removed - ~~src/hooks/useApiOnMount.ts~~ - Legacy hook removed - ~~src/hooks/useApiOnMount.test.ts~~ - Test file removed **Benefits Achieved:** - ✅ Removed all legacy `useApi` and `useApiOnMount` hooks - ✅ Complete TanStack Query coverage for all data fetching - ✅ Consistent error handling across the entire application - ✅ Unified caching strategy for all server state ### Phase 8: Additional Component Migration (✅ Complete - 2026-01-10) **Goal:** Migrate remaining components with manual data fetching to TanStack Query. **Files Created:** - [src/hooks/queries/useUserProfileDataQuery.ts](../../src/hooks/queries/useUserProfileDataQuery.ts) - Combined user profile + achievements query - [src/hooks/queries/useLeaderboardQuery.ts](../../src/hooks/queries/useLeaderboardQuery.ts) - Public leaderboard data - [src/hooks/queries/usePriceHistoryQuery.ts](../../src/hooks/queries/usePriceHistoryQuery.ts) - Historical price data for watched items **Files Modified:** - [src/hooks/useUserProfileData.ts](../../src/hooks/useUserProfileData.ts) - Refactored to use useUserProfileDataQuery - [src/components/Leaderboard.tsx](../../src/components/Leaderboard.tsx) - Refactored to use useLeaderboardQuery - [src/features/charts/PriceHistoryChart.tsx](../../src/features/charts/PriceHistoryChart.tsx) - Refactored to use usePriceHistoryQuery **Benefits Achieved:** - ✅ Parallel fetching for profile + achievements data - ✅ Public leaderboard cached with 2-minute stale time - ✅ Price history cached with 10-minute stale time (data changes infrequently) - ✅ Backward-compatible setProfile function via queryClient.setQueryData - ✅ Stable query keys with sorted IDs for price history ## Migration Status Current Coverage: **100% complete** | Category | Total | Migrated | Status | | ----------------------------- | ----- | -------- | ------- | | Query Hooks (User) | 7 | 7 | ✅ 100% | | Query Hooks (Admin) | 4 | 4 | ✅ 100% | | Query Hooks (Analytics) | 3 | 3 | ✅ 100% | | Query Hooks (Phase 8) | 3 | 3 | ✅ 100% | | Mutation Hooks | 8 | 8 | ✅ 100% | | User Hooks | 2 | 2 | ✅ 100% | | Analytics Features | 2 | 2 | ✅ 100% | | Component Migration (Phase 8) | 3 | 3 | ✅ 100% | | Legacy Hook Cleanup | 4 | 4 | ✅ 100% | **Completed:** - ✅ Core query hooks (flyers, flyerItems, masterItems, watchedItems, shoppingLists) - ✅ Admin query hooks (activityLog, applicationStats, suggestedCorrections, categories) - ✅ Analytics query hooks (bestSalePrices, flyerItemsForFlyers, flyerItemCount) - ✅ Auth/Profile query hooks (authProfile, userAddress) - ✅ Phase 8 query hooks (userProfileData, leaderboard, priceHistory) - ✅ All mutation hooks (watched items, shopping lists, geocode) - ✅ Provider refactoring (AppProviders, FlyersProvider, MasterItemsProvider, UserDataProvider, AuthProvider) - ✅ User hooks refactoring (useWatchedItems, useShoppingLists, useProfileAddress, useUserProfileData) - ✅ Admin component migration (ActivityLog, AdminStatsPage, CorrectionsPage) - ✅ Analytics features (MyDealsPage, useActiveDeals) - ✅ Component migration (Leaderboard, PriceHistoryChart) - ✅ Legacy hooks removed (useApi, useApiOnMount) See [plans/adr-0005-master-migration-status.md](../../plans/adr-0005-master-migration-status.md) for complete tracking of all components. ## Implementation Guide See [plans/adr-0005-implementation-plan.md](../../plans/adr-0005-implementation-plan.md) for detailed implementation steps.