11 KiB
ADR-0005 Master Migration Status
Last Updated: 2026-01-08
This document tracks the complete migration status of all data fetching patterns in the application to TanStack Query (React Query) as specified in ADR-0005.
Migration Overview
| Category | Total | Migrated | Remaining | % Complete |
|---|---|---|---|---|
| User Features | 5 queries + 7 mutations | 12/12 | 0 | ✅ 100% |
| Admin Features | 3 queries | 0/3 | 3 | ❌ 0% |
| Analytics Features | 2 queries | 0/2 | 2 | ❌ 0% |
| Legacy Hooks | 3 hooks | 0/3 | 3 | ❌ 0% |
| TOTAL | 20 items | 12/20 | 8 | 🟡 60% |
✅ COMPLETED: User-Facing Features (Phase 1-3)
Query Hooks (5)
| Hook | File | Query Key | Status | Phase |
|---|---|---|---|---|
| useFlyersQuery | src/hooks/queries/useFlyersQuery.ts | ['flyers', { limit, offset }] |
✅ Done | 1 |
| useFlyerItemsQuery | src/hooks/queries/useFlyerItemsQuery.ts | ['flyer-items', flyerId] |
✅ Done | 2 |
| useMasterItemsQuery | src/hooks/queries/useMasterItemsQuery.ts | ['master-items'] |
✅ Done | 2 |
| useWatchedItemsQuery | src/hooks/queries/useWatchedItemsQuery.ts | ['watched-items'] |
✅ Done | 1 |
| useShoppingListsQuery | src/hooks/queries/useShoppingListsQuery.ts | ['shopping-lists'] |
✅ Done | 1 |
Mutation Hooks (7)
| Hook | File | Invalidates | Status | Phase |
|---|---|---|---|---|
| useAddWatchedItemMutation | src/hooks/mutations/useAddWatchedItemMutation.ts | ['watched-items'] |
✅ Done | 3 |
| useRemoveWatchedItemMutation | src/hooks/mutations/useRemoveWatchedItemMutation.ts | ['watched-items'] |
✅ Done | 3 |
| useCreateShoppingListMutation | src/hooks/mutations/useCreateShoppingListMutation.ts | ['shopping-lists'] |
✅ Done | 3 |
| useDeleteShoppingListMutation | src/hooks/mutations/useDeleteShoppingListMutation.ts | ['shopping-lists'] |
✅ Done | 3 |
| useAddShoppingListItemMutation | src/hooks/mutations/useAddShoppingListItemMutation.ts | ['shopping-lists'] |
✅ Done | 3 |
| useUpdateShoppingListItemMutation | src/hooks/mutations/useUpdateShoppingListItemMutation.ts | ['shopping-lists'] |
✅ Done | 3 |
| useRemoveShoppingListItemMutation | src/hooks/mutations/useRemoveShoppingListItemMutation.ts | ['shopping-lists'] |
✅ Done | 3 |
Providers Migrated (4)
| Provider | Uses | Status |
|---|---|---|
| AppProviders.tsx | QueryClientProvider wrapper | ✅ Done |
| FlyersProvider.tsx | useFlyersQuery | ✅ Done |
| MasterItemsProvider.tsx | useMasterItemsQuery | ✅ Done |
| UserDataProvider.tsx | useWatchedItemsQuery + useShoppingListsQuery | ✅ Done |
❌ NOT MIGRATED: Admin & Analytics Features
High Priority - Admin Features
| Feature | Component/Hook | Current Pattern | API Calls | Priority |
|---|---|---|---|---|
| Activity Log | ActivityLog.tsx | useState + useEffect | fetchActivityLog(20, 0) |
🔴 HIGH |
| Admin Stats | AdminStatsPage.tsx | useState + useEffect | getApplicationStats() |
🔴 HIGH |
| Corrections | CorrectionsPage.tsx | useState + useEffect + Promise.all | getSuggestedCorrections(), fetchMasterItems(), fetchCategories() |
🔴 HIGH |
Issues:
- Manual state management with useState/useEffect
- No caching - data refetches on every mount
- No automatic refetching or background updates
- Manual loading/error state handling
- Duplicate API calls (CorrectionsPage fetches master items separately)
Recommended Query Hooks to Create:
// src/hooks/queries/useActivityLogQuery.ts
queryKey: ['activity-log', { limit, offset }]
staleTime: 30 seconds (frequently updated)
// src/hooks/queries/useApplicationStatsQuery.ts
queryKey: ['application-stats']
staleTime: 2 minutes (changes moderately)
// src/hooks/queries/useSuggestedCorrectionsQuery.ts
queryKey: ['suggested-corrections']
staleTime: 1 minute
// src/hooks/queries/useCategoriesQuery.ts
queryKey: ['categories']
staleTime: 10 minutes (rarely changes)
Medium Priority - Analytics Features
| Feature | Component/Hook | Current Pattern | API Calls | Priority |
|---|---|---|---|---|
| My Deals | MyDealsPage.tsx | useState + useEffect | fetchBestSalePrices() |
🟡 MEDIUM |
| Active Deals | useActiveDeals.tsx | useApi hook | countFlyerItemsForFlyers(), fetchFlyerItemsForFlyers() |
🟡 MEDIUM |
Issues:
- useActiveDeals uses old
useApihook pattern - MyDealsPage has manual state management
- No caching for best sale prices
- No relationship to watched-items cache (could be optimized)
Recommended Query Hooks to Create:
// src/hooks/queries/useBestSalePricesQuery.ts
queryKey: ['best-sale-prices', watchedItemIds]
staleTime: 2 minutes
// Should invalidate when flyers or flyer-items update
// Refactor useActiveDeals to use TanStack Query
// Could share cache with flyer-items query
Low Priority - Voice Lab
| Feature | Component | Current Pattern | Priority |
|---|---|---|---|
| Voice Lab | VoiceLabPage.tsx | Direct async/await | 🟢 LOW |
Notes:
- Event-driven API calls (not data fetching)
- Speech generation and voice sessions
- Mutation-like operations, not query-like
- Could create mutations but not critical for caching
⚠️ LEGACY HOOKS STILL IN USE
Hooks to Deprecate/Remove
| Hook | File | Used By | Status |
|---|---|---|---|
| useApi | src/hooks/useApi.ts | useActiveDeals, useWatchedItems, useShoppingLists | ⚠️ Active |
| useApiOnMount | src/hooks/useApiOnMount.ts | None (deprecated) | ⚠️ Remove |
| useInfiniteQuery | src/hooks/useInfiniteQuery.ts | None (deprecated) | ⚠️ Remove |
Plan:
- Phase 4: Refactor useWatchedItems/useShoppingLists to use TanStack Query mutations
- Phase 5: Refactor useActiveDeals to use TanStack Query
- Phase 6: Remove useApi, useApiOnMount, custom useInfiniteQuery
📊 MIGRATION PHASES
✅ Phase 1: Core Queries (Complete)
- Infrastructure setup (QueryClientProvider)
- Flyers, Watched Items, Shopping Lists queries
- Providers refactored
✅ Phase 2: Additional Queries (Complete)
- Master Items query
- Flyer Items query
- Per-resource caching strategies
✅ Phase 3: Mutations (Complete)
- All watched items mutations
- All shopping list mutations
- Automatic cache invalidation
🔄 Phase 4: Hook Refactoring (Planned)
- Refactor useWatchedItems to use mutation hooks
- Refactor useShoppingLists to use mutation hooks
- Remove deprecated setters from context
⏳ Phase 5: Admin Features (Not Started)
- Create useActivityLogQuery
- Create useApplicationStatsQuery
- Create useSuggestedCorrectionsQuery
- Create useCategoriesQuery
- Migrate ActivityLog.tsx
- Migrate AdminStatsPage.tsx
- Migrate CorrectionsPage.tsx
⏳ Phase 6: Analytics Features (Not Started)
- Create useBestSalePricesQuery
- Migrate MyDealsPage.tsx
- Refactor useActiveDeals to use TanStack Query
⏳ Phase 7: Cleanup (Not Started)
- Remove useApi hook
- Remove useApiOnMount hook
- Remove custom useInfiniteQuery hook
- Remove all stub implementations
- Update all tests
🎯 RECOMMENDED NEXT STEPS
Option A: Complete User Features First (Phase 4)
Focus on finishing the user-facing feature migration by refactoring the remaining custom hooks. This provides a complete, polished user experience.
Pros:
- Completes the user-facing story
- Simplifies codebase for user features
- Sets pattern for admin features
Cons:
- Admin features still use old patterns
Option B: Migrate Admin Features (Phase 5)
Create query hooks for admin features to improve admin user experience and establish complete ADR-0005 coverage.
Pros:
- Faster admin pages with caching
- Consistent patterns across entire app
- Better for admin users
Cons:
- User-facing hooks still partially old pattern
Option C: Parallel Migration (Phase 4 + 5)
Work on both user hook refactoring and admin feature migration simultaneously.
Pros:
- Fastest path to complete migration
- Comprehensive coverage quickly
Cons:
- Larger scope, more testing needed
📝 NOTES
Query Key Organization
Currently using literal strings for query keys. Consider creating a centralized query keys file:
// src/config/queryKeys.ts
export const queryKeys = {
flyers: (limit: number, offset: number) => ['flyers', { limit, offset }] as const,
flyerItems: (flyerId: number) => ['flyer-items', flyerId] as const,
masterItems: () => ['master-items'] as const,
watchedItems: () => ['watched-items'] as const,
shoppingLists: () => ['shopping-lists'] as const,
// Add admin keys
activityLog: (limit: number, offset: number) => ['activity-log', { limit, offset }] as const,
applicationStats: () => ['application-stats'] as const,
suggestedCorrections: () => ['suggested-corrections'] as const,
categories: () => ['categories'] as const,
bestSalePrices: (itemIds: number[]) => ['best-sale-prices', itemIds] as const,
};
Cache Invalidation Strategy
Admin features may need different invalidation strategies:
- Activity log should refetch after mutations
- Stats should refetch after significant operations
- Corrections should refetch after approving/rejecting
Stale Time Recommendations
| Data Type | Stale Time | Reasoning |
|---|---|---|
| Master Items | 10 minutes | Rarely changes |
| Categories | 10 minutes | Rarely changes |
| Flyers | 2 minutes | Moderate changes |
| Flyer Items | 5 minutes | Static once created |
| User Lists | 1 minute | Frequent changes |
| Admin Stats | 2 minutes | Moderate changes |
| Activity Log | 30 seconds | Frequently updated |
| Corrections | 1 minute | Moderate changes |
| Best Prices | 2 minutes | Recalculated periodically |