PERFORMANCE: The bookings/get endpoint was taking 24s due to materializing 400+ email
addresses as individual parameters in WHERE IN clauses. This caused massive UNION
queries that overwhelmed the database.
Changes:
- Replace IN clauses with Kysely subqueries for queries 4, 5, 6, and 7
- Query 4 & 5: Use subquery to get emails from users via Membership table
- Query 6: Use subquery to get event type IDs from EventType table
- Query 7: Use subquery to get user IDs from Membership table
- Only fetch user IDs when needed for userIds filter validation
- Add new getUserIdsFromTeamIds function (lighter version without emails)
Before: WHERE email IN ($1, $2, ..., $400+) - passes 400+ parameters
After: WHERE email IN (SELECT email FROM users JOIN Membership...) - passes only team IDs
This reduces parameter count from 400+ to typically 1-10 team IDs, letting the
database optimize the query execution plan.
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
* fix: use FeatureOptInService for bookings-v3 check
* refactor: simplify FeatureOptInService API and fix bookings page
- Add resolveFeatureStates method that takes only userId and featureIds
- Update listFeaturesForUser to take only userId parameter
- Remove getUserOrgAndTeamIds from _router.ts (now internal to service)
- Fix bookings page to use new resolveFeatureStates method
- Parallelize getUserFeaturesStatus and resolveFeatureStates calls
Co-Authored-By: eunjae@cal.com <hey@eunjae.dev>
* check session?.user?.id first
* remove comment
---------
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
* feat: add invoice URL to proration and test seed scripts
- Add invoiceUrl field to MonthlyProration schema
- Update billing service to return hosted_invoice_url after finalizing
- Save invoice URL when creating proration invoices
- Add seed script for testing proration with real Stripe data
- Add cleanup script for test data removal
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* add invoice url
* add invoice URL to tests
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
* feat: add composite indexes for booking queries at scale
Add new composite indexes to optimize common query patterns for the Booking
and Attendee tables. These indexes are designed to support the system at scale
(14M+ bookings, 50K daily inserts) while minimizing write overhead.
New indexes on Booking table:
- (userId, endTime): Optimizes /bookings/upcoming queries
- (userId, status, startTime): Optimizes busy times and filtered queries
- (eventTypeId, status): Optimizes round-robin and team booking queries
- (userId, createdAt): Optimizes API queries with createdAt sorting
New index on Attendee table:
- (bookingId, email): Optimizes JOIN queries filtering by attendee email
These indexes target the most common query patterns identified in:
- get.handler.ts (bookings list endpoints)
- BookingRepository.ts (busy times, round-robin)
- API v1 bookings endpoint
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
* feat: add migration file for booking composite indexes
Add SQL migration to create the new composite indexes:
- Attendee(bookingId, email)
- Booking(userId, endTime)
- Booking(userId, status, startTime)
- Booking(eventTypeId, status)
- Booking(userId, createdAt)
Also clean up comments in schema.prisma to be more generic.
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
* fix: swap Attendee index column order to (email, bookingId)
Per Cubic AI review feedback - place email first to match the filter
column order in queries that filter by email.
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
---------
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
* refactor: lazy load KBar data fetching hooks only when opened
Co-Authored-By: alex@cal.com <me@alexvanandel.com>
* refactor: move KBar data fetching into RenderResults for proper lazy loading
Co-Authored-By: alex@cal.com <me@alexvanandel.com>
---------
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
* feat: add forcedSlowMode rate limit to Team and Organization DELETE endpoints
Co-Authored-By: alex@cal.com <me@alexvanandel.com>
* test: add NoOpThrottlerGuard to disable rate limiting in tests
- Create NoOpThrottlerGuard class that always allows requests through
- Create withNoThrottler helper function to override CustomThrottlerGuard
- Update teams.controller.e2e-spec.ts to use withNoThrottler
- Update organizations-teams.controller.e2e-spec.ts to use withNoThrottler
- Update organizations-organizations.controller.e2e-spec.ts to use withNoThrottler
This prevents race conditions when tests fire rapidly against rate-limited endpoints.
Co-Authored-By: alex@cal.com <me@alexvanandel.com>
* fix: use jest.spyOn to mock throttler guard in tests
Changed approach from overrideGuard to jest.spyOn for mocking
CustomThrottlerGuard.handleRequest to always return true. This
properly disables rate limiting in tests for the DELETE endpoints.
Co-Authored-By: alex@cal.com <me@alexvanandel.com>
---------
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: Morgan <33722304+ThyMinimalDev@users.noreply.github.com>
* Create `getSalesforceTokenLifetime`
* When connecting salesforce, add token_lifetime
* Migrate token_lifetime and refetch if token expiry doesn't match
* Add tests for Salesforce token lifetime feature
- Add unit tests for getSalesforceTokenLifetime function
- Add integration tests for token lifecycle management in CrmService
- Fix type error in CrmService.ts by extracting refreshToken variable
Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>
* chore: re-trigger CI
Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>
---------
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
* feat: add proration invoice and reminder email templates
Add email templates for monthly proration billing notifications:
- ProrationInvoiceEmail: Sent when invoice is created for additional seats
- ProrationReminderEmail: Sent 7 days later if invoice remains unpaid
Includes:
- React email templates using V2BaseEmailHtml
- BaseEmail classes for rendering
- Billing email service functions
- Translation keys for email content
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* fix: use allSettled
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Add three new optional callbacks to CalProvider that enable users to react during the access token refresh lifecycle:
- onTokenRefreshStart: Called when token refresh begins
- onTokenRefreshSuccess: Called when token refresh succeeds
- onTokenRefreshError: Called when token refresh fails with error message
These callbacks are invoked in both token refresh locations:
1. Response interceptor (when API returns 498 status)
2. Initial access token validation
The callbacks are properly passed through the component hierarchy:
CalProvider -> BaseCalProvider -> useOAuthFlow hook
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: Rajiv Sahal <sahalrajiv-extc@atharvacoe.ac.in>
* fix: remove sticky positioning from page headers in pages using ShellMain
* correct fix (mostly)
* fix: disable sticky headers on routing forms and members pages
Applied disableSticky={true} to remaining affected pages:
- Routing Forms page
- Organization Members view
- Platform Members view
---------
Co-authored-by: Dhairyashil <dhairyashil10101010@gmail.com>
* wip flow
* add tests
* WIP migrateing view
* push back step
* fix tests and logic for adding new members to existing teams
* few UI fixes
* type fixes
* fix nits
* few UI + re-route fixes
* fix teamId when migrating
* fix: use createPortal for FeatureOptInBanner to avoid Intercom widget conflict
Co-Authored-By: eunjae@cal.com <hey@eunjae.dev>
* fix: guard portal rendering against non-browser environments
Add typeof document check before accessing document.body in createPortal
to prevent SSR/test crashes when document is undefined.
Co-Authored-By: unknown <>
---------
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
* refactor(companion): split calcom.ts into modular service files
Split the monolithic 1692-line calcom.ts file into focused modules:
- auth.ts: Authentication configuration and token management
- bookings.ts: Booking CRUD operations and actions
- conferencing.ts: Conferencing options
- event-types.ts: Event type CRUD operations
- private-links.ts: Private link management for event types
- request.ts: Core HTTP request functionality
- schedules.ts: Schedule CRUD operations
- user.ts: User profile management
- utils.ts: JSON parsing and payload sanitization utilities
- webhooks.ts: Webhook management (global and event type specific)
- index.ts: Re-exports all functions and maintains backward compatibility
This improves code organization, maintainability, and makes it easier
to understand and modify specific functionality.
Co-Authored-By: peer@cal.com <peer@cal.com>
* fix(companion): avoid logging sensitive booking response data
Replace logging of full responseText (which may contain PII like attendee
emails and names) with responseLength for safer debugging.
Addresses Cubic AI review feedback (confidence 9/10).
Co-Authored-By: unknown <>
---------
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>