Skip to main content

Query Cache Migration Plan

Goal

Standardize TanStack Query usage across the app so that:
  • every query key comes from one shared factory
  • every user-scoped query includes userId at index [1]
  • every read uses a useQuery hook under hooks/queries/
  • every write uses a useMutation hook under hooks/mutations/
  • invalidation is intentional, minimal, and type-safe
  • cache behavior is documented in AGENTS.md and becomes the default pattern for future work

Problem Summary

The current codebase has several related issues:
  • query keys are scattered as inline arrays across hooks, components, and pages
  • many user-specific queries are not user-scoped, which creates cross-user cache leakage risk
  • queryClient.clear() is being used as a broad safety net in lib/react-query.tsx
  • writes are implemented inconsistently, with many raw fetch calls inside components/pages
  • invalidation blocks often overlap and refetch the same query multiple times
  • there is no single registry for root cache key names, which increases the chance of typos and drift

Target Architecture

1. Uppercase cache key registry

Create lib/cache-keys.ts as the single source of truth for root key names. This should be an uppercase registry such as CACHE_KEYS, used in an enum-like way. We should keep it as a constant object rather than a TypeScript enum so it stays aligned with the project rule to prefer unions/constants over enums. Example:

2. Shared query key factory

Create lib/query-keys.ts with:
  • globalKeys for non-user data
  • userKeys(userId) for user-scoped data
Every user-scoped query key must place userId at index [1].

3. Hook-only data layer

  • reads belong in hooks/queries/
  • writes belong in hooks/mutations/
  • pages and components should not call fetch directly for app data

4. Standard mutation policy

Use the same mutation pattern across the repo:
We are explicitly choosing this invalidation-based approach over setQueryData and setQueriesData to keep mutation behavior consistent and easier to audit.

Workstreams

Phase 0: Foundations

Deliverables:
  • lib/cache-keys.ts
  • lib/query-keys.ts
  • documentation set under docs/react-query/
Acceptance criteria:
  • all root key names come from CACHE_KEYS
  • new key arrays are composed only in lib/query-keys.ts

Phase 1: Query hook migration

Scope:
  • migrate all query hooks to globalKeys or userKeys(userId)
  • remove local key factories such as createQueryKeys
  • ensure every user-scoped query includes userId
Acceptance criteria:
  • no inline queryKey: [...] in query hooks
  • no user-specific query missing userId in the key

Phase 2: Mutation and fetch standardization

Scope:
  • move all raw write-side fetch calls into hooks/mutations/
  • move all raw read-side fetch calls into hooks/queries/
  • replace component/page mutation logic with hook usage
  • replace setQueryData and setQueriesData with invalidateQueries in mutation flows
Acceptance criteria:
  • no page/component should own app-data mutation logic directly
  • no mutation should rely on setQueryData or setQueriesData

Phase 3: Invalidation audit and cleanup

Scope:
  • review every invalidateQueries usage file by file
  • remove overlapping invalidations
  • keep refetchQueries only where immediate UX requires it
Acceptance criteria:
  • each invalidation block is justified by dependent data
  • redundant cases like multiple invalidations for the same active query are removed

Phase 4: Query client provider cleanup

Scope:
  • replace full-cache queryClient.clear() with targeted removal of user-scoped queries
  • preserve global cache where appropriate across sign-in/sign-out transitions
Acceptance criteria:
  • user-scoped cache is removed safely on user switch
  • global/public cache is not unnecessarily destroyed

Phase 5: Documentation and guardrails

Scope:
  • document the rules in AGENTS.md
  • add grep-based or lint-style checks where practical
Acceptance criteria:
  • future query/mutation work follows the documented pattern
  • regressions are easier to catch during review

PR Breakdown

Suggested PR order:
  1. Foundation files and docs
  2. Core query hook migration
  3. Remaining query hook migration by domain
  4. Mutation hook migration
  5. Component/page fetch extraction
  6. Invalidation audit and cleanup
  7. Query client provider cleanup
  8. AGENTS.md update and guardrails

Detailed Docs

  • docs/react-query/01-CACHE-KEY-REGISTRY.md
  • docs/react-query/02-QUERY-HOOK-MIGRATION.md
  • docs/react-query/03-MUTATION-STANDARDIZATION.md
  • docs/react-query/04-INVALIDATION-AUDIT.md
  • docs/react-query/05-PROVIDER-AND-AGENTS-UPDATE.md

Verification

  • npm run build
  • smoke test authenticated flows
  • mutation test on accounts/holdings/net-worth paths
  • React Query DevTools inspection of key shapes
  • multi-user sign-out/sign-in validation
  • grep review for inline keys and raw component/page fetch usage