+
+ }
+ />
+ } />
+
+ ,
+ )
+
+ // The protected page should not render.
+ expect(screen.queryByTestId('home-content')).not.toBeInTheDocument()
+
+ // We landed on / (the public landing route), not /landing.
+ expect(screen.getByTestId('probe-pathname')).toHaveTextContent('/')
+ expect(screen.getByTestId('probe-from')).toHaveTextContent('/home')
+ })
+})
diff --git a/frontend/src/pages/AssistantChatPage.tsx b/frontend/src/pages/AssistantChatPage.tsx
index 4e6f6fca..bcd214de 100644
--- a/frontend/src/pages/AssistantChatPage.tsx
+++ b/frontend/src/pages/AssistantChatPage.tsx
@@ -2416,7 +2416,7 @@ export default function AssistantChatPage() {
setShowConclude(false)
if (activeSessionStatus === 'escalated') {
toast.info('Session escalated. Heading back to your dashboard.')
- navigate('/')
+ navigate('/home')
}
}}
onConclude={handleConclude}
diff --git a/frontend/src/pages/ContactPage.tsx b/frontend/src/pages/ContactPage.tsx
index e7d68adf..dade0f1a 100644
--- a/frontend/src/pages/ContactPage.tsx
+++ b/frontend/src/pages/ContactPage.tsx
@@ -7,7 +7,7 @@ export default function ContactPage() {
- ← Back to home
+ ← Back to home
Contact ResolutionFlow
We respond to customer inquiries Monday through Friday during U.S. business hours, excluding federal holidays. Email is the fastest path to a response.
diff --git a/frontend/src/pages/OAuthCallbackPage.tsx b/frontend/src/pages/OAuthCallbackPage.tsx
index b32dd080..e606ac27 100644
--- a/frontend/src/pages/OAuthCallbackPage.tsx
+++ b/frontend/src/pages/OAuthCallbackPage.tsx
@@ -112,10 +112,10 @@ export function OAuthCallbackPage() {
// Invitee path lands on the dashboard with the teammate-welcome
// marker; new self-serve owners go to the welcome wizard; returning
- // users to /.
- let dest = '/'
+ // users to /home.
+ let dest = '/home'
if (decoded?.accountInviteCode) {
- dest = '/?welcome=teammate'
+ dest = '/home?welcome=teammate'
} else if (result.is_new_user) {
dest = '/welcome'
}
diff --git a/frontend/src/pages/PoliciesPage.tsx b/frontend/src/pages/PoliciesPage.tsx
index eaabb472..1da097cd 100644
--- a/frontend/src/pages/PoliciesPage.tsx
+++ b/frontend/src/pages/PoliciesPage.tsx
@@ -7,7 +7,7 @@ export default function PoliciesPage() {
- ← Back to home
+ ← Back to home
Customer Policies
Last updated: May 7, 2026
Operator: ResolutionFlow, LLC (the “Company”), operator of ResolutionFlow (“Service”).
diff --git a/frontend/src/pages/PrivacyPage.tsx b/frontend/src/pages/PrivacyPage.tsx
index 1478bbca..9a6fc5f3 100644
--- a/frontend/src/pages/PrivacyPage.tsx
+++ b/frontend/src/pages/PrivacyPage.tsx
@@ -7,7 +7,7 @@ export default function PrivacyPage() {
- ← Back to home
+ ← Back to home
Privacy Policy
Last updated: March 21, 2026
diff --git a/frontend/src/pages/PromotionsPage.tsx b/frontend/src/pages/PromotionsPage.tsx
index 132ad10b..f495f1dd 100644
--- a/frontend/src/pages/PromotionsPage.tsx
+++ b/frontend/src/pages/PromotionsPage.tsx
@@ -7,7 +7,7 @@ export default function PromotionsPage() {
} />
,
)
@@ -100,7 +100,7 @@ describe('WelcomeRouter', () => {
})
})
- it('redirects to / when onboarding_step_completed >= 3', async () => {
+ it('redirects to /home when onboarding_step_completed >= 3', async () => {
useAuthStore.setState({
user: makeUser({ onboarding_step_completed: 3 }),
})
@@ -110,7 +110,7 @@ describe('WelcomeRouter', () => {
})
})
- it('redirects to / when onboarding_dismissed is true', async () => {
+ it('redirects to /home when onboarding_dismissed is true', async () => {
useAuthStore.setState({
user: makeUser({
onboarding_step_completed: 1,
diff --git a/frontend/src/pages/welcome/__tests__/WelcomeStep1.test.tsx b/frontend/src/pages/welcome/__tests__/WelcomeStep1.test.tsx
index 93483add..a067d171 100644
--- a/frontend/src/pages/welcome/__tests__/WelcomeStep1.test.tsx
+++ b/frontend/src/pages/welcome/__tests__/WelcomeStep1.test.tsx
@@ -65,7 +65,7 @@ function renderPage() {
} />
step-2
} />
- dashboard
} />
+ dashboard
} />
,
)
@@ -148,7 +148,7 @@ describe('WelcomeStep1', () => {
})
})
- it('Skip-the-rest dismisses and navigates to /', async () => {
+ it('Skip-the-rest dismisses and navigates to /home', async () => {
const user = userEvent.setup()
renderPage()
diff --git a/frontend/src/pages/welcome/__tests__/WelcomeStep2.test.tsx b/frontend/src/pages/welcome/__tests__/WelcomeStep2.test.tsx
index 57b2a9bd..3cb5c9ef 100644
--- a/frontend/src/pages/welcome/__tests__/WelcomeStep2.test.tsx
+++ b/frontend/src/pages/welcome/__tests__/WelcomeStep2.test.tsx
@@ -66,7 +66,7 @@ function renderPage() {
} />
step-3
} />
integrations
} />
- dashboard
} />
+ dashboard
} />
,
)
@@ -158,7 +158,7 @@ describe('WelcomeStep2', () => {
expect(screen.queryByTestId('welcome-step-2-connect-now')).not.toBeInTheDocument()
})
- it('Skip-the-rest dismisses and navigates to /', async () => {
+ it('Skip-the-rest dismisses and navigates to /home', async () => {
const user = userEvent.setup()
renderPage()
From f9f98b1a65c276140727a779d997ab0800fd71ba Mon Sep 17 00:00:00 2001
From: Michael Chihlas
Date: Fri, 15 May 2026 00:34:23 -0400
Subject: [PATCH 4/4] fix(routing): finish /home migration in WelcomeStep3 +
VerifyEmailPage
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
The original public-landing routing refactor migrated WelcomeRouter,
WelcomeStep1, and WelcomeStep2 post-onboarding redirects to /home, but
left four sites still pointing at the old / + query-string destinations:
- WelcomeStep3 `completeWizardAndExit` (Send invites)
- WelcomeStep3 `handleSkipStep` (Skip)
- VerifyEmailPage post-verify auto-redirect (`setTimeout`)
- VerifyEmailPage success-state "Go to dashboard" Link
These all worked by accident because PublicLanding redirects authed
users from / to /home — so users still landed on the dashboard, but
through an unnecessary mount-and-redirect flicker, and the
`?welcome=true` / `?verified=1` query markers got dropped on the way.
Drop both query markers — neither is read anywhere in the codebase
(grepped frontend/src; the dashboard's onboarding UX is driven by
`getOnboardingStatus`, not URL state). Carrying dead URL params
just invites future "is this load-bearing?" investigations.
Test stubs in WelcomeStep3.test.tsx and VerifyEmailPage.test.tsx
moved from `` to `` so the
assertions verify the new destination instead of accidentally matching
the old one (the previous stubs masked the partial migration).
Out of scope: AcceptInvitePage and OAuthCallbackPage still use
`?welcome=teammate`, but that one carries an explicit "decoded by the
dashboard in Task 41" annotation and may be wired up later, so left
untouched.
Co-Authored-By: Claude Opus 4.7 (1M context)
---
frontend/src/pages/VerifyEmailPage.tsx | 10 ++++------
frontend/src/pages/__tests__/VerifyEmailPage.test.tsx | 6 +++---
frontend/src/pages/welcome/WelcomeStep3.tsx | 6 +++---
.../src/pages/welcome/__tests__/WelcomeStep3.test.tsx | 2 +-
4 files changed, 11 insertions(+), 13 deletions(-)
diff --git a/frontend/src/pages/VerifyEmailPage.tsx b/frontend/src/pages/VerifyEmailPage.tsx
index 12fb49b8..0ac355a0 100644
--- a/frontend/src/pages/VerifyEmailPage.tsx
+++ b/frontend/src/pages/VerifyEmailPage.tsx
@@ -20,8 +20,7 @@ const SUCCESS_REDIRECT_MS = 1200
* "Already verified" state. No API call.
* - Else fire `POST /auth/email/verify` exactly once (a `useRef` guard keeps
* React 19 strict-mode double-invoke from double-firing the call). On
- * success, refresh the auth store and bounce to `/?verified=1` so the
- * dashboard surfaces a toast.
+ * success, refresh the auth store and bounce to `/home`.
* - On error, show "Invalid or expired token" + a "Resend" CTA that calls
* `POST /auth/email/send-verification`.
*/
@@ -70,10 +69,9 @@ export function VerifyEmailPage() {
if (cancelled) return
setStatus('success')
toast.success('Email verified')
- // Brief success state, then redirect with a query flag so the
- // dashboard can re-surface confirmation if it wants to.
+ // Brief success state, then redirect to the dashboard.
window.setTimeout(() => {
- navigate('/?verified=1', { replace: true })
+ navigate('/home', { replace: true })
}, SUCCESS_REDIRECT_MS)
})
.catch((err) => {
@@ -126,7 +124,7 @@ export function VerifyEmailPage() {
Redirecting you to the dashboard…
} />
- dashboard} />
+ dashboard} />
,
@@ -130,7 +130,7 @@ describe('VerifyEmailPage', () => {
} />
- dashboard} />
+ dashboard} />
,
@@ -142,7 +142,7 @@ describe('VerifyEmailPage', () => {
} />
- dashboard} />
+ dashboard} />
,
diff --git a/frontend/src/pages/welcome/WelcomeStep3.tsx b/frontend/src/pages/welcome/WelcomeStep3.tsx
index b345dfa3..be2f6309 100644
--- a/frontend/src/pages/welcome/WelcomeStep3.tsx
+++ b/frontend/src/pages/welcome/WelcomeStep3.tsx
@@ -39,7 +39,7 @@ function makeEmptyRow(): InviteRow {
*
* 1. POST `/accounts/me/invites/bulk` with populated rows.
* 2. PATCH `/users/me/onboarding-step` `{step: 3, action: "complete"}`.
- * 3. Navigate to `/?welcome=true` and fire a "You're all set" toast.
+ * 3. Navigate to `/home` and fire a "You're all set" toast.
*
* Partial-failure UX: rows in `failed[]` keep their input and show an
* inline error. The wizard does NOT auto-advance when there are failures —
@@ -109,7 +109,7 @@ export function WelcomeStep3() {
await onboardingApi.updateStep({ step: 3, action: 'complete' })
await fetchUser()
toast.success("You're all set!")
- navigate('/?welcome=true')
+ navigate('/home')
}
const handleSendInvites = async () => {
@@ -177,7 +177,7 @@ export function WelcomeStep3() {
await onboardingApi.updateStep({ step: 3, action: 'skip' })
await fetchUser()
toast.success("You're all set!")
- navigate('/?welcome=true')
+ navigate('/home')
} catch {
setError('Could not save. Please try again.')
setSubmitting(null)
diff --git a/frontend/src/pages/welcome/__tests__/WelcomeStep3.test.tsx b/frontend/src/pages/welcome/__tests__/WelcomeStep3.test.tsx
index c90be2dd..b6d0788e 100644
--- a/frontend/src/pages/welcome/__tests__/WelcomeStep3.test.tsx
+++ b/frontend/src/pages/welcome/__tests__/WelcomeStep3.test.tsx
@@ -88,7 +88,7 @@ function renderPage() {
} />
- dashboard} />
+ dashboard} />
,
)