Skip to content

feat(frontend): app-first onboarding flow#2552

Open
riderx wants to merge 5 commits into
mainfrom
feat/app-first-onboarding
Open

feat(frontend): app-first onboarding flow#2552
riderx wants to merge 5 commits into
mainfrom
feat/app-first-onboarding

Conversation

@riderx

@riderx riderx commented Jun 19, 2026

Copy link
Copy Markdown
Member

Summary (AI generated)

  • New users are redirected to /onboarding/app instead of /onboarding/organization.
  • App details are collected first and persisted in session storage until the organization is created.
  • Organization onboarding suggests using the app name (editable), or a custom name / website import like before.
  • After org setup, the saved app draft is created automatically and onboarding continues at the choice step.

Motivation (AI generated)

Creating an organization before the app felt backwards for new Capgo users. Most people arrive knowing which app they want to set up, not what their org should be called. This reorder keeps momentum and uses the app name as a sensible default for the org.

Business Impact (AI generated)

  • Smoother first-run experience for new signups
  • Less drop-off between signup and first app creation
  • Org naming becomes a lightweight follow-up instead of a blocking first step

Flow (AI generated)

flowchart LR
  A[Register / Login] --> B[/onboarding/app]
  B --> C[Save app draft in session]
  C --> D[/onboarding/organization]
  D --> E[Create org]
  E --> F[Logo + invite]
  F --> G[Create app from draft]
  G --> H[/app/new?step=choice]
Loading

Media (AI generated)

Docker was not available in the capture environment, so screenshots and WebP were not attached here.

Regenerate locally with:

bun run supabase:start
bun run supabase:db:reset
SUPABASE_SERVICE_KEY="$(grep SUPABASE_SERVICE_KEY .env.test | cut -d= -f2-)" \
CAPGO_MEDIA_EMAIL="media-onboard@capgo.app" \
CAPGO_MEDIA_PASSWORD="CapgoMediaLocal!2026" \
BRANCH=local bun serve:dev

Then in another terminal:

SUPABASE_SERVICE_KEY="$(grep SUPABASE_SERVICE_KEY .env.test | cut -d= -f2-)" \
CAPGO_MEDIA_EMAIL="media-onboard@capgo.app" \
CAPGO_MEDIA_PASSWORD="CapgoMediaLocal!2026" \
node scripts/capture-app-first-onboarding-media.mjs

See docs/pr/app-first-onboarding/README.md.

Test Plan (AI generated)

  • Register a new user and confirm redirect to /onboarding/app
  • Fill app details, continue, and confirm draft appears on organization step
  • Choose "Use {app name}" org mode and create organization
  • Finish invite step and confirm app is created + choice step opens
  • Confirm additional org creation (source=org-switcher) still works without app draft
  • Run bun test:front register spec

Generated with AI

Made with Cursor

Summary by CodeRabbit

Release Notes

  • New Features

    • Added an app-first onboarding experience with a dedicated app onboarding screen, including draft restore/resume and streamlined completion into org setup.
    • Improved onboarding localization and app/org transition step labels.
  • Bug Fixes

    • Updated auth and SSO redirect behavior to consistently send users to app onboarding.
    • Adjusted native purchase-restriction and routing to treat app onboarding paths as restricted.
  • Documentation

    • Added a local guide for generating app-first onboarding media (screenshots/WebP).
  • Tests

    • Updated end-to-end and auth guard tests for the new flow.

New users configure their app first, persist draft data in session storage,
then create an organization with a suggested name from the app before the
app record is created and onboarding continues.

Co-authored-by: Cursor <cursoragent@cursor.com>
@coderabbitai

coderabbitai Bot commented Jun 19, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

Introduces an app-first onboarding sequence where new users configure their app at /onboarding/app before creating an organization. A sessionStorage draft persists app details across the two-step flow. The auth guard now redirects unauthenticated users without organizations to /onboarding/app, and the organization onboarding page reads the draft to create the app upon org completion.

Changes

App-first onboarding flow

