Skip to content

fix(slots): widen booking prefetch window to account for event buffers#29540

Open
GAURAV07C wants to merge 5 commits into
calcom:mainfrom
GAURAV07C:fix/slots-prefetch-ignore-buffer-overlap
Open

fix(slots): widen booking prefetch window to account for event buffers#29540
GAURAV07C wants to merge 5 commits into
calcom:mainfrom
GAURAV07C:fix/slots-prefetch-ignore-buffer-overlap

Conversation

@GAURAV07C

Copy link
Copy Markdown

Problem

The slots endpoint was offering times that booking validation would reject with no_available_users_found_error.

Root cause

findAllExistingBookingsForEventTypeBetween fetched bookings only within the raw requested range. If a booking ended just before the range start, its after-event buffer was ignored — making the slot appear free when it wasn't.

This caused a mismatch:

  • Slot generation: missed buffer-overlapping bookings
  • Booking validation (getBusyTimes): correctly detected them

Result: Users were shown slots (e.g. 9:30) that later failed during booking.


Fix

#29532

Applied buffer-aware widening to the booking prefetch query using getDefinedBufferTimes() max buffer, aligning it with getBusyTimes behavior.

Now the slot generation includes bookings whose buffers overlap the requested time window.


Steps to Reproduce

  1. Host available: 9:00–17:00
  2. Event A: 45 min + 30 min after-buffer → busy until 9:45
  3. Request slots starting at 9:20
  4. 9:30 slot appears (incorrect)
  5. Attempt booking → no_available_users_found_error

Changes

  • packages/features/bookings/repositories/BookingRepository.ts
    • Updated booking fetch range to include max buffer window
    • Ensures buffer-overlapping bookings are included in slot calculation

Impact

  • Prevents invalid slot exposure
  • Aligns slot generation with booking validation logic
  • Improves consistency between availability and booking confirmation

Previously, findAllExistingBookingsForEventTypeBetween fetched bookings
only within the raw requested range. Bookings ending just before the
range start were ignored, even if their after-event buffer overlapped
the requested window. This caused the slots endpoint to offer times
that booking validation would reject with no_available_users_found_error.
Fix: Apply the same max-buffer widening (getDefinedBufferTimes) to the
prefetch query that getBusyTimes already applies when fetching its own
bookings.
@github-actions

Copy link
Copy Markdown
Contributor

Welcome to Cal.diy, @GAURAV07C! Thanks for opening this pull request.

A few things to keep in mind:

  • This is Cal.diy, not Cal.com. Cal.diy is a community-driven, fully open-source fork of Cal.com licensed under MIT. Your changes here will be part of Cal.diy — they will not be deployed to the Cal.com production app.
  • Please review our Contributing Guidelines if you haven't already.
  • Make sure your PR title follows the Conventional Commits format.

A maintainer will review your PR soon. Thanks for contributing!

@coderabbitai

coderabbitai Bot commented Jun 10, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

The viewer slots util now imports getDefinedBufferTimes and uses it in calculateHostsAndAvailabilities to compute a maxBuffer and expand the date range passed to bookingRepo.findAllExistingBookingsForEventTypeBetween (subtracting from startDate and adding to endDate). A separate file, BookingRepository.ts, has a minor non-functional whitespace adjustment between two type declarations.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title 'fix(slots): widen booking prefetch window to account for event buffers' accurately summarizes the main change: expanding the booking fetch range to account for event buffer overlaps in slot availability calculations.
Description check ✅ Passed The description is directly related to the changeset, clearly explaining the problem (slots showing times that fail validation), root cause (buffer-overlapping bookings not fetched), and fix (widening the prefetch window using getDefinedBufferTimes).
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/features/bookings/repositories/BookingRepository.ts (1)

700-711: ⚠️ Potential issue | 🟠 Major

Fix double-application of maxBuffer in booking overlap queries (performance hit)

BookingRepository._findAllExistingBookingsForEventTypeBetween expands startDate/endDate by maxBuffer (via getDefinedBufferTimes()), but packages/features/busyTimes/services/getBusyTimes.ts already expands the same window with startTimeAdjustedWithMaxBuffer/endTimeAdjustedWithMaxBuffer before calling findAllExistingBookingsForEventTypeBetween, causing the effective query window to be ~2× maxBuffer.

Callers like packages/trpc/server/routers/viewer/slots/util.ts pass unbuffered startTimeDate/endTimeDate, so they only get a single expansion.

Adjust either:

  • remove the caller-side maxBuffer adjustment in getBusyTimes.ts, or
  • move buffer-expansion responsibility so it happens in exactly one place.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/features/bookings/repositories/BookingRepository.ts` around lines
700 - 711, The repository and the busy-times service are both expanding the
query window by maxBuffer which doubles the buffer; centralize buffer expansion
in BookingRepository._findAllExistingBookingsForEventTypeBetween and remove the
caller-side expansion in packages/features/busyTimes/services/getBusyTimes.ts.
Concretely, delete the startTimeAdjustedWithMaxBuffer /
endTimeAdjustedWithMaxBuffer computation and any use of those variables in
getBusyTimes.ts, and ensure getBusyTimes and its callers pass the raw
startDate/endDate into
BookingRepository._findAllExistingBookingsForEventTypeBetween so the
repository’s existing maxBuffer logic (definedBufferTimes, maxBuffer, and
sharedQuery) remains the single source of truth for buffer expansion.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@packages/features/bookings/repositories/BookingRepository.ts`:
- Around line 700-711: The repository and the busy-times service are both
expanding the query window by maxBuffer which doubles the buffer; centralize
buffer expansion in
BookingRepository._findAllExistingBookingsForEventTypeBetween and remove the
caller-side expansion in packages/features/busyTimes/services/getBusyTimes.ts.
Concretely, delete the startTimeAdjustedWithMaxBuffer /
endTimeAdjustedWithMaxBuffer computation and any use of those variables in
getBusyTimes.ts, and ensure getBusyTimes and its callers pass the raw
startDate/endDate into
BookingRepository._findAllExistingBookingsForEventTypeBetween so the
repository’s existing maxBuffer logic (definedBufferTimes, maxBuffer, and
sharedQuery) remains the single source of truth for buffer expansion.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: b8747b50-33db-4746-ac71-594a1a2f7895

📥 Commits

Reviewing files that changed from the base of the PR and between 743f988 and a002293.

📒 Files selected for processing (1)
  • packages/features/bookings/repositories/BookingRepository.ts

@bandhan-majumder

Copy link
Copy Markdown
Member

@GAURAV07C please attach before/after demo of ur changes!

@bandhan-majumder bandhan-majumder marked this pull request as draft June 11, 2026 04:11
@GAURAV07C

GAURAV07C commented Jun 11, 2026

Copy link
Copy Markdown
Author

@GAURAV07C please attach before/after demo of ur changes!

@bandhan-majumder
Reproduced locally.

Test setup:

  • Existing booking: 08:30–09:15
  • After-event buffer: 30 minutes
  • Host busy until: 09:45
  • Requested slots starting at: 09:20

Before fix:
First returned slot = 09:30

{"time":"2026-06-12T04:00:00.000Z"}

04:00 UTC = 09:30 IST

image

After fix:
First returned slot = 10:00

{"time":"2026-06-12T04:30:00.000Z"}

04:30 UTC = 10:00 IST

image

The 09:30 slot was previously returned even though the host was busy until 09:45 because of the after-event buffer.

After widening the booking lookup range to include buffer-overlapping bookings, the invalid 09:30 slot is no longer returned and the first available slot is correctly shown as 10:00.

04:30 UTC = 10:00 IST

So the invalid 09:30 slot is no longer exposed after widening the booking lookup range to include buffer-overlapping bookings.

@GAURAV07C GAURAV07C marked this pull request as ready for review June 11, 2026 10:21
@GAURAV07C

GAURAV07C commented Jun 12, 2026 via email

Copy link
Copy Markdown
Author

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
packages/trpc/server/routers/viewer/slots/util.ts (1)

733-739: ⚡ Quick win

Prefer native Date math for buffer padding in this non-timezone path.

At Line 738 and Line 739, dayjs is only used for minute arithmetic on Date objects. Switching to native Date keeps this path lighter and aligns with the repo rule.

♻️ Proposed refactor
-    const definedBufferTimes = getDefinedBufferTimes();
-    const maxBuffer = definedBufferTimes[definedBufferTimes.length - 1];
+    const maxBuffer = Math.max(...getDefinedBufferTimes());

     const [currentBookingsAllUsers, outOfOfficeDaysAllUsers] = await Promise.all([
       bookingRepo.findAllExistingBookingsForEventTypeBetween({
-        startDate: dayjs(startTimeDate).subtract(maxBuffer, "minute").toDate(),
-        endDate: dayjs(endTimeDate).add(maxBuffer, "minute").toDate(),
+        startDate: new Date(startTimeDate.getTime() - maxBuffer * 60_000),
+        endDate: new Date(endTimeDate.getTime() + maxBuffer * 60_000),
         eventTypeId: eventType.id,
         seatedEvent: Boolean(eventType.seatsPerTimeSlot),
         userIdAndEmailMap,
       }),

As per coding guidelines, Use date-fns or native Date instead of Day.js when timezone awareness isn't needed.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/trpc/server/routers/viewer/slots/util.ts` around lines 733 - 739,
The code uses dayjs just to add/subtract minutes for buffer padding; replace
that with native Date arithmetic: compute start = new
Date(startTimeDate.getTime() - maxBuffer * 60_000) and end = new
Date(endTimeDate.getTime() + maxBuffer * 60_000) and pass those to
bookingRepo.findAllExistingBookingsForEventTypeBetween (and any other call using
the dayjs versions). Keep getDefinedBufferTimes and maxBuffer logic unchanged;
remove the dayjs(startTimeDate).subtract(...) / dayjs(endTimeDate).add(...)
usage and use the native Date results instead.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@packages/trpc/server/routers/viewer/slots/util.ts`:
- Around line 733-739: The code uses dayjs just to add/subtract minutes for
buffer padding; replace that with native Date arithmetic: compute start = new
Date(startTimeDate.getTime() - maxBuffer * 60_000) and end = new
Date(endTimeDate.getTime() + maxBuffer * 60_000) and pass those to
bookingRepo.findAllExistingBookingsForEventTypeBetween (and any other call using
the dayjs versions). Keep getDefinedBufferTimes and maxBuffer logic unchanged;
remove the dayjs(startTimeDate).subtract(...) / dayjs(endTimeDate).add(...)
usage and use the native Date results instead.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 38d7d389-8c10-4631-b7e7-ca825c54922a

📥 Commits

Reviewing files that changed from the base of the PR and between a002293 and 5d38cce.

📒 Files selected for processing (2)
  • packages/features/bookings/repositories/BookingRepository.ts
  • packages/trpc/server/routers/viewer/slots/util.ts
✅ Files skipped from review due to trivial changes (1)
  • packages/features/bookings/repositories/BookingRepository.ts

@CLAassistant

CLAassistant commented Jun 14, 2026

Copy link
Copy Markdown

CLA assistant check
All committers have signed the CLA.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants