Skip to content

fix(onboarding): hydrate authStore on signup + cover OAuth InsertWithTx - #12

Merged
hades217 merged 2 commits into
mainfrom
fix/welcome-redirect-real
May 17, 2026
Merged

fix(onboarding): hydrate authStore on signup + cover OAuth InsertWithTx#12
hades217 merged 2 commits into
mainfrom
fix/welcome-redirect-real

Conversation

@hades217

Copy link
Copy Markdown

Summary

This is the actually-tested fix for "我注册的时候没有触发onboarding". PR #11 fixed two real bugs (Setting type mismatch, OAuth seed in Insert) but missed three more that I only caught by running the flow end-to-end:

# File Bug Effect
1 `web/default/src/features/auth/sign-up/components/sign-up-form.tsx` After register, we called `navigate('/welcome')` without hydrating authStore `/welcome` user-guard saw `user === null` → bounced to `/sign-in`. Looked like onboarding never opened.
2 `model/user.go::InsertWithTx` PR #11 only added `persona="unset"` seed to `Insert()` `controller/oauth.go::OAuthBind` uses `InsertWithTx`, so generic OAuth users still skipped the wizard.
3 `Dockerfile.dev` `COPY LICENSE NOTICE THIRD-PARTY-LICENSES.md /licenses/` Files don't exist in this fork → local backend rebuild fails at stage-1 step 4. Hid the actual Go compile errors.

Verified

```
✅ docker compose -f docker-compose.dev.yml -p deeprouter up --build
✅ POST /api/user/register {} → DB has persona="unset"
✅ POST /api/user/register {persona,brand,client} → DB has all 3 + onboarding_completed_at
✅ Browser: /sign-up → submit → /welcome (NOT /sign-in)
✅ /welcome renders: 👋 banner, ¥1.00 trial credit (≈200 chats), 3-persona picker, Step 1 of 3
```

What CI didn't catch (so we know to fix this separately)

  • `pr-check.yml` runs for 12 seconds — does not invoke `go build`
  • `airbotix-internal.yml` runs `go build ./internal/... ./model/... ./constant/... ./middleware/... ./service/... ./relay/...` — excludes `./controller/...`
  • Full build only happens for pushes to `alpha` / `nightly` branches (docker-image workflows) or for tags (release.yml)

That's why PR #8's `cleanUser.Setting = &settingStr` (`*string` to `string`) silently merged. CI scope expansion is out of scope for this PR but worth tracking.

Test plan

  • Sign up via /sign-up form → land on /welcome (not /sign-in)
  • Welcome wizard shows trial credit + 3-step picker
  • Existing users with persona set don't see /welcome
  • OAuth (github/wechat/etc.) callback for a new account → /welcome
  • `bun run typecheck` clean
  • `docker compose -f docker-compose.dev.yml up --build` succeeds end-to-end

🤖 Generated with Claude Code

hades217 and others added 2 commits May 17, 2026 15:17
Three real fixes verified by running the registration flow end-to-end
in a browser (Playwright + docker-built backend):

1. sign-up-form.tsx — after register() succeeds, call handleLoginSuccess
   to fetch /api/user/self and write the user into the authStore before
   navigating to /welcome. Previously we just called navigate('/welcome'),
   but /welcome's user guard reads from authStore (not the backend session
   cookie) and bounced us straight to /sign-in. This is the root cause of
   "我注册的时候没有触发onboarding啊" — the redirect happened so fast
   it looked like onboarding never opened.

2. model/user.go InsertWithTx — same persona="unset" seed as Insert(),
   for controller/oauth.go::OAuthBind which uses the transactional
   variant. Previous fix only covered Insert(); OAuth users created via
   the generic /api/oauth/* endpoints would still skip the wizard.

3. Dockerfile.dev — drop the COPY of LICENSE/NOTICE/THIRD-PARTY-LICENSES.md
   into /licenses/. Those files don't exist in this fork, so the dev
   image build failed at stage-1 step 4 — blocking any local rebuild of
   the backend after Go code changes.

Verification:
- docker compose -f docker-compose.dev.yml -p deeprouter up --build (✅)
- POST /api/user/register with empty body → DB row has persona="unset" (✅)
- POST /api/user/register with persona/brand/client → DB has all fields
  + onboarding_completed_at stamped (✅)
- Browser: /sign-up → submit → /welcome wizard renders with trial credit
  banner, 3-persona picker, Step 1 of 3 (✅)

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
… partial PATCH + step URLs

End-to-end test of the wizard exposed three more bugs the previous PRs missed:

1. controller.UpdateUserSetting only knew about notify_type / webhook / bark /
   gotify. The frontend wizard sends persona / brand_preference /
   preferred_client / sidebar_modules, but the handler:
     a) Returned MsgSettingInvalidType ("Invalid warning type") because
        notify_type was empty — this is the toast the user kept seeing.
     b) Built dto.UserSetting{} from scratch, wiping persona/brand/client
        even when validation passed.

   Reworked as a real partial-update endpoint:
     - notify_type validation block runs only when notify_type is non-empty
       (treats empty as "not updating notify config")
     - settings = existingSettings, then override only fields the caller
       provided (pointer fields for B2C, gate-by-isNotifyUpdate for the
       notify cluster)
     - Notify-channel reset moved inside the gate so switching from
       webhook → bark still clears stale webhook URL.

2. Welcome wizard: default-select Casual so Continue is enabled on landing.
   Non-technical users had to discover that they had to click the card
   before they could move on.

3. ChoiceCard description had `line-clamp-2` — Team / Enterprise card was
   cut at "team-only tools coming soon" + ellipsis. Removed the clamp;
   each step now shows the full description.

4. Each wizard step has its own URL via ?step=persona|brand|client search
   param. Browser back/forward works correctly, deep-links land on the
   right step, Back button rewinds. Deep-link guard: ?step=brand without
   a persona pick rewinds to ?step=persona.

Verified end-to-end:
- POST /api/user/register → /welcome (default Casual selected)
- /welcome?step=brand → pick Claude → /welcome?step=client
- /welcome?step=client → Cherry Studio auto-selected → Finish
- DB: persona=casual, preferred_client=cherry-studio, sidebar_modules
  swapped to casual preset, acquisition_channel/timezone preserved
- Browser navigated to /onboarding/cherry-studio (no longer silently fails)
- No more "Invalid warning type" toast on the Finish click

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@hades217
hades217 merged commit 467c8d4 into main May 17, 2026
1 check passed
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