Skip to content

feat(auth): trigger handleSignupOrganization on verifyEmail success (best-effort)#3765

Merged
PierreBrisorgueil merged 1 commit into
masterfrom
feat/promote-verifyemail-signup-org
Jun 1, 2026
Merged

feat(auth): trigger handleSignupOrganization on verifyEmail success (best-effort)#3765
PierreBrisorgueil merged 1 commit into
masterfrom
feat/promote-verifyemail-signup-org

Conversation

@PierreBrisorgueil
Copy link
Copy Markdown
Contributor

@PierreBrisorgueil PierreBrisorgueil commented Jun 1, 2026

Summary

Promote-up from trawl_node (trawl#1317 + alignment plan 2026-05-30-trawl-devkit-perfect-alignment.md E.1 — Task 4 of 2026-06-01-trawl-promote-up-followups.md).

  • Wire AuthOrganizationService.handleSignupOrganization(user) into verifyEmail after the emailVerified flag is persisted to DB and marked on the local object
  • Wrapped in try/catchorg-setup failure must NEVER fail email verification (regression risk if wrapper is removed; second test proves it)
  • user.emailVerified = true marked on the local object before the call so handleSignupOrganization sees the correct flag state

Why this is needed

When a downstream uses a real mailer (SMTP configured), org provisioning is deferred at signup time (the user hasn't verified yet). Without this call, users who go through the email-verification flow never get their org/grant provisioned. The signup handler already calls handleSignupOrganization, but that path short-circuits when mailer is active — verifyEmail is the completion point.

handleSignupOrganization is idempotent (convergence guard: re-verify edge cases do not double-credit the grant, and if the org already exists it converges cleanly).

Safety

Best-effort try/catch — an org-setup error (transient DB, re-verify edge case) logs a warn and lets email verification succeed. This is the identical pattern used in trawl production since trawl#1251.

Files changed

  • modules/auth/controllers/auth.controller.js — 15 lines: user.emailVerified = true mark + handleSignupOrganization try/catch block in verifyEmail
  • modules/auth/tests/auth.verifyEmail.signup-org.unit.tests.js (new) — 2 unit tests: (1) handler called with emailVerified=true user; (2) org failure does NOT crash verifyEmail

Pre-push gate

/critical-review --via deepseek: OK — 0 critical/high/medium, 1 low (cosmetic log field, matches trawl reference verbatim). Verdict: proceed.

Closes #3762

Summary by CodeRabbit

  • New Features

    • Email verification now automatically provisions user organization access and associated grants upon successful email confirmation, streamlining the new user onboarding experience and eliminating additional manual setup steps.
  • Tests

    • Added comprehensive test coverage to ensure organization provisioning is correctly triggered during email verification and operates as expected within the verification workflow.

…best-effort)

Wire AuthOrganizationService.handleSignupOrganization into verifyEmail after
the emailVerified flag is persisted. Required for mailer-deferred org/grant
provisioning (N2 signup path): when email verification is deferred, org setup
must run at verify-time, not only at signup time.

The call is idempotent (convergence guard: re-verify edge cases do not
double-credit the grant). Wrapped in try/catch — org-setup failure must
NEVER fail email verification (regression risk if wrapper is removed).

Closes #3762
Promotes trawl_node trawl#1317 up to devkit. Part of infra plan
2026-06-01-trawl-promote-up-followups.md Task 4.
Copilot AI review requested due to automatic review settings June 1, 2026 19:21
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Jun 1, 2026

Review Change Stack

Walkthrough

The PR wires post-verification organization provisioning into the email verification flow. After successful email verification, verifyEmail marks the user as emailVerified: true and calls handleSignupOrganization for org/grant provisioning. Org provisioning failures are caught and logged without blocking the verification success response. Two unit tests verify the wiring and error-handling behavior.

Changes

Email verification with org provisioning

Layer / File(s) Summary
Post-verification org provisioning with error handling
modules/auth/controllers/auth.controller.js, modules/auth/tests/auth.verifyEmail.signup-org.unit.tests.js
verifyEmail sets user.emailVerified = true and calls AuthOrganizationService.handleSignupOrganization(user) to provision orgs and grants after email verification succeeds. Org provisioning errors are caught, logged, and do not fail verification. Tests assert handleSignupOrganization is called with the marked user and that failures do not crash the response flow.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Possibly related PRs

  • pierreb-devkit/Node#3680: Directly exercises the handleSignupOrganization signup/workspace and suggestedJoin behavior after the new post-verification org provisioning call.
  • pierreb-devkit/Node#3234: Implements the emailVerified gating check inside handleSignupOrganization that the new verifyEmail wiring depends on when mailer is configured.
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main change: wiring handleSignupOrganization into verifyEmail with best-effort error handling.
Description check ✅ Passed The description covers all required template sections: summary, why-needed, scope (module impacted), safety considerations, validation checklist items, and guardrails (tests added, no secrets).
Linked Issues check ✅ Passed All objectives from issue #3762 are met: handleSignupOrganization is called post-verification [#3762], user.emailVerified is marked locally [#3762], wrapped in try/catch for best-effort [#3762], and tests cover handler invocation and failure resilience [#3762].
Out of Scope Changes check ✅ Passed All changes directly support the linked issue #3762: controller modification for org provisioning, new unit tests for coverage, no unrelated code changes or scope drift detected.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

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

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/promote-verifyemail-signup-org

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Wires AuthOrganizationService.handleSignupOrganization(user) into the verifyEmail controller flow so that org/grant provisioning happens at email verification time when mailer-deferred verification is in use. The call is wrapped in a best-effort try/catch so a provisioning error cannot fail email verification.

Changes:

  • Mark user.emailVerified = true on the local object after persisting the verified flag, then invoke handleSignupOrganization inside verifyEmail.
  • Wrap the org-setup call in a try/catch that logs a warning on failure (idempotent + non-fatal).
  • Add a new unit test file with two cases: handler called with emailVerified=true, and verifyEmail still succeeds when org provisioning throws.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.

File Description
modules/auth/controllers/auth.controller.js Adds local emailVerified=true mark plus best-effort handleSignupOrganization try/catch in verifyEmail.
modules/auth/tests/auth.verifyEmail.signup-org.unit.tests.js New ESM unit tests covering happy path and best-effort failure path for the new wiring.

@codecov
Copy link
Copy Markdown

codecov Bot commented Jun 1, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 90.14%. Comparing base (7ed5291) to head (b19ad58).
⚠️ Report is 1 commits behind head on master.

Additional details and impacted files
@@             Coverage Diff             @@
##           master    #3765       +/-   ##
===========================================
+ Coverage   59.43%   90.14%   +30.71%     
===========================================
  Files         151      151               
  Lines        4970     4974        +4     
  Branches     1577     1577               
===========================================
+ Hits         2954     4484     +1530     
+ Misses       1491      385     -1106     
+ Partials      525      105      -420     
Flag Coverage Δ
integration 59.48% <75.00%> (+0.05%) ⬆️
unit 69.05% <100.00%> (?)

Flags with carried forward coverage won't be shown. Click here to find out more.


Continue to review full report in Codecov by Sentry.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 7ed5291...b19ad58. Read the comment docs.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

coderabbitai[bot]
coderabbitai Bot previously requested changes Jun 1, 2026
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 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 `@modules/auth/controllers/auth.controller.js`:
- Around line 672-682: When handleSignupOrganization fails we should record a
reconciliation trigger so provisioning is retried later; catch the error in
AuthOrganizationService.handleSignupOrganization call (the existing try/catch)
and instead of only logging, set a durable flag on the User (e.g.,
user.needsOrgProvisioning = true) or enqueue a background job to retry
provisioning, then save the user; also update signin/token flow (where
autoSetCurrentOrganization is invoked) to detect verified users with no active
membership and either call AuthOrganizationService.handleSignupOrganization
again or enqueue the same retry job so provisioning occurs on next signin;
optionally implement a periodic background sweep that queries users with
needsOrgProvisioning to re-run handleSignupOrganization and clear the flag on
success.
🪄 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: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 79038e53-9165-463a-8d8e-dfc5b2487c71

📥 Commits

Reviewing files that changed from the base of the PR and between 7ed5291 and b19ad58.

📒 Files selected for processing (2)
  • modules/auth/controllers/auth.controller.js
  • modules/auth/tests/auth.verifyEmail.signup-org.unit.tests.js

Comment on lines +672 to +682
// Post-verification org setup — provision org/grant if not yet done (best-effort).
// handleSignupOrganization is idempotent: if the org already exists it converges
// without double-crediting. Failure must never block email verification success.
try {
await AuthOrganizationService.handleSignupOrganization(user);
} catch (orgErr) {
logger.warn('[auth.verifyEmail] org/grant provisioning failed (non-fatal)', {
userId: user.id,
error: orgErr?.message,
});
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

Best-effort swallow is correct, but consider a reconciliation path for permanent provisioning failures.

Wrapping handleSignupOrganization in try/catch and logging is the right call for the "must not block verification" requirement, and the service's idempotent convergence guard makes re-invocation safe. However, when provisioning fails here the error is only logged — a verified user can end up with no organization/grants and no automatic recovery, since signin/token only call autoSetCurrentOrganization (which sets an existing membership, never creates one). Consider a reconciliation trigger (e.g., re-attempt handleSignupOrganization on next signin when the user has verified email but no active membership, or a background sweep) so a transient failure here doesn't strand the account.

🤖 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 `@modules/auth/controllers/auth.controller.js` around lines 672 - 682, When
handleSignupOrganization fails we should record a reconciliation trigger so
provisioning is retried later; catch the error in
AuthOrganizationService.handleSignupOrganization call (the existing try/catch)
and instead of only logging, set a durable flag on the User (e.g.,
user.needsOrgProvisioning = true) or enqueue a background job to retry
provisioning, then save the user; also update signin/token flow (where
autoSetCurrentOrganization is invoked) to detect verified users with no active
membership and either call AuthOrganizationService.handleSignupOrganization
again or enqueue the same retry job so provisioning occurs on next signin;
optionally implement a periodic background sweep that queries users with
needsOrgProvisioning to re-run handleSignupOrganization and clear the flag on
success.

@PierreBrisorgueil PierreBrisorgueil dismissed coderabbitai[bot]’s stale review June 1, 2026 19:25

The finding requests a durable retry mechanism (needsOrgProvisioning flag + signin retry + background sweep). That is a valid product enhancement but is out of scope for this PR, which is a verbatim promote-up port of trawl's existing production behavior (best-effort try/catch, no retry). Trawl has run this pattern since #1251 without issue — handleSignupOrganization is idempotent so a manual retry or re-verify already recovers gracefully. A proper retry mechanism would require User schema changes + signin/token handler changes + a background cron and will be tracked as a separate issue if the team decides to add it.

@PierreBrisorgueil PierreBrisorgueil merged commit 5604011 into master Jun 1, 2026
9 checks 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.

feat(auth): wire handleSignupOrganization into verifyEmail (post-verification org setup)

2 participants