Skip to content

feat: add signup watchlist review mode#27912

Merged
emrysal merged 11 commits intomainfrom
devin/1770927902-signup-watchlist-review
Feb 12, 2026
Merged

feat: add signup watchlist review mode#27912
emrysal merged 11 commits intomainfrom
devin/1770927902-signup-watchlist-review

Conversation

@emrysal
Copy link
Copy Markdown
Contributor

@emrysal emrysal commented Feb 12, 2026

What does this PR do?

Adds a toggle-able "signup watchlist review" mode. When the signup-watchlist-review feature flag is enabled:

  1. New signups (without a token) have their email added to the global Watchlist with BLOCK action and SIGNUP source
  2. The newly created user is locked (locked: true)
  3. The signup page shows an "account under review" message instead of proceeding to sign-in

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: calcomSignupHandler only — selfHostedHandler is intentionally out of scope.

Changes

  • Feature flag: signup-watchlist-review added to AppFlags, useFlags, seeded via Prisma migration
  • Prisma schema: SIGNUP added to WatchlistSource enum
  • calcomSignupHandler: Checks the flag post-creation using FeaturesRepository and GlobalWatchlistRepository, adds email to watchlist, and locks the user via UserRepository.lockByEmail. Watchlist check runs before the checkoutSessionId early return so premium username signups are also covered. Token-based signups (team invites) are excluded via the !token guard.
  • UserRepository: Added lockByEmail method to keep user-locking logic in the repository layer
  • Frontend: signup-view.tsx shows a shield icon + "account under review" message when the API returns accountUnderReview: true
  • fetchSignup: Added accountUnderReview to SignupSuccessResponse, extracted SignupSuccessResult type, added isAccountUnderReview helper
  • i18n: Added account_under_review_title and account_under_review_description
  • Tests: 4 unit tests for isAccountUnderReview helper; added mocks for FeaturesRepository, GlobalWatchlistRepository, and normalizeEmail in calcomSignupHandler tests

Note on diff noise: Biome auto-formatting reordered imports in signup-view.tsx and calcomSignupHandler.ts, and prisma format adjusted whitespace in schema.prisma. The functional changes in these files are small relative to the diff size.

Mandatory Tasks (DO NOT REMOVE)

  • I have self-reviewed the code (A decent size PR without self-review might be rejected).
  • I have updated the developer docs in /docs if this PR makes changes that would require a documentation change. N/A
  • I confirm automated tests are in place that prove my fix is effective or that my feature works.

How should this be tested?

  1. Enable the signup-watchlist-review feature flag in admin settings (or set it to true in the Feature table)
  2. Sign up with a new email (not via a team invite link)
  3. Expect: "Your account is under review" message is displayed; the email appears in the Watchlist; the user's locked field is true
  4. Disable the flag → sign up again → normal flow proceeds
  5. Sign up via a team invite link (with token) → normal flow proceeds regardless of flag state

Human Review Checklist

  • Verify the watchlist entry is created with correct type: EMAIL, action: BLOCK, source: SIGNUP, isGlobal: true
  • Verify the user is locked after signup when flag is enabled
  • Verify the "account under review" UI renders correctly
  • Confirm the migration runs without issues on existing databases
  • Premium username flow: With the flag enabled, premium username signups (without token) should get the "under review" response — verify this is the intended behavior
  • Race condition: findBlockedEmail + createEntry for duplicate email check is not atomic — two concurrent signups with the same email could create duplicate entries
  • Email normalization: Watchlist uses normalizeEmail(email) but lockByEmail uses the raw email — confirm this is correct
  • Translation keys: Verify account_under_review_title and account_under_review_description translation keys exist

Checklist

  • I have read the contributing guide
  • My code follows the style guidelines of this project
  • I have checked if my changes generate no new warnings
  • My PR is not too large (>500 lines or >10 files)

Link to Devin run: https://app.devin.ai/sessions/c166613dbc3c44a6ba25d2e64d945c61
Requested by: @emrysal

- 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-integration
Copy link
Copy Markdown
Contributor

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR that start with 'DevinAI' or '@devin'.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment and CI monitoring

@github-actions github-actions bot added the ❗️ migrations contains migration files label Feb 12, 2026
Co-Authored-By: alex@cal.com <me@alexvanandel.com>
Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

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

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.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Feb 12, 2026

Devin AI is addressing Cubic AI's review feedback

New feedback has been sent to the existing Devin session.

View Devin Session


✅ Pushed commit 6fb9835

- 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>
Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

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

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.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Feb 12, 2026

Devin AI is addressing Cubic AI's review feedback

New feedback has been sent to the existing Devin session.

View Devin Session


✅ No changes pushed

devin-ai-integration bot and others added 2 commits February 12, 2026 21:05
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>
Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

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

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.

@github-actions
Copy link
Copy Markdown
Contributor

Devin AI is addressing Cubic AI's review feedback

New feedback has been sent to the existing Devin session.

View Devin Session

Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
@emrysal emrysal marked this pull request as ready for review February 12, 2026 22:10
@emrysal emrysal requested a review from a team as a code owner February 12, 2026 22:10
@graphite-app graphite-app bot added foundation core area: core, team members only labels Feb 12, 2026
Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

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

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>
@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Feb 12, 2026

Devin AI is addressing Cubic AI's review feedback

New feedback has been sent to the existing Devin session.

View Devin Session


✅ No changes pushed

…turesRepository

Co-Authored-By: alex@cal.com <me@alexvanandel.com>
Copy link
Copy Markdown
Member

@alishaz-polymath alishaz-polymath left a comment

Choose a reason for hiding this comment

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

LGTM

Copy link
Copy Markdown
Contributor

@pedroccastro pedroccastro left a comment

Choose a reason for hiding this comment

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

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>
alishaz-polymath

This comment was marked as outdated.

Co-Authored-By: alex@cal.com <me@alexvanandel.com>
Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

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

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.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Feb 12, 2026

Devin AI is addressing Cubic AI's review feedback

New feedback has been sent to the existing Devin session.

View Devin Session


✅ No changes pushed

Copy link
Copy Markdown
Member

@alishaz-polymath alishaz-polymath left a comment

Choose a reason for hiding this comment

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

Image

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Feb 12, 2026

E2E results are ready!

@emrysal emrysal disabled auto-merge February 12, 2026 23:12
@emrysal emrysal merged commit d3bbed0 into main Feb 12, 2026
88 of 93 checks passed
@emrysal emrysal deleted the devin/1770927902-signup-watchlist-review branch February 12, 2026 23:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

core area: core, team members only foundation ❗️ migrations contains migration files ready-for-e2e size/XL

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants