Skip to content

feat(controlplane): verify email before cloud trial and enqueue welcome#2726

Open
mekilis wants to merge 4 commits into
mainfrom
feat/pde-917-918-onboarding-and-trial-verify
Open

feat(controlplane): verify email before cloud trial and enqueue welcome#2726
mekilis wants to merge 4 commits into
mainfrom
feat/pde-917-918-onboarding-and-trial-verify

Conversation

@mekilis

@mekilis mekilis commented Jul 17, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • Cloud StartTrial fails closed when the authenticated user is not email-verified; OSS and self-hosted skip the gate (UsesOrgBilling() only).
  • Trial modal refreshes profile verification state and blocks start until verified; verify-email patches local auth cache for UX.
  • After cloud signup, fire-and-forget Overwatch welcome enqueue (ensure billing org + onboarding welcome), fail-open so registration still returns 201.

Test plan

  • Unverified cloud user: POST …/subscriptions/trial returns 403; modal CTA disabled until verify.
  • Verified cloud user can start trial; unverified path clears after verify-email success + profile refresh.
  • Cloud signup returns 201 even if Overwatch welcome is slow/down; welcome still delivered when Overwatch is up and ONBOARDING_EMAILS_MODE=enforce.
  • go test ./api/handlers/ -run TestCloudTrialEmailVerified passes (includes OSS skip case).

Note

Medium Risk
Touches auth signup paths, billing trial gating, and profile email updates; changes are scoped with fail-open welcome and tests for the trial gate, but unverified users are newly blocked from cloud trials.

Overview
Cloud Start trial now fails closed unless the authenticated user has a verified email (OSS/self-hosted unchanged). The trial modal refreshes profile verification state, disables the CTA until verified, and shows guidance when not verified.

Email changes on profile update now clear verification, mint a new token, and queue a verification email so trial gating stays aligned with the current address. The dashboard invalidates cached profile/auth state after verify, profile save, and related flows.

After successful cloud signup (password register, new SSO registration, Google OAuth setup), a fail-open background job enqueues the Overwatch onboarding welcome via a new billing client method, with retries while async billing-org sync catches up. Registration/login responses are unchanged if welcome enqueue fails.

Reviewed by Cursor Bugbot for commit 6721006. Bugbot is set up for automated code reviews on this repo. Configure here.

@linear

linear Bot commented Jul 17, 2026

Copy link
Copy Markdown

PDE-917

PDE-918

Comment thread api/handlers/user.go
Comment thread api/handlers/billing_cloud.go
Comment thread web/ui/dashboard/src/app/private/pages/settings/billing/trial-modal.component.ts Outdated
Comment thread web/ui/dashboard/src/app/public/verify-email/verify-email.component.ts Outdated
Comment thread api/handlers/user.go Outdated
Comment thread services/update_user.go
Comment thread services/update_user.go
Comment thread web/ui/dashboard/src/app/private/private.service.ts
mekilis added 4 commits July 18, 2026 08:20
Gate cloud StartTrial on DB-backed email_verified (OSS/self-hosted skip),
fail-closed in the trial modal, and fire-and-forget Motunrayo welcome
enqueue to Overwatch after cloud signup.
… oauth signups

Changing the profile email now unverifies the account and reissues a
verification token so the cloud trial gate cannot be passed with an
unverified address. Google OAuth and new SSO registrations get the same
onboarding welcome enqueue as password signups. Dashboard email_verified
cache sync is centralized in PrivateService and drops the stale profile
cache after verify.
RunBillingOrganisationSync stays the single owner of billing-org
creation; the welcome enqueue no longer issues its own CreateOrganisation
and instead retries briefly until the sync has created the org, with the
Overwatch sweep as the named backfill on failure. Profile save now drops
the cached profile so the verify chip refetches after an email change
unverifies the account.
clearProfileDetailsCache now emits profileChanged, and the private shell
subscribes to re-read the profile so the verify chip reflects an email
change or verify without a full remount.
@mekilis
mekilis force-pushed the feat/pde-917-918-onboarding-and-trial-verify branch from e51931e to 6721006 Compare July 18, 2026 07:24

@cursor cursor 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.

Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 6721006. Configure here.

Comment thread services/update_user.go
u.User.EmailVerified = false
u.User.EmailVerificationToken = ulid.Make().String()
u.User.EmailVerificationExpiresAt = time.Now().Add(time.Hour * 2)
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Email change can lock profile

High Severity

Changing email sets EmailVerified to false, but UpdateUserService still refuses any update when the user is unverified. A mistyped new address leaves the account unable to correct the email until that address is verified, which is impossible if the user does not control it.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 6721006. Configure here.

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