Merged
Conversation
Greptile SummaryThis PR introduces a redesigned onboarding flow that front-loads the Instagram connection and shows users a live AI-generated DM reply preview before collecting their profile and business details. It also consolidates the sidekick onboarding from 5 steps to 4 by merging "Your Offers" and "What You Sell" into a single step, and upgrades the Instagram OAuth callback to support a cookie-based dynamic Key changes:
Confidence Score: 2/5
Important Files Changed
Sequence DiagramsequenceDiagram
participant U as User
participant OP as Onboarding Page
participant IG_API as /api/auth/instagram
participant IG_CB as /api/auth/instagram/callback
participant Instagram as Instagram OAuth
participant SA as Server Actions
U->>OP: Visit /onboarding (step 0)
OP->>SA: getInstagramOnboardingState()
SA-->>OP: { connected: false }
U->>IG_API: GET /api/auth/instagram?returnTo=/onboarding
IG_API->>IG_API: normalizeReturnTo("/onboarding")
IG_API->>IG_API: Set pilot_instagram_return_to cookie
IG_API-->>Instagram: Redirect to OAuth URL
Instagram-->>IG_CB: GET /callback?code=...
IG_CB->>IG_CB: Read & delete return_to cookie
IG_CB->>Instagram: exchangeCodeForAccessToken()
Instagram-->>IG_CB: accessToken, appScopedUserId
IG_CB->>Instagram: fetchInstagramProfile()
Instagram-->>IG_CB: username, user_id
IG_CB->>Instagram: exchangeLongLivedInstagramToken()
Instagram-->>IG_CB: longLivedToken
IG_CB->>SA: saveInstagramConnection()
SA-->>IG_CB: { success: true }
IG_CB-->>OP: Redirect to /onboarding?success=instagram_connected
OP->>SA: getInstagramOnboardingState()
SA-->>OP: { connected: true, username }
OP->>OP: setActiveStep(1) — advance to Preview step
OP->>SA: prepareInstagramPreview()
SA->>Instagram: fetchConversationsForSync()
Instagram-->>SA: conversations[]
SA->>SA: getPersonalizedAutoReplyPrompt()
SA->>SA: generateText() via Gemini
SA-->>OP: { data: { previewMessages, replyPreview, ... } }
OP->>OP: Show DM preview + AI reply
U->>OP: Continue → steps 2-4 (personal info, usage, business)
OP->>SA: updateOnboardingStep() × 3
OP->>SA: completeOnboarding()
OP-->>U: Redirect to /sidekick-onboarding
Last reviewed commit: 0954fe5 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Greptile Summary
This PR introduces a redesigned onboarding flow that prepends two new steps — Instagram connect and an AI-generated DM preview — before the existing profile/goals questionnaire, then redirects users to a sidekick onboarding page. On the sidekick side, the "Offers" and "What You Sell" steps are merged into one combined step, reducing total steps from 5 to 4. A new
instagram-auth.tsutility centralises shared OAuth helpers, and the Instagram auth routes now support a cookie-basedreturnTomechanism so the user lands back at the correct page after connecting.Key changes:
prepareInstagramPreviewandgetInstagramOnboardingStatefetch real Instagram DM context and generate an AI reply preview during onboarding.onboarding/page.tsxgains two new steps (Instagram connect at index 0, preview at index 1) and shifts the original three questionnaire steps to indices 2–4.sidekick-onboarding/page.tsxconsolidates initialization into a singlePromise.all, adds anisMountedguard, and merges steps 1 and 2.returnToin anhttpOnlycookie and redirect back to the originating page on success or failure, rather than always going to/settings.instagram-auth.tsextracted as a shared module — fixing the previously flaggednormalizeReturnToduplication.Issues found:
business_typevalue format regression (onboarding/page.tsx): The radio group now stores raw option strings (e.g."Coach/Consultant","SaaS") instead of theoptionToValue-normalised forms ("coach_consultant","saas") used previously. Any user whosebusiness_typewas saved under the old format will see a blank (unselected) radio group on return, and the "Other" conditional (watchedBusinessType === "Other") won't fire for values stored as"other". All other radio groups in the same file still useoptionToValue, making this inconsistent.INSTAGRAM_RETURN_TO_COOKIEconstant duplicated (route.tsandcallback/route.ts): The string"pilot_instagram_return_to"is defined identically in both files rather than exported from the sharedinstagram-auth.ts. A one-sided rename would silently break the OAuth flow.Confidence Score: 2/5
business_typevalue format regression, which will silently break pre-fill for any user with existing partial onboarding data.business_typeradio group now stores raw option strings instead of theoptionToValue-normalised values used by every other field — and by the existing DB rows. This is a silent data-mismatch regression affecting returning/partial-onboarding users. The duplicated cookie constant is a lower-severity maintenance hazard but not immediately breaking.apps/app/src/app/(onboarding)/onboarding/page.tsx— specifically thebusiness_typeradio group refactor and how it interacts with pre-filled data fromcheckOnboardingStatusAndPrefill.Important Files Changed
prepareInstagramPreviewandgetInstagramOnboardingStateserver actions. Logic is well-structured with fallbacks and error boundaries. No new critical issues beyond the previously flaggedmessage.fromguard.business_typeradio values changed fromoptionToValue(option)to raw option strings, breaking pre-fill for any user with previously saved data. Previously flagged infinite-retry loop on preview failure now guarded bypreviewErrorin the effect dependency array.Promise.all, and step indices updated throughout.isMountedguard added for async cleanup. No critical bugs identified.returnTofrom a cookie and uses it for all redirects. Previously-flaggednormalizeReturnToduplication is now fixed via sharedinstagram-auth.ts. TheINSTAGRAM_RETURN_TO_COOKIEstring constant is still duplicated here and in the initiation route.returnTofrom search params into anhttpOnlycookie before redirecting to Instagram. Cookie attributes (sameSite: "lax", shortmaxAge) are appropriate for OAuth.INSTAGRAM_RETURN_TO_COOKIEconstant is duplicated from the callback route.normalizeInstagramReturnTo,getInstagramAppBaseUrl, andgetInstagramCallbackUrl. The open-redirect guard innormalizeInstagramReturnTois thorough and correct.Sequence Diagram
sequenceDiagram participant User participant OnboardingPage participant InstagramRoute as /api/auth/instagram participant Instagram participant CallbackRoute as /api/auth/instagram/callback participant OnboardingActions User->>OnboardingPage: Visit /onboarding (Step 0) User->>OnboardingPage: Click "Connect Instagram" OnboardingPage->>InstagramRoute: GET /api/auth/instagram?returnTo=/onboarding InstagramRoute->>InstagramRoute: Store returnTo in httpOnly cookie InstagramRoute->>Instagram: Redirect to Instagram OAuth URL Instagram->>CallbackRoute: GET /api/auth/instagram/callback?code=... CallbackRoute->>CallbackRoute: Read returnTo cookie & delete it CallbackRoute->>Instagram: Exchange code for access token CallbackRoute->>Instagram: Exchange for long-lived token CallbackRoute->>OnboardingActions: saveInstagramConnection() CallbackRoute->>OnboardingPage: Redirect to /onboarding?success=instagram_connected OnboardingPage->>OnboardingPage: Detect success param → advance to Step 1 (Preview) OnboardingPage->>OnboardingActions: prepareInstagramPreview() OnboardingActions->>Instagram: fetchConversationsForSync() OnboardingActions->>OnboardingActions: selectPreviewConversation() OnboardingActions->>OnboardingActions: buildReplyPreview() via Gemini AI OnboardingActions->>OnboardingPage: Return preview data OnboardingPage->>OnboardingPage: Step 2 – About You OnboardingPage->>OnboardingPage: Step 3 – How You Work OnboardingPage->>OnboardingPage: Step 4 – Goals OnboardingPage->>User: Redirect to /sidekick-onboardingComments Outside Diff (1)
apps/app/src/app/(onboarding)/onboarding/page.tsx, line 1671 (link)business_typeoption value format changed, breaking pre-fill for returning usersThe
business_typeradio group was refactored to use the raw option string (e.g."Coach/Consultant","SaaS","Other") as the form value, instead of theoptionToValue(option)transformation used everywhere else (which produces"coach_consultant","saas","other").When
checkOnboardingStatusAndPrefillruns, it calls:Any user who saved a
business_typevalue under the old format will have the field pre-filled with e.g."coach_consultant"or"saas", but none of the radio<RadioGroupItem value={option}>elements will have those values — they now expect"Coach/Consultant"or"SaaS". The result is a blank (unselected) radio group, and the "Tell us about your business type" conditional (watchedBusinessType === "Other") will also never fire for users who previously selected "Other" (stored as"other").This affects any user who partially completed onboarding and returns to the page, or any database row where
business_typewas previously saved.Either revert to using
optionToValue(option)as the radio value (consistent withgender,use_case,active_platforms, andcurrent_tracking), or migrate existing DB values to the new casing.Prompt To Fix All With AI
Last reviewed commit: 45583e1