Follow-up from the TanStack Router/Query plan in docs/HANDOFF_TANSTACK_ROUTER_QUERY.md (Effort 3).
Problem
Auth-dependent queries (useProfile, useUserPermissions, useUserVotes, useGroupVotes) cannot prefetch in route loaders today because AuthProvider — and the user it owns — is rendered inside __root's component, below the router. So context.user isn't available to loaders, and these queries can't use ensureQueryData / useSuspenseQuery.
Decision (from grilling session)
The router resolves the session independently; AuthProvider stays fully intact:
- Root
beforeLoad calls supabase.auth.getSession() to put user in context.user, making it available to loaders.
- A router-side
supabase.auth.onAuthStateChange listener calls router.invalidate() for reactivity (login/logout re-runs beforeLoad + loaders).
AuthProvider is not changed: it keeps its own session state, profile, needsOnboarding, the AuthDialog modal, SIGNED_IN invite processing, and signOut. The 23 useAuth consumers are untouched.
- Both the router and
AuthProvider project from the supabase client (the real source of truth). This deliberately accepts a second getSession/listener as the price of keeping the heavily-used provider risk-free.
Scope / care points
- Sequence the reactivity carefully (
router.invalidate() on auth state change); decide where the router-side onAuthStateChange subscription lives and is cleaned up.
- This is a prerequisite for adopting loaders +
useSuspenseQuery on auth-dependent routes; until it lands, those queries stay useQuery.
Dependencies
Do after Effort 1 (the src/api restructure) and ideally after Effort 2 (router adoption for non-auth features) so the pattern is established.
This decision is intentionally not recorded as an ADR yet — tracked here as a follow-up to revisit at implementation time.
Follow-up from the TanStack Router/Query plan in
docs/HANDOFF_TANSTACK_ROUTER_QUERY.md(Effort 3).Problem
Auth-dependent queries (
useProfile,useUserPermissions,useUserVotes,useGroupVotes) cannot prefetch in route loaders today becauseAuthProvider— and theuserit owns — is rendered inside__root's component, below the router. Socontext.userisn't available to loaders, and these queries can't useensureQueryData/useSuspenseQuery.Decision (from grilling session)
The router resolves the session independently;
AuthProviderstays fully intact:beforeLoadcallssupabase.auth.getSession()to putuserincontext.user, making it available to loaders.supabase.auth.onAuthStateChangelistener callsrouter.invalidate()for reactivity (login/logout re-runsbeforeLoad+ loaders).AuthProvideris not changed: it keeps its own session state,profile,needsOnboarding, theAuthDialogmodal,SIGNED_INinvite processing, andsignOut. The 23useAuthconsumers are untouched.AuthProviderproject from the supabase client (the real source of truth). This deliberately accepts a secondgetSession/listener as the price of keeping the heavily-used provider risk-free.Scope / care points
router.invalidate()on auth state change); decide where the router-sideonAuthStateChangesubscription lives and is cleaned up.useSuspenseQueryon auth-dependent routes; until it lands, those queries stayuseQuery.Dependencies
Do after Effort 1 (the
src/apirestructure) and ideally after Effort 2 (router adoption for non-auth features) so the pattern is established.This decision is intentionally not recorded as an ADR yet — tracked here as a follow-up to revisit at implementation time.