What — On a signup that requires email verification, the user can be dropped straight into the app WITHOUT ever seeing the "check your inbox" step — when organizations are disabled, or when the server-config fetch returned null.
Why — The email-verification step is a deliberate gate. Skipping it lets an unverified user into the app, and no router guard enforces email-verified downstream, so nothing catches it.
Scope — src/modules/auth/views/signup.view.vue's watch.auth (~lines 260-269) calls pushAfterAuth() → router.push(config.sign.route) as soon as the store sets this.auth = true (done synchronously inside the signup() action). That pre-flush watcher job flushes on an EARLIER microtask than validate()'s await authStore.signup() continuation, so the watcher runs while signupStep is still 'form' — BEFORE validate() reaches if (result.emailVerificationRequired) { signupStep = 'emailVerification'; return; }.
On the !serverConfig?.organizations?.enabled path (which is also true when serverConfig === null after a failed fetchServerConfig()), the watcher therefore navigates into the app and the verification gate is defeated. app.router.js's beforeEach has org / plan / ability gates but no emailVerified check, so nothing bounces the unverified user back.
Dormant when organizations are enabled and the config loads cleanly; deterministic on organizations-disabled deployments with email verification, and reachable anywhere fetchServerConfig() transiently returns null. Also untested — the signup view unit test mocks a static { auth: false } store, so the watcher never fires and the "shows email verification step" case is green while masking the interplay.
Fix: gate the watcher's navigation on the result classification — e.g. have signup() not flip auth (or set a separate pendingEmailVerification flag) when emailVerificationRequired, or set a synchronous submitting flag at the top of validate() and guard the watcher with it, so the emailVerification step is never skipped. validate() already calls pushAfterAuth() in every terminal branch, so the watcher's fast-path push may simply be redundant for the email/password flow (OAuth uses full-page href redirects handled by created()). Add a unit test that flips the store's real auth to exercise the race.
Refs: signup.view.vue watch.auth + validate(); auth.store.js signup().
Created via /dev:issue
What — On a signup that requires email verification, the user can be dropped straight into the app WITHOUT ever seeing the "check your inbox" step — when organizations are disabled, or when the server-config fetch returned null.
Why — The email-verification step is a deliberate gate. Skipping it lets an unverified user into the app, and no router guard enforces email-verified downstream, so nothing catches it.
Scope —
src/modules/auth/views/signup.view.vue'swatch.auth(~lines 260-269) callspushAfterAuth()→router.push(config.sign.route)as soon as the store setsthis.auth = true(done synchronously inside thesignup()action). That pre-flush watcher job flushes on an EARLIER microtask thanvalidate()'sawait authStore.signup()continuation, so the watcher runs whilesignupStepis still'form'— BEFOREvalidate()reachesif (result.emailVerificationRequired) { signupStep = 'emailVerification'; return; }.On the
!serverConfig?.organizations?.enabledpath (which is also true whenserverConfig === nullafter a failedfetchServerConfig()), the watcher therefore navigates into the app and the verification gate is defeated.app.router.js'sbeforeEachhas org / plan / ability gates but noemailVerifiedcheck, so nothing bounces the unverified user back.Dormant when organizations are enabled and the config loads cleanly; deterministic on organizations-disabled deployments with email verification, and reachable anywhere
fetchServerConfig()transiently returns null. Also untested — the signup view unit test mocks a static{ auth: false }store, so the watcher never fires and the "shows email verification step" case is green while masking the interplay.Fix: gate the watcher's navigation on the result classification — e.g. have
signup()not flipauth(or set a separatependingEmailVerificationflag) whenemailVerificationRequired, or set a synchronoussubmittingflag at the top ofvalidate()and guard the watcher with it, so the emailVerification step is never skipped.validate()already callspushAfterAuth()in every terminal branch, so the watcher's fast-path push may simply be redundant for the email/password flow (OAuth uses full-page href redirects handled bycreated()). Add a unit test that flips the store's realauthto exercise the race.Refs:
signup.view.vuewatch.auth + validate();auth.store.jssignup().Created via /dev:issue