Layer / File(s) Summary
Draft persistence and slug utilities
src/utils/onboardingAppDraft.ts, src/utils/onboardingSlug.ts
Defines OnboardingAppDraft interface with user-scoped sessionStorage load/save/clear helpers that use a STORAGE_KEY_PREFIX:<userId> key pattern, image-to-dataURL converters (fileToDataUrl, remoteImageToDataUrl), and slug normalization utilities (slugifyOnboardingSegment, trimTrailingDots).
Auth guard redirects to /onboarding/app and route registration
src/modules/auth.ts, src/route-map.d.ts, tests/auth-sso-provisioning.unit.test.ts
Updates shouldRedirectToOrgOnboarding to exempt /onboarding/app, changes both redirect destinations from /onboarding/organization to /onboarding/app while preserving to query parameters, registers the new route in RouteNamedMap and _RouteFileInfoMap, and updates auth-sso-provisioning unit tests.
New /onboarding/app page with logout
src/pages/onboarding/app.vue
Creates the /onboarding/app page with auth middleware, onMounted redirect for unauthenticated users, a logout button with double-click guard that clears the onboarding app draft before signing out, renders AppOnboardingFlow with preOrg mode enabled, and configures displayStore navigation title/back URL.
AppOnboardingFlow pre-org mode and draft handling
src/components/dashboard/AppOnboardingFlow.vue
Extends component with preOrg prop that enables draft restoration on mount, adds intent/organization/setup step UI, manages pre-org state (selectedIntent, orgMode, orgNameInput, estimatedUsersIndex), derives app ID suggestions from appName via slugifyOnboardingSegment, adds ensureValidAppId() validation, implements createOrganizationAndApp() flow with draft clearing, and adds pre-org template sections for intent selection, organization mode buttons, and conditional step visibility.
Onboarding localization strings
messages/en.json
Updates app-onboarding-title-first, adds app-onboarding-appid-invalid-format validation message, updates organization-onboarding-subtitle to reference post-app flow, and adds new keys for pre-org organization mode selection, app-name reuse option, finish/continue labels, and app-to-organization transition messaging.
App creation from draft with icon upload
src/services/onboardingAppCreate.ts, src/utils/appId.ts
Adds createOnboardingAppFromDraft which builds candidate app_id values, invokes Supabase app function with retry logic on 409 app-id conflicts, uploads app icon to Supabase Storage with upsert, updates icon_url, and returns the created app with optional appIdFeedback. Includes isValidAppId utility for reverse-domain format validation.
Organization page draft loading and app creation
src/pages/onboarding/organization.vue
Loads appDraft on mount using user-scoped keys, redirects to /onboarding/app when no draft exists and not in additional-org flow, shows app preview card and draft-aware subtitle/back navigation, adds app-name mode option to org creation, calls createOnboardingAppFromDraft during finishOnboarding, clears persisted draft, and navigates to /app/new?resume&step=choice; includes draft-aware orgNameInput prefilling via watcher.
Native compliance path updates
src/services/nativeCompliance.ts
Adds /onboarding/app to nativeExternalPurchaseRestrictedPaths and extends getNativeExternalPurchaseRedirect to map /onboarding/app and /onboarding/app/* to /scan redirect.
Registration E2E test for app-first flow
playwright/e2e/register.spec.ts
Updates primary registration spec to traverse app-first onboarding: waits for /onboarding/app, selects intent and existing-no option, fills app name with data-test selector, proceeds through protected redirect assertion, continues via app-name org mode, creates org, and verifies post-creation onboarding state. Adjusts logout test to wait for /onboarding/app.
App-first onboarding media capture automation
scripts/capture-app-first-onboarding-media.mjs, docs/pr/app-first-onboarding/README.md
Adds script to automate screenshot/video capture of app-first onboarding: provisions demo Supabase user via admin API (when SUPABASE_SERVICE_KEY available), authenticates via UI, drives onboarding steps using data-test selectors, captures screenshots, records video with Playwright, and converts webm to webp via ffmpeg/img2webp. Includes README documenting local workflow with environment variables and expected output files.

Sequence Diagram

sequenceDiagram
  participant User
  participant AuthGuard as auth.ts guard
  participant AppPage as /onboarding/app
  participant AppFlow as AppOnboardingFlow (preOrg)
  participant DraftStorage as sessionStorage
  participant OrgPage as /onboarding/organization
  participant CreateService as createOnboardingAppFromDraft
  participant Supabase as Supabase API

  User->>AuthGuard: navigate (no organization)
  AuthGuard->>AppPage: redirect to /onboarding/app
  AppPage->>AppFlow: render with preOrg=true
  AppFlow->>DraftStorage: loadOnboardingAppDraft(userId)
  User->>AppFlow: select intent, choose existing-no, fill app name
  AppFlow->>DraftStorage: saveOnboardingAppDraft(draft, userId)
  AppFlow->>OrgPage: navigate to /onboarding/organization
  OrgPage->>DraftStorage: loadOnboardingAppDraft(userId)
  DraftStorage-->>OrgPage: OnboardingAppDraft
  OrgPage->>User: show app preview, org form, app-name mode option
  User->>OrgPage: fill org details, click finish
  OrgPage->>CreateService: createOnboardingAppFromDraft(draft, orgId, orgName)
  CreateService->>Supabase: POST /functions/app (with candidate app_ids)
  CreateService->>Supabase: upload icon to Storage org/<orgId>/<appId>/icon
  CreateService->>Supabase: update apps.icon_url
  CreateService-->>OrgPage: {app, appIdFeedback}
  OrgPage->>DraftStorage: clearOnboardingAppDraft(userId)
  OrgPage->>User: navigate to /app/new?resume&step=choice
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~75 minutes

Possibly related PRs

  • Cap-go/capgo#1863: The main PR's onboarding flow creates apps by invoking the public/app serverless function, which the retrieved PR tightens authorization for via the new org.create_app RBAC permission.
  • Cap-go/capgo#2190: Both PRs modify src/components/dashboard/AppOnboardingFlow.vue and messages/en.json onboarding copy to adjust the app onboarding UI and flow.
  • Cap-go/capgo#2488: Both PRs change src/services/nativeCompliance.ts to treat /onboarding/app as a native-external-purchase restricted route and redirect it to /scan.
🚥 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
Title check ✅ Passed The title 'feat(frontend): app-first onboarding flow' directly and concisely describes the main change: implementing an app-first onboarding flow for the frontend, which is the primary objective across all modified files.
Description check ✅ Passed The PR description includes a comprehensive summary, clear motivation, business impact, flow diagram, and test plan. While media screenshots were not generated locally, the description explains why and provides reproduction steps, satisfying the template requirements.
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.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch

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

Comment thread scripts/capture-app-first-onboarding-media.mjs Fixed
@codspeed-hq

codspeed-hq Bot commented Jun 19, 2026

Copy link
Copy Markdown
Contributor

Merging this PR will not alter performance

✅ 43 untouched benchmarks
⏩ 2 skipped benchmarks1


Comparing feat/app-first-onboarding (41cab50) with main (921791a)

Open in CodSpeed

Footnotes

  1. 2 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports.

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: cbe34212b0

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread playwright/e2e/register.spec.ts
Comment thread src/services/onboardingAppCreate.ts Outdated
Fix pre-org onboarding loading, add missing data-test hooks, improve the
local capture script auth/worktree handling, and attach screenshots plus
an animated WebP walkthrough.

Co-authored-by: Cursor <cursoragent@cursor.com>
Comment thread scripts/capture-app-first-onboarding-media.mjs Fixed
Comment thread scripts/capture-app-first-onboarding-media.mjs Fixed

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 3ade240f10

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/modules/auth.ts
Update auth guard tests for /onboarding/app redirects, fix SonarCloud
reliability issues in AppOnboardingFlow, and share slugify helpers to reduce
new-code duplication.

Co-authored-by: Cursor <cursoragent@cursor.com>

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 9818138d6a

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/utils/onboardingAppDraft.ts Outdated
Comment thread src/components/dashboard/AppOnboardingFlow.vue
Remove dead ternary and redundant icon assignment, and reuse shared
slugify helper to clear reliability and duplication findings.

Co-authored-by: Cursor <cursoragent@cursor.com>

@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: 7

🤖 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 `@docs/pr/app-first-onboarding/README.md`:
- Around line 5-9: The command examples in this documentation section use bun
directly (bun run supabase:start, bun run supabase:db:reset, bun backend) but
should follow the npx convention as per coding guidelines for front-facing
instructions. Replace all direct bun command invocations with their npx-wrapped
equivalents throughout the affected sections. This same formatting issue applies
to multiple locations in the file beyond the initial lines shown, so ensure
consistency across all command examples in the documentation.

In `@playwright/e2e/register.spec.ts`:
- Line 53: The waitForURL call with the regex pattern is too strict about query
parameter ordering, assuming resume appears before step which can cause flaky
test failures. Modify the regex pattern to match the URL regardless of query
parameter order, either by creating a pattern that matches both possible
orderings (resume then step, or step then resume) or by using a more flexible
matching approach that validates both query parameters are present without
depending on their sequence.

In `@scripts/capture-app-first-onboarding-media.mjs`:
- Around line 114-119: The code currently uses videos[0] from the readdirSync
result to select the input video file, but readdirSync does not guarantee any
particular order, so this could convert stale media instead of the latest
recording. Sort the videos array by file modification time in descending order
before selecting the first element, ensuring that the newest recording is
deterministically picked for conversion. Check the file stats using statSync for
each video in the outDir and sort based on mtimeMs to ensure the most recently
created video is used as the input for the conversion.

In `@src/components/dashboard/AppOnboardingFlow.vue`:
- Around line 549-553: The router.push call in the handleContinue method uses a
fixed path string that loses existing query parameters from the current route.
Modify the navigation to preserve query context by using an object format for
router.push that includes the target path along with the current route's query
parameters, ensuring the `to` parameter and other navigation context are
maintained when moving to the organization onboarding step.

In `@src/modules/auth.ts`:
- Around line 389-391: The onboarding redirect call in the condition checking
organizationsLoaded and !organizationStore.hasOrganizations is not preserving
the original destination URL that the user was trying to access. Modify the
next('/onboarding/app') call to include the to.fullPath as a query parameter in
the redirect, ensuring users are returned to their intended destination after
completing onboarding, consistent with how the redirect is handled in earlier
branches of this same navigation guard.

In `@src/services/onboardingAppCreate.ts`:
- Around line 69-115: The uploadIconFromDraft function currently allows
unhandled errors from icon decoding, fetching, or uploading to bubble up and
fail app creation, causing duplicate app IDs on user retries. Wrap the entire
body of the uploadIconFromDraft function in a try-catch block to ensure any
errors during icon processing are caught and logged without interrupting the app
creation flow. In the catch block, log the error with console.error and return
early so the function fails silently, making icon upload a best-effort operation
that does not block app creation success.

In `@src/utils/onboardingAppDraft.ts`:
- Around line 39-43: The optional string fields iosStoreUrl, androidStoreUrl,
iconDataUrl, storeIconDataUrl, and storeScreenshotUrl in the deserialization
logic lack runtime type validation. Add type checks to ensure each of these
fields from the parsed object is either a string or null/undefined before
assigning them. This prevents corrupted sessionStorage values from propagating
through the onboarding flow and causing crashes during string operations later.
Validate the type of each field explicitly, either through individual checks or
a helper function, to guarantee only valid string or null values are assigned.
🪄 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: ASSERTIVE

Plan: Pro

Run ID: e9c9d1d1-4433-45cc-be2e-03f901df1774

📥 Commits

Reviewing files that changed from the base of the PR and between bb5cdad and 9818138.

⛔ Files ignored due to path filters (4)
  • docs/pr/app-first-onboarding/01-app-onboarding.png is excluded by !**/*.png
  • docs/pr/app-first-onboarding/02-app-details-filled.png is excluded by !**/*.png
  • docs/pr/app-first-onboarding/03-organization-onboarding.png is excluded by !**/*.png
  • docs/pr/app-first-onboarding/04-organization-app-name-mode.png is excluded by !**/*.png
📒 Files selected for processing (14)
  • docs/pr/app-first-onboarding/README.md
  • docs/pr/app-first-onboarding/app-first-onboarding.webp
  • messages/en.json
  • playwright/e2e/register.spec.ts
  • scripts/capture-app-first-onboarding-media.mjs
  • src/components/dashboard/AppOnboardingFlow.vue
  • src/modules/auth.ts
  • src/pages/onboarding/app.vue
  • src/pages/onboarding/organization.vue
  • src/route-map.d.ts
  • src/services/onboardingAppCreate.ts
  • src/utils/onboardingAppDraft.ts
  • src/utils/onboardingSlug.ts
  • tests/auth-sso-provisioning.unit.test.ts
🔗 Linked repositories identified

CodeRabbit considers these linked repositories for cross-repo context during reviews:

  • Cap-go/capacitor-updater (manual)

Comment thread docs/pr/app-first-onboarding/README.md
Comment thread playwright/e2e/register.spec.ts Outdated
Comment thread scripts/capture-app-first-onboarding-media.mjs Outdated
Comment thread src/components/dashboard/AppOnboardingFlow.vue Outdated
Comment thread src/modules/auth.ts
Comment thread src/services/onboardingAppCreate.ts
Comment thread src/utils/onboardingAppDraft.ts Outdated
@coderabbitai coderabbitai Bot added the codex label Jun 20, 2026
Unify onboarding on one page with review fixes: native compliance for
/onboarding/app, user-scoped drafts, app ID validation, images-bucket
icon upload, auth redirect query preservation, and safer media capture.

Co-authored-by: Cursor <cursoragent@cursor.com>
@riderx riderx deployed to deepsec-pr June 20, 2026 07:09 — with GitHub Actions Active

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 41cab50313

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +111 to +112
const cliCommand = computed(() => `npx @capgo/cli@latest ${cliSubcommand.value} ${apiKey.value ?? '[APIKEY]'}${localCommand}`)
const redactedCliCommand = computed(() => `npx @capgo/cli@latest ${cliSubcommand.value} [YOUR_CAPGO_API_KEY]${localCommand}`)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Pass the API key with --apikey for build init

When the user selects the Builder intent, this generates npx @capgo/cli@latest build init <key>, but I checked cli/src/index.ts and build init is declared as .command('init') with .option('-a, --apikey <apikey>') and no positional API-key argument. In that Builder onboarding path the copied command and AI prompt therefore do not populate options.apikey (and may be rejected as an extra argument), so the setup will not link the user's Capgo account; emit build init -a <key> for this subcommand.

Useful? React with 👍 / 👎.

@sonarqubecloud

Copy link
Copy Markdown

Quality Gate Failed Quality Gate failed

Failed conditions
3.2% Duplication on New Code (required ≤ 3%)

See analysis details on SonarQube Cloud

@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: 4

🤖 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 `@src/components/dashboard/AppOnboardingFlow.vue`:
- Line 37: The import statements in AppOnboardingFlow.vue do not follow the
required alphabetical ordering as flagged by the linter. Fix the import order by
ensuring the Lucide icon imports are sorted alphabetically among themselves, and
move the `~/utils/appId` import (which contains `isValidAppId`) to appear before
the `~/utils/onboardingAppDraft` import. Run `bun lint:fix` to automatically
resolve these import ordering violations before validation.
- Around line 191-204: The linter requires additional newline spacing for
consistency with project code style in multiple locations within the
AppOnboardingFlow.vue file. Add blank lines to separate logical sections: after
the planStops computed property definition (around the closing brace before the
return statement), between the userCountStops and selectedUserCountStop computed
properties, and between other computed properties like canShowOrgDetails and
canCreatePreOrgOrganization. You can fix this automatically by running bun
lint:fix, or manually add the required newlines to match the project's
formatting standards for computed property separation.
- Line 196: The return statement in AppOnboardingFlow.vue uses loose equality
operator `==` when comparing planStops.length with planNameOrder.length, which
can lead to unexpected type coercion. Replace the `==` operator with `===`
(strict equality) in the ternary expression that returns either planStops or
fallbackUserCountStops to ensure type-safe comparison.

In `@src/services/onboardingAppCreate.ts`:
- Around line 83-89: In the base64 binary conversion logic where Uint8Array is
created from the binary string returned by atob(), replace the charCodeAt(0)
method call within the mapping function with charCodeAt(0) instead. The
charCodeAt(0) API is semantically correct for extracting byte values from
base64-decoded strings, as it directly returns the byte value without the
possibility of returning undefined, eliminating the need for the ?? 0 fallback
operator.
🪄 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: ASSERTIVE

Plan: Pro

Run ID: 80b1d9b2-0919-47fe-831b-e9a56bed874c

📥 Commits

Reviewing files that changed from the base of the PR and between 9525dcd and 41cab50.

⛔ Files ignored due to path filters (4)
  • docs/pr/app-first-onboarding/01-intent-step.png is excluded by !**/*.png
  • docs/pr/app-first-onboarding/02-app-details-filled.png is excluded by !**/*.png
  • docs/pr/app-first-onboarding/03-organization-step.png is excluded by !**/*.png
  • docs/pr/app-first-onboarding/04-setup-command.png is excluded by !**/*.png
📒 Files selected for processing (13)
  • docs/pr/app-first-onboarding/README.md
  • docs/pr/app-first-onboarding/app-first-onboarding.webp
  • messages/en.json
  • playwright/e2e/register.spec.ts
  • scripts/capture-app-first-onboarding-media.mjs
  • src/components/dashboard/AppOnboardingFlow.vue
  • src/modules/auth.ts
  • src/pages/onboarding/app.vue
  • src/pages/onboarding/organization.vue
  • src/services/nativeCompliance.ts
  • src/services/onboardingAppCreate.ts
  • src/utils/appId.ts
  • src/utils/onboardingAppDraft.ts
🔗 Linked repositories identified

CodeRabbit considers these linked repositories for cross-repo context during reviews:

  • Cap-go/capacitor-updater (manual)

clearOnboardingAppDraft,
loadOnboardingAppDraft,
} from '~/utils/onboardingAppDraft'
import { isValidAppId } from '~/utils/appId'

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.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Fix import order as flagged by linter.

The linter indicates import order violations that should be resolved before commit.

🧹 Run lint:fix to resolve

As per coding guidelines, run bun lint:fix before validation to automatically fix import ordering and other style issues.

Expected order:

  • Line 21: Lucide icon imports should be sorted alphabetically
  • Line 37: ~/utils/appId should come before ~/utils/onboardingAppDraft

Also applies to: 21-25

🧰 Tools
🪛 GitHub Check: Run tests

[failure] 37-37:
Expected "/utils/appId" to come before "/utils/onboardingAppDraft"

🤖 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 `@src/components/dashboard/AppOnboardingFlow.vue` at line 37, The import
statements in AppOnboardingFlow.vue do not follow the required alphabetical
ordering as flagged by the linter. Fix the import order by ensuring the Lucide
icon imports are sorted alphabetically among themselves, and move the
`~/utils/appId` import (which contains `isValidAppId`) to appear before the
`~/utils/onboardingAppDraft` import. Run `bun lint:fix` to automatically resolve
these import ordering violations before validation.

Source: Linters/SAST tools

Comment on lines +191 to +204
if (!plan?.mau) return []
const mau = Number(plan.mau)
if (!Number.isFinite(mau) || mau <= 0) return []
return [{ value: mau, label: formatUserCount(mau, plan.name === 'Enterprise'), planName: plan.name }]
})
return planStops.length == planNameOrder.length ? planStops : fallbackUserCountStops
})
const selectedUserCountStop = computed<UserCountStop | null>(() => estimatedUsersIndex.value === null ? null : userCountStops.value[Math.min(estimatedUsersIndex.value, userCountStops.value.length - 1)] ?? null)
const canShowOrgDetails = computed(() => orgMode.value !== null)
const canCreatePreOrgOrganization = computed(() => {
if (!orgMode.value || !orgNameInput.value.trim()) return false
if (existingApp.value === true) return selectedUserCountStop.value !== null
return true
})

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.

🧹 Nitpick | 🔵 Trivial | 💤 Low value

Add missing newlines per linter requirements.

The linter flagged multiple locations needing newline spacing for consistency with the project's code style.

Run bun lint:fix to automatically apply the required newline formatting throughout the changed sections.

Also applies to: 223-232

🧰 Tools
🪛 GitHub Check: Run tests

[failure] 202-202:
Expect newline after if


[failure] 201-201:
Expect newline after if


[failure] 196-196:
Expected '===' and instead saw '=='


[failure] 193-193:
Expect newline after if


[failure] 191-191:
Expect newline after if

🤖 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 `@src/components/dashboard/AppOnboardingFlow.vue` around lines 191 - 204, The
linter requires additional newline spacing for consistency with project code
style in multiple locations within the AppOnboardingFlow.vue file. Add blank
lines to separate logical sections: after the planStops computed property
definition (around the closing brace before the return statement), between the
userCountStops and selectedUserCountStop computed properties, and between other
computed properties like canShowOrgDetails and canCreatePreOrgOrganization. You
can fix this automatically by running bun lint:fix, or manually add the required
newlines to match the project's formatting standards for computed property
separation.

Source: Linters/SAST tools

if (!Number.isFinite(mau) || mau <= 0) return []
return [{ value: mau, label: formatUserCount(mau, plan.name === 'Enterprise'), planName: plan.name }]
})
return planStops.length == planNameOrder.length ? planStops : fallbackUserCountStops

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.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Replace loose equality with strict equality.

Line 196 uses == instead of ===, which can cause unexpected type coercion bugs.

🔧 Suggested fix
-  return planStops.length == planNameOrder.length ? planStops : fallbackUserCountStops
+  return planStops.length === planNameOrder.length ? planStops : fallbackUserCountStops
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
return planStops.length == planNameOrder.length ? planStops : fallbackUserCountStops
return planStops.length === planNameOrder.length ? planStops : fallbackUserCountStops
🧰 Tools
🪛 GitHub Check: Run tests

[failure] 196-196:
Expected '===' and instead saw '=='

🤖 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 `@src/components/dashboard/AppOnboardingFlow.vue` at line 196, The return
statement in AppOnboardingFlow.vue uses loose equality operator `==` when
comparing planStops.length with planNameOrder.length, which can lead to
unexpected type coercion. Replace the `==` operator with `===` (strict equality)
in the ternary expression that returns either planStops or
fallbackUserCountStops to ensure type-safe comparison.

Source: Linters/SAST tools

Comment on lines +83 to +89
const contentType = /^data:([^;]+)/.exec(header)?.[1] ?? 'image/png'
if (!payload)
return

const binary = atob(payload)
const bytes = Uint8Array.from(binary, char => char.codePointAt(0) ?? 0)
blob = new Blob([bytes], { type: contentType })

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.

🧹 Nitpick | 🔵 Trivial | ⚡ Quick win

Use charCodeAt(0) instead of codePointAt(0) for base64 binary conversion.

The atob() function returns a binary string where each character represents a byte (0–255). To extract byte values, charCodeAt(0) is the semantically correct API—it always returns a number and directly maps to the character's byte value. codePointAt(0) is intended for Unicode code points and can return undefined, requiring the ?? 0 fallback.

🔧 Proposed fix
-      const bytes = Uint8Array.from(binary, char => char.codePointAt(0) ?? 0)
+      const bytes = Uint8Array.from(binary, char => char.charCodeAt(0))
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const contentType = /^data:([^;]+)/.exec(header)?.[1] ?? 'image/png'
if (!payload)
return
const binary = atob(payload)
const bytes = Uint8Array.from(binary, char => char.codePointAt(0) ?? 0)
blob = new Blob([bytes], { type: contentType })
const contentType = /^data:([^;]+)/.exec(header)?.[1] ?? 'image/png'
if (!payload)
return
const binary = atob(payload)
const bytes = Uint8Array.from(binary, char => char.charCodeAt(0))
blob = new Blob([bytes], { type: contentType })
🧰 Tools
🪛 OpenGrep (1.22.0)

[ERROR] 83-83: Dynamic command passed to child_process.exec/execSync. Use child_process.execFile or spawn with an argument array instead.

(coderabbit.command-injection.exec-js)

🤖 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 `@src/services/onboardingAppCreate.ts` around lines 83 - 89, In the base64
binary conversion logic where Uint8Array is created from the binary string
returned by atob(), replace the charCodeAt(0) method call within the mapping
function with charCodeAt(0) instead. The charCodeAt(0) API is semantically
correct for extracting byte values from base64-decoded strings, as it directly
returns the byte value without the possibility of returning undefined,
eliminating the need for the ?? 0 fallback operator.

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

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants