feat: add signup watchlist review mode#27912
Conversation
- Add 'signup-watchlist-review' global feature flag - Add SIGNUP to WatchlistSource enum in Prisma schema - When flag enabled, lock new signups and add email to watchlist - Show 'account under review' message on signup page - Add i18n strings for review UI - Create seed migration for the feature flag Co-Authored-By: alex@cal.com <me@alexvanandel.com>
🤖 Devin AI EngineerI'll be helping with this pull request! Here's what you should know: ✅ I will automatically:
Note: I can only respond to comments from users who have write access to this repository. ⚙️ Control Options:
|
Co-Authored-By: alex@cal.com <me@alexvanandel.com>
There was a problem hiding this comment.
3 issues found across 9 files
Prompt for AI agents (all issues)
Check if these issues are valid — if so, understand the root cause of each and fix them.
<file name="apps/web/modules/signup-view.tsx">
<violation number="1" location="apps/web/modules/signup-view.tsx:3">
P0: Bug: `import process from "node:process"` will break at runtime in this `"use client"` component. The `node:` protocol is Node.js-only and unavailable in the browser. Next.js already handles `process.env.NEXT_PUBLIC_*` substitution at build time, so this import is both unnecessary and harmful. Remove this line.</violation>
</file>
<file name="apps/web/app/api/auth/signup/handlers/calcomSignupHandler.ts">
<violation number="1" location="apps/web/app/api/auth/signup/handlers/calcomSignupHandler.ts:307">
P1: Premium username signups bypass the watchlist review entirely. When `checkoutSessionId` is set (premium username flow, HTTP 402), the handler returns early before reaching the `signupWatchlistReviewEnabled` check. A user could sign up with a premium username to skip the review/locking mechanism. Consider moving the feature flag check and watchlist logic before the `checkoutSessionId` early return, or adding an equivalent check in the premium path.</violation>
</file>
<file name="apps/web/app/api/auth/signup/handlers/selfHostedHandler.ts">
<violation number="1" location="apps/web/app/api/auth/signup/handlers/selfHostedHandler.ts:238">
P2: Missing `select` clause on `prisma.watchlist.create`. The return value is not used, but Prisma still fetches all columns. Add `select: { id: true }` to be consistent with the project's Prisma querying guidelines and the `findFirst` call just above.</violation>
</file>
Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.
Devin AI is addressing Cubic AI's review feedbackNew feedback has been sent to the existing Devin session. ✅ Pushed commit |
- Remove 'import process from node:process' in signup-view.tsx (P0 bug in 'use client' component) - Move watchlist review check before checkoutSessionId early return in calcomSignupHandler (P1 premium bypass) - Revert selfHostedHandler to original state (out of scope per user request) - Add test mocks for FeaturesRepository and GlobalWatchlistRepository Co-Authored-By: alex@cal.com <me@alexvanandel.com>
There was a problem hiding this comment.
2 issues found across 4 files (changes from recent commits).
Prompt for AI agents (all issues)
Check if these issues are valid — if so, understand the root cause of each and fix them.
<file name="apps/web/app/api/auth/signup/handlers/calcomSignupHandler.ts">
<violation number="1" location="apps/web/app/api/auth/signup/handlers/calcomSignupHandler.ts:307">
P3: This existence check now pulls the full watchlist record via `findBlockedEmail`, which selects many fields. For signup flow you only need to know if a record exists; fetching extra columns adds unnecessary data exposure and overhead. Prefer a select that only returns `id` (or add a repo method that does so).</violation>
<violation number="2" location="apps/web/app/api/auth/signup/handlers/calcomSignupHandler.ts:331">
P1: Rule violated: **Avoid Logging Sensitive Information**
Avoid logging sensitive tokens. The checkoutSessionId is a payment session identifier and should not be written to logs per the sensitive-data logging rule.</violation>
</file>
Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.
Devin AI is addressing Cubic AI's review feedbackNew feedback has been sent to the existing Devin session. ✅ No changes pushed |
Co-Authored-By: alex@cal.com <me@alexvanandel.com>
Token is present in normal email-verified signups, so the !token condition was incorrectly skipping watchlist review for verified users. Co-Authored-By: alex@cal.com <me@alexvanandel.com>
There was a problem hiding this comment.
1 issue found across 1 file (changes from recent commits).
Prompt for AI agents (all issues)
Check if these issues are valid — if so, understand the root cause of each and fix them.
<file name="apps/web/app/api/auth/signup/handlers/calcomSignupHandler.ts">
<violation number="1" location="apps/web/app/api/auth/signup/handlers/calcomSignupHandler.ts:304">
P2: Invite-based signups will now be forced into watchlist review because the `!token` guard was removed. Team invite signups are expected to bypass review mode, so this change will lock invited users and add them to the watchlist.</violation>
</file>
Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.
Devin AI is addressing Cubic AI's review feedbackNew feedback has been sent to the existing Devin session. |
Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
There was a problem hiding this comment.
1 issue found across 1 file (changes from recent commits).
Prompt for AI agents (all issues)
Check if these issues are valid — if so, understand the root cause of each and fix them.
<file name="apps/web/app/api/auth/signup/handlers/calcomSignupHandler.ts">
<violation number="1" location="apps/web/app/api/auth/signup/handlers/calcomSignupHandler.ts:304">
P2: The added `&& !token` guard disables watchlist review for token-based/invite signups, which contradicts the stated requirement that the review applies to all signups when the flag is enabled. This allows those signups to bypass watchlist entry and locking.</violation>
</file>
Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.
Co-Authored-By: alex@cal.com <me@alexvanandel.com>
Devin AI is addressing Cubic AI's review feedbackNew feedback has been sent to the existing Devin session. ✅ No changes pushed |
…t-manager.devin.ai/proxy/github.com/calcom/cal.com into devin/1770927902-signup-watchlist-review
…turesRepository Co-Authored-By: alex@cal.com <me@alexvanandel.com>
pedroccastro
left a comment
There was a problem hiding this comment.
I think the removal from watchlist is not connected with the locked = false. What do you think of connecting them, so we mitigate the risk of a user being left in an inconsistent state (watchlist entry removed but still locked)?
… review Co-Authored-By: alex@cal.com <me@alexvanandel.com>
ad9b58f
Co-Authored-By: alex@cal.com <me@alexvanandel.com>
b68c2af
There was a problem hiding this comment.
1 issue found across 3 files (changes from recent commits).
Prompt for AI agents (all issues)
Check if these issues are valid — if so, understand the root cause of each and fix them.
<file name="packages/trpc/server/routers/viewer/admin/lockUserAccount.handler.ts">
<violation number="1" location="packages/trpc/server/routers/viewer/admin/lockUserAccount.handler.ts:39">
P2: Unlocking a user deletes any blocked email entry regardless of why it was blocked. This can remove manually managed or policy-based watchlist entries; consider only deleting entries created for the signup-review flow (e.g., source == SIGNUP).</violation>
</file>
Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.
Devin AI is addressing Cubic AI's review feedbackNew feedback has been sent to the existing Devin session. ✅ No changes pushed |
E2E results are ready! |

What does this PR do?
Adds a toggle-able "signup watchlist review" mode. When the
signup-watchlist-reviewfeature flag is enabled:BLOCKaction andSIGNUPsourcelocked: true)Token-based signups (team invites) bypass the watchlist review and proceed normally.
Admins can manage flagged emails through the existing Watchlist admin UI at any time.
Scope:
calcomSignupHandleronly —selfHostedHandleris intentionally out of scope.Changes
signup-watchlist-reviewadded toAppFlags,useFlags, seeded via Prisma migrationSIGNUPadded toWatchlistSourceenumFeaturesRepositoryandGlobalWatchlistRepository, adds email to watchlist, and locks the user viaUserRepository.lockByEmail. Watchlist check runs before thecheckoutSessionIdearly return so premium username signups are also covered. Token-based signups (team invites) are excluded via the!tokenguard.lockByEmailmethod to keep user-locking logic in the repository layersignup-view.tsxshows a shield icon + "account under review" message when the API returnsaccountUnderReview: trueaccountUnderReviewtoSignupSuccessResponse, extractedSignupSuccessResulttype, addedisAccountUnderReviewhelperaccount_under_review_titleandaccount_under_review_descriptionisAccountUnderReviewhelper; added mocks forFeaturesRepository,GlobalWatchlistRepository, andnormalizeEmailin calcomSignupHandler testsMandatory Tasks (DO NOT REMOVE)
How should this be tested?
signup-watchlist-reviewfeature flag in admin settings (or set it totruein theFeaturetable)lockedfield istruetoken) → normal flow proceeds regardless of flag stateHuman Review Checklist
type: EMAIL,action: BLOCK,source: SIGNUP,isGlobal: truefindBlockedEmail+createEntryfor duplicate email check is not atomic — two concurrent signups with the same email could create duplicate entriesnormalizeEmail(email)butlockByEmailuses the rawemail— confirm this is correctaccount_under_review_titleandaccount_under_review_descriptiontranslation keys existChecklist
Link to Devin run: https://app.devin.ai/sessions/c166613dbc3c44a6ba25d2e64d945c61
Requested by: @emrysal