Commit Graph
1594 Commits
Author SHA1 Message Date
Syed Ali ShahbazGitHubali@cal.com <alishahbaz7@gmail.com>ali@cal.com <alishahbaz7@gmail.com>ali@cal.com <alishahbaz7@gmail.com>ali@cal.com <alishahbaz7@gmail.com>Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
3a7122d613 fix: revert assignmentReason breaking change in webhook payloads (#27891)
* fix: revert assignmentReason breaking change in webhook payloads

Remove the new { category, details } format from EventPayloadType to
maintain backward compatibility for webhook consumers. The new format
is stripped at all webhook payload construction sites by destructuring
assignmentReason out of CalendarEvent before spreading into the payload.

A sanitizeAssignmentReasonForWebhook function provides an additional
safety net in sendPayload itself. Emails and booking single view
continue to use the new format via CalendarEvent.

Co-Authored-By: ali@cal.com <alishahbaz7@gmail.com>

* fix: strip assignmentReason from handlePaymentSuccess webhook payload

Co-Authored-By: ali@cal.com <alishahbaz7@gmail.com>

* fix: strip assignmentReason from triggerWebhooks and handleSeats webhook payloads

Co-Authored-By: ali@cal.com <alishahbaz7@gmail.com>

* refactor: use zod safeParse instead of type assertion in sanitizeAssignmentReasonForWebhook

Co-Authored-By: ali@cal.com <alishahbaz7@gmail.com>

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-02-16 21:55:10 -03:00
21d28c9747 refactor: apply biome formatting to packages/trpc (#27928)
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-16 12:46:42 -03:00
Syed Ali ShahbazGitHubali@cal.com <alishahbaz7@gmail.com>ali@cal.com <alishahbaz7@gmail.com>ali@cal.com <alishahbaz7@gmail.com>ali@cal.com <alishahbaz7@gmail.com>Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
50c7210d6b fix: resolve signup watchlist review issues and auto-unlock on SIGNUP entry removal (#27923)
* fix: resolve signup watchlist review issues with deleteEntry, email verification ordering, and unlock flow

Co-Authored-By: ali@cal.com <alishahbaz7@gmail.com>

* fix: scope sendEmailVerification to non-invite signups only

Co-Authored-By: ali@cal.com <alishahbaz7@gmail.com>

* feat: auto-unlock users when SIGNUP-source watchlist entries are removed

Co-Authored-By: ali@cal.com <alishahbaz7@gmail.com>

* fix: remove PII from error logging in unlockSignupUser

Co-Authored-By: ali@cal.com <alishahbaz7@gmail.com>

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-02-13 10:13:33 +00:00
Alex van AndelGitHubalex@cal.com <me@alexvanandel.com>cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>alex@cal.com <me@alexvanandel.com>alex@cal.com <me@alexvanandel.com>alex@cal.com <me@alexvanandel.com>alex@cal.com <me@alexvanandel.com>Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
d3bbed01f6 feat: add signup watchlist review mode (#27912)
* feat: add signup watchlist review feature flag and handler logic

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

* test: add isAccountUnderReview tests to fetchSignup test suite

Co-Authored-By: alex@cal.com <me@alexvanandel.com>

* fix: address Cubic AI review feedback (confidence >= 9/10)

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

* fix: remove node:process import from useFlags.ts (client-side file)

Co-Authored-By: alex@cal.com <me@alexvanandel.com>

* fix: remove !token condition from watchlist review check

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>

* Apply suggestion from @cubic-dev-ai[bot]

Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>

* refactor: move user lock to UserRepository.lockByEmail

Co-Authored-By: alex@cal.com <me@alexvanandel.com>

* refactor: use cached getFeatureRepository() instead of deprecated FeaturesRepository

Co-Authored-By: alex@cal.com <me@alexvanandel.com>

* refactor: remove user locking, keep only watchlist addition on signup review

Co-Authored-By: alex@cal.com <me@alexvanandel.com>

* feat: lock user on signup review, remove watchlist entry on unlock

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: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
2026-02-12 23:14:31 +00:00
sean-brydonandGitHub 98ec38aeaa feat: add annual plans for teams/organizations (#27896)
* wip: add annual plan priceId support

* fix type errors

* type cast
2026-02-12 14:05:24 +00:00
sean-brydonGitHubunknown <>unknown <>sean@cal.com <Sean@brydon.io>Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
d52e2d9fad feat: active user billing (#27867)
* factory and statergie

* chore: use correct method of DI

* feat: add onchagne

* add logic to HWM stat

* add webhook resolver methods to each statergy

* move seat tracking + webhooks over to own statergy

* Move to factory base approach

* move logic to correct class

* rename create -> createByTeamId

* fix: remove debug `true ||` overrides from IS_STRIPE_ENABLED and IS_TEAM_BILLING_ENABLED

Remove accidentally committed debug overrides that short-circuited
IS_STRIPE_ENABLED and IS_TEAM_BILLING_ENABLED to always be true,
bypassing Stripe credential checks. This would break self-hosted
instances without Stripe configured.

Identified by cubic (https://cubic.dev)

Co-Authored-By: unknown <>

* feat: active user billing

* add tests

* UI side for users on active billing

* use correct period of stripe sub

* feat: claude feedback

* fix: skip Stripe sync for canceled/expired subscriptions to prevent repeated API calls

Co-Authored-By: unknown <>

* feat: feedback

* feat: only render when active users mode is set

* fix type error

* fix: constants + feature flags

* fix: default to null in tests

* chore: use seats in test

* fix: use node:crypto protocol for Node.js builtin imports

Co-Authored-By: sean@cal.com <Sean@brydon.io>

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-02-12 13:57:32 +00:00
+4
Joe Au-YeungGitHubjoe@cal.com <j.auyeung419@gmail.com>cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>joe@cal.com <j.auyeung419@gmail.com>joe@cal.com <j.auyeung419@gmail.com>alex@cal.com <me@alexvanandel.com>alex@cal.com <me@alexvanandel.com>alex@cal.com <me@alexvanandel.com>Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>Claude Opus 4.5hariom@cal.com <hariombalhara@gmail.com>cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>alex@cal.com <me@alexvanandel.com>
7cfb053026 feat: add wrong routing tab under Insights for reviewing assignment reports (#27423)
* Add DB table for wrong assignment reports

* When report is submitted write to the db

* Prevent duplicate reportings

* test: add migration and tests for WrongAssignmentReport table

Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>

* fix: add unique constraint on bookingUid and booking access check for hasWrongAssignmentReport

- Add @unique constraint on bookingUid in WrongAssignmentReport model to prevent duplicate reports at DB level
- Add booking ownership check using BookingAccessService in hasWrongAssignmentReport endpoint
- Refactor hasWrongAssignmentReport into separate handler and schema files

Addresses Cubic AI review feedback on PR #27405

Co-Authored-By: unknown <>

* feat: add routingFormId to WrongAssignmentReport and fix Select clearing

- Add routingFormId field to WrongAssignmentReport model in schema.prisma
- Add relation to App_RoutingForms_Form with SetNull on delete
- Update WrongAssignmentReportRepository.createReport to accept routingFormId
- Update BookingRepository.findByUidIncludeEventTypeAndTeamAndAssignmentReason to include routedFromRoutingFormReponse
- Extract routingFormId from booking in reportWrongAssignment handler
- Fix Select clearing issue: handle null case when user clears team member selection
- Update tests to include routingFormId field

Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>

* chore: add migration for routingFormId in WrongAssignmentReport

Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>

* feat: add wrong assignment reports dashboard under routing tab

- Add reviewedById and reviewedAt fields to WrongAssignmentReport model
- Add repository methods for listing reports by status and updating status
- Create tRPC endpoints for fetching reports and updating status
- Create dashboard UI with pending/reviewed tabs showing routing form name
- Add translation keys for dashboard UI
- Integrate dashboard into routing insights page

Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>

* fix: move hooks before early return and fix indentation

Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>

* fix: address Udit's review comments

- hasWrongAssignmentReport: throw UNAUTHORIZED error instead of returning false
- reportWrongAssignment: add try-catch for Prisma P2002 unique constraint error
- WrongAssignmentReport: add Team relation to teamId field
- WrongAssignmentReportRepository: use findUnique instead of findFirst
- reportWrongAssignment: use i18n for error messages

Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>

* fix: revert hasWrongAssignmentReport to return false when user lacks access

Per PR checklist, hasWrongAssignmentReport should return { hasReport: false }
when user lacks access to booking, not throw an error. This allows the UI
to gracefully treat 'no access' as 'no report exists'.

Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>

* test: update mocks for findUnique and i18n in unit tests

Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>

* fix: throw UNAUTHORIZED in hasWrongAssignmentReport and squash migrations

Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>

* feat: move wrong assignment reports to its own tab under Insights

Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>

* Use data table for wrong reports

* Add option to view routing trace

* feat: add view routing form submission action to wrong assignment reports

Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>

* feat: add RoutingFormResponseSheet component for viewing form submissions

- Create slide-out sheet to display routing form responses
- Map option IDs to display labels for select/multiselect fields
- Handle both legacy and modern option formats
- Add i18n strings: form_submission, no_responses_found

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* feat: improve wrong assignment reports UX

- Integrate RoutingFormResponseSheet as slide-out panel instead of new tab
- Fix dropdown padding by using StartIcon prop instead of manual Icon
- Allow direct status changes for reviewed reports (no need to reopen first)
- Remove unused Icon import

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix: change User relation onDelete from Cascade to SetNull in WrongAssignmentReport

Address Hariom's review feedback:
- Changed reportedById from Int to Int? (nullable)
- Changed reportedBy relation from onDelete: Cascade to onDelete: SetNull
- Updated migration SQL to reflect these changes

This preserves wrong assignment reports even when the reporting user is deleted,
as the data is still useful for analysis.

Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>

* feat: add missing i18n strings for wrong assignment reports dashboard

Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>

* refactor: move form response display value resolution server-side

Replace client-side option ID to label resolution in
RoutingFormResponseSheet with a new lean tRPC endpoint
(getFormResponseDisplay) that resolves values server-side using
the existing getHumanReadableFieldResponseValue utility. This
enforces DTO boundaries by returning a clean pre-resolved payload
instead of leaking internal option format details to the client.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* feat: add report wrong assignment button to routing trace sheet

Wire up the WrongAssignmentDialog from the routing trace sheet header
so users can flag wrong assignments directly while viewing the trace.
The report button is disabled with a tooltip when a report already
exists.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* refactor: reuse existing WrongAssignmentDialog from parent

Replace the duplicate WrongAssignmentDialog in RoutingTraceSheet with
a callback to the existing instance in BookingActionsDropdown. This
reduces the prop surface from a 6-field reportContext object to an
onReport callback and hasExistingReport boolean.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* refactor: use repository instead of direct Prisma in getFormResponseDisplay

Replace direct Prisma query with PrismaRoutingFormResponseRepository's
findByIdIncludeForm method. Extend the method to also select form name,
description, userId, and teamId needed for display and auth checks.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* refactor: replace direct Prisma calls with repository methods

Use MembershipRepository.hasMembership() for auth checks and
TeamRepository.findAllByParentId() for child team queries instead
of direct Prisma calls. Replace direct user query with
UserRepository.getTimeZoneAndDefaultScheduleId(). Remove unused
seed script.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* refactor: use PBAC services for wrong assignment report auth

Replace manual MembershipRepository.hasMembership() checks with
PBAC-aware permission checking. getWrongAssignmentReports uses
createTeamPbacProcedure middleware since teamId is in input.
updateWrongAssignmentReportStatus uses PermissionCheckService
directly since teamId is discovered from the report entity.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: resolve type errors in RoutingFormResponseSheet and wrong-routing view

Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>

* feat: add seed script for wrong assignment reports test data

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

* Revert "feat: add seed script for wrong assignment reports test data"

This reverts commit 0bd60e9661858a59aab1573d14d57d81733b7991.

* Only update reviewed fields when not pending

Co-authored-by: devin-ai-integration[bot] <158243242+devin-ai-integration[bot]@users.noreply.github.com>

* refactor: wrap handleStatusChange in useCallback to fix useMemo recalculation

Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>

* Fix routing sheet UI

* fix: use appropriate error message in getFormResponseDisplay handler

Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>

* refactor: extract WrongAssignmentReportService from tRPC handlers

Move business logic (booking lookup, duplicate check, report creation,
webhook dispatch, org-level team resolution) into a dedicated service
in packages/features. Handlers become thin controllers that only handle
auth checks and delegate to the service.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: restrict report status updates to admin/owner roles

Remove MembershipRole.MEMBER from fallbackRoles in
updateWrongAssignmentReportStatus permission check. Updating report
status is an administrative action that should be limited to team
admins and owners.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: localize hard-coded success message in WrongAssignmentReportService

Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>

* fix: rename reviewed tab to handled and add missing translations

Rename the "Reviewed" tab to "Handled" since it groups three distinct
statuses (Reviewed, Resolved, Dismissed). Also add missing translation
keys for "resolved" and "dismissed" status badges.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* merge: resolve conflicts with main branch

Merge main into devin/1769747741-wrong-assignment-dashboard, resolving conflicts in:
- BookingActionsDropdown.tsx: use main's booking prop with PR's fragment structure
- reportWrongAssignment.handler.ts: keep PR's service-based approach
- reportWrongAssignment.handler.test.ts: use main's class-based mocks with PR's additions
- WrongAssignmentReportService.ts: align with main's repo method and field names

Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>

* Add guard when accessing assignmentReasonSortedByCreatedAt

Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>

* fix: address Cubic AI review feedback - select projection and useLocale refactor

Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>

* fix: remove stale TRPCError assertion in test (service throws ErrorWithCode)

Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>

* refactor: remove unused findByTeamIdAndStatus and findByTeamIdAndStatuses methods

Co-Authored-By: alex@cal.com <me@alexvanandel.com>

* perf: add composite index on WrongAssignmentReport and narrow findByIdIncludeForm select

Co-Authored-By: alex@cal.com <me@alexvanandel.com>

* perf: use lightweight findTeamIdById in update-status handler instead of findById

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: Claude Opus 4.5 <noreply@anthropic.com>
Co-authored-by: hariom@cal.com <hariombalhara@gmail.com>
Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
Co-authored-by: alex@cal.com <me@alexvanandel.com>
2026-02-12 13:02:33 +00:00
Joe Au-YeungGitHubjoe@cal.com <j.auyeung419@gmail.com>joe@cal.com <j.auyeung419@gmail.com>joe@cal.com <j.auyeung419@gmail.com>Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
06bb994145 fix: Improve wrong assignment report (#27162)
* Pass already fetched booking

* Fetch the assignment reason

* Update tests

* Label as first assignment reason

* Pass single booking object

* Remove unused repository method

* Only pass bookingUid to handler

* Rename booking `assignmentReason` to `assignmentReasonSortedByCreatedAt`

* fix: use renamed assignmentReasonSortedByCreatedAt property

Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>

* Remove take statement

* fix: address Udit's review comments

- Restore BookingAccessService for access control checks
- Rename repository method from findByUidForWrongAssignmentReport to findByUidIncludeUserAndEventTypeTeamAndAttendeesAndAssignmentReason

Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>

* test: update tests to use BookingAccessService mock

Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>

* fix: use latest assignment reason in BookingDetailsSheet for consistency

Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-02-11 13:12:21 -05:00
Keith WilliamsGitHubDevin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
bc8ebb9213 perf: use UNION ALL with DISTINCT for bookings query optimization (#27841)
* perf: use UNION ALL with DISTINCT for bookings query optimization

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

* test: add unionAll and distinct to kysely test mocks

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

* test: add integration tests for getBookings query

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

* test: add totalCount deduplication test for multi-branch union scenario

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

* test: fix totalCount assertion to be exact instead of gte

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

* Apply suggestion from @keithwillcode

* perf: restore COUNT(DISTINCT id) for totalCount query

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

* Add tests: packages/trpc/server/routers/viewer/bookings/get.handler.integration-test.ts

Generated by Paragon from proposal for PR #27841

* Add tests: packages/trpc/server/routers/viewer/bookings/get.handler.test.ts

Generated by Paragon from proposal for PR #27841

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-02-11 11:33:11 -03:00
Everton ResendeandGitHub dc3e681e01 fix: hide cancel/reschedule links in emails when disabled (#27637)
When disableCancelling or disableRescheduling is enabled on an event type,
the confirmation email still showed non-functional cancel/reschedule links.

The ManageLink email component already had correct conditional logic to
hide these links, but two flows constructed the CalendarEvent manually
without including the flags: the booking confirmation handler and the
payment booking flow. This caused the flags to be undefined, which
ManageLink interpreted as enabled.

Added disableCancelling and disableRescheduling to the Prisma select and
CalendarEvent object in both confirm.handler.ts and getBooking.ts.

Closes #22906
2026-02-10 18:57:54 -03:00
sean-brydonGitHubunknown <>Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
f4abbb2de1 feat: refactor billing to strategy implemention (#27828)
* factory and statergie

* chore: use correct method of DI

* feat: add onchagne

* add logic to HWM stat

* add webhook resolver methods to each statergy

* move seat tracking + webhooks over to own statergy

* Move to factory base approach

* move logic to correct class

* rename create -> createByTeamId

* fix: remove debug `true ||` overrides from IS_STRIPE_ENABLED and IS_TEAM_BILLING_ENABLED

Remove accidentally committed debug overrides that short-circuited
IS_STRIPE_ENABLED and IS_TEAM_BILLING_ENABLED to always be true,
bypassing Stripe credential checks. This would break self-hosted
instances without Stripe configured.

Identified by cubic (https://cubic.dev)

Co-Authored-By: unknown <>

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-02-10 13:11:36 -03:00
Benny JooGitHubunknown <>benny@cal.com <sldisek783@gmail.com>benny@cal.com <sldisek783@gmail.com>benny@cal.com <sldisek783@gmail.com>Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
ae31e05bec refactor: decouple @calcom/features from @calcom/trpc/server [2] (#27821)
* inviteMemberUtils in featuers

* update imports

* wip

* wip

* fix: remove PII from log statements in inviteMemberUtils

- Remove email (usernameOrEmail) from error log in sendSignupToOrganizationEmail
- Replace full user object with userId in debug log in sendExistingUserTeamInviteEmails

Co-Authored-By: unknown <>

* revert: restore original code for pure relocation (no formatting/logic changes)

Co-Authored-By: benny@cal.com <sldisek783@gmail.com>

* fix

* fix: update test mocks to use new import path for inviteMemberUtils

Co-Authored-By: benny@cal.com <sldisek783@gmail.com>

* revert: restore original formatting in proration test and handleGroupEvents

Co-Authored-By: benny@cal.com <sldisek783@gmail.com>

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-02-10 09:29:32 -03:00
Benny JooGitHubbenny@cal.com <sldisek783@gmail.com>Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
431fbe44fc refactor: decouple @calcom/features from @calcom/trpc/server (#27751)
* make GetPublicEventInput

* space

* mv feature flags router to trpc

* remove trpc imports

* wip

* mv OrgMembershipLookup to features

* fix

* fix

* update

* fix

* revert formatting-only changes to improve PR reviewability

Co-Authored-By: benny@cal.com <sldisek783@gmail.com>

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-02-10 09:28:37 -03:00
Joe Au-YeungGitHubjoe@cal.com <j.auyeung419@gmail.com>Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
c0504993a6 feat: Write wrong assignment reports to the database (#27405)
* Add DB table for wrong assignment reports

* When report is submitted write to the db

* Prevent duplicate reportings

* test: add migration and tests for WrongAssignmentReport table

Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>

* fix: add unique constraint on bookingUid and booking access check for hasWrongAssignmentReport

- Add @unique constraint on bookingUid in WrongAssignmentReport model to prevent duplicate reports at DB level
- Add booking ownership check using BookingAccessService in hasWrongAssignmentReport endpoint
- Refactor hasWrongAssignmentReport into separate handler and schema files

Addresses Cubic AI review feedback on PR #27405

Co-Authored-By: unknown <>

* feat: add routingFormId to WrongAssignmentReport and fix Select clearing

- Add routingFormId field to WrongAssignmentReport model in schema.prisma
- Add relation to App_RoutingForms_Form with SetNull on delete
- Update WrongAssignmentReportRepository.createReport to accept routingFormId
- Update BookingRepository.findByUidIncludeEventTypeAndTeamAndAssignmentReason to include routedFromRoutingFormReponse
- Extract routingFormId from booking in reportWrongAssignment handler
- Fix Select clearing issue: handle null case when user clears team member selection
- Update tests to include routingFormId field

Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>

* chore: add migration for routingFormId in WrongAssignmentReport

Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>

* fix: address Udit's review comments

- hasWrongAssignmentReport: throw UNAUTHORIZED error instead of returning false
- reportWrongAssignment: add try-catch for Prisma P2002 unique constraint error
- WrongAssignmentReport: add Team relation to teamId field
- WrongAssignmentReportRepository: use findUnique instead of findFirst
- reportWrongAssignment: use i18n for error messages

Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>

* fix: revert hasWrongAssignmentReport to return false when user lacks access

Per PR checklist, hasWrongAssignmentReport should return { hasReport: false }
when user lacks access to booking, not throw an error. This allows the UI
to gracefully treat 'no access' as 'no report exists'.

Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>

* test: update mocks for findUnique and i18n in unit tests

Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>

* fix: throw UNAUTHORIZED in hasWrongAssignmentReport and squash migrations

Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>

* fix: change User relation onDelete from Cascade to SetNull in WrongAssignmentReport

Address Hariom's review feedback:
- Changed reportedById from Int to Int? (nullable)
- Changed reportedBy relation from onDelete: Cascade to onDelete: SetNull
- Updated migration SQL to reflect these changes

This preserves wrong assignment reports even when the reporting user is deleted,
as the data is still useful for analysis.

Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-02-10 08:00:01 -03:00
Hariom BalharaGitHubunknown <>hariom@cal.com <hariombalhara@gmail.com>hariom@cal.com <hariombalhara@gmail.com>hariom@cal.com <hariombalhara@gmail.com>hariom@cal.com <hariombalhara@gmail.com>hariom@cal.com <hariombalhara@gmail.com>Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
e04a394e1c fix: (booking-audit) Remove IS_PRODUCTION gate and add feature flag check in producer (#26524)
* fix: remove IS_PRODUCTION gate from BookingAuditProducer

Remove the IS_PRODUCTION check that was preventing booking audits from
being queued in production. Audits are still properly gated by:

1. Organization check: Audits are skipped for non-organization bookings
   (organizationId === null)
2. Feature flag: The BookingAuditTaskConsumer checks if the 'booking-audit'
   feature is enabled for the organization via featuresRepository.checkIfTeamHasFeature()

The IS_PRODUCTION gate was intentionally added to prevent logs from being
created in production while the action data versioning was being actively
reviewed and finalized. Without proper versioning handling, the Booking
History UI could crash when encountering unversioned data. Now that the
versioning system is in place, this gate can be safely removed.

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

* fix: revert formatting, keep only IS_PRODUCTION removal

Reverts the unintended formatting changes from the previous commit.
Only removes the IS_PRODUCTION gate without changing indentation.

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

* feat: add booking-audit feature flag check in producer to avoid unnecessary task creation

- Query booking-audit and booking-email-sms-tasker flags in parallel before fireBookingEvents
- Pass isBookingAuditEnabled through BookingEventHandler to producer's queueTask method
- Add conditional check in queueTask with debug log when skipping audit
- Reuse pre-queried isBookingEmailSmsTaskerEnabled flag instead of querying again

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

* feat: make isBookingAuditEnabled required and pass it through all booking audit flows

- Make isBookingAuditEnabled a required property in BookingAuditProducerService interface
- Update all BookingEventHandler methods to require isBookingAuditEnabled
- Add feature flag check in all flows that call booking audit:
  - handleSeats (seat booking/rescheduling)
  - RecurringBookingService (bulk bookings)
  - handleCancelBooking (booking cancellation)
  - handleConfirmation (booking acceptance)
  - roundRobinReassignment (automatic reassignment)
  - roundRobinManualReassignment (manual reassignment)
  - trpc handlers: addGuests, confirm, editLocation, requestReschedule
- Skip queueing audit tasks when feature is disabled with debug logging

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

* fix: add featuresRepository dependency to RecurringBookingService DI module

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

* refactor: make isBookingAuditEnabled optional for non-main flows

Keep feature flag check only in main flows (handleSeats, RegularBookingService, RecurringBookingService) which are frequently triggered. For other flows (handleCancelBooking, handleConfirmation, roundRobinReassignment, etc.), rely on the existing consumer-level check.

Changes:
- Revert feature flag check from non-main flows
- Make isBookingAuditEnabled optional in interface for non-main flow methods
- Keep isBookingAuditEnabled required for main flow methods (queueCreatedAudit, queueRescheduledAudit, queueSeatBookedAudit, queueSeatRescheduledAudit, queueBulkCreatedAudit, queueBulkRescheduledAudit)
- Update BookingEventHandlerService to use required params for main flows and optional for non-main flows

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

* refactor: remove isBookingAuditEnabled from non-main flow methods

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

* feat: make isBookingAuditEnabled required in all BookingEventHandlerService methods

- Add isBookingAuditEnabled as required parameter in all BookingAuditProducerService interface methods
- Update BookingAuditTaskerProducerService to use simplified check (!params.isBookingAuditEnabled)
- Update BookingEventHandlerService to require isBookingAuditEnabled in all methods
- Update all callers to query booking-audit feature flag and pass isBookingAuditEnabled:
  - handleCancelBooking
  - handleConfirmation
  - roundRobinReassignment
  - roundRobinManualReassignment
  - addGuests.handler
  - confirm.handler
  - editLocation.handler
  - requestReschedule.handler
- Inject featuresRepository in API V2's booking-location.service.ts

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

* test: update roundRobinReassignment tests to include isBookingAuditEnabled

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

* test: update roundRobinManualReassignment tests to include isBookingAuditEnabled

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

* fix: inject featuresRepository in API V2 RecurringBookingService

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

* fix: import PrismaWorkerModule for PrismaFeaturesRepository dependency

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

* fix: use booking's organization for feature flag check in addGuests handler

Use booking.user?.profiles?.[0]?.organizationId instead of user.organizationId
to check the booking-audit feature flag. This ensures the feature flag is
checked against the booking's organization rather than the actor's organization,
which is consistent with other handlers in this PR.

Addresses Cubic AI review feedback (confidence 9/10).

Co-Authored-By: unknown <>

* Add comment

* fix: use user.organizationId for feature flag check in addGuests handler

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

* fix: use booking's organizationId for feature flag check in addGuests handler

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

* fix: revert to user.organizationId for feature flag check in addGuests handler

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

* fix: add isBookingAuditEnabled to onNoShowUpdated calls after main merge

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

* fix: add isBookingAuditEnabled to onNoShowUpdated calls and update tests

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

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-02-09 09:25:33 -03:00
Benny JooGitHubbenny@cal.com <sldisek783@gmail.com>benny@cal.com <sldisek783@gmail.com>benny@cal.com <sldisek783@gmail.com>benny@cal.com <sldisek783@gmail.com>Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
96bec9f7b9 refactor: Move repositories from @calcom/lib to @calcom/features domain folders (#27570)
* refactor: move repositories from lib to features domain folders

- Move HolidayRepository to features/holidays/repositories
- Move PrismaTrackingRepository to features/bookings/repositories
- Move PrismaBookingPaymentRepository to features/bookings/repositories
- Move PrismaRoutingFormResponseRepository to features/routing-forms/repositories
- Move PrismaAssignmentReasonRepository to features/assignment-reason/repositories
- Move VerificationTokenRepository to features/auth/repositories
- Move WorkspacePlatformRepository to features/workspace-platform/repositories
- Move DTO files to their respective feature domains
- Merge lib DestinationCalendarRepository into features version
- Merge lib SelectedCalendarRepository into features version
- Update all import paths across the codebase

This follows the vertical slice architecture pattern by organizing
repositories by domain rather than by technical layer.

Co-Authored-By: benny@cal.com <sldisek783@gmail.com>

* fix: update VerificationTokenService import path to new location

Co-Authored-By: benny@cal.com <sldisek783@gmail.com>

* fix: update test file imports to use new repository locations

Co-Authored-By: benny@cal.com <sldisek783@gmail.com>

* mv

* fix structure

* fix

* refactor: merge unit tests for SelectedCalendarRepository into single file

Co-Authored-By: benny@cal.com <sldisek783@gmail.com>

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-02-09 08:41:04 -03:00
Rajiv SahalGitHubDevin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
d4a059033e fix: restore listWithTeam query to include team events with userId set and add comprehensive tests (#27752)
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-02-09 11:40:47 +00:00
Benny JooandGitHub eba0635a07 refactor: eliminate all @calcom/trpc/react imports and tRPC hooks from @calcom/features (#27728)
* migrate booker layout selector

* move schedule hooks and types

* migrate feature opt in components

* migrate feedback dialog

* update

* migrate schedule hooks

* migrate useSegments

* update

* update import paths

* fix import paths

* mv useTimesForSchedule back to features

* fix

* add useEvent to web

* remove the old file

* update imports

* clean up

* migrate Segment

* update imports

* update imports

* fix name

* fix tests

* fix

* fix

* update imports

* remove trpc/react

* remove trpc dependency from package.json

* rm

* wip

* wip

* fix types

* fix

* migrate PhoneInput

* mv LocationInput

* remove dead file

* update import paths

* rm dead import

* rm useApp hook

* cleanup

* wip

* restore

* wip

* remove dead code

* fix

* simplify

* fix

* fix

* fix

* fix

* fix

* fix

* format

* format

* restore

* remove prop
2026-02-09 08:39:28 -03:00
Rajiv SahalandGitHub 8a17ebc2ef feat: Troubleshooter atom (#27497) 2026-02-06 17:34:58 +02:00
Hariom BalharaGitHubhariom@cal.com <hariombalhara@gmail.com>Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
54da93ab02 chore: Integrate mark-no-show booking audit (#26570)
* chore: Integrate mark-no-show booking audit

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

* fix: Simplify host no-show audit and add comment for attendee actor

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

* fix: Make actionSource required with ValidActionSource type and remove unnecessary comments

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

* fix: Remove merge conflict markers from bookings.service.ts

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

* feat: implement SYSTEM as a booking audit source for background tasks, including no-show triggers.

* refactor: Move prisma query to BookingRepository for audit logging

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

* Conflict resolution

* refactor: introduce `handleMarkHostNoShow` for public viewer and standardize actor and action source parameters for no-show actions.

* refactor: Combine HostNoShowUpdatedAuditActionService and AttendeeNoShowUpdatedAuditActionService into NoShowUpdatedActionService

- Create new NoShowUpdatedAuditActionService with combined schema supporting both noShowHost and noShowAttendee as optional fields
- Update BookingAuditActionServiceRegistry to use combined service with NO_SHOW_UPDATED action type
- Update BookingAuditTaskerProducerService with single queueNoShowUpdatedAudit method
- Update BookingAuditProducerService.interface.ts with combined method
- Update BookingEventHandlerService with single onNoShowUpdated method
- Update handleMarkNoShow.ts to use combined audit service
- Update tasker tasks (triggerGuestNoShow, triggerHostNoShow) to use combined service
- Add NO_SHOW_UPDATED to Prisma BookingAuditAction enum
- Remove old separate HostNoShowUpdatedAuditActionService and AttendeeNoShowUpdatedAuditActionService files

This allows a single API action (e.g., API V2 markAbsent) that updates both host and attendee no-show status to be logged as a single audit event.

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

* chore: Add migration for NO_SHOW_UPDATED audit action enum value

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

* refactor: Update no-show audit schema to use host and attendees array

- Rename noShowHost to host and noShowAttendee to attendees (remove redundant prefix)
- Change attendees from single value to array to support multiple attendees in single audit entry
- Update handleMarkNoShow.ts to create single audit entry for all attendees
- Update tasker tasks (triggerGuestNoShow, triggerHostNoShow) to use new schema
- Update display data types to reflect new schema structure

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

* Update schema to be more clear. Call onNoShowUpdated immediately after DB update as audit only cares about DB update, and this would avoid any accidental Audit update on DB change

* chore: accommodate schema changes and fix type errors for no-show audit

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

* fix: Update migration to remove old no-show enum values

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

* fix: Use updated attendees in webhook payload for guest no-show

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

* fix: Remove duplicate imports and fix actor parameter in bookings.service.ts

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

* refactor: Move booking query to BookingRepository and remove unused method

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

* refactor: centralize no-show audit event firing and attendee fetching within `handleMarkNoShow` for improved clarity.

* fix: Build attendeesNoShow as Record with attendee IDs as keys

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

* Fix and add tests for handleMarkBoShow

* refactor: Move prisma queries to AttendeeRepository and BookingRepository

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

* fix: Correct return type for updateNoShow method (noShow can be null)

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

* fix: Update handleMarkNoShow tests to mock new repository methods

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

* fix triggerGuestNoShow

* refactor: Move triggerGuestNoShow queries to AttendeeRepository and add unit tests

- Add new methods to AttendeeRepository:
  - findByBookingId: Get attendees with id, email, noShow
  - findByBookingIdWithDetails: Get full attendee details
  - updateManyNoShowByBookingIdAndEmails: Update specific attendees
  - updateManyNoShowByBookingIdExcludingEmails: Update all except specific emails
- Refactor triggerGuestNoShow.ts to use AttendeeRepository instead of direct Prisma calls
- Add comprehensive unit tests for triggerGuestNoShow following handleMarkNoShow.test.ts pattern:
  - Mock repositories and external services
  - In-memory DB simulation
  - Test core functionality, audit logging, webhook payload, error handling, and edge cases

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

* refactor: Move triggerHostNoShow queries to repositories and delete unit test file

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

* refactor: Convert repository methods to use named parameters objects

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

* refactor: Enhance no-show handling by consolidating audit logging and updating repository interactions

- Refactor `buildResultPayload` to accept a structured argument for better clarity.
- Update `updateAttendees` to use a named parameter object for improved readability.
- Introduce `fireNoShowUpdatedEvent` to centralize no-show audit logging for both hosts and guests.
- Remove redundant methods and streamline attendee retrieval in `AttendeeRepository`.
- Add comprehensive unit tests for no-show event handling, ensuring accurate audit logging and webhook triggering.

* test: Add tests for handleMarkHostNoShow guest actor and unmarking host no-show

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

* fix: update attendeesNoShow validation to handle numeric keys

- Changed attendeesNoShow schema to use z.coerce.number() for key validation, ensuring string keys are correctly coerced to numbers.
- Updated test to validate attendeesNoShow data using numeric key comparison, improving robustness of the audit data checks.

* test: Add integration tests for NoShowUpdatedAuditActionService coerce fix

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

* feat: add graceful error handling for audit log enrichment

- Add hasError field to EnrichedAuditLog type
- Create buildFallbackAuditLog() method for failed enrichments
- Wrap enrichAuditLog() in try-catch to handle errors gracefully
- Add booking_audit_action.error_processing translation key
- Update BookingHistory.tsx to show warning icon for error logs
- Hide 'Show details' button for logs with hasError
- Add comprehensive test cases for error handling scenarios

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

* feat: Enhance booking audit action services with new display fields and improved validation

- Added "attendee_no_show_updated" and "no_show_updated" translations to common.json.
- Updated IAuditActionService to include new methods for handling display fields and migration.
- Enhanced NoShowUpdatedAuditActionService to differentiate between host and attendee no-show updates.
- Improved ReassignmentAuditActionService to ensure consistent handling of audit data.
- Refactored BookingAuditViewerService for better clarity and maintainability.

* refactor: Use attendeeEmail instead of attendeeId as key in audit data and store host's userUuid

- Updated schema to use attendee email as key instead of attendee ID because attendee records can be reused with different person's data
- Store host's userUuid in audit data with format: host: { userUuid, noShow: { old, new } }
- Updated fireNoShowUpdated to accept hostUserUuid parameter
- Added uuid field to BookingRepository.findByUidIncludeEventTypeAttendeesAndUser
- Updated NoShowUpdatedAuditActionService getDisplayFields to work with email-based keys
- Added attendeeRepository to DI modules for BookingAuditTaskConsumer
- Updated tests to match new schema format

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

* test: Update integration tests to use new schema format with host.userUuid and email keys

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

* fix: correct audit schema for SYSTEM source and ensure attendee lookup by bookingId

- Fix schema inconsistency: use host.userUuid format instead of hostNoShow
- Add user.uuid to getBooking select for audit logging
- Log warning when hostUserUuid is undefined but host no-show is being updated
- Use email as key for attendeesNoShow (not attendee ID) to match schema
- Fetch attendees by bookingId before updating to ensure correct scoping
- Remove unused safeStringify import

* refactor: Change attendeesNoShow schema from Record to Array format

- Update NoShowUpdatedAuditActionService schema to use array format:
  attendeesNoShow: Array<{attendeeEmail: string, noShow: {old, new}}>
- Update handleMarkNoShow.ts to build attendeesNoShow as array
- Update common.ts fireNoShowUpdatedEvent to convert Map to array
- Update all tests to use new array format with attendeeEmail property

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

* refactor: Update attendeesNoShow schema to use array format in triggerNoShow tasks

- Refactor `triggerGuestNoShow` and `triggerHostNoShow` to replace Map with array for `attendeesNoShowAudit`.
- Update `fireNoShowUpdatedEvent` to handle the new array format for attendees.
- Ensure consistent data structure across no-show audit logging for better clarity and maintainability.

* fix: Update ReassignmentAuditActionService to use GetDisplayFieldsParams interface

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

* fix: Update ReassignmentAuditActionService tests to use GetDisplayFieldsParams interface

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

* fix: Use handleMarkAttendeeNoShow for API v2 mark absent endpoint

- Export handleMarkAttendeeNoShow from platform-libraries
- Update API v2 bookings service to use handleMarkAttendeeNoShow with actionSource
- Add validation for userUuid before calling handleMarkAttendeeNoShow

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

* refactor: Enhance display fields structure in booking audit components

- Updated `BookingHistory.tsx` to allow for more flexible display fields, including optional raw values and arrays of values.
- Introduced `DisplayFieldValue` component for rendering display fields, improving clarity and maintainability.
- Adjusted `IAuditActionService` and `NoShowUpdatedAuditActionService` to align with the new display fields structure.
- Ensured consistent handling of display fields across the booking audit service for better data representation.

* fix: Remove debug code that duplicated first attendee in display fields

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

* refactor: Update attendee repository methods to use structured parameters

- Modified `updateNoShow`, `updateManyNoShowByBookingIdAndEmails`, and `updateManyNoShowByBookingIdExcludingEmails` methods to accept structured `where` and `data` parameters for better clarity and maintainability.
- Updated calls to these methods throughout the codebase to reflect the new parameter structure.
- Removed unused `findByIdWithNoShow` method and adjusted related logic to streamline attendee data retrieval.

* feat: Add infrastructure for no-show audit integration

- Add Prisma migrations for SYSTEM source and NO_SHOW_UPDATED audit action
- Add NoShowUpdatedAuditActionService with array-based attendeesNoShow schema
- Update BookingAuditActionServiceRegistry to include NO_SHOW_UPDATED
- Update BookingAuditTaskConsumer and BookingAuditViewerService
- Add AttendeeRepository methods for no-show queries
- Update IAuditActionService interface with values array support
- Update locales with no-show audit translation keys

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

* fix: Add NO_SHOW_UPDATED to BookingAuditAction and SYSTEM to ActionSource types

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

* fix: Remove HOST_NO_SHOW_UPDATED and ATTENDEE_NO_SHOW_UPDATED from BookingAuditAction type to match Prisma schema

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

* fix: Update BookingAuditActionSchema to use NO_SHOW_UPDATED instead of HOST_NO_SHOW_UPDATED and ATTENDEE_NO_SHOW_UPDATED

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

* refactor: Remove deprecated no-show audit services and unify to NoShowUpdatedAuditActionService

- Delete HostNoShowUpdatedAuditActionService and AttendeeNoShowUpdatedAuditActionService
- Update BookingAuditProducerService.interface.ts to use queueNoShowUpdatedAudit
- Update BookingAuditTaskerProducerService.ts to use queueNoShowUpdatedAudit
- Update BookingEventHandlerService.ts to use onNoShowUpdated
- Add integration tests for NoShowUpdatedAuditActionService

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

* fix: Update test mock to match new AttendeeRepository.updateNoShow signature

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

* refactor: rename handleMarkAttendeeNoShow to handleMarkNoShow and update related types

- Renamed `handleMarkAttendeeNoShow` to `handleMarkNoShow` for clarity.
- Updated type definitions to reflect the new naming convention.
- Modified the `markNoShow` handler to require `userUuid` and adjusted related logic.
- Enhanced the `fireNoShowUpdatedEvent` to accommodate changes in event type structure.
- Updated references across various files to ensure consistency with the new function name.

* handle null value

* fix: add explicit parentheses for operator precedence clarity

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

* Fix cubic reported bug

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-02-06 09:27:25 -03:00
512002aaef refactor: replace FeaturesRepository with DI-based feature repositories (#27200)
* refactor: replace FeaturesRepository with DI-based feature repositories

Migrate from the legacy FeaturesRepository pattern to separate DI-based repositories:
- Add checkIfFeatureIsEnabledGlobally to IFeatureRepository
- Add getTeamsWithFeatureEnabled to ITeamFeatureRepository
- Update CalendarSubscriptionService to use featureRepository, teamFeatureRepository, and userFeatureRepository
- Update SelectedCalendarRepository.findNextSubscriptionBatch to filter by teamIds instead of featureIds
- Update OnboardingPathService to use DI via getFeatureRepository()
- Remove prisma parameter from OnboardingPathService callsites

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* test: update tests to use new DI-based feature repositories

Update CalendarSubscriptionService and SelectedCalendarRepository tests
to use the new separate repository interfaces:
- featureRepository for global feature checks
- teamFeatureRepository for team-level feature checks
- userFeatureRepository for user-level feature checks

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix: update API routes to use DI-based feature repositories

Update cron and webhook routes to use the new separate repository
interfaces instead of the combined FeaturesRepository.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix: remove prisma arg from getGettingStartedPathWithParams call

The OnboardingPathService method no longer requires a prisma argument
as it now uses DI containers internally.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* test: update route tests to expect new DI-based feature repositories

Update service instantiation tests to expect featureRepository,
teamFeatureRepository, and userFeatureRepository instead of the
old featuresRepository.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix: optimize global feature check and add guard in checkForNewSubscriptions

- Use targeted select for only `enabled` field in checkIfFeatureIsEnabledGlobally
- Add global feature flag guard in checkForNewSubscriptions to avoid unnecessary
  DB queries and API calls when the cache feature is globally disabled

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* remove redundant comment

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-06 09:34:03 +00:00
Pedro CastroGitHubDevin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
cb36fc201f fix: add URL validation to webhook endpoints (#26593)
Validates webhook URLs on create and update:
- HTTPS required (HTTP allowed for self-hosted and E2E)
- Blocks private IP ranges and localhost
- Blocks cloud metadata endpoints

Existing webhooks are preserved: validation only applies when URL is created or changed.

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-02-05 16:18:10 -03:00
Eunjae LeeGitHubClaude Opus 4.5Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2364cff54d feat: custom feedback dialog for feature opt-in (#27578)
* feat: add delayed formbricks tracking for feature opt-in

Adds delayed Formbricks survey tracking for feature opt-in. When a user
opts into a feature, this allows triggering a Formbricks action after a
configurable delay (e.g., 24 hours later) to collect feedback once
they've had time to use the feature.

Key changes:
- Added `formbricks` config option to `OptInFeatureConfig` interface
  with `actionName` and `delayMs` properties
- Created `useFormbricksOptInTracking` hook that handles the delayed
  tracking logic
- Added `isFeatureTracked` / `setFeatureTracked` storage helpers to
  prevent duplicate tracking
- Integrated the tracking hook into `useFeatureOptInBanner`

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* upgrade formbricks

* feat: replace formbricks popup with custom feedback dialog

Instead of using Formbricks' built-in popup, we now show a custom
Cal.com-styled feedback dialog that submits responses directly to
Formbricks API via tRPC mutation.

- Add FeedbackDialog component with emoji rating selector
- Add feedback tRPC router for server-side Formbricks submission
- Update useFormbricksOptInTracking to return dialog state
- Add survey config fields (surveyId, questions) to config

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* feat: position feedback dialog at bottom-right corner

- Use base-ui Dialog primitives for custom positioning
- Position dialog at bottom-right to avoid Intercom overlap
- Use z-index 10000 (below Intercom's high z-index)
- Keep blocking backdrop for modal behavior
- Use i18n keys for title/description
- Add survey IDs for bookings-v3 feedback

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* feat: add i18n keys for feedback dialog title/description

Allow each feature to specify custom i18n keys for the feedback dialog
title and description via the formbricks config.

- Add titleKey/descriptionKey to formbricks config interface
- Pass i18n keys through feedbackDialogProps
- Add bookings_v3_feedback_title/description translation keys

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* refactor: move FeedbackDialog into FeatureOptInBannerWrapper

Better encapsulation - consumers of the feature opt-in banner
no longer need to handle the feedback dialog separately.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* feat: add 5 second delay before showing feedback dialog

Ensures the page has time to finish loading before showing
the feedback dialog, avoiding showing it while skeletons
are still visible.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* refactor: simplify feedback dialog UI

- Remove redundant question labels
- Add "(optional)" to comment placeholder

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix: remove emoji button borders and add footer gap

- Remove borders from rating emoji buttons
- Add proper gap between textarea and footer (pb-4)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix: delayMs is opt-in waiting period, not setTimeout delay

delayMs represents the minimum time that must pass since opt-in
before showing the feedback form (e.g., 3 days). If not enough
time has passed, we skip showing the form entirely instead of
setting a long setTimeout.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* feat: custom feedback dialog for feature opt-in

- Replace Formbricks popup with Cal.com-styled dialog
- Add configurable delay (waitAfterDays) before showing feedback
- Position dialog at bottom-right, non-blocking
- Add localStorage tracking to prevent duplicate feedback
- Add device targeting (showOn: desktop/mobile/all)
- Create tRPC endpoint for Formbricks API submission
- Use proper logger for error handling

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* refactor: rename tracking terminology to feedback

- Rename useFormbricksOptInTracking → useOptInFeedback
- Rename FormbricksOptInTrackingResult → OptInFeedbackState
- Rename formbricksTracking property → feedback
- Rename FormbricksTrackingState → FeedbackState

We no longer "track" events to Formbricks. Instead, we show
our custom feedback dialog when conditions are met.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix: set waitAfterDays to 3 for production feedback delay

Co-Authored-By: unknown <>

* fix: update formbricks JS SDK usage for v3.0.0

The @formbricks/js SDK v3.0.0 changed its API:
- setup() no longer accepts debug, userId, or attributes
- Use setUserId() and setAttributes() after setup instead
- track() now expects { hiddenFields: ... } or undefined

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-02-05 11:01:14 +00:00
sean-brydonGitHubunknown <>Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
c652c61e0c feat: refactor UI to use coss + coupons UI (#27647)
* feat: refactor UI to use coss + coupons UI

* fix: use TRPCError and remove sensitive logging in createCoupon handler

- Replace plain Error with TRPCError for consistent tRPC error handling
- Use INTERNAL_SERVER_ERROR for missing env configuration
- Use UNAUTHORIZED for permission denied errors
- Use BAD_REQUEST for API failure errors
- Remove console.warn that logged username (sensitive info)

Co-Authored-By: unknown <>

* feat: add copy button and fix 0 on % off

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-02-05 10:05:57 +00:00
MorganGitHubDevin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2f16758de3 fix: improve error handling in delegation credential workspace configuration (#26985)
- Changed checkIfSuccessfullyConfiguredInWorkspace to throw detailed errors instead of returning boolean
- Updated testDelegationCredentialSetup in Google Calendar and Office365 Calendar services to throw specific errors
- Updated assertWorkspaceConfigured to let errors propagate naturally
- Updated Calendar interface type to reflect Promise<void> return type
- Updated CalendarCacheWrapper and CalendarTelemetryWrapper to match new interface

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-02-04 21:48:56 +00:00
Pedro CastroandGitHub 5d7738e39d fix: use SMS-specific rate limits for verification code (#27635)
Replace core rate limit with sms + smsMonth types to align with sendSMS handler and move check before billing gate for early rejection
2026-02-04 17:42:21 -03:00
sean-brydonandGitHub 1a0bf47bc5 fix: verification code perf (#27631) 2026-02-04 18:41:41 +00:00
fc3815a150 fix: show personal credits even when user is on teams plan (#27511)
* show personal credits even if on team plan

* show personal credits even when on teams plan

* fix learn more link

---------

Co-authored-by: CarinaWolli <wollencarina@gmail.com>
2026-02-03 10:02:14 +01:00
+10
Joe Au-YeungGitHubjoe@cal.com <j.auyeung419@gmail.com>joe@cal.com <j.auyeung419@gmail.com>joe@cal.com <j.auyeung419@gmail.com>joe@cal.com <j.auyeung419@gmail.com>joe@cal.com <j.auyeung419@gmail.com>joe@cal.com <j.auyeung419@gmail.com>joe@cal.com <j.auyeung419@gmail.com>joe@cal.com <j.auyeung419@gmail.com>joe@cal.com <j.auyeung419@gmail.com>joe@cal.com <j.auyeung419@gmail.com>joe@cal.com <j.auyeung419@gmail.com>joe@cal.com <j.auyeung419@gmail.com>joe@cal.com <j.auyeung419@gmail.com>joe@cal.com <j.auyeung419@gmail.com>joe@cal.com <j.auyeung419@gmail.com>joe@cal.com <j.auyeung419@gmail.com>joe@cal.com <j.auyeung419@gmail.com>Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
c0f6a1b088 feat: add redirect option for non-routed visits to event types (#27468)
* feat: add redirect option for non-routing form bookings

Add a new event type option that redirects to a custom URL when the booking
was not made through a routing form (no cal.routingFormResponseId or
cal.queuedFormResponseId query parameters).

Changes:
- Add redirectUrlOnNoRoutingFormResponse field to EventType schema
- Add UI toggle in Advanced tab to configure the redirect URL
- Implement redirect logic in bookingSuccessRedirect hook
- Add translations for new UI strings

Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>

* fix: add redirectUrlOnNoRoutingFormResponse to test builder

Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>

* fix: add redirectUrlOnNoRoutingFormResponse to BookerEvent type

Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>

* fix: add redirectUrlOnNoRoutingFormResponse to getPublicEventSelect

Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>

* fix: add redirect logic to getServerSideProps for non-routing form bookings

Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>

* fix: remove redirectUrlOnNoRoutingFormResponse from booking success flow

Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>

* fix: use 'in' operator for type narrowing on redirectUrlOnNoRoutingFormResponse

Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>

* fix: exclude redirectUrlOnNoRoutingFormResponse from test assertions

Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>

* fix: include redirectUrlOnNoRoutingFormResponse in test assertions and update description

Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>

* fix: add redirectUrlOnNoRoutingFormResponse to mockUpdatedEventType

Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>

* fix: remove redirect logic from instant meetings

Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>

* fix: add redirectUrlOnNoRoutingFormResponse to EventTypeRepository select

Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>

* fix: add redirectUrlOnNoRoutingFormResponse to form default values

Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>

* Reword string

* fix: bust tRPC cache for redirectUrlOnNoRoutingFormResponse

Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>

* fix: guard redirect when rescheduleUid or bookingUid is present

Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>

* fix: add redirectUrlOnNoRoutingFormResponse to dynamicEvent defaults

Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>

* fix: add bookingUid guard to team getServerSideProps redirect

Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-02-02 15:48:23 -03:00
Pedro CastroandGitHub 1ff307bb44 fix: instant booking location lookup (#27517)
Use booking uid instead of numeric id for instant booking location
  endpoint, aligning with existing booking endpoint patterns
2026-02-02 14:19:52 -03:00
Anik Dhabal BabuandGitHub 7611e0ea39 fix: filter attendees in emails when seatsShowAttendees is disabled (#27520)
* seated event

* Reorder imports in attendee-scheduled-email.ts
2026-02-02 17:07:35 +00:00
Lauris SkraucisandGitHub d743c92479 fix: trpc build (#27516) 2026-02-02 14:38:06 +00:00
sean-brydonGitHubDevin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
4f0a1d0f9b feat: show invoices on team/org (#27120)
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-02-02 13:37:25 +00:00
Eunjae LeeGitHubunknown <>Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
29ec2b9cb6 refactor: split flag repositories into Prisma and Cached layers (#27186)
* refactor: split flag repositories into Prisma and Cached layers

- Rename FeatureRepository to PrismaFeatureRepository (raw DB access)
- Rename TeamFeatureRepository to PrismaTeamFeatureRepository (raw DB access)
- Rename UserFeatureRepository to PrismaUserFeatureRepository (raw DB access)
- Create CachedFeatureRepository with @Memoize wrapping PrismaFeatureRepository
- Create CachedTeamFeatureRepository with @Memoize/@Unmemoize wrapping PrismaTeamFeatureRepository
- Create CachedUserFeatureRepository with @Memoize/@Unmemoize wrapping PrismaUserFeatureRepository
- Update DI tokens, modules, and containers for all 6 repositories
- Update imports in FeatureOptInService and related modules
- Update tests to use new repository structure

Co-Authored-By: eunjae@cal.com <hey@eunjae.dev>

* refactor: simplify @Memoize key patterns and delegate batch methods to Prisma

- Use direct function references for @Memoize key (e.g., KEY.all instead of () => KEY.all())
- Simplify batch methods in Cached repositories to delegate to Prisma repository
- Update tests to reflect the new delegation pattern

Co-Authored-By: eunjae@cal.com <hey@eunjae.dev>

* fix: add orderBy to TeamRepository.findAllByParentId for deterministic results

Co-Authored-By: eunjae@cal.com <hey@eunjae.dev>

* test: update TeamRepository test to expect orderBy in findAllByParentId

Co-Authored-By: eunjae@cal.com <hey@eunjae.dev>

* refactor: cleanup features repository and add specialized repository methods (#27195)

* refactor: cleanup features repository and add findBySlug, update methods

- Remove unused methods from FeaturesRepository (keep getTeamsWithFeatureEnabled)
- Add findAll(), findBySlug(), update() to IFeatureRepository interface
- Add findAll() with caching to CachedFeatureRepository
- Add findBySlug() with caching to CachedFeatureRepository
- Add update() with Unmemoize to CachedFeatureRepository
- Add checkIfFeatureIsEnabledGlobally() to CachedFeatureRepository
- Update toggleFeatureFlag.handler.ts to use repository instead of raw Prisma
- Add comprehensive unit tests for all new methods

Co-Authored-By: eunjae@cal.com <hey@eunjae.dev>

* fix: update updatedAt timestamp in feature update method

Co-Authored-By: eunjae@cal.com <hey@eunjae.dev>

* refactor: move feature check methods to specialized repositories

- Replace getUserFeaturesStatus with two checkIfUserHasFeature calls in bookings page
- Move checkIfTeamHasFeature to PrismaTeamFeatureRepository with pass-through in CachedTeamFeatureRepository
- Move checkIfUserHasFeature and checkIfUserHasFeatureNonHierarchical to PrismaUserFeatureRepository with pass-throughs in CachedUserFeatureRepository
- Add getEnabledFeatures to PrismaTeamFeatureRepository with caching in CachedTeamFeatureRepository
- Keep FeaturesRepository methods as pass-throughs for backward compatibility
- Update test to expect updatedAt in feature update

Co-Authored-By: eunjae@cal.com <hey@eunjae.dev>

* refactor: remove getUserFeaturesStatus and unused methods from FeaturesRepository

Co-Authored-By: eunjae@cal.com <hey@eunjae.dev>

* restore comment

* fix: invalidate all-features cache on update and enabledFeatures cache on upsert/delete

- CachedFeatureRepository: Add KEY.all() to @Unmemoize keys in update() to prevent stale findAll() results
- CachedTeamFeatureRepository: Add KEY.enabledFeatures(teamId) to @Unmemoize keys in upsert() and delete() to prevent stale getEnabledFeatures() results

Co-Authored-By: unknown <>

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

* test: add CachedUserFeatureRepository tests

Add comprehensive tests for CachedUserFeatureRepository covering:
- findByUserIdAndFeatureId (cache hit, cache miss, not found)
- findByUserIdAndFeatureIds (empty input, multiple features)
- upsert (with cache invalidation)
- delete (with cache invalidation)
- findAutoOptInByUserId (cache hit, cache miss, not found)
- setAutoOptIn (with cache invalidation)

Co-Authored-By: unknown <>

* test: remove tests for methods removed from FeaturesRepository

Remove integration tests for methods that were intentionally removed:
- getUserFeatureStates
- getTeamsFeatureStates
- getUserAutoOptIn
- getTeamsAutoOptIn
- setUserAutoOptIn
- setTeamAutoOptIn

Co-Authored-By: unknown <>

* avoid N+1 query

* refactor: add select clauses to PrismaFeatureRepository queries

- Add explicit select clauses to findAll, findBySlug, and update methods
- Only fetch fields needed for FeatureDto (slug, enabled, description, type, stale, lastUsedAt, createdAt, updatedAt, updatedBy)
- Update tests to expect select clauses
- Fix UserFeatureRepository test to use findMany mock

Co-Authored-By: unknown <>

* fix bad conflict resolved

* use userId

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-02-02 14:26:23 +01:00
devin-ai-integration[bot]GitHubDevin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>ali@cal.com <ali@cal.com>
101cef72ac fix: query Host table directly to determine isCurrentUserHost flag (#27268)
The previous implementation relied on the hosts array returned from
findTeamEventTypes, which is limited to 5 hosts for display purposes.
This caused the 'Assigned' badge to not show for users who were hosts
but not in the first 5 returned by the query.

This fix queries the Host table directly with a single batch query to
get all event type IDs where the current user is a host, ensuring the
badge shows correctly regardless of how many hosts an event type has.

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: ali@cal.com <ali@cal.com>
2026-01-30 13:02:16 +00:00
Alex van AndelandGitHub fc9c26e8dd feat: add encryptedKey column to Credential table for calendar integrations (#27154)
Adds encrypted credential storage using a new keyring system:
  - New `encryptedKey` column with AES-256-GCM encryption
  - Decryption in getCalendarsEvents with fallback to legacy `key`
  - buildCredentialCreateData service for credential creation
  - Phase 1: Google Calendar only, other integrations follow
2026-01-30 09:15:13 -03:00
Joe Au-YeungGitHubClaude Opus 4.5joe@cal.com <j.auyeung419@gmail.com>joe@cal.com <j.auyeung419@gmail.com>Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
7abbc8c22c feat: Routing trace presenter (#27372)
* feat: Add routing trace presenters

Add domain-specific presenters (SalesforceRoutingTracePresenter,
RoutingFormTracePresenter) that format trace steps into human-readable
strings, and a core RoutingTracePresenter that delegates to them based
on step domain. Includes unit tests for all presenters.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* feat: Add findByBookingUid to RoutingTraceRepository

Add method to look up a routing trace by booking UID, needed by the
routing trace presenter tRPC endpoint.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* feat: Add getRoutingTrace tRPC endpoint

Expose routing trace data for a booking via viewer.bookings.getRoutingTrace.
Tries the permanent RoutingTrace first (round robin bookings), then falls
back to PendingRoutingTrace via the booking's form response relation.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* feat: Add routing trace side sheet to booking list item

Add a route icon button on booking list items that came from routing
forms. Clicking it opens a side sheet displaying the full routing trace
as human-readable steps. Adds RoutingTraceSheet component, store state,
and translation key.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* refactor: Move routing trace action to dropdown menu

Move the routing trace button from a standalone icon on the booking list
item into the actions dropdown menu alongside "Report wrong assignment".
The RoutingTraceSheet is now rendered from BookingActionsDropdown.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix: Improve routing trace UI and handle unnamed routes

- Redesign RoutingTraceSheet with vertical timeline layout, domain badges,
  skeleton loading state, and millisecond timestamps
- Use Salesforce app-store icon for Salesforce steps
- Fall back to "Unnamed route" when route name is missing or matches route ID
- Fix dropdown menu icon to git-merge (valid icon, unique in menu)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* test: Add tests for getRoutingTrace handler and findByBookingUid repository method

Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>

* Abstract functions

* Fix build error

* Add permission check

* fix: Update getRoutingTrace tests to include ctx and mock BookingAccessService

Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-01-29 15:26:44 -03:00
3c91703415 feat: add invoice banner + block additions to teams/orgs (#27327)
* 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>

* feat: add due invoice banner and invitation blocking for orgs

- Add DueInvoiceBanner component showing overdue prorations
- Add DueInvoiceService for checking blocking status and banner data
- Block invitations when proration invoices are 7+ days overdue
- Allow sub-team invites for existing org members (exception)
- Show banner to users with billing management permissions
- Link directly to Stripe invoice URL when available

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix: set subscriptionId in team metadata in seed script

The seed script was not setting subscriptionId on the team metadata,
causing checkIfOrgNeedsUpgrade to treat the org as needing upgrade
and showing the "trialing" banner.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* push trigger test to script

* fix mocks

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-29 11:23:27 +00:00
08a2b0bfb5 feat: add organization.passwordReset PBAC permission (#27377)
* feat: add organization.passwordReset PBAC permission

Allow org admins/owners to reset passwords for members of their
organization via a new PBAC permission. Previously this was only
available to system-level admins.

- Add PasswordReset to CustomAction enum and PERMISSION_REGISTRY
- Create migration to grant permission to admin_role (owner has wildcard)
- Add org-scoped tRPC endpoint using createOrgPbacProcedure
- Handler validates org membership, prevents self-targeting, and blocks
  resetting owner passwords
- Wire permission through MemberPermissions, getOrgMembersPageData, and
  the org members table UI dropdown

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix: use targeted select in org password reset to avoid over-fetching

Replace findById with findForPasswordReset repository method that only
selects email, name, and locale instead of the full userSelect which
includes sensitive fields like twoFactorSecret and backupCodes.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* test: add unit tests for sendPasswordReset handler

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-29 11:18:02 +00:00
Joe Au-YeungGitHubunknown <>joe@cal.com <j.auyeung419@gmail.com>joe@cal.com <j.auyeung419@gmail.com>Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>Pedro Castro
620445d85f feat: Use RoutingTraceService to write assignment reasons (#27225)
* Add DB schema

* Init zod schema

* Init RoutingTrace and PendingRoutingTrace repository interfaces

* Create PrismaPendingRoutingTraceRepository

* Init RoutingTraceService

* Create RoutingTraceService container

* User routing trace service in routing

* Create RoutingTraceRepository and PrismaRoutingTraceRepoistory

* Add findByFormResponseId and findByQueuedFormResponseId to PendingRoutingTraceRepository

* Update DI containers

* RoutingTraceService create process booking method

* Use pending routing trace rather than URL params

* Fix schema

* Fix writing assignment reason for routed booking

* Remove  from  service

* Refactor RoutingTraceService to not rely on async local storage

* Pass RoutingTraceService through routing call

* Add attribute-logic-evaluated to routing trace step

* Add routing trace to trpc endpoint

* Add CRM routing trace step

* Fix extracting routing trace to assignment reason

* Add back CRM params to prevent refetching

* test: Add unit tests for RoutingTraceService and repositories

Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>

* test: Add missing mock for RoutingTraceService in getRoutedUrl tests

Also fix pre-existing lint issues in the test file:
- Add explicit types to mockForm and mockSerializableForm variables
- Add explicit type to url parameter in mockContext
- Replace 'as any' with 'as unknown as InstanceType<typeof UserRepository>'

Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>

* Link pending form submission to routing trace

* Clean up

* Add lookup field assignment reasons

* Rename to PendingRoutingTrace

* Add migration file

* fix: Update RoutingTraceService tests to use assignmentReasonRepository mock

- Add getStepsCount() method back to RoutingTraceService
- Add queuedFormResponseId support to processForBooking method
- Update tests to use mockAssignmentReasonRepository instead of prisma mock
- Remove test for missing routingTraceRepository (all deps now required)

Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>

* fix: Remove PII (organizer email) from log payload in RoutingTraceService

Addresses Cubic AI review feedback with confidence 9/10.
Logging PII violates sensitive information logging rules.

Co-Authored-By: unknown <>

* Write field values at the time of routing

* Write attributes used to route

* fix: Add CHECK constraint to ensure at least one response ID is set in routing trace tables

Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>

* fix: Address PR review comments for routing trace feature

- Add checkedFallback to routing trace step data (Comment 11)
- Extract hardcoded domain/step strings to constants (Comment 13)
- Use @default(now()) for createdAt in PendingRoutingTrace and RoutingTrace (Comment 15)
- Add DEFAULT CURRENT_TIMESTAMP to migration for createdAt fields

Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>

* fix: Use UTC-safe timezone expression for createdAt defaults in routing trace tables

Addresses Cubic AI review feedback (confidence 9/10) to prevent timezone
issues by using dbgenerated("timezone('UTC', now())") instead of bare now()
for the createdAt fields in PendingRoutingTrace and RoutingTrace models.

Co-Authored-By: unknown <>

* fix: Align migration SQL with Prisma's expected timezone syntax

Use 'UTC'::text cast in timezone() function to match Prisma's generated SQL.

Co-Authored-By: unknown <>

* fix: Revert migration SQL to match Prisma schema timezone syntax

Remove ::text cast from timezone() function to match what Prisma generates
from the schema definition.

Co-Authored-By: unknown <>

* fix: Use explicit ::text cast in timezone() for PostgreSQL compatibility

PostgreSQL normalizes timezone('UTC', now()) to timezone('UTC'::text, now())
internally. Update both schema and migration to use the explicit cast to
ensure they match and pass the migration check.

Co-Authored-By: unknown <>

* fix: Use CURRENT_TIMESTAMP for createdAt defaults (standard Cal.com pattern)

Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>

* fix: Use @default(now()) for createdAt in routing trace tables to match migration

Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: Pedro Castro <pedro@cal.com>
2026-01-28 12:45:15 -05:00
+3
Alex van AndelGitHubalex@cal.com <me@alexvanandel.com>alex@cal.com <me@alexvanandel.com>alex@cal.com <me@alexvanandel.com>alex@cal.com <me@alexvanandel.com>alex@cal.com <me@alexvanandel.com>alex@cal.com <me@alexvanandel.com>alex@cal.com <me@alexvanandel.com>alex@cal.com <me@alexvanandel.com>cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
c9bd18e866 chore: Disables syncing of calendarList on overlay calendar fetch (#27020)
* chore: Disables syncing of calendarList on overlay calendar fetch

* Unwrap ToggledConnectedCalendars

* Pick the right type for connectedCalendars

* further type amends

* Type fixes, tons of em

* Some further fixups consistent with what was before

* fix: resolve type incompatibility in getConnectedDestinationCalendars return type

Co-Authored-By: alex@cal.com <me@alexvanandel.com>

* fix: update DestinationCalendarProps to accept tRPC handler return type

Co-Authored-By: alex@cal.com <me@alexvanandel.com>

* fix: use generic type for DestinationCalendarProps to accept tRPC enriched types

Co-Authored-By: alex@cal.com <me@alexvanandel.com>

* fix: simplify DestinationCalendarProps type for better compatibility

Co-Authored-By: alex@cal.com <me@alexvanandel.com>

* fix: export ConnectedCalendar type for consistent type inference

Co-Authored-By: alex@cal.com <me@alexvanandel.com>

* fix: use permissive type for connectedCalendars to accept tRPC enriched types

Co-Authored-By: alex@cal.com <me@alexvanandel.com>

* fix: export ConnectedCalendar and ConnectedDestinationCalendars types from platform-libraries

Co-Authored-By: alex@cal.com <me@alexvanandel.com>

* fix: update ConnectedCalendar type to use boolean | null for primary field

Co-Authored-By: alex@cal.com <me@alexvanandel.com>

* Update ConnectedCalendarItem

* Undo some of Devins fixes, more fixes

* Fixup the destination calendar return type, historically not null

* Change init to undefined to deal with null

* Approach to connect selected calendars with the right credential

* This return type is used way too much everywhere, not refactoring

* Add the selectedCalendars to the type

* Actually fix overlay calendar

* set calendarsToLoad param as required

* Apply suggestion from @cubic-dev-ai[bot]

Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>

* Add new translation for 'Calendar Settings'

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
2026-01-28 14:20:19 -03:00
Alex van AndelGitHubDevin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
718aef579c fix: optimize bookings/get query to use subqueries instead of materializing 400+ parameters (#27319)
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>
2026-01-28 12:21:49 -03:00
Eunjae LeeGitHubeunjae@cal.com <hey@eunjae.dev>Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
ddceabe5d4 fix: use FeatureOptInService for bookings-v3 check (#27183)
* 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>
2026-01-28 14:28:36 +00:00
Keith WilliamsGitHubDevin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
21500c7047 fix: remove _count children query from EventType and Workflow repositories (#27309)
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-01-27 15:23:26 -03:00
Joe Au-YeungandGitHub 3355fab4fb feat: display assignment reason in organizer emails and booking single view (#27192) 2026-01-23 20:50:07 -03:00
Udit TakkarGitHubunknown <>Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
a40c3eebd6 feat: group same booking reports together (#26529)
Co-authored-by: unknown <>
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-01-23 16:31:56 +00:00
sean-brydonandGitHub 09194c58e1 fix: onboarding - team invites (#27113) 2026-01-23 16:31:35 +00:00
Udit TakkarGitHubunknown <>unknown <>unknown <>Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
0ad4367005 feat: Custom host location (#25916)
* chore: save progress

* chore:

* feat: add input dialog

* fix: type error

* feat: mass apply dialog

* test: per host location

* test: fix test

* fix: address Cubic AI review feedback (confidence >= 9/10)

- Remove PII (address, phone number) from tracing logs in RegularBookingService.ts
- Constrain HostLocation.type to EventLocationType["type"] for compile-time validation

Co-Authored-By: unknown <>

* fix: translation

* refactor: improvements

* fix: correct grammar in custom host locations tooltip

Change 'custom host locations is enabled' to 'custom host locations are enabled' (plural subject requires plural verb).

Addresses Cubic AI review feedback (confidence 9/10).

Co-Authored-By: unknown <>

* refactor: improvements

* fix: auth

* fix: check

* refactor: improvements

* fix: address Cubic AI review feedback (confidence >= 9/10)

- Add scheduleId to newly created hosts in update.handler.ts to persist
  host-specific schedules during create operations
- Change host location deletion filter from !host.location to
  host.location === null to only delete when explicitly set to null
- Fix static-link per-host locations to use actual link instead of type
  in locationBodyString for bookingLocationService.ts

Co-Authored-By: unknown <>

* fix: preserve existing host scheduleId when not explicitly provided

Change scheduleId handling for existing hosts from 'host.scheduleId ?? null'
to 'host.scheduleId === undefined ? undefined : host.scheduleId' so that
when the client doesn't provide a scheduleId, the existing value is preserved
instead of being cleared to null.

Co-Authored-By: unknown <>

* fix; type erro

* fix; type erro

* fix; type erro

* refactor: move repository

* refactor: move repository

* fix: add singular/plural translations for location_applied_to_hosts

Addresses Cubic AI review feedback (confidence 9/10) to fix '1 hosts' rendering as '1 host' by using i18next plural format with _one and _other suffixes.

Co-Authored-By: unknown <>

* refactor: feedback

* fix: type err

* fix: use uuid in schema and remove attendee locaiton

* fix: type err

* fix: type err

* fix: validate eventTypeId as integer in massApplyHostLocation schema

Co-Authored-By: unknown <>

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-01-23 11:18:43 -03:00
Syed Ali ShahbazandGitHub 4115eaacbd chore: Add initial webhook wiring (TRPC handlers) to the new architecture (#27170)
* --init

* clean up

* unnecessary comment

* remove comment

* fix factory resolver

* Add active filter to webhook query
2026-01-23 16:50:34 +04:00
Hariom BalharaandGitHub 95f7f03f0e chore: Integrate round-robin reassignment booking audit (#26586)
## What does this PR do?

Implements booking audit logging for round-robin reassignment events (both manual and automatic). This is part of the booking audit integration plan (PR 7).

Changes:
- Added audit logging to `roundRobinManualReassignment.ts` for manual host reassignments
- Added audit logging to `roundRobinReassignment.ts` for automatic round-robin reassignments
- Updated tRPC handlers to pass `actionSource: "WEBAPP"` and `reassignedByUuid`
- Updated API v2 bookings service to pass `actionSource: "API_V2"` and `reassignedByUuid`
- Updated `ReassignmentAuditActionService.ts` with proper field schemas and translation keys

The audit logging uses `BookingEventHandlerService.onReassignment()` with proper actor identification and action source tracking.

## Updates since last revision

Addressed review feedback:
- Renamed `title` field to `hostName` for semantic clarity (tracks host name changes, not booking titles)
- Fixed `assignedById` schema: changed from `NumberChangeSchema` to `z.number()` (no old/new pattern needed - it's always the user who performed the reassignment)
- Fixed `reassignmentReason` schema: changed from `StringChangeSchema` to `z.string().nullable()` (no old/new pattern needed)
- Added `ValidActionSource` type that excludes `UNKNOWN` - clients must pass explicit action sources
- Made `actionSource` required in both reassignment functions (no longer optional)
- Added integration tests for `ReassignmentAuditActionService` (15 tests covering all methods)
- Updated `roundRobinManualReassign.handler.ts` to pass required `actionSource` and `reassignedByUuid` params

**Latest fixes:**
- Fixed `hasAttendeeUpdated` check in `ReassignmentAuditActionService.ts`: changed from `!== null` to `!= null` to properly handle undefined values
- Updated test expectations in `ReassignmentAuditActionService.test.ts` to match the new display JSON field names (`hostAttendeeUserUuidNew`/`hostAttendeeUserUuidOld` instead of `newAssignedRRHostUuid`/`previousAssignedRRHostUuid`)
- Fixed async `getDisplayFields` tests to properly await the Promise and include the `previous_assignee` field
- Fixed `hasAttendeeUpdated` to check for `hostAttendeeUpdated` object presence instead of optional `id` field - host changes with only `withUserUuid` populated were being ignored (identified by Cubic AI, confidence 9/10)
- Fixed test expectation in `getDisplayJson` test: removed incorrect null expectations for `hostAttendeeIdUpdated`, `hostAttendeeUserUuidNew`, `hostAttendeeUserUuidOld` - the implementation uses conditional spreading to omit these fields when `hostAttendeeUpdated` is not present, rather than setting them to null

## Mandatory Tasks (DO NOT REMOVE)

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

## How should this be tested?

1. Trigger a manual round-robin reassignment via the webapp and verify audit logs are created with `actionSource: "WEBAPP"`
2. Trigger an automatic round-robin reassignment and verify audit logs are created
3. Use API v2 to reassign a booking and verify audit logs are created with `actionSource: "API_V2"`
4. Verify the audit data contains correct values for `organizerUuid`, `hostAttendeeUpdated`, `reassignmentReason`, and `reassignmentType`

## Checklist

- [x] My code follows the style guidelines of this project
- [x] I have checked if my changes generate no new warnings

## Human Review Checklist


- [x] Verify the `hasAttendeeUpdated` fix is correct: now checks `fields.hostAttendeeUpdated != null` to detect any host attendee update regardless of whether `id` is populated
- [x] Verify `getDisplayJson` test fix: fields are correctly omitted (not set to null) when `hostAttendeeUpdated` is not present, matching the conditional spreading implementation
- [ ] Verify all callers of reassignment functions pass required `actionSource` and `reassignedByUuid`
- [ ] Confirm `getDisplayFields` is properly awaited in all call sites (it's now async)
- [ ] Check that `ValidActionSource` type properly excludes `UNKNOWN` for client-side validation

## Important Notes for Reviewer

1. **Dependency on base PR**: The translation key changes use the format from base PR (#26046). This PR should be merged after the base PR.

2. **Schema changes**: The `organizerUuid` and `hostAttendeeUpdated` fields track both organizer changes and round-robin host attendee changes separately for complete audit trail.

---


Link to Devin run: https://app.devin.ai/sessions/e4353e2ec6ea4a51ab33313bdc630aba
Requested by: @hariombalhara
2026-01-23 08:13:22 +05:30