Skip to content

Comments

feat: Add spam blocker DI structure#24040

Merged
alishaz-polymath merged 91 commits intomainfrom
feat/spam-block-di
Oct 14, 2025
Merged

feat: Add spam blocker DI structure#24040
alishaz-polymath merged 91 commits intomainfrom
feat/spam-block-di

Conversation

@alishaz-polymath
Copy link
Member

@alishaz-polymath alishaz-polymath commented Sep 24, 2025

What does this PR do?

Summary

This PR introduces a lean, testable Dependency Injection (DI) structure for the Watchlist/Spam-Blocker feature and applies it at the key edges (signup/admin/API/booking flows). This PR also updates the Watchlist schema for a more scalable and purposeful design. The goal is simple: keep data access in repositories, keep orchestration in controllers, and keep business logic in services—with a small façade as the entrypoint.

Highlights

  • Replace scattered, hard-to-mock checks with a single feature façade.
  • Ensure only repositories touch Prisma (no ORM in services/controllers/utils).
  • Make telemetry consistent and tests reliable (no flaky sync/async span behavior).

What changed (high level)

  • Feature boundary

    • Added Watchlist DI surface: tokens, module, container, and a façade exposing:

      • globalBlocking.isBlocked(email)
      • orgBlocking.isBlocked(email, orgId)
  • Repositories only

    • All Prisma access is encapsulated in repositories. Services/controllers no longer import or receive Prisma/tx.
  • Services

    • Business logic sits in services (global vs. org checks, list/CRUD, etc.).
    • Logging & telemetry flow through the service layer (see “Telemetry” below).
  • Controllers / Edges

    • API and booking handlers call the façade instead of constructing repos or touching Prisma.
    • Input normalization (email/domain) is centralized and reused.
  • Telemetry

    • Uniform async spans: Sentry startSpan usage is normalized so span wrappers always return a Promise. Easier to stub/no-op in tests.
  • Tests

    • Added/updated integration tests at the route level (e.g., /api/users), verifying real request → controller → service → repo flow.
    • Unit tests use repo-level stubs/mocks rather than mocking the façade globally.

Behavior (intentionally simple)

  • Precedence:
    Global Email Blocklist -> Global Domain Blocklist -> Org Email Blocklist -> Org Domain Blocklist

How to validate

  1. Skim the façade (getWatchlistFeature) to see the small surface and the precedence/failure-default JSDoc.
  2. Follow an edge path (e.g., user creation or booking confirmation flags): controller → façade → service → repository.
  3. Run integration tests (e.g., POST /api/users) to see real data flow and watchlist auto-lock behavior.

Risks & mitigations

  • Logger differences (getSubLogger vs child): addressed via a small scoping/wrapper so services don’t break across logger backends.
  • Telemetry in tests: spans standardized to Promises; tests use a no-op wrapper—no Sentry env needed.
  • Behavioral drift: kept contracts small and added integration tests on high-traffic paths.

Reviewer checklist

  • No direct @calcom/prisma (or @prisma/client) imports outside **/repository/**.
  • Controllers don’t new-up repos; they call the façade.
  • Services contain the business logic; repositories are thin DB adapters.
  • Telemetry wrapping returns a Promise consistently (no sync/async drift).
  • Integration tests cover “blocked” and “not blocked” flows end-to-end.

Outcome: A pragmatic, DI-first foundation for spam blocking: simple today, clean seams for future policy/DTO growth, and reliable tests that exercise the real wiring.

Visual Demo (For contributors especially)

A visual demonstration is strongly recommended, for both the original and new change (video / image - any one).

Video Demo (if applicable):

  • Show screen recordings of the issue or feature.
  • Demonstrate how to reproduce the issue, the behavior before and after the change.

Image Demo (if applicable):

  • Add side-by-side screenshots of the original and updated change.
  • Highlight any significant change(s).

Mandatory Tasks (DO NOT REMOVE)

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

Checklist

@vercel
Copy link

vercel bot commented Sep 24, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

2 Skipped Deployments
Project Deployment Preview Comments Updated (UTC)
cal Ignored Ignored Oct 14, 2025 1:11am
cal-eu Ignored Ignored Oct 14, 2025 1:11am

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Sep 24, 2025

Walkthrough

Replaces legacy Watchlist repository API with a DI-based Watchlist feature façade and wiring (tokens, module, container). Adds typed DTOs, normalization and telemetry utilities, Global/Organization blocking services, WatchlistService and WatchlistAuditService, Prisma-backed repositories, and a free-email-domain check. Refactors controllers to accept structured params and optional spans, removes old repository/mocks, and adds/updates tests. Also introduces an ApiKeyService and updates verifyApiKey middleware to use it.

Possibly related PRs

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Title Check ✅ Passed The title succinctly captures the primary purpose of the changeset by indicating the addition of a dependency-injection structure for the spam-blocker functionality, which aligns with the extensive introduction of DI tokens, modules, containers, and a façade. It is concise, specific, and avoids unnecessary details or ambiguous wording. A teammate scanning the history will immediately understand the main enhancement without being distracted by secondary changes.
Docstring Coverage ✅ Passed No functions found in the changes. Docstring coverage check skipped.
Description Check ✅ Passed The pull request description clearly outlines the introduction of a dependency injection structure for the Watchlist feature, the relocation of Prisma access into repositories, the creation of facades and services, telemetry normalization, and the added integration and unit tests, all of which directly correspond to the detailed changes in the diff.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/spam-block-di

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.

@keithwillcode keithwillcode added core area: core, team members only enterprise area: enterprise, audit log, organisation, SAML, SSO labels Sep 24, 2025
@alishaz-polymath alishaz-polymath marked this pull request as ready for review September 24, 2025 11:20
@graphite-app graphite-app bot requested a review from a team September 24, 2025 11:21
@dosubot dosubot bot added platform Anything related to our platform plan ✨ feature New feature or request labels Sep 24, 2025
@graphite-app graphite-app bot requested a review from a team September 24, 2025 11:22
coderabbitai[bot]

This comment was marked as outdated.

coderabbitai[bot]

This comment was marked as resolved.

coderabbitai[bot]

This comment was marked as outdated.

coderabbitai[bot]

This comment was marked as outdated.

@alishaz-polymath alishaz-polymath merged commit a2bee76 into main Oct 14, 2025
39 of 40 checks passed
@alishaz-polymath alishaz-polymath deleted the feat/spam-block-di branch October 14, 2025 07:16
devin-ai-integration bot added a commit that referenced this pull request Oct 14, 2025
- Integrate SpamCheckService with handleNewBooking workflow
- Implement parallel spam check execution for minimal performance impact
- Add decoy booking response with localStorage-based success page
- Extract organization ID from event type for org-specific blocking
- Add comprehensive test coverage for spam detection scenarios
- Create reusable components for booking success cards
- Implement fail-open behavior to never block legitimate bookings

This builds on the spam blocker DI infrastructure from PR #24040 by
adding the actual integration into the booking flow and implementing
the decoy response mechanism to avoid revealing spam detection to
malicious actors.

Related: #24040
Co-Authored-By: hariom@cal.com <hariombalhara@gmail.com>
hariombalhara added a commit that referenced this pull request Oct 14, 2025
- Integrate SpamCheckService with handleNewBooking workflow
- Implement parallel spam check execution for minimal performance impact
- Add decoy booking response with localStorage-based success page
- Extract organization ID from event type for org-specific blocking
- Add comprehensive test coverage for spam detection scenarios
- Create reusable components for booking success cards
- Implement fail-open behavior to never block legitimate bookings

This builds on the spam blocker DI infrastructure from PR #24040 by
adding the actual integration into the booking flow and implementing
the decoy response mechanism to avoid revealing spam detection to
malicious actors.

Related: #24040
Co-Authored-By: hariom@cal.com <hariombalhara@gmail.com>
hariombalhara added a commit that referenced this pull request Oct 14, 2025
- Integrate SpamCheckService with handleNewBooking workflow
- Implement parallel spam check execution for minimal performance impact
- Add decoy booking response with localStorage-based success page
- Extract organization ID from event type for org-specific blocking
- Add comprehensive test coverage for spam detection scenarios
- Create reusable components for booking success cards
- Implement fail-open behavior to never block legitimate bookings

This builds on the spam blocker DI infrastructure from PR #24040 by
adding the actual integration into the booking flow and implementing
the decoy response mechanism to avoid revealing spam detection to
malicious actors.

Related: #24040
Co-Authored-By: hariom@cal.com <hariombalhara@gmail.com>
hariombalhara added a commit that referenced this pull request Oct 14, 2025
- Integrate SpamCheckService with handleNewBooking workflow
- Implement parallel spam check execution for minimal performance impact
- Add decoy booking response with localStorage-based success page
- Extract organization ID from event type for org-specific blocking
- Add comprehensive test coverage for spam detection scenarios
- Create reusable components for booking success cards
- Implement fail-open behavior to never block legitimate bookings

This builds on the spam blocker DI infrastructure from PR #24040 by
adding the actual integration into the booking flow and implementing
the decoy response mechanism to avoid revealing spam detection to
malicious actors.

Related: #24040
Co-Authored-By: hariom@cal.com <hariombalhara@gmail.com>
hariombalhara added a commit that referenced this pull request Oct 14, 2025
- Integrate SpamCheckService with handleNewBooking workflow
- Implement parallel spam check execution for minimal performance impact
- Add decoy booking response with localStorage-based success page
- Extract organization ID from event type for org-specific blocking
- Add comprehensive test coverage for spam detection scenarios
- Create reusable components for booking success cards
- Implement fail-open behavior to never block legitimate bookings

This builds on the spam blocker DI infrastructure from PR #24040 by
adding the actual integration into the booking flow and implementing
the decoy response mechanism to avoid revealing spam detection to
malicious actors.

Related: #24040
Co-Authored-By: hariom@cal.com <hariombalhara@gmail.com>
hariombalhara added a commit that referenced this pull request Oct 14, 2025
- Integrate SpamCheckService with handleNewBooking workflow
- Implement parallel spam check execution for minimal performance impact
- Add decoy booking response with localStorage-based success page
- Extract organization ID from event type for org-specific blocking
- Add comprehensive test coverage for spam detection scenarios
- Create reusable components for booking success cards
- Implement fail-open behavior to never block legitimate bookings

This builds on the spam blocker DI infrastructure from PR #24040 by
adding the actual integration into the booking flow and implementing
the decoy response mechanism to avoid revealing spam detection to
malicious actors.

Related: #24040
Co-Authored-By: hariom@cal.com <hariombalhara@gmail.com>
devin-ai-integration bot added a commit that referenced this pull request Oct 14, 2025
- Integrate SpamCheckService with handleNewBooking workflow
- Implement parallel spam check execution for minimal performance impact
- Add decoy booking response with localStorage-based success page
- Extract organization ID from event type for org-specific blocking
- Add comprehensive test coverage for spam detection scenarios
- Create reusable components for booking success cards
- Implement fail-open behavior to never block legitimate bookings

This builds on the spam blocker DI infrastructure from PR #24040 by
adding the actual integration into the booking flow and implementing
the decoy response mechanism to avoid revealing spam detection to
malicious actors.

Related: #24040
Co-Authored-By: hariom@cal.com <hariombalhara@gmail.com>
alishaz-polymath pushed a commit that referenced this pull request Oct 14, 2025
* feat: Add async spam check integration and decoy booking response

- Integrate SpamCheckService with handleNewBooking workflow
- Implement parallel spam check execution for minimal performance impact
- Add decoy booking response with localStorage-based success page
- Extract organization ID from event type for org-specific blocking
- Add comprehensive test coverage for spam detection scenarios
- Create reusable components for booking success cards
- Implement fail-open behavior to never block legitimate bookings

This builds on the spam blocker DI infrastructure from PR #24040 by
adding the actual integration into the booking flow and implementing
the decoy response mechanism to avoid revealing spam detection to
malicious actors.

Related: #24040
Co-Authored-By: hariom@cal.com <hariombalhara@gmail.com>

* Do checks in paralle

* Fix leaking host name in title

* Reduce expoiry time localstorage

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
@coderabbitai coderabbitai bot mentioned this pull request Oct 14, 2025
3 tasks
hariombalhara added a commit that referenced this pull request Dec 12, 2025
…g data (#24450)

* feat: Add async spam check integration and decoy booking response

- Integrate SpamCheckService with handleNewBooking workflow
- Implement parallel spam check execution for minimal performance impact
- Add decoy booking response with localStorage-based success page
- Extract organization ID from event type for org-specific blocking
- Add comprehensive test coverage for spam detection scenarios
- Create reusable components for booking success cards
- Implement fail-open behavior to never block legitimate bookings

This builds on the spam blocker DI infrastructure from PR #24040 by
adding the actual integration into the booking flow and implementing
the decoy response mechanism to avoid revealing spam detection to
malicious actors.

Related: #24040
Co-Authored-By: hariom@cal.com <hariombalhara@gmail.com>

* Do checks in paralle

* Fix leaking host name in title

* Reduce expoiry time localstorage

* refactor: Use sessionStorage instead of localStorage for decoy booking data

- Replace localStorage with sessionStorage for automatic expiration on tab close
- Remove timestamp tracking and TTL logic (no longer needed)
- Improve privacy by auto-clearing data when browser tab/window closes
- Update documentation to reflect sessionStorage behavior

This change addresses privacy concerns by ensuring decoy booking data
(including attendee email) is automatically removed when the user closes
the tab, rather than persisting for 5 minutes or requiring manual cleanup.

Co-Authored-By: hariom@cal.com <hariombalhara@gmail.com>

* feat: Add sessionStorage wrapper to webstorage module

Co-Authored-By: hariom@cal.com <hariombalhara@gmail.com>

* Reset RegularBookingService.ts to main's version exactly

* feat: Add 5-minute expiration timeout to decoy booking data

- Adds timestamp to DecoyBookingData interface
- Checks expiration when retrieving booking data
- Automatically removes expired data from sessionStorage
- Provides defense-in-depth against potential misuse
- Works alongside sessionStorage auto-clear on tab close

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
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 enterprise area: enterprise, audit log, organisation, SAML, SSO ✨ feature New feature or request platform Anything related to our platform plan ready-for-e2e size/XXL

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants