Skip to content

feat(onboarding): let users permanently skip the onboarding flow - #3525

Open
baktun14 wants to merge 1 commit into
mainfrom
feat/onboarding-add-permanent-skip
Open

feat(onboarding): let users permanently skip the onboarding flow#3525
baktun14 wants to merge 1 commit into
mainfrom
feat/onboarding-add-permanent-skip

Conversation

@baktun14

@baktun14 baktun14 commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

Why

The new onboarding flow has no exit. An authenticated user with a managed wallet but zero leases is force-routed to /onboarding, and "onboarded" is derived purely from on-chain lease count, so a broken auto-deploy can strand the user on the stripped /new-deployment/configure screen with only a logout. This adds a permanent, cross-device skip so the gate never routes them back in.

Closes CON-750

What

Backend (apps/api)

  • New nullable onboardingSkippedAt timestamp on the userSetting table (migration 0034), exposed on /v1/user/me.
  • New idempotent POST /v1/user/skipOnboarding that sets the flag once via a set-if-null update, so the original skip time is never overwritten by repeat calls.

Frontend (apps/deploy-web)

  • useSkipOnboarding hook: tracks onboarding_skipped, persists the flag, awaits a session refresh, then routes to the deployments list (navigates even if the refresh fails; skips navigation if the persist fails).
  • The onboarding gate (RequireOnboarding) and the stripped-chrome hook (useOnboardingChrome) both treat a skipped user as onboarded, known as soon as identity is, so a skipper never waits on leases and is never sent back into the funnel.
  • Shared SkipOnboardingButton on the picker header (source: "picker") and the minimal nav of the auto-deploy screen (source: "auto_deploy").

Skipping is pure navigation and touches nothing on-chain: any orphaned in-flight deployment is left intact for the user to close from /deployments.

The legacy /signup stepper is intentionally untouched (out of scope; slated for removal).

Summary by CodeRabbit

  • New Features

    • Added a Skip option throughout onboarding and deployment flows.
    • Skipping onboarding records the choice and redirects users to deployments.
    • Skipped users can access the app without lease-based onboarding delays or redirects.
    • Added analytics tracking for onboarding skips.
  • Bug Fixes

    • Skip actions are disabled while processing, with errors handled safely.

Adds a permanent, cross-device skip to the new onboarding flow so a
no-lease user is no longer trapped in the picker or the stripped
auto-deploy screen.

Backend: new nullable `onboardingSkippedAt` timestamp on the user
settings table (migration 0034), exposed on `/v1/user/me`, and a new
idempotent `POST /v1/user/skipOnboarding` that sets it once via a
set-if-null update so the original skip time is never overwritten.

Frontend: a `useSkipOnboarding` hook that records the event, persists
the flag, awaits a session refresh, then routes to the deployments
list; the onboarding gate and stripped-chrome hook both treat a skipped
user as onboarded; and a shared SkipOnboardingButton on the picker and
the minimal nav of the auto-deploy screen.

Closes CON-750
@codecov

codecov Bot commented Jul 27, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 96.87500% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 73.23%. Comparing base (627ad0c) to head (50166fa).
✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
apps/deploy-web/src/components/layout/Nav.tsx 0.00% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #3525      +/-   ##
==========================================
- Coverage   74.18%   73.23%   -0.96%     
==========================================
  Files        1142     1054      -88     
  Lines       29721    27399    -2322     
  Branches     7447     6990     -457     
==========================================
- Hits        22049    20066    -1983     
+ Misses       6771     6462     -309     
+ Partials      901      871      -30     
Flag Coverage Δ *Carryforward flag
api 87.41% <ø> (ø) Carriedforward from 627ad0c
deploy-web 63.73% <96.87%> (+0.05%) ⬆️
log-collector ?
notifications 93.84% <ø> (ø) Carriedforward from 627ad0c
provider-console 81.38% <ø> (ø) Carriedforward from 627ad0c
provider-inventory ?
provider-proxy 88.17% <ø> (ø) Carriedforward from 627ad0c
tx-signer ?

*This pull request uses carry forward flags. Click here to find out more.

Files with missing lines Coverage Δ
apps/api/src/app/console.ts 0.00% <ø> (ø)
...i/src/core/services/job-queue/job-queue.service.ts 93.39% <ø> (ø)
...s/api/src/user/controllers/user/user.controller.ts 42.42% <ø> (ø)
...pps/api/src/user/model-schemas/user/user.schema.ts 100.00% <ø> (ø)
apps/api/src/user/schemas/user.schema.ts 100.00% <ø> (ø)
apps/api/src/user/services/user/user.service.ts 95.00% <ø> (ø)
...deploy-web/src/components/layout/TopNav/TopNav.tsx 90.90% <100.00%> (+0.21%) ⬆️
...ponents/onboarding-picker/OnboardingPickerPage.tsx 96.36% <ø> (ø)
...cker/SkipOnboardingButton/SkipOnboardingButton.tsx 100.00% <100.00%> (ø)
...onboarding/RequireOnboarding/RequireOnboarding.tsx 100.00% <100.00%> (ø)
... and 4 more

... and 91 files with indirect coverage changes

🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@coderabbitai

coderabbitai Bot commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

Adds a persisted onboarding-skip timestamp, authenticated API endpoint, client-side skip controls and mutation handling, analytics tracking, and onboarding gate behavior for skipped users.

Changes

Onboarding skip flow

Layer / File(s) Summary
Persist onboarding-skip state
apps/api/drizzle/*, apps/api/src/user/model-schemas/*, apps/api/src/user/services/*, apps/api/test/seeders/*, apps/api/src/app/console.ts, apps/api/src/core/services/job-queue/*, apps/deploy-web/src/types/user.ts
Adds nullable onboardingSkippedAt storage and user shapes, initializes execution contexts and seed data, and updates the user timestamp only when it is unset.
Expose and execute skip action
apps/api/src/user/controllers/*, apps/api/src/user/routes/*, apps/deploy-web/src/hooks/useSkipOnboarding.*, apps/deploy-web/src/components/onboarding-picker/SkipOnboardingButton/*, apps/deploy-web/src/services/analytics/*
Adds the authenticated POST /v1/user/skipOnboarding route, client persistence and session refresh behavior, analytics tracking, and a disabled-while-pending skip button.
Apply skipped state in navigation and gates
apps/deploy-web/src/components/layout/*, apps/deploy-web/src/components/onboarding-picker/*, apps/deploy-web/src/components/onboarding/RequireOnboarding/*, apps/deploy-web/src/hooks/useOnboardingChrome.*
Renders skip controls in minimal and picker headers, and treats skipped users as already onboarded for routing and chrome decisions without waiting for leases.

Estimated code review effort: 4 (Complex) | ~45 minutes

Possibly related PRs

Suggested reviewers: stalniy

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/onboarding-add-permanent-skip

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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (2)
apps/api/src/user/services/user/user.service.integration.ts (1)

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

Use faker for username instead of Date.now().

username is unique-constrained; millisecond timestamps can collide across parallel workers or fast consecutive creates. userId already uses faker.string.uuid() — do the same here.

♻️ Proposed change
-        username: `test-user-${Date.now()}`,
+        username: `test-user-${faker.string.uuid()}`,

Also applies to: 358-364

🤖 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/api/src/user/services/user/user.service.integration.ts` around lines 342
- 348, Replace the Date.now()-based username values in the userRepository.create
test fixtures with a faker-generated username, matching the existing faker usage
for userId. Apply this change to both create blocks, including the additional
occurrence.
apps/deploy-web/src/components/onboarding/RequireOnboarding/RequireOnboarding.spec.tsx (1)

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

Keep the skipped-user fixture type-checked.

The user mock is created with a broad as never cast, which can hide mismatches with CustomUserProfile. Use mock<CustomUserProfile>({...}) instead so future user-shape changes fail at compile time.

🤖 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/deploy-web/src/components/onboarding/RequireOnboarding/RequireOnboarding.spec.tsx`
around lines 156 - 162, Update the buildDependencies user fixture to construct
the user value with mock<CustomUserProfile> instead of the broad as never cast,
while preserving the existing logged-out, userId, and onboardingSkippedAt
behavior. Ensure the fixture remains type-checked against CustomUserProfile.

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/deploy-web/src/hooks/useSkipOnboarding.ts`:
- Around line 41-42: Prevent useSkipOnboarding from navigating when checkSession
fails: report the refresh error and return before router.push, unless local
skipped state is updated first. Update
apps/deploy-web/src/hooks/useSkipOnboarding.spec.ts lines 37-45 to assert no
navigation occurs after a failed refresh; the hook change is required in
apps/deploy-web/src/hooks/useSkipOnboarding.ts lines 41-42.

---

Nitpick comments:
In `@apps/api/src/user/services/user/user.service.integration.ts`:
- Around line 342-348: Replace the Date.now()-based username values in the
userRepository.create test fixtures with a faker-generated username, matching
the existing faker usage for userId. Apply this change to both create blocks,
including the additional occurrence.

In
`@apps/deploy-web/src/components/onboarding/RequireOnboarding/RequireOnboarding.spec.tsx`:
- Around line 156-162: Update the buildDependencies user fixture to construct
the user value with mock<CustomUserProfile> instead of the broad as never cast,
while preserving the existing logged-out, userId, and onboardingSkippedAt
behavior. Ensure the fixture remains type-checked against CustomUserProfile.
🪄 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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 941167de-19ad-4c97-abe0-bf8892281452

📥 Commits

Reviewing files that changed from the base of the PR and between 627ad0c and 50166fa.

📒 Files selected for processing (27)
  • apps/api/drizzle/0034_add_onboarding_skipped_at.sql
  • apps/api/drizzle/meta/0034_snapshot.json
  • apps/api/drizzle/meta/_journal.json
  • apps/api/src/app/console.ts
  • apps/api/src/core/services/job-queue/job-queue.service.ts
  • apps/api/src/user/controllers/user/user.controller.spec.ts
  • apps/api/src/user/controllers/user/user.controller.ts
  • apps/api/src/user/model-schemas/user/user.schema.ts
  • apps/api/src/user/routes/user-settings/user-settings.router.ts
  • apps/api/src/user/schemas/user.schema.ts
  • apps/api/src/user/services/user/user.service.integration.ts
  • apps/api/src/user/services/user/user.service.spec.ts
  • apps/api/src/user/services/user/user.service.ts
  • apps/api/test/seeders/user.seeder.ts
  • apps/deploy-web/src/components/layout/Nav.tsx
  • apps/deploy-web/src/components/layout/TopNav/TopNav.tsx
  • apps/deploy-web/src/components/onboarding-picker/OnboardingPickerPage.tsx
  • apps/deploy-web/src/components/onboarding-picker/SkipOnboardingButton/SkipOnboardingButton.spec.tsx
  • apps/deploy-web/src/components/onboarding-picker/SkipOnboardingButton/SkipOnboardingButton.tsx
  • apps/deploy-web/src/components/onboarding/RequireOnboarding/RequireOnboarding.spec.tsx
  • apps/deploy-web/src/components/onboarding/RequireOnboarding/RequireOnboarding.tsx
  • apps/deploy-web/src/hooks/useOnboardingChrome.spec.ts
  • apps/deploy-web/src/hooks/useOnboardingChrome.ts
  • apps/deploy-web/src/hooks/useSkipOnboarding.spec.ts
  • apps/deploy-web/src/hooks/useSkipOnboarding.ts
  • apps/deploy-web/src/services/analytics/analytics.service.ts
  • apps/deploy-web/src/types/user.ts

Comment on lines +41 to +42
await checkSession().catch(() => undefined);
router.push(urlService.deploymentList());

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Avoid navigation before the skipped state reaches the gate. A failed session refresh leaves RequireOnboarding with onboardingSkippedAt unset, so navigating a lease-less user immediately re-enters onboarding.

  • apps/deploy-web/src/hooks/useSkipOnboarding.ts#L41-L42: on refresh failure, report the error and return before router.push, or update local user state before navigation.
  • apps/deploy-web/src/hooks/useSkipOnboarding.spec.ts#L37-L45: expect no navigation when refresh fails, unless local skipped state is explicitly updated first.
📍 Affects 2 files
  • apps/deploy-web/src/hooks/useSkipOnboarding.ts#L41-L42 (this comment)
  • apps/deploy-web/src/hooks/useSkipOnboarding.spec.ts#L37-L45
🤖 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/deploy-web/src/hooks/useSkipOnboarding.ts` around lines 41 - 42, Prevent
useSkipOnboarding from navigating when checkSession fails: report the refresh
error and return before router.push, unless local skipped state is updated
first. Update apps/deploy-web/src/hooks/useSkipOnboarding.spec.ts lines 37-45 to
assert no navigation occurs after a failed refresh; the hook change is required
in apps/deploy-web/src/hooks/useSkipOnboarding.ts lines 41-42.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant