Skip to content

feat: prefetch route data via loaders to eliminate white-screen flash on nav (JEF-64) - #178

Merged
mankatcheung merged 1 commit into
mainfrom
worktree-jef-64-route-prefetch
Aug 1, 2026
Merged

mankatcheung merged 1 commit into
mainfrom
worktree-jef-64-route-prefetch

Conversation

@mankatcheung

@mankatcheung mankatcheung commented Aug 1, 2026

Copy link
Copy Markdown
Owner

Summary

Navigating to a page not yet visited this session showed a brief blank flash. router.tsx already set defaultPreload: 'intent' (prefetches a route's JS chunk on hover), but no route defined a loader, so each page's GraphQL query only started fetching after the component mounted post-navigation — not during the hover-intent preload window. TanStack Router blocks a navigation's transition on its target route's loader, so once a loader exists, the previous page stays on screen (no blank frame) until data is ready, then swaps in with the query cache already warm.

  • router.tsx / __root.tsx: wire the app's queryClient into the router context (createRootRouteWithContext) so loaders can call context.queryClient.ensureQueryData(...).
  • dashboard, calendar: queryOptions() shared between the new loader and the existing useQuery call (single source of truth for queryKey + queryFn, so they can't drift out of sync).
  • applications/board, analytics: same pattern, but the query options had to move into new sibling -board-queries.ts / -analytics-queries.ts modules rather than living inside -board-page.tsx / -analytics-page.tsx — those routes use lazyRouteComponent specifically to keep dnd-kit and recharts out of the eagerly-loaded route chunk, and importing the query options directly from the component file would have dragged those dependencies in eagerly along with them. Verified post-build that -board-page/-analytics-page remain separate chunks.
  • applications/index: infiniteQueryOptions() + ensureInfiniteQueryData. loaderDeps only tracks the URL-driven status/starred filters (not the local-state search input, which is always empty on a fresh nav) so hovering a filtered link (e.g. the "Applied" tab) also prefetches correctly, not just the unfiltered default.
  • applications/$applicationId/{index,edit}: both routes fetch the exact same application by id under the same query key but each had its own copy of the query string and Application type; extracted both into a shared -application-query.ts so the two routes' loaders and the detail/edit pages' useQuery calls all reference one definition.

Deliberately left out: account.tsx (7 independent queries with no single blocking one — the page already renders progressively rather than blank) and assistant.tsx (no data-fetching query on load at all).

Ref: Linear JEF-64.

Test plan

  • pnpm --filter @job-finder/web typecheck / lint / build — clean
  • pnpm --filter @job-finder/web test — 148/148 passing, unaffected since tests mock createFileRoute and render components directly, bypassing loaders entirely
  • Confirmed via build output that -board-page/-analytics-page remain their own separate chunks (code-splitting intact) and the main router chunk size didn't grow appreciably
  • Manually verified end-to-end with Playwright against a live dev server: registered a user, clicked through to Calendar and Analytics, and confirmed via a DOM-attach watcher that the loading-skeleton element never appears during the transition (previously the empty component would mount and show it while its own query fetched)

🤖 Generated with Claude Code

https://claude.ai/code/session_01N2PBmsuzPhrmNnfZf6C3BM

Summary by CodeRabbit

  • Performance

    • Improved page loading by preloading analytics, applications, application details, board data, calendar events and dashboard data before rendering.
    • Shared data-fetching behaviour now provides more consistent caching and fewer duplicate requests.
  • User Experience

    • Preserved existing application pagination, filtering, search, calendar, board and analytics functionality while improving data availability during navigation.

… on nav (JEF-64)

Navigating to a page not yet visited this session showed a brief blank
flash. router.tsx already set defaultPreload: 'intent' (prefetches a
route's JS chunk on hover), but no route defined a `loader`, so each
page's GraphQL query only started fetching after the component mounted
post-navigation — not during the hover-intent preload window. TanStack
Router blocks a navigation's transition on its target route's loader,
so once a loader exists, the previous page stays on screen (no blank
frame) until data is ready, then swaps in with the query cache already
warm.

- router.tsx / __root.tsx: wire the app's queryClient into the router
  context (createRootRouteWithContext) so loaders can call
  `context.queryClient.ensureQueryData(...)`.
- dashboard, calendar: queryOptions() shared between the new loader and
  the existing useQuery call (single source of truth for queryKey +
  queryFn, so they can't drift out of sync).
- applications/board, analytics: same pattern, but the query options
  had to move into new sibling -board-queries.ts / -analytics-queries.ts
  modules rather than living inside -board-page.tsx / -analytics-page.tsx
  — those routes use `lazyRouteComponent` specifically to keep dnd-kit
  and recharts out of the eagerly-loaded route chunk, and importing the
  query options directly from the component file would have dragged
  those dependencies in eagerly along with them. Verified post-build
  that -board-page and -analytics-page remain separate chunks.
- applications/index: infiniteQueryOptions() + ensureInfiniteQueryData.
  loaderDeps only tracks the URL-driven status/starred filters (not the
  local-state search input, which is always empty on a fresh nav) so
  hovering a filtered link (e.g. the "Applied" tab) also prefetches
  correctly, not just the unfiltered default.
- applications/$applicationId/{index,edit}: both routes fetch the exact
  same application by id under the same query key but each had its own
  copy of the query string and Application type; extracted both into a
  shared -application-query.ts so the two routes' loaders and the
  detail/edit pages' useQuery calls all reference one definition.

Deliberately left out: account.tsx (7 independent queries with no
single blocking one — the page already renders progressively rather
than blank) and assistant.tsx (no data-fetching query on load at all).

Verified: typecheck/lint/test/build all clean (148/148 web tests,
unaffected since tests mock createFileRoute and render components
directly, bypassing loaders entirely). Confirmed via build output that
-board-page/-analytics-page chunks stayed separate (code-splitting
intact) and the main router chunk size didn't grow appreciably.
Manually verified end-to-end with Playwright against a live dev server:
registered a user, clicked through to Calendar and Analytics, and
confirmed via a DOM-attach watcher that the loading-skeleton element
never appears during the transition (previously the empty component
would mount and show it while its own query fetched).

Ref: JEF-64
@coderabbitai

coderabbitai Bot commented Aug 1, 2026

Copy link
Copy Markdown

Review Change Stack

Walkthrough

The web app now passes queryClient through TanStack Router context. Routes define shared TanStack Query options for analytics, applications, dashboard, and calendar data, then preload and consume the same options.

Changes

TanStack Query route preloading

Layer / File(s) Summary
Router query-client context
apps/web/src/router.tsx, apps/web/src/routes/__root__.tsx
The root route defines typed RouterContext. The router supplies queryClient through that context.
Analytics query preloading
apps/web/src/routes/_authenticated/-analytics-queries.ts, apps/web/src/routes/_authenticated/-analytics-page.tsx, apps/web/src/routes/_authenticated/analytics.tsx
Shared analytics query options now contain the GraphQL request and result type. The route loader and page use the shared options.
Application detail query sharing
apps/web/src/routes/_authenticated/applications/$applicationId/-application-query.ts, apps/web/src/routes/_authenticated/applications/$applicationId/index.tsx, apps/web/src/routes/_authenticated/applications/$applicationId/edit.tsx
Shared ID-based application query options replace local query definitions. Both routes preload and consume the shared query.
Application collection query sharing
apps/web/src/routes/_authenticated/applications/-board-queries.ts, apps/web/src/routes/_authenticated/applications/-board-page.tsx, apps/web/src/routes/_authenticated/applications/board.tsx, apps/web/src/routes/_authenticated/applications/index.tsx
Board and paginated application queries use shared options. Route loaders preload the relevant application data.
Dashboard and calendar preloading
apps/web/src/routes/_authenticated/dashboard.tsx, apps/web/src/routes/_authenticated/calendar.tsx
Dashboard and calendar pages use shared query options. Their route loaders ensure query data before rendering.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Possibly related issues

Possibly related PRs

Poem

A rabbit finds queries in one tidy place,
Routes preload data at a steady pace.
The board, calendar, dashboard align,
Analytics follows the same clear design.
queryClient hops through the router with glee.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main change: prefetching route data through loaders to prevent blank navigation flashes.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch worktree-jef-64-route-prefetch

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions

github-actions Bot commented Aug 1, 2026

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (2)
apps/web/src/routes/_authenticated/analytics.tsx (1)

3-3: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Use the required #/* alias for shared analytics query imports.

Both imports resolve inside apps/web/src and should use the repository alias.

  • apps/web/src/routes/_authenticated/analytics.tsx#L3-L3: replace ./-analytics-queries with #/routes/_authenticated/-analytics-queries.
  • apps/web/src/routes/_authenticated/-analytics-page.tsx#L5-L5: replace ./-analytics-queries with #/routes/_authenticated/-analytics-queries.

As per coding guidelines, apps/web/src/**/*.{ts,tsx} must use the #/* path alias for imports resolving to ./src/* where applicable.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/web/src/routes/_authenticated/analytics.tsx` at line 3, Update the
analyticsQueryOptions imports in
apps/web/src/routes/_authenticated/analytics.tsx at lines 3-3 and
apps/web/src/routes/_authenticated/-analytics-page.tsx at lines 5-5 to use the
`#/routes/_authenticated/-analytics-queries` alias instead of the relative
./-analytics-queries path.

Source: Coding guidelines

apps/web/src/routes/__root.tsx (1)

11-11: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Use the #/* alias for the internal stylesheet import.

../styles.css?url resolves to apps/web/src/styles.css. Replace it with #/styles.css?url when the configured alias supports asset URL imports.

As per coding guidelines, files under apps/web/src/**/*.{ts,tsx} must use the #/* path alias for imports that resolve to ./src/* where applicable.

Proposed change
-import appCss from '../styles.css?url';
+import appCss from '`#/styles.css`?url';
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/web/src/routes/__root.tsx` at line 11, Update the appCss import in the
root route module to use the configured `#/`* alias for the internal stylesheet
asset, replacing the relative ../styles.css?url path with the equivalent aliased
URL import.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@apps/web/src/routes/_authenticated/applications/`$applicationId/index.tsx:
- Around line 71-72: Disable SSR in both protected application route
configurations:
apps/web/src/routes/_authenticated/applications/$applicationId/index.tsx lines
71-72 and
apps/web/src/routes/_authenticated/applications/$applicationId/edit.tsx lines
45-46. Add the route-level ssr: false setting alongside each loader so
applicationQueryOptions loaders run only after client hydration.

In `@apps/web/src/routes/_authenticated/applications/board.tsx`:
- Around line 4-6: Update the Route configurations in
apps/web/src/routes/_authenticated/applications/board.tsx lines 4-6 and
apps/web/src/routes/_authenticated/applications/index.tsx lines 116-124 to
disable SSR and enable session hydration with the established client-only auth
configuration, ensuring hydrateSession runs for both API-backed protected
loaders.

---

Nitpick comments:
In `@apps/web/src/routes/__root.tsx`:
- Line 11: Update the appCss import in the root route module to use the
configured `#/`* alias for the internal stylesheet asset, replacing the relative
../styles.css?url path with the equivalent aliased URL import.

In `@apps/web/src/routes/_authenticated/analytics.tsx`:
- Line 3: Update the analyticsQueryOptions imports in
apps/web/src/routes/_authenticated/analytics.tsx at lines 3-3 and
apps/web/src/routes/_authenticated/-analytics-page.tsx at lines 5-5 to use the
`#/routes/_authenticated/-analytics-queries` alias instead of the relative
./-analytics-queries path.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 7ebf4762-79ed-43c4-8f64-5aafa4f3b0b1

📥 Commits

Reviewing files that changed from the base of the PR and between 9192216 and af2070d.

📒 Files selected for processing (14)
  • apps/web/src/router.tsx
  • apps/web/src/routes/__root.tsx
  • apps/web/src/routes/_authenticated/-analytics-page.tsx
  • apps/web/src/routes/_authenticated/-analytics-queries.ts
  • apps/web/src/routes/_authenticated/analytics.tsx
  • apps/web/src/routes/_authenticated/applications/$applicationId/-application-query.ts
  • apps/web/src/routes/_authenticated/applications/$applicationId/edit.tsx
  • apps/web/src/routes/_authenticated/applications/$applicationId/index.tsx
  • apps/web/src/routes/_authenticated/applications/-board-page.tsx
  • apps/web/src/routes/_authenticated/applications/-board-queries.ts
  • apps/web/src/routes/_authenticated/applications/board.tsx
  • apps/web/src/routes/_authenticated/applications/index.tsx
  • apps/web/src/routes/_authenticated/calendar.tsx
  • apps/web/src/routes/_authenticated/dashboard.tsx

Comment on lines +71 to +72
loader: ({ context: { queryClient }, params: { applicationId } }) =>
queryClient.ensureQueryData(applicationQueryOptions(applicationId)),

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== candidate files =="
for f in \
  apps/web/src/routes/_authenticated/applications/\$applicationId/index.tsx \
  apps/web/src/routes/_authenticated/applications/\$applicationId/edit.tsx
do
  echo "--- $f"
  wc -l "$f"
  sed -n '1,140p' "$f"
done

echo "== route declarations =="
rg -n "CreateRootRoute|createFileRoute|ssr:|ssr \?|hydratedRoute|loader:" apps/web/src/routes apps/web/src -g '*.ts' -g '*.tsx' | sed -n '1,220p'

Repository: mankatcheung/job-finder

Length of output: 23254


🌐 Web query:

TanStack Router SSR loader execution before hydration API server cookie unavailable react start

💡 Result:

In TanStack Router (especially when using TanStack Start for SSR), loaders are client-first but execute on both the client and the server during SSR [1]. Because browser-only APIs like document.cookie do not exist on the server, you cannot directly access cookies within a loader using standard client-side methods [1]. To access cookies securely on the server during the initial SSR request, you must use server-side primitives provided by TanStack Start rather than trying to read the browser's cookie storage directly [2][3]. Key strategies for handling this include: 1. Use Server Functions for Server-Side Access: Instead of accessing cookies directly in the loader, define a createServerFn to handle authentication or data fetching that requires cookie access [4][5]. Server functions have access to the underlying request context and can safely read cookies on the server using getCookie from @tanstack/react-start/server [6][3]. You can then call this server function from your beforeLoad or loader [4][7]. 2. Context-Based Authentication: The recommended pattern is to validate the session on the server via beforeLoad in your root route or layout [4]. - Use a createServerFn to read the HttpOnly cookie and validate it against your API or session store [4][8]. - Return the authenticated user or session data from this server function [8]. - Assign the result to the router's context in beforeLoad so that it is available to all nested routes, preventing the need for subsequent cookie-based lookups [4]. 3. Isomorphic Logic: If you need logic that runs in both environments, you must use an isomorphic approach to account for the different execution contexts [6]. - Server: Use getCookie from @tanstack/react-start/server [6][3]. - Client: Use standard browser APIs (e.g., document.cookie) [6]. - You can combine these using a utility like createIsomorphicFn to maintain clean, type-safe code that avoids runtime errors during build or SSR execution [6]. Important Note: TanStack Router loaders are not "server-only" (unlike Remix or Next.js loaders) [1]. They will run on the client during client-side navigation. Therefore, ensure any code interacting with cookies is either server-only (called via server functions) or environment-aware to prevent hydration mismatches or server crashes caused by referencing non-existent browser globals [6][1].

Citations:


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== route tree relevant entries =="
sed -n '420,460p' apps/web/src/routeTree.gen.ts | cat -n

echo "== SSR config references =="
rg -n "dehydrate|hydrateSession|beforeLoad|hydrate\(|reactServer|`@tanstack/react-start`|serverContext|ssr: false|ssr \? " apps/web/src apps/web -g '*.ts' -g '*.tsx' -g '*.js' -g '*.json' | sed -n '1,260p'

echo "== query client / server setup files =="
fd -e ts -e tsx -e js -e json . apps/web/src | rg 'queryClient|server|start|client|router|hydration|route' | sed -n '1,120p'

Repository: mankatcheung/job-finder

Length of output: 11116


🌐 Web query:

TanStack Router ssr false loader execute server browser cookie unavailable initial request hydration

💡 Result:

When you set ssr: false in TanStack Router, the router disables server-side execution of that route's beforeLoad and loader functions, as well as the server-side rendering of the route component [1][2]. Consequently, because the server does not execute the loader, it does not have access to client-side cookies during the initial request [3][4]. In this configuration, the initial HTML sent to the browser is a "shell" (often a loading state or empty), and the route's data loading and component rendering are deferred until the client takes over [1][2]. Once the application loads in the browser, the router hydrates, and the loader executes on the client, where it can naturally access browser cookies via document.cookie or other client-side storage APIs [3][5]. To avoid issues with missing cookies or hydration mismatches: 1. Client-Side Access: If you use ssr: false, your loaders will only run on the client, allowing them to access browser cookies directly [3]. However, this means the user will initially see a loading state while the browser fetches data [1]. 2. Server-Side Access (Recommended for Auth): If you need to access cookies during the initial request to perform server-side checks (e.g., for authentication) and avoid hydration mismatches, you should keep ssr: true and use server functions [6][7]. You can create a createServerFn that accesses the request object to read cookies from the Cookie header [6][7]. By calling this server function within your loader (which is isomorphic), the server can validate the session and return the necessary data, which the router then automatically dehydrates and provides to the client upon hydration [3][7]. Using ssr: false purely to "solve" cookie access issues is generally considered a workaround that results in a worse user experience due to the loss of initial server-rendered data [3]. The preferred architectural pattern is to use isomorphic server functions to handle cookie-based data requirements, ensuring the data is available on the server during the initial request and correctly hydrated on the client [3][7].

Citations:


Disable SSR for both protected application loaders.

Global ssr is enabled for this app, so these routes inherit server-side loader execution unless overridden. Add ssr: false to both route configurations so the loaders only run after client hydration and can use the API cookie.

  • apps/web/src/routes/_authenticated/applications/$applicationId/index.tsx
  • apps/web/src/routes/_authenticated/applications/$applicationId/edit.tsx
📍 Affects 2 files
  • apps/web/src/routes/_authenticated/applications/$applicationId/index.tsx#L71-L72 (this comment)
  • apps/web/src/routes/_authenticated/applications/$applicationId/edit.tsx#L45-L46
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/web/src/routes/_authenticated/applications/`$applicationId/index.tsx
around lines 71 - 72, Disable SSR in both protected application route
configurations:
apps/web/src/routes/_authenticated/applications/$applicationId/index.tsx lines
71-72 and
apps/web/src/routes/_authenticated/applications/$applicationId/edit.tsx lines
45-46. Add the route-level ssr: false setting alongside each loader so
applicationQueryOptions loaders run only after client hydration.

Source: Coding guidelines

Comment on lines 4 to +6
export const Route = createFileRoute('/_authenticated/applications/board')({
loader: ({ context: { queryClient } }) =>
queryClient.ensureQueryData(boardApplicationsQueryOptions),

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Find the established client-side authentication route pattern.
rg -n -C 4 'hydrateSession|ssr:\s*false' apps/web/src/routes apps/web/src

Repository: mankatcheung/job-finder

Length of output: 19582


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '--- candidate files ---\n'
wc -l apps/web/src/routes/_authenticated/applications/board.tsx apps/web/src/routes/_authenticated/applications/index.tsx apps/web/src/routes/_authenticated/route.tsx

printf '\n--- board.tsx ---\n'
cat -n apps/web/src/routes/_authenticated/applications/board.tsx

printf '\n--- index.tsx relevant section ---\n'
sed -n '90,135p' apps/web/src/routes/_authenticated/applications/index.tsx | cat -n

printf '\n--- _authenticated/route.tsx relevant section ---\n'
sed -n '70,86p' apps/web/src/routes/_authenticated/route.tsx | cat -n

Repository: mankatcheung/job-finder

Length of output: 252


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo '--- candidate files line counts ---'
wc -l apps/web/src/routes/_authenticated/applications/board.tsx apps/web/src/routes/_authenticated/applications/index.tsx apps/web/src/routes/_authenticated/route.tsx

echo
echo '--- board.tsx ---'
cat -n apps/web/src/routes/_authenticated/applications/board.tsx

echo
echo '--- index.tsx relevant section ---'
sed -n '90,135p' apps/web/src/routes/_authenticated/applications/index.tsx | cat -n

echo
echo '--- _authenticated/route.tsx relevant section ---'
sed -n '70,86p' apps/web/src/routes/_authenticated/route.tsx | cat -n

Repository: mankatcheung/job-finder

Length of output: 3453


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo '--- board query options and client auth setup ---'
sed -n '1,180p' apps/web/src/routes/_authenticated/applications/-board-queries.tsx | cat -n

echo
echo '--- graphql client auth/session ---'
sed -n '1,120p' apps/web/src/graphql/client.ts | cat -n

echo
echo '--- access token handling in graphql client ---'
rg -n 'accessToken|setAccessToken|Authorization|getAccessToken|hydrateSession' apps/web/src/graphql/client.ts apps/web/src/routes/_authenticated/applications/-board-queries.tsx

Repository: mankatcheung/job-finder

Length of output: 321


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo '--- locate board query file ---'
fd -a -i 'board.*queries' . || true

echo
echo '--- relevant auth helpers ---'
sed -n '1,120p' apps/web/src/graphql/client.ts | cat -n

echo
echo '--- search board application files ---'
git ls-files apps/web/src/routes/_authenticated/applications | sort

Repository: mankatcheung/job-finder

Length of output: 5485


Disable SSR and hydrate the session for API-backed protected loaders.

hydrateSession() must run after ssr: false can preserve the in-memory access token for these child routes; otherwise the loaders can invalidate queries when the web server has no bearer token to attach.

  • apps/web/src/routes/_authenticated/applications/board.tsx#L4-L6: add the client-only auth configuration.
  • apps/web/src/routes/_authenticated/applications/index.tsx#L116-L124: add the same client-only auth configuration.
📍 Affects 2 files
  • apps/web/src/routes/_authenticated/applications/board.tsx#L4-L6 (this comment)
  • apps/web/src/routes/_authenticated/applications/index.tsx#L116-L124
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/web/src/routes/_authenticated/applications/board.tsx` around lines 4 -
6, Update the Route configurations in
apps/web/src/routes/_authenticated/applications/board.tsx lines 4-6 and
apps/web/src/routes/_authenticated/applications/index.tsx lines 116-124 to
disable SSR and enable session hydration with the established client-only auth
configuration, ensuring hydrateSession runs for both API-backed protected
loaders.

Source: Coding guidelines

@mankatcheung
mankatcheung merged commit bd3d0a0 into main Aug 1, 2026
11 checks passed
@mankatcheung
mankatcheung deleted the worktree-jef-64-route-prefetch branch August 18, 2026 11:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant