Summary

When a host reschedules a booking, the system now checks if any attendees (guests) are Cal.com users and fetches their accepted bookings as busy times. This prevents the host from accidentally double-booking a guest during reschedule.

Fixes #16378

/claim #16378

How it works

  1. When rescheduleUid is present in the slot calculation, look up the booking’s attendees
  2. Filter out host emails to isolate guest-only emails
  3. Look up Cal.com users matching guest emails (primary + verified secondary emails)
  4. Query their accepted bookings in the date range (using overlap semantics)
  5. Inject as guestBusyTimes into the availability calculation, where they are merged into detailedBusyTimes

Changes (4 files, ~170 lines)

File Change
packages/features/users/repositories/UserRepository.ts Add findByEmails() — raw SQL UNION matching primary + verified secondary emails, excludes locked accounts
packages/features/bookings/repositories/BookingRepository.ts Add findAcceptedByUserIdsOrEmails() — queries accepted bookings with overlap date semantics
packages/features/availability/lib/getUserAvailability.ts Add guestBusyTimes? to GetUserAvailabilityInitialData; spread into detailedBusyTimes
packages/trpc/server/routers/viewer/slots/util.ts Add getGuestBusyTimesForReschedule() function + call site in calculateHostsAndAvailabilities()

Design decisions

  • Raw SQL UNION for user lookup: Follows the existing findVerifiedUsersByEmailsRaw pattern in UserRepository for performance (avoids Prisma OR + secondary email join). No LOWER() on columns to preserve B-tree index usage.
  • Overlap semantics for date queries: Uses startTime <= endDate AND endTime >= startDate to catch bookings that partially overlap the search window, not just those fully contained within it.
  • Host-email exclusion: Hosts are excluded from the guest list so a host’s own calendar is not counted twice.
  • Excludes the booking being rescheduled: The excludeUid parameter prevents the original booking’s time from being treated as a conflict.
  • Skipped for COLLECTIVE: All hosts are already checked in COLLECTIVE scheduling, making guest-level checks redundant.
  • Graceful degradation: If the guest availability lookup fails, rescheduling still works. Errors are logged as warnings.
  • No schema changes: guestBusyTimes is an optional field on GetUserAvailabilityInitialData, fully backwards-compatible.
  • Follows Cal.com patterns: Uses select (not include), repository pattern with DI, case-insensitive email matching.

Test plan

  • Unit tests for getGuestBusyTimesForReschedule (8 tests)
  • Unit tests for BookingRepository.findAcceptedByUserIdsOrEmails (5 tests)
  • Unit tests for UserRepository.findByEmails (3 tests)
  • All 19 tests passing
  • Existing slot tests unaffected (4 test files, 19 tests pass)
  • Manual: Create a booking with a Cal.com user guest, guest accepts another booking overlapping a reschedule slot, host opens reschedule — conflicting slot should not appear
  • Manual: Rescheduling with non-Cal.com guests behaves identically to before

🤖 Generated with Claude Code

Claim

Total prize pool $200
Total paid $0
Status Pending
Submitted March 17, 2026
Last updated March 17, 2026

Contributors

JA

janekissington

@janekissington

100%

Sponsors

CA

Cal.com, Inc.

@cal

$200