Skip to content

perf: import enums from @calcom/prisma/enums#23582

Merged
keithwillcode merged 4 commits intomainfrom
refactor/get-rid-of-imports-from-prisma-directly
Sep 4, 2025
Merged

perf: import enums from @calcom/prisma/enums#23582
keithwillcode merged 4 commits intomainfrom
refactor/get-rid-of-imports-from-prisma-directly

Conversation

@hbjORbj
Copy link
Contributor

@hbjORbj hbjORbj commented Sep 4, 2025

What does this PR do?

  • This PR refactors to import enums from @calcom/prisma/enums instead of @calcom/prisma/client or @prisma/client.

Impact

With @prisma/client: Bundles ~28MB of prisma client code
With @calcom/prisma/enums: Bundles ~0.1KB

Mandatory Tasks (DO NOT REMOVE)

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

How should this be tested?

  • All tests passing are sufficient

@hbjORbj hbjORbj requested a review from a team September 4, 2025 10:50
@hbjORbj hbjORbj requested a review from a team as a code owner September 4, 2025 10:50
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Sep 4, 2025

Walkthrough

This PR changes many enum imports across the codebase to import from @calcom/prisma/enums instead of @prisma/client or @calcom/prisma/client, removes several unused imports, consolidates some type-only Prisma imports, updates a few Swagger decorators to ApiPropertyOptional, and expands the exported UserWithProfile type to optionally include a profiles[] field. No runtime control flow or business-logic changes were introduced.

Possibly related PRs

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch refactor/get-rid-of-imports-from-prisma-directly

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbitai help to get the list of available commands.

Other keywords and placeholders

  • Add @coderabbitai ignore or @coderabbit ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@graphite-app graphite-app bot requested a review from a team September 4, 2025 10:50
@keithwillcode keithwillcode added core area: core, team members only foundation labels Sep 4, 2025
@hbjORbj hbjORbj changed the title refactor: get rid of imports from prisma directly perf: import enums from @calcom/prisma/enums Sep 4, 2025
@dosubot dosubot bot added platform Anything related to our platform plan 💻 refactor labels Sep 4, 2025
@vercel
Copy link

vercel bot commented Sep 4, 2025

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

2 Skipped Deployments
Project Deployment Preview Comments Updated (UTC)
cal Ignored Ignored Sep 4, 2025 11:08am
cal-eu Ignored Ignored Sep 4, 2025 11:08am

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

Caution

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

⚠️ Outside diff range comments (13)
apps/api/v2/src/modules/webhooks/outputs/webhook.output.ts (1)

52-55: Fix type/decorators mismatch on data. data is typed string but decorated as nested WebhookOutputDto, which breaks transformation/validation and misleads Swagger. Either remove @ValidateNested()/@Type() and keep data!: string; or change to data!: WebhookOutputDto[] with @IsArray(), @ValidateNested({ each: true }) and @Type(() => WebhookOutputDto).

apps/api/v2/src/modules/organizations/teams/index/outputs/organization-team.output.ts (1)

10-12: Fix validator on accepted (should be boolean).

Using @IsString() on a boolean field causes incorrect validation and docs.

-  @IsString()
+  @IsBoolean()
   @Expose()
   readonly accepted!: boolean;
apps/api/v2/src/modules/workflows/inputs/workflow-trigger.input.ts (1)

78-84: Broken validation: IsIn receives a nested array.

@isin([WORKFLOW_TRIGGER_TYPES]) passes a single element array whose only element is the array of values, causing validation to fail.

Apply:

-  @IsIn([WORKFLOW_TRIGGER_TYPES])
+  @IsIn(WORKFLOW_TRIGGER_TYPES)
apps/api/v2/src/ee/bookings/2024-08-13/services/input.service.ts (1)

205-215: Spread null bug: getRoutingFormData returns null but callers spread the result.

transformInputCreateBooking/transformInputCreateRecurringBooking do { ..., ...this.getRoutingFormData(routing) }. Spreading null throws at runtime.

Apply one of:

-    if (!routing) return null;
+    if (!routing) return {};

or change call sites to ...(this.getRoutingFormData(routing) ?? {}).

apps/api/v2/src/modules/workflows/inputs/workflow-step.input.ts (2)

59-66: Bug: TEMPLATES_TO_ENUM mapping is inverted for REMINDER.

First entry maps enum→string instead of string→enum; causes incorrect lookup for REMINDER.

-export const TEMPLATES_TO_ENUM = {
-  [WorkflowTemplates.REMINDER]: REMINDER,
-  [CUSTOM]: WorkflowTemplates.CUSTOM,
-  [RESCHEDULED]: WorkflowTemplates.RESCHEDULED,
-  [CANCELLED]: WorkflowTemplates.CANCELLED,
-  [COMPLETED]: WorkflowTemplates.COMPLETED,
-  [RATING]: WorkflowTemplates.RATING,
-} as const;
+export const TEMPLATES_TO_ENUM = {
+  [REMINDER]: WorkflowTemplates.REMINDER,
+  [CUSTOM]: WorkflowTemplates.CUSTOM,
+  [RESCHEDULED]: WorkflowTemplates.RESCHEDULED,
+  [CANCELLED]: WorkflowTemplates.CANCELLED,
+  [COMPLETED]: WorkflowTemplates.COMPLETED,
+  [RATING]: WorkflowTemplates.RATING,
+} as const;

79-79: Bug: HOST constant value looks wrong.

"const" should be "host" to match recipient types.

-export const HOST = "const";
+export const HOST = "host";
apps/api/v2/src/modules/workflows/workflows.repository.ts (1)

27-31: Prisma guideline: replace include with select.

Project rule: “only select data you need; never use include.” Please migrate these queries to select with explicit fields.

Example pattern:

-      include: {
-        steps: true,
-        activeOn: { select: { eventTypeId: true } },
-      },
+      select: {
+        // enumerate needed Workflow scalar fields explicitly
+        id: true,
+        name: true,
+        trigger: true,
+        time: true,
+        timeUnit: true,
+        teamId: true,
+        steps: true,
+        activeOn: { select: { eventTypeId: true } },
+      },

Repeat similarly for findMany and create (replace include with select). If helpful, I can draft a workflowSelect constant to centralize the field list.

Also applies to: 41-44, 61-61

apps/api/v2/src/ee/bookings/2024-04-15/controllers/bookings.controller.ts (5)

203-209: Don’t combine void with await — it blocks unnecessarily.

This defeats fire-and-forget and can slow the booking response.

-        void (await this.billingService.increaseUsageByUserId(booking.userId, {
+        void this.billingService.increaseUsageByUserId(booking.userId, {
           uid: booking.uid,
           startTime: booking.startTime,
           fromReschedule: booking.fromReschedule,
-        }));
+        });

256-258: Same here: remove await when intentionally ignoring the result.

-          void (await this.billingService.cancelUsageByBookingUid(res.bookingUid));
+          void this.billingService.cancelUsageByBookingUid(res.bookingUid);

329-336: Avoid async Array.forEach — rejections become unhandled.

Use for...of with fire-and-forget or Promise.allSettled.

-      createdBookings.forEach(async (booking) => {
-        if (booking.userId && booking.uid && booking.startTime) {
-          void (await this.billingService.increaseUsageByUserId(booking.userId, {
-            uid: booking.uid,
-            startTime: booking.startTime,
-          }));
-        }
-      });
+      for (const booking of createdBookings) {
+        if (booking.userId && booking.uid && booking.startTime) {
+          void this.billingService.increaseUsageByUserId(booking.userId, {
+            uid: booking.uid,
+            startTime: booking.startTime,
+          });
+        }
+      }

367-371: Same pattern in instant booking.

-        void (await this.billingService.increaseUsageByUserId(instantMeeting.userId, {
+        void this.billingService.increaseUsageByUserId(instantMeeting.userId, {
           uid: instantMeeting.bookingUid,
           startTime: now,
-        }));
+        });

387-391: Replace api.apiKeyPrefix with the defined api.keyPrefix for both prefix check and stripping
In apps/api/v2/src/ee/bookings/2024-04-15/controllers/bookings.controller.ts (and similarly in the 2024-08-13 service), api.apiKeyPrefix doesn’t exist in your config—use api.keyPrefix consistently:

-        if (isApiKey(bearerToken, this.config.get<string>("api.apiKeyPrefix") ?? "cal_")) {
-          const strippedApiKey = stripApiKey(bearerToken, this.config.get<string>("api.keyPrefix"));
+        const keyPrefix = this.config.get<string>("api.keyPrefix");
+        if (isApiKey(bearerToken, keyPrefix)) {
+          const strippedApiKey = stripApiKey(bearerToken, keyPrefix);
apps/api/v2/src/modules/oauth-clients/controllers/oauth-client-users/oauth-client-users.controller.ts (1)

85-87: Avoid logging PII by stringifying request bodies

Bodies can contain personal data. Log minimal, non-sensitive context instead.

Apply:

-    this.logger.log(
-      `Creating user with data: ${JSON.stringify(body, null, 2)} for OAuth Client with ID ${oAuthClientId}`
-    );
+    this.logger.log(`Creating managed user for OAuth Client ${oAuthClientId}`);
-    this.logger.log(`Updating user with ID ${userId}: ${JSON.stringify(body, null, 2)}`);
+    this.logger.log(`Updating managed user ${userId}`);
-    this.logger.log(`Forcing new access tokens for managed user with ID ${userId}`);
+    this.logger.log(`Forcing new access tokens for managed user ${userId}`);

Also applies to: 133-133, 173-173

🧹 Nitpick comments (28)
apps/api/v2/src/modules/webhooks/outputs/webhook.output.ts (1)

41-44: Verify exposure of secret in responses.

secret is marked with @Expose() and will be serialized. If this is a credential, avoid returning it except at creation time (and consider writeOnly in docs).

If secret must not be in responses:

-  @IsString()
-  @Expose()
-  readonly secret?: string;
+  // Intentionally not exposed in responses
+  @IsString()
+  readonly secret?: string;

Or document-only visibility:

+import { ApiPropertyOptional } from "@nestjs/swagger";
...
-  @IsString()
-  @Expose()
-  readonly secret?: string;
+  @IsString()
+  @ApiPropertyOptional({ writeOnly: true })
+  readonly secret?: string;
apps/api/v2/src/modules/oauth-clients/controllers/oauth-clients/oauth-clients.controller.ts (2)

74-76: Avoid logging full request bodies; scrub sensitive fields.

JSON.stringify(body) may include PII or secrets in some inputs. Prefer structured, minimal logs with redaction.

-    this.logger.log(
-      `For organisation ${organizationId} creating OAuth Client with data: ${JSON.stringify(body)}`
-    );
+    const { name, clientType } = body as any;
+    this.logger.log(
+      `For organization ${organizationId} creating OAuth Client with data: ${JSON.stringify({ name, clientType })}`
+    );

Please confirm CreateOAuthClientInput and UpdateOAuthClientInput never carry secrets; if they can, let’s mask common fields (e.g., clientSecret, secret, privateKey).


145-146: Same logging concern on update path.

Apply the same redaction pattern here.

-    this.logger.log(`For client ${clientId} updating OAuth Client with data: ${JSON.stringify(body)}`);
+    const { name, clientType } = body as any;
+    this.logger.log(
+      `For client ${clientId} updating OAuth Client with data: ${JSON.stringify({ name, clientType })}`
+    );
apps/api/v2/src/modules/organizations/teams/index/outputs/organization-team.output.ts (2)

28-32: Array DTO validation: validate elements and mark as array.

For arrays, prefer @IsArray() and @ValidateNested({ each: true }) so each element is validated.

   @Expose()
-  @ValidateNested()
+  @IsArray()
+  @ValidateNested({ each: true })
   @Type(() => OrgTeamOutputDto)
   data!: OrgTeamOutputDto[];

39-43: Same array DTO validation improvement.

Apply @IsArray() and @ValidateNested({ each: true }) here as well.

   @Expose()
-  @ValidateNested()
+  @IsArray()
+  @ValidateNested({ each: true })
   @Type(() => OrgTeamOutputDto)
   data!: OrgTeamOutputDto[];
apps/api/v2/src/modules/teams/teams/outputs/teams/get-teams.output.ts (1)

9-11: Prefer IsIn over IsEnum for literal values array.

status validates against two literals, not a TS/JS enum object. Use IsIn for clarity.

Apply:

-  @IsEnum([SUCCESS_STATUS, ERROR_STATUS])
+  @IsIn([SUCCESS_STATUS, ERROR_STATUS])
apps/api/v2/src/modules/organizations/event-types/services/output.service.ts (3)

16-16: Use enum constants instead of string literals for SchedulingType.

Mixing enum members and raw strings is brittle. Compare against SchedulingType.* consistently.

Apply:

-    const hosts =
-      databaseEventType.schedulingType === "MANAGED"
+    const hosts =
+      databaseEventType.schedulingType === SchedulingType.MANAGED
         ? await this.getManagedEventTypeHosts(databaseEventType.id)
         : await this.getNonManagedEventTypeHosts(databaseEventType.hosts, databaseEventType.schedulingType)
-      if (schedulingType === "ROUND_ROBIN") {
+      if (schedulingType === SchedulingType.ROUND_ROBIN) {

Also applies to: 106-109, 175-176


47-47: Duplicate key in Input Pick list.

"lockTimeZoneToggleOnBookingPage" appears twice; drop the duplicate to avoid confusion.

   | "requiresBookerEmailVerification"
   | "hideCalendarNotes"
-  | "lockTimeZoneToggleOnBookingPage"
   | "eventTypeColor"

Also applies to: 75-75


147-161: Avoid N+1 queries when building managed hosts.

This loop issues 1 query per child. Batch-fetch by IDs once.

   async getManagedEventTypeHosts(eventTypeId: number) {
     const children = await this.teamsEventTypesRepository.getEventTypeChildren(eventTypeId);
-    const transformedHosts: TeamEventTypeResponseHost[] = [];
-    for (const child of children) {
-      if (child.userId) {
-        const user = await this.usersRepository.findById(child.userId);
-        transformedHosts.push({
-          userId: child.userId,
-          name: user?.name || "",
-          username: user?.username || "",
-          avatarUrl: user?.avatarUrl,
-        });
-      }
-    }
-    return transformedHosts;
+    const userIds = [...new Set(children.map((c) => c.userId).filter(Boolean) as number[])];
+    const users = await this.usersRepository.findByIds(userIds);
+    const usersById = new Map(users.map((u) => [u.id, u]));
+    return children
+      .filter((c): c is { userId: number } => !!c.userId)
+      .map((c) => {
+        const u = usersById.get(c.userId);
+        return {
+          userId: c.userId,
+          name: u?.name || "",
+          username: u?.username || "",
+          avatarUrl: u?.avatarUrl,
+        };
+      });
   }
apps/api/v2/src/modules/workflows/inputs/workflow-step.input.ts (1)

171-178: Swagger examples should be numbers, not strings.

verifiedEmailId/verifiedPhoneId are numbers; fix example values.

-    example: "31214",
+    example: 31214,
...
-    example: "3243434",
+    example: 3243434,
...
-    example: "3243434",
+    example: 3243434,

Also applies to: 225-234, 274-283

apps/api/v2/src/modules/oauth-clients/services/oauth-clients-users.service.ts (1)

13-15: Prefer enum for role instead of raw string.

Use MembershipRole.MEMBER for consistency with the enums refactor.

-import { createNewUsersConnectToOrgIfExists, slugify } from "@calcom/platform-libraries";
-import { CreationSource } from "@calcom/prisma/enums";
+import { createNewUsersConnectToOrgIfExists, slugify } from "@calcom/platform-libraries";
+import { CreationSource, MembershipRole } from "@calcom/prisma/enums";
...
-              role: "MEMBER",
+              role: MembershipRole.MEMBER,

Also applies to: 51-53

apps/api/v2/src/ee/bookings/2024-04-15/controllers/bookings.controller.ts (1)

512-542: Remove unused private method createNextApiRecurringBookingRequest. No calls were found in the codebase, so this dead code should be removed to prevent drift.

apps/api/v2/src/modules/organizations/teams/memberships/inputs/update-organization-team-membership.input.ts (1)

12-15: Drive Swagger enum from source enum to prevent drift.

-  @ApiPropertyOptional({ enum: ["MEMBER", "OWNER", "ADMIN"] })
+  @ApiPropertyOptional({ enum: MembershipRole, enumName: "MembershipRole" })
apps/api/v2/src/modules/teams/memberships/outputs/team-membership.output.ts (1)

74-77: Use IsEnum and enum from source to keep docs in sync.

-  @IsString()
-  @ApiProperty({ enum: ["MEMBER", "OWNER", "ADMIN"] })
+  @IsEnum(MembershipRole)
+  @ApiProperty({ enum: MembershipRole, enumName: "MembershipRole" })
   @Expose()
   readonly role!: MembershipRole;
apps/api/v2/test/fixtures/repository/membership.repository.fixture.ts (2)

33-39: Wrap create+user update in a single transaction to avoid partial writes.

-  async addUserToOrg(user: User, org: Team, role: MembershipRole, accepted: boolean) {
-    const membership = await this.prismaWriteClient.membership.create({
-      data: { createdAt: new Date(), teamId: org.id, userId: user.id, role, accepted },
-    });
-    await this.prismaWriteClient.user.update({ where: { id: user.id }, data: { organizationId: org.id } });
-    return membership;
-  }
+  async addUserToOrg(user: User, org: Team, role: MembershipRole, accepted: boolean) {
+    const [membership] = await this.prismaWriteClient.$transaction([
+      this.prismaWriteClient.membership.create({
+        data: { createdAt: new Date(), teamId: org.id, userId: user.id, role, accepted },
+      }),
+      this.prismaWriteClient.user.update({ where: { id: user.id }, data: { organizationId: org.id } }),
+    ]);
+    return membership;
+  }

25-31: Prefer select to return only required fields (repo guideline).

These reads return whole rows. Consider adding a minimal select for tests to speed up fixtures.

Also applies to: 41-43

apps/api/v2/src/modules/organizations/memberships/inputs/create-organization-membership.input.ts (1)

16-21: Keep Swagger enum tied to MembershipRole to avoid hard-coded lists.

-  @ApiProperty({
-    enum: ["MEMBER", "OWNER", "ADMIN"],
+  @ApiProperty({
+    enum: MembershipRole,
+    enumName: "MembershipRole",
     description: "If you are platform customer then managed users should only have MEMBER role.",
   })
apps/api/v2/src/modules/oauth-clients/controllers/oauth-client-users/oauth-client-users.controller.ts (1)

35-35: Use a type-only import for Prisma model to avoid loading @prisma/client at runtime

This User usage is purely for typing; using a value import needlessly pulls in @prisma/client.

Apply:

-import { User } from "@prisma/client";
+import type { User } from "@prisma/client";

Also consider whether the PR goal intends to eliminate all direct Prisma imports. If yes, re-export model types from an internal package and consume those instead.

apps/api/v2/src/modules/organizations/memberships/inputs/update-organization-membership.input.ts (1)

12-15: Keep Swagger enum in sync with the source enum

Using a hardcoded array risks drifting from MembershipRole. Prefer referencing the enum directly.

Apply:

-  @ApiPropertyOptional({ enum: ["MEMBER", "OWNER", "ADMIN"] })
+  @ApiPropertyOptional({ enum: MembershipRole })
apps/api/v2/src/modules/webhooks/inputs/webhook.input.ts (1)

2-2: Validate subscriberUrl as a URL, not just a string

Strengthen input validation to prevent bad webhook targets.

Apply:

-import { IsArray, IsBoolean, IsEnum, IsOptional, IsString } from "class-validator";
+import { IsArray, IsBoolean, IsEnum, IsOptional, IsString, IsUrl } from "class-validator";
-  @IsString()
+  @IsUrl({ protocols: ["http", "https"] }, { message: "subscriberUrl must be a valid http(s) URL" })
   @ApiProperty()
   subscriberUrl!: string;

Also applies to: 26-29

apps/api/v2/src/modules/oauth-clients/controllers/oauth-client-webhooks/oauth-client-webhooks.controller.ts (2)

20-21: Import Prisma model as type-only to avoid runtime cost

Webhook is used only for typing; make it a type-only import to prevent loading @prisma/client.

Apply:

-import { Webhook } from "@prisma/client";
+import type { Webhook } from "@prisma/client";

If the PR aims for zero direct Prisma imports, consider consuming a re-exported type from an internal package instead.


60-63: Optional: Prefer plainToInstance over deprecated plainToClass

class-transformer recommends plainToInstance. Not required for this PR, but improves forward-compatibility.

Apply:

-import { plainToClass } from "class-transformer";
+import { plainToInstance } from "class-transformer";
-      data: plainToClass(OAuthClientWebhookOutputDto, new WebhookOutputPipe().transform(webhook), {
+      data: plainToInstance(OAuthClientWebhookOutputDto, new WebhookOutputPipe().transform(webhook), {
         strategy: "excludeAll",
       }),

Repeat similarly for other occurrences in this file.

Also applies to: 80-83, 92-96, 130-134

apps/api/v2/src/modules/organizations/teams/memberships/inputs/create-organization-team-membership.input.ts (1)

16-19: Use enum object in Swagger to avoid drift

Replace hardcoded array with the enum object (adds reuse and prevents mismatches if roles change).

-  @ApiProperty({ enum: ["MEMBER", "OWNER", "ADMIN"] })
+  @ApiProperty({ enum: MembershipRole, enumName: "MembershipRole" })
apps/api/v2/src/modules/organizations/attributes/index/inputs/update-organization-attribute.input.ts (1)

17-21: Name the enum in Swagger for cleaner schema

Add enumName so the generated OpenAPI uses a named reusable schema.

-  @ApiPropertyOptional({ enum: AttributeType })
+  @ApiPropertyOptional({ enum: AttributeType, enumName: "AttributeType" })
apps/api/v2/src/modules/teams/memberships/inputs/update-team-membership.input.ts (1)

12-15: Avoid hardcoded enum values in Swagger

Prefer referencing the enum directly so docs stay in sync if roles evolve.

-  @ApiPropertyOptional({ enum: ["MEMBER", "OWNER", "ADMIN"] })
+  @ApiPropertyOptional({ enum: MembershipRole, enumName: "MembershipRole" })
apps/api/v2/src/modules/users/users.repository.ts (2)

78-85: Prisma: replace include with select per repo guideline

This file uses include in several queries. Our guideline for **/*.ts is “only select data you need; never use include”. Consider migrating these to select. Example for findByIdWithProfile:

-  return this.dbRead.prisma.user.findUnique({
-    where: { id: userId },
-    include: {
-      movedToProfile: {
-        include: { organization: { select: { isPlatform: true, name: true, slug: true, id: true } } },
-      },
-      profiles: {
-        include: { organization: { select: { isPlatform: true, name: true, slug: true, id: true } } },
-      },
-    },
-  });
+  return this.dbRead.prisma.user.findUnique({
+    where: { id: userId },
+    select: {
+      // add only the user fields actually needed by callers, e.g.:
+      id: true,
+      email: true,
+      username: true,
+      movedToProfile: {
+        select: { organization: { select: { isPlatform: true, name: true, slug: true, id: true } } },
+      },
+      profiles: {
+        select: { organization: { select: { isPlatform: true, name: true, slug: true, id: true } } },
+      },
+    },
+  });

Same pattern applies to the other marked blocks.

Do callers rely on full User shape here? If yes, consider defining a constrained output type and migrating incrementally.

Also applies to: 99-106, 117-119, 138-141, 158-165, 288-291


260-264: No-op setter—either remove or implement

formatInput currently re-assigns weekStart to itself. Drop it or implement the intended normalization.

-  formatInput(userInput: CreateManagedUserInput | UpdateManagedUserInput) {
-    if (userInput.weekStart) {
-      userInput.weekStart = userInput.weekStart;
-    }
-  }
+  formatInput(_userInput: CreateManagedUserInput | UpdateManagedUserInput) {
+    // Intentionally left blank – add normalization when requirements are defined.
+  }
apps/api/v2/src/modules/organizations/event-types/organizations-event-types.e2e-spec.ts (1)

9-9: Use type-only imports for Prisma models in tests

These are used purely for typing; avoid creating runtime bindings.

-import { User } from "@prisma/client";
+import type { User } from "@prisma/client";
@@
-import { Team } from "@calcom/prisma/client";
+import type { Team } from "@calcom/prisma/client";

Also applies to: 35-35

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between b052c2e and 6363b3e.

📒 Files selected for processing (32)
  • apps/api/v2/src/ee/bookings/2024-04-15/controllers/bookings.controller.ts (1 hunks)
  • apps/api/v2/src/ee/bookings/2024-08-13/services/input.service.ts (1 hunks)
  • apps/api/v2/src/lib/roles/constants.ts (1 hunks)
  • apps/api/v2/src/modules/auth/decorators/roles/membership-roles.decorator.ts (1 hunks)
  • apps/api/v2/src/modules/oauth-clients/controllers/oauth-client-users/oauth-client-users.controller.ts (1 hunks)
  • apps/api/v2/src/modules/oauth-clients/controllers/oauth-client-webhooks/oauth-client-webhooks.controller.ts (1 hunks)
  • apps/api/v2/src/modules/oauth-clients/controllers/oauth-clients/oauth-clients.controller.ts (1 hunks)
  • apps/api/v2/src/modules/oauth-clients/services/oauth-clients-users.service.ts (1 hunks)
  • apps/api/v2/src/modules/organizations/attributes/index/inputs/create-organization-attribute.input.ts (1 hunks)
  • apps/api/v2/src/modules/organizations/attributes/index/inputs/update-organization-attribute.input.ts (1 hunks)
  • apps/api/v2/src/modules/organizations/event-types/organizations-event-types.e2e-spec.ts (2 hunks)
  • apps/api/v2/src/modules/organizations/event-types/services/output.service.ts (1 hunks)
  • apps/api/v2/src/modules/organizations/memberships/inputs/create-organization-membership.input.ts (1 hunks)
  • apps/api/v2/src/modules/organizations/memberships/inputs/update-organization-membership.input.ts (1 hunks)
  • apps/api/v2/src/modules/organizations/teams/index/outputs/organization-team.output.ts (1 hunks)
  • apps/api/v2/src/modules/organizations/teams/memberships/inputs/create-organization-team-membership.input.ts (1 hunks)
  • apps/api/v2/src/modules/organizations/teams/memberships/inputs/update-organization-team-membership.input.ts (1 hunks)
  • apps/api/v2/src/modules/organizations/users/index/inputs/create-organization-user.input.ts (1 hunks)
  • apps/api/v2/src/modules/organizations/users/index/services/organizations-users-service.ts (1 hunks)
  • apps/api/v2/src/modules/teams/memberships/inputs/create-team-membership.input.ts (1 hunks)
  • apps/api/v2/src/modules/teams/memberships/inputs/update-team-membership.input.ts (1 hunks)
  • apps/api/v2/src/modules/teams/memberships/outputs/team-membership.output.ts (1 hunks)
  • apps/api/v2/src/modules/teams/teams/outputs/teams/get-team.output.ts (1 hunks)
  • apps/api/v2/src/modules/teams/teams/outputs/teams/get-teams.output.ts (1 hunks)
  • apps/api/v2/src/modules/teams/teams/outputs/teams/update-team.output.ts (1 hunks)
  • apps/api/v2/src/modules/users/users.repository.ts (1 hunks)
  • apps/api/v2/src/modules/webhooks/inputs/webhook.input.ts (1 hunks)
  • apps/api/v2/src/modules/webhooks/outputs/webhook.output.ts (1 hunks)
  • apps/api/v2/src/modules/workflows/inputs/workflow-step.input.ts (1 hunks)
  • apps/api/v2/src/modules/workflows/inputs/workflow-trigger.input.ts (1 hunks)
  • apps/api/v2/src/modules/workflows/workflows.repository.ts (1 hunks)
  • apps/api/v2/test/fixtures/repository/membership.repository.fixture.ts (1 hunks)
🧰 Additional context used
📓 Path-based instructions (4)
**/*.{service,repository}.ts

📄 CodeRabbit inference engine (.cursor/rules/review.mdc)

Avoid dot-suffixes like .service.ts or .repository.ts for new files; reserve .test.ts, .spec.ts, .types.ts for their specific purposes

Files:

  • apps/api/v2/src/modules/oauth-clients/services/oauth-clients-users.service.ts
  • apps/api/v2/src/modules/workflows/workflows.repository.ts
  • apps/api/v2/src/ee/bookings/2024-08-13/services/input.service.ts
  • apps/api/v2/src/modules/organizations/event-types/services/output.service.ts
  • apps/api/v2/src/modules/users/users.repository.ts
**/*.ts

📄 CodeRabbit inference engine (.cursor/rules/review.mdc)

**/*.ts: For Prisma queries, only select data you need; never use include, always use select
Ensure the credential.key field is never returned from tRPC endpoints or APIs

Files:

  • apps/api/v2/src/modules/oauth-clients/services/oauth-clients-users.service.ts
  • apps/api/v2/src/modules/webhooks/outputs/webhook.output.ts
  • apps/api/v2/src/modules/organizations/attributes/index/inputs/update-organization-attribute.input.ts
  • apps/api/v2/src/modules/teams/teams/outputs/teams/get-teams.output.ts
  • apps/api/v2/src/modules/workflows/inputs/workflow-step.input.ts
  • apps/api/v2/src/modules/teams/teams/outputs/teams/get-team.output.ts
  • apps/api/v2/src/modules/webhooks/inputs/webhook.input.ts
  • apps/api/v2/src/lib/roles/constants.ts
  • apps/api/v2/src/modules/teams/memberships/inputs/create-team-membership.input.ts
  • apps/api/v2/src/modules/workflows/inputs/workflow-trigger.input.ts
  • apps/api/v2/src/modules/workflows/workflows.repository.ts
  • apps/api/v2/src/modules/organizations/attributes/index/inputs/create-organization-attribute.input.ts
  • apps/api/v2/src/modules/organizations/memberships/inputs/update-organization-membership.input.ts
  • apps/api/v2/src/modules/organizations/teams/memberships/inputs/update-organization-team-membership.input.ts
  • apps/api/v2/src/modules/auth/decorators/roles/membership-roles.decorator.ts
  • apps/api/v2/src/ee/bookings/2024-04-15/controllers/bookings.controller.ts
  • apps/api/v2/src/ee/bookings/2024-08-13/services/input.service.ts
  • apps/api/v2/src/modules/organizations/event-types/services/output.service.ts
  • apps/api/v2/src/modules/teams/teams/outputs/teams/update-team.output.ts
  • apps/api/v2/src/modules/organizations/users/index/services/organizations-users-service.ts
  • apps/api/v2/src/modules/organizations/users/index/inputs/create-organization-user.input.ts
  • apps/api/v2/src/modules/organizations/memberships/inputs/create-organization-membership.input.ts
  • apps/api/v2/src/modules/organizations/teams/index/outputs/organization-team.output.ts
  • apps/api/v2/src/modules/oauth-clients/controllers/oauth-clients/oauth-clients.controller.ts
  • apps/api/v2/src/modules/teams/memberships/inputs/update-team-membership.input.ts
  • apps/api/v2/src/modules/teams/memberships/outputs/team-membership.output.ts
  • apps/api/v2/src/modules/users/users.repository.ts
  • apps/api/v2/src/modules/organizations/teams/memberships/inputs/create-organization-team-membership.input.ts
  • apps/api/v2/src/modules/oauth-clients/controllers/oauth-client-users/oauth-client-users.controller.ts
  • apps/api/v2/src/modules/organizations/event-types/organizations-event-types.e2e-spec.ts
  • apps/api/v2/test/fixtures/repository/membership.repository.fixture.ts
  • apps/api/v2/src/modules/oauth-clients/controllers/oauth-client-webhooks/oauth-client-webhooks.controller.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/review.mdc)

Flag excessive Day.js use in performance-critical code; prefer native Date or Day.js .utc() in hot paths like loops

Files:

  • apps/api/v2/src/modules/oauth-clients/services/oauth-clients-users.service.ts
  • apps/api/v2/src/modules/webhooks/outputs/webhook.output.ts
  • apps/api/v2/src/modules/organizations/attributes/index/inputs/update-organization-attribute.input.ts
  • apps/api/v2/src/modules/teams/teams/outputs/teams/get-teams.output.ts
  • apps/api/v2/src/modules/workflows/inputs/workflow-step.input.ts
  • apps/api/v2/src/modules/teams/teams/outputs/teams/get-team.output.ts
  • apps/api/v2/src/modules/webhooks/inputs/webhook.input.ts
  • apps/api/v2/src/lib/roles/constants.ts
  • apps/api/v2/src/modules/teams/memberships/inputs/create-team-membership.input.ts
  • apps/api/v2/src/modules/workflows/inputs/workflow-trigger.input.ts
  • apps/api/v2/src/modules/workflows/workflows.repository.ts
  • apps/api/v2/src/modules/organizations/attributes/index/inputs/create-organization-attribute.input.ts
  • apps/api/v2/src/modules/organizations/memberships/inputs/update-organization-membership.input.ts
  • apps/api/v2/src/modules/organizations/teams/memberships/inputs/update-organization-team-membership.input.ts
  • apps/api/v2/src/modules/auth/decorators/roles/membership-roles.decorator.ts
  • apps/api/v2/src/ee/bookings/2024-04-15/controllers/bookings.controller.ts
  • apps/api/v2/src/ee/bookings/2024-08-13/services/input.service.ts
  • apps/api/v2/src/modules/organizations/event-types/services/output.service.ts
  • apps/api/v2/src/modules/teams/teams/outputs/teams/update-team.output.ts
  • apps/api/v2/src/modules/organizations/users/index/services/organizations-users-service.ts
  • apps/api/v2/src/modules/organizations/users/index/inputs/create-organization-user.input.ts
  • apps/api/v2/src/modules/organizations/memberships/inputs/create-organization-membership.input.ts
  • apps/api/v2/src/modules/organizations/teams/index/outputs/organization-team.output.ts
  • apps/api/v2/src/modules/oauth-clients/controllers/oauth-clients/oauth-clients.controller.ts
  • apps/api/v2/src/modules/teams/memberships/inputs/update-team-membership.input.ts
  • apps/api/v2/src/modules/teams/memberships/outputs/team-membership.output.ts
  • apps/api/v2/src/modules/users/users.repository.ts
  • apps/api/v2/src/modules/organizations/teams/memberships/inputs/create-organization-team-membership.input.ts
  • apps/api/v2/src/modules/oauth-clients/controllers/oauth-client-users/oauth-client-users.controller.ts
  • apps/api/v2/src/modules/organizations/event-types/organizations-event-types.e2e-spec.ts
  • apps/api/v2/test/fixtures/repository/membership.repository.fixture.ts
  • apps/api/v2/src/modules/oauth-clients/controllers/oauth-client-webhooks/oauth-client-webhooks.controller.ts
**/*.{ts,tsx,js,jsx}

⚙️ CodeRabbit configuration file

Flag default exports and encourage named exports. Named exports provide better tree-shaking, easier refactoring, and clearer imports. Exempt main components like pages, layouts, and components that serve as the primary export of a module.

Files:

  • apps/api/v2/src/modules/oauth-clients/services/oauth-clients-users.service.ts
  • apps/api/v2/src/modules/webhooks/outputs/webhook.output.ts
  • apps/api/v2/src/modules/organizations/attributes/index/inputs/update-organization-attribute.input.ts
  • apps/api/v2/src/modules/teams/teams/outputs/teams/get-teams.output.ts
  • apps/api/v2/src/modules/workflows/inputs/workflow-step.input.ts
  • apps/api/v2/src/modules/teams/teams/outputs/teams/get-team.output.ts
  • apps/api/v2/src/modules/webhooks/inputs/webhook.input.ts
  • apps/api/v2/src/lib/roles/constants.ts
  • apps/api/v2/src/modules/teams/memberships/inputs/create-team-membership.input.ts
  • apps/api/v2/src/modules/workflows/inputs/workflow-trigger.input.ts
  • apps/api/v2/src/modules/workflows/workflows.repository.ts
  • apps/api/v2/src/modules/organizations/attributes/index/inputs/create-organization-attribute.input.ts
  • apps/api/v2/src/modules/organizations/memberships/inputs/update-organization-membership.input.ts
  • apps/api/v2/src/modules/organizations/teams/memberships/inputs/update-organization-team-membership.input.ts
  • apps/api/v2/src/modules/auth/decorators/roles/membership-roles.decorator.ts
  • apps/api/v2/src/ee/bookings/2024-04-15/controllers/bookings.controller.ts
  • apps/api/v2/src/ee/bookings/2024-08-13/services/input.service.ts
  • apps/api/v2/src/modules/organizations/event-types/services/output.service.ts
  • apps/api/v2/src/modules/teams/teams/outputs/teams/update-team.output.ts
  • apps/api/v2/src/modules/organizations/users/index/services/organizations-users-service.ts
  • apps/api/v2/src/modules/organizations/users/index/inputs/create-organization-user.input.ts
  • apps/api/v2/src/modules/organizations/memberships/inputs/create-organization-membership.input.ts
  • apps/api/v2/src/modules/organizations/teams/index/outputs/organization-team.output.ts
  • apps/api/v2/src/modules/oauth-clients/controllers/oauth-clients/oauth-clients.controller.ts
  • apps/api/v2/src/modules/teams/memberships/inputs/update-team-membership.input.ts
  • apps/api/v2/src/modules/teams/memberships/outputs/team-membership.output.ts
  • apps/api/v2/src/modules/users/users.repository.ts
  • apps/api/v2/src/modules/organizations/teams/memberships/inputs/create-organization-team-membership.input.ts
  • apps/api/v2/src/modules/oauth-clients/controllers/oauth-client-users/oauth-client-users.controller.ts
  • apps/api/v2/src/modules/organizations/event-types/organizations-event-types.e2e-spec.ts
  • apps/api/v2/test/fixtures/repository/membership.repository.fixture.ts
  • apps/api/v2/src/modules/oauth-clients/controllers/oauth-client-webhooks/oauth-client-webhooks.controller.ts
🧠 Learnings (4)
📚 Learning: 2025-08-21T12:28:42.018Z
Learnt from: alishaz-polymath
PR: calcom/cal.com#23247
File: packages/features/webhooks/lib/factory/WebhookPayloadFactory.ts:274-282
Timestamp: 2025-08-21T12:28:42.018Z
Learning: In webhook DTOs in packages/features/webhooks/lib/dto/types.ts, the booking fields are restricted structures containing only specific fields (id, eventTypeId, userId, and sometimes additional fields like startTime or smsReminderNumber) rather than full database booking objects, so there are no security or PII leakage concerns when using these booking objects in webhook payloads.

Applied to files:

  • apps/api/v2/src/modules/webhooks/outputs/webhook.output.ts
  • apps/api/v2/src/modules/webhooks/inputs/webhook.input.ts
📚 Learning: 2025-08-26T20:09:17.089Z
Learnt from: Udit-takkar
PR: calcom/cal.com#22995
File: packages/features/ee/workflows/components/WorkflowStepContainer.tsx:641-649
Timestamp: 2025-08-26T20:09:17.089Z
Learning: In packages/features/ee/workflows/components/WorkflowStepContainer.tsx, Cal.AI actions are intentionally filtered out/hidden for organization workflows when props.isOrganization is true. This restriction is by design per maintainer Udit-takkar in PR #22995, despite the broader goal of enabling Cal.AI self-serve.

Applied to files:

  • apps/api/v2/src/modules/workflows/inputs/workflow-step.input.ts
📚 Learning: 2025-08-27T13:32:46.887Z
Learnt from: supalarry
PR: calcom/cal.com#23364
File: apps/api/v2/src/ee/event-types/event-types_2024_06_14/transformers/internal-to-api/internal-to-api.spec.ts:295-296
Timestamp: 2025-08-27T13:32:46.887Z
Learning: In calcom/cal.com, when transforming booking fields from internal to API format, tests in organizations-event-types.e2e-spec.ts already expect name field label and placeholder to be empty strings ("") rather than undefined. PR changes that set these to explicit empty strings are typically fixing implementation to match existing test expectations rather than breaking changes.

Applied to files:

  • apps/api/v2/src/ee/bookings/2024-04-15/controllers/bookings.controller.ts
  • apps/api/v2/src/modules/organizations/event-types/services/output.service.ts
  • apps/api/v2/src/modules/organizations/event-types/organizations-event-types.e2e-spec.ts
📚 Learning: 2025-08-21T13:44:06.805Z
Learnt from: supalarry
PR: calcom/cal.com#23217
File: apps/api/v2/src/ee/event-types/event-types_2024_06_14/services/output-event-types.service.ts:93-94
Timestamp: 2025-08-21T13:44:06.805Z
Learning: In apps/api/v2/src/ee/event-types/event-types_2024_06_14/event-types.repository.ts, repository functions that use explicit Prisma select clauses (like getEventTypeWithSeats) are used for specific purposes and don't need to include all EventType fields like bookingRequiresAuthentication. These methods don't feed into the general OutputEventTypesService_2024_06_14 flow.

Applied to files:

  • apps/api/v2/src/modules/organizations/event-types/services/output.service.ts
⏰ Context from checks skipped due to timeout of 180000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Install dependencies / Yarn install & cache
🔇 Additional comments (33)
apps/api/v2/src/modules/webhooks/outputs/webhook.output.ts (1)

6-6: Enum import source change looks good.

Switching WebhookTriggerEvents to @calcom/prisma/enums aligns with the PR objective and avoids pulling from @prisma/client directly.

apps/api/v2/src/modules/oauth-clients/controllers/oauth-clients/oauth-clients.controller.ts (1)

43-43: Enum import source change looks good.

Using MembershipRole from @calcom/prisma/enums is consistent with the refactor goal.

apps/api/v2/src/modules/organizations/teams/index/outputs/organization-team.output.ts (1)

7-7: Enum import source change looks good.

Moving MembershipRole to @calcom/prisma/enums aligns with the refactor scope.

apps/api/v2/src/modules/teams/teams/outputs/teams/get-team.output.ts (1)

3-3: Import cleanup looks good.

Removing unused imports keeps the DTO lean.

apps/api/v2/src/modules/teams/teams/outputs/teams/update-team.output.ts (1)

3-3: Import cleanup looks good.

Same as above—good tidy-up.

apps/api/v2/src/lib/roles/constants.ts (1)

1-1: Enum import migration looks good; confirm runtime enum availability.

These constants rely on MembershipRole values at runtime (template strings). Ensure @calcom/prisma/enums exports concrete runtime values (not type-only or const enums), otherwise ORG_/TEAM_ strings will become "undefined".

If unsure, quickly assert at runtime:

// e.g., in a Jest test or ts-node REPL
expect(typeof MembershipRole.OWNER).toBe("string");
apps/api/v2/src/modules/teams/teams/outputs/teams/get-teams.output.ts (1)

3-3: Import cleanup LGTM.

Unused imports removed; keeps the file lean.

apps/api/v2/src/modules/workflows/inputs/workflow-trigger.input.ts (1)

5-6: Enum import migration LGTM.

Matches the PR goal; no functional changes implied.

apps/api/v2/src/modules/organizations/attributes/index/inputs/create-organization-attribute.input.ts (1)

14-15: Enum import migration looks correct; verify runtime enum for validators/Swagger.

Both @IsEnum(AttributeType) and ApiProperty({ enum: AttributeType }) require a runtime object. Confirm @calcom/prisma/enums exposes AttributeType at runtime.

Quick check:

expect(AttributeType && typeof AttributeType).toBe("object");
expect(Object.values(AttributeType).length).toBeGreaterThan(0);
apps/api/v2/src/ee/bookings/2024-08-13/services/input.service.ts (3)

48-49: Enum import migration LGTM.

CreationSource moved to @calcom/prisma/enums; usages remain the same.


675-683: Possible config key mismatch for API key prefix.

Using api.apiKeyPrefix in isApiKey but api.keyPrefix in stripApiKey can desync behavior if keys differ.

Consider aligning keys:

-          const strippedApiKey = stripApiKey(bearerToken, this.config.get<string>("api.keyPrefix"));
+          const strippedApiKey = stripApiKey(bearerToken, this.config.get<string>("api.apiKeyPrefix"));

Verify against your actual config schema.


510-549: Consistency: Ensure CreationSource is set for reschedules.

You set creationSource on create/reschedule paths above; confirm downstream expects it (analytics, auditing). Current code sets it correctly in both OAuth and non-OAuth branches—good; just calling it out for visibility.

apps/api/v2/src/modules/teams/memberships/inputs/create-team-membership.input.ts (1)

4-4: LGTM: enum import source migrated correctly.

No behavior change; Swagger metadata still matches the known roles.

apps/api/v2/src/modules/oauth-clients/services/oauth-clients-users.service.ts (1)

15-15: LGTM: CreationSource import moved to enums.

No functional change.

apps/api/v2/src/ee/bookings/2024-04-15/controllers/bookings.controller.ts (1)

67-68: Enum import migration looks good.

Importing CreationSource from @calcom/prisma/enums matches the PR goal.

apps/api/v2/src/modules/organizations/teams/memberships/inputs/update-organization-team-membership.input.ts (1)

4-5: Enum import migration LGTM.

apps/api/v2/src/modules/teams/memberships/outputs/team-membership.output.ts (1)

5-6: Enum import migration LGTM.

apps/api/v2/test/fixtures/repository/membership.repository.fixture.ts (1)

6-7: Enum import migration LGTM (tests).

apps/api/v2/src/modules/organizations/memberships/inputs/create-organization-membership.input.ts (1)

4-5: Enum import migration LGTM.

apps/api/v2/src/modules/organizations/users/index/inputs/create-organization-user.input.ts (1)

5-5: Enum source migration looks good

Importing MembershipRole from @calcom/prisma/enums aligns with the PR goal and keeps Swagger decorators/type guards intact.

apps/api/v2/src/modules/oauth-clients/controllers/oauth-client-users/oauth-client-users.controller.ts (1)

38-38: Enum import migrated correctly

MembershipRole now comes from @calcom/prisma/enums. Matches project direction.

apps/api/v2/src/modules/organizations/memberships/inputs/update-organization-membership.input.ts (1)

4-4: Enum import source updated correctly

Switch to @calcom/prisma/enums is consistent with the refactor plan.

apps/api/v2/src/modules/webhooks/inputs/webhook.input.ts (1)

4-4: Enum import source updated correctly

WebhookTriggerEvents now from @calcom/prisma/enums; consistent with the migration.

apps/api/v2/src/modules/oauth-clients/controllers/oauth-client-webhooks/oauth-client-webhooks.controller.ts (1)

25-25: Enum import migration acknowledged

MembershipRole moved to @calcom/prisma/enums; matches the repo-wide refactor.

apps/api/v2/src/modules/organizations/teams/memberships/inputs/create-organization-team-membership.input.ts (1)

4-4: Enum import migration LGTM

Importing MembershipRole from @calcom/prisma/enums matches the PR goal. No functional changes.

apps/api/v2/src/modules/organizations/attributes/index/inputs/update-organization-attribute.input.ts (1)

4-4: Enum import migration LGTM

AttributeType now sourced from @calcom/prisma/enums.

apps/api/v2/src/modules/teams/memberships/inputs/update-team-membership.input.ts (1)

1-1: Imports update LGTM

Switch to ApiPropertyOptional and enum import from @calcom/prisma/enums aligns with the refactor.

Also applies to: 4-4

apps/api/v2/src/modules/organizations/users/index/services/organizations-users-service.ts (1)

7-7: Enum source split LGTM — no leftover @prisma/client enum imports detected
Search for MembershipRole, CreationSource, AttributeType, SchedulingType, WebhookTriggerEvents, WorkflowActions, WorkflowTemplates, and TimeUnit imports from @prisma/client returned no results. Please manually confirm that the CreationSource enum values in @calcom/prisma/enums exactly match the originals from @prisma/client to avoid DB mismatches, and audit Swagger decorators for any hard-coded enum arrays.

apps/api/v2/src/modules/auth/decorators/roles/membership-roles.decorator.ts (1)

3-5: Decorator type import migration LGTM

Type source updated; no runtime impact on Reflector decorator.

apps/api/v2/src/modules/users/users.repository.ts (2)

8-8: Enum import migration LGTM

Moving CreationSource to @calcom/prisma/enums is correct and within PR scope.


35-36: No CreationSource imports from @prisma/client remain
All occurrences now import from @calcom/prisma/enums.

apps/api/v2/src/modules/organizations/event-types/organizations-event-types.e2e-spec.ts (2)

36-36: Importing SchedulingType from enums is correct

Matches the refactor goal to stop sourcing enums from @prisma/client.


9-9: No Prisma enum imports found in API tests Verified that there are no remaining imports of enums from @prisma/client in apps/api/v2 tests.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

Caution

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

⚠️ Outside diff range comments (17)
packages/app-store/routing-forms/trpc/utils.ts (1)

139-161: Fix: unawaited webhook sends and secret leakage in logs

  • The map callback does not return the promise, so promisesFormSubmitted becomes an array of undefined and Promise.all won’t await webhook sends.
  • Logging the entire webhook object risks leaking webhook.secret.

Return the promise and log only safe identifiers. Also, prefer the enum for triggerEvent to avoid drift.

-  const promisesFormSubmitted = webhooksFormSubmitted.map((webhook) => {
-    sendGenericWebhookPayload({
-      secretKey: webhook.secret,
-      triggerEvent: "FORM_SUBMITTED",
-      createdAt: new Date().toISOString(),
-      webhook,
-      data: {
-        formId: form.id,
-        formName: form.name,
-        teamId: form.teamId,
-        responses: fieldResponsesByIdentifier,
-      },
-      rootData: {
-        // Send responses unwrapped at root level for backwards compatibility
-        ...Object.entries(fieldResponsesByIdentifier).reduce((acc, [key, value]) => {
-          acc[key] = value.value;
-          return acc;
-        }, {} as Record<string, FormResponse[keyof FormResponse]["value"]>),
-      },
-    }).catch((e) => {
-      console.error(`Error executing routing form webhook`, webhook, e);
-    });
-  });
+  const promisesFormSubmitted = webhooksFormSubmitted.map((webhook) =>
+    sendGenericWebhookPayload({
+      secretKey: webhook.secret,
+      triggerEvent: WebhookTriggerEvents.FORM_SUBMITTED,
+      createdAt: new Date().toISOString(),
+      webhook,
+      data: {
+        formId: form.id,
+        formName: form.name,
+        teamId: form.teamId,
+        responses: fieldResponsesByIdentifier,
+      },
+      rootData: {
+        // Send responses unwrapped at root level for backwards compatibility
+        ...Object.entries(fieldResponsesByIdentifier).reduce((acc, [key, value]) => {
+          acc[key] = value.value;
+          return acc;
+        }, {} as Record<string, FormResponse[keyof FormResponse]["value"]>),
+      },
+    }).catch((e) => {
+      moduleLogger.error("Error executing routing form webhook", {
+        webhookId: webhook.id,
+        error: e?.message ?? e,
+      });
+    })
+  );
apps/web/app/(use-page-wrapper)/auth/error/page.tsx (2)

41-49: Localize provider labels instead of hardcoded English strings.
Per guidelines, use t() for user-facing text. Replace inline strings for providerName with translated labels.

Apply:

-      const providerName =
-        provider === IdentityProvider.GOOGLE
-          ? "Google"
-          : provider === IdentityProvider.CAL
-          ? "Email and Password"
-          : provider === IdentityProvider.SAML
-          ? "SAML (like Okta)"
-          : "your original login method";
+      const providerName =
+        provider === IdentityProvider.GOOGLE
+          ? t("google")
+          : provider === IdentityProvider.CAL
+          ? t("email_and_password")
+          : provider === IdentityProvider.SAML
+          ? t("saml_like_okta")
+          : t("your_original_login_method");

51-51: Localize “Error code” suffix.
Avoid embedding English; use a dedicated translation key.

Apply:

-    return t("error_during_login") + (error ? ` Error code: ${error}` : "");
+    return error ? t("error_during_login_with_code", { code: error }) : t("error_during_login");
apps/web/playwright/organization/organization-invitation.e2e.ts (1)

520-520: Await navigation to avoid race conditions.
Missing await can cause flakes.

-  signupPage.goto(inviteLink);
+  await signupPage.goto(inviteLink);
packages/lib/server/repository/workflow.ts (3)

28-69: Prisma: prefer select over include.
Guideline: never use include; select only needed fields to reduce payload and coupling.

Proposed pattern:

-const { include: includedFields } = {
-  include: {
+const workflowSelect = {
+  activeOn: {
+    select: {
+      eventType: {
+        select: {
+          id: true,
+          title: true,
+          parentId: true,
+          _count: { select: { children: true } },
+        },
+      },
+    },
+  },
+  activeOnTeams: {
     select: {
-      eventType: {
-        select: {
-          id: true,
-          title: true,
-          parentId: true,
-          _count: {
-            select: {
-              children: true,
-            },
-          },
-        },
-      },
+      team: { select: { id: true, name: true } },
     },
   },
-  activeOnTeams: {
-    select: {
-      team: {
-        select: {
-          id: true,
-          name: true,
-        },
-      },
-    },
-  },
   steps: true,
   team: {
     select: {
       id: true,
       slug: true,
       name: true,
       members: true,
       logoUrl: true,
       isOrganization: true,
     },
   },
-},
-} satisfies Prisma.WorkflowDefaultArgs;
+} satisfies Prisma.WorkflowSelect;

And switch usages:

-      include: includedFields,
+      select: workflowSelect,

Apply the above in both findMany calls below.


235-235: Switch include → select (usage 1).

-      include: includedFields,
+      select: workflowSelect,

293-293: Switch include → select (usage 2).

-        include: includedFields,
+        select: workflowSelect,
packages/trpc/server/routers/viewer/admin/setSMSLockState.handler.ts (1)

19-29: Use Prisma select to fetch only needed fields (repo guideline: avoid include, prefer select).

Tighten reads/updates to reduce payloads and comply with our Prisma usage rule.

Apply:

-    const userToUpdate = await prisma.user.findUnique({ where: { id: userId } });
+    const userToUpdate = await prisma.user.findUnique({ where: { id: userId }, select: { id: true } });

-    const updatedUser = await prisma.user.update({
+    const updatedUser = await prisma.user.update({
       where: {
         id: userId,
       },
       data: {
         smsLockState: lock ? SMSLockState.LOCKED : SMSLockState.UNLOCKED,
         smsLockReviewedByAdmin: true,
       },
+      select: { username: true },
     });

-    const userToUpdate = await prisma.user.findFirst({
+    const userToUpdate = await prisma.user.findFirst({
       where: {
         username,
         profiles: { none: {} },
       },
+      select: { id: true },
     });

-    const updatedUser = await prisma.user.update({
+    const updatedUser = await prisma.user.update({
       where: {
         id: userToUpdate.id,
       },
       data: {
         smsLockState: lock ? SMSLockState.LOCKED : SMSLockState.UNLOCKED,
         smsLockReviewedByAdmin: true,
       },
+      select: { username: true },
     });

-    const teamToUpdate = await prisma.team.findUnique({
+    const teamToUpdate = await prisma.team.findUnique({
       where: {
         id: teamId,
       },
+      select: { id: true },
     });

-    const updatedTeam = await prisma.team.update({
+    const updatedTeam = await prisma.team.update({
       where: {
         id: teamId,
       },
       data: {
         smsLockState: lock ? SMSLockState.LOCKED : SMSLockState.UNLOCKED,
         smsLockReviewedByAdmin: true,
       },
+      select: { slug: true },
     });

-    const teamToUpdate = await prisma.team.findFirst({
+    const teamToUpdate = await prisma.team.findFirst({
       where: {
         slug: teamSlug,
         parentId: null,
       },
+      select: { id: true },
     });

-    const updatedTeam = await prisma.team.update({
+    const updatedTeam = await prisma.team.update({
       where: {
         id: teamToUpdate.id,
       },
       data: {
         smsLockState: lock ? SMSLockState.LOCKED : SMSLockState.UNLOCKED,
         smsLockReviewedByAdmin: true,
       },
+      select: { slug: true },
     });

Also applies to: 39-47, 50-64, 67-82

apps/web/app/api/auth/two-factor/totp/disable/route.ts (1)

30-31: Replace include with select and narrow fields (policy: select-only).

Avoid fetching entire related models; select only what’s used.

-  const user = await prisma.user.findUnique({ where: { id: session.user.id }, include: { password: true } });
+  const user = await prisma.user.findUnique({
+    where: { id: session.user.id },
+    select: {
+      id: true,
+      identityProvider: true,
+      twoFactorEnabled: true,
+      twoFactorSecret: true,
+      backupCodes: true,
+      password: { select: { hash: true } },
+    },
+  });
packages/lib/server/repository/membership.ts (1)

318-330: Switch include to select for the availability query.

Adhere to select-only rule and limit top-level fields via the existing membershipSelect.

-    const memberships = await prisma.membership.findMany({
-      where: { teamId },
-      include: {
-        user: {
-          select: {
-            credentials: {
-              select: credentialForCalendarServiceSelect,
-            }, // needed for getUserAvailability
-            ...availabilityUserSelect,
-          },
-        },
-      },
-    });
+    const memberships = await prisma.membership.findMany({
+      where: { teamId },
+      select: {
+        ...membershipSelect,
+        user: {
+          select: {
+            credentials: { select: credentialForCalendarServiceSelect }, // needed for getUserAvailability
+            ...availabilityUserSelect,
+          },
+        },
+      },
+    });
apps/web/components/apps/installation/EventTypeConferencingAppSettings.tsx (1)

36-48: Fix early return: prefillLocation only inspects the first group

return res; inside the outer loop short-circuits scanning remaining groups. Move return outside, or flatten before searching.

-  const prefillLocation = useMemo(() => {
-    let res: SingleValueLocationOption | undefined = undefined;
-    for (const item of eventType?.locationOptions || []) {
-      for (const option of item.options) {
-        if (option.slug === slug) {
-          res = {
-            ...option,
-          };
-        }
-      }
-      return res;
-    }
-  }, [slug, eventType?.locationOptions]);
+  const prefillLocation = useMemo(() => {
+    const options = (eventType?.locationOptions ?? []).flatMap((g) => g.options);
+    const match = options.find((o) => o.slug === slug);
+    return match ? { ...match } : undefined;
+  }, [slug, eventType?.locationOptions]);
packages/trpc/server/routers/viewer/attributes/toggleActive.handler.ts (2)

24-26: Fix grammar in user-facing error message (“a part” vs “apart”).

Current copy reads awkwardly to users.

-      message: "You need to be apart of an organization to use this feature",
+      message: "You need to be a part of an organization to use this feature",

40-42: Fix grammar in user-facing error message.

Same issue as above.

-      message: "You need to be apart of this organization to use this feature",
+      message: "You need to be a part of this organization to use this feature",
packages/trpc/server/routers/viewer/attributes/edit.handler.ts (2)

24-27: Fix grammar in user-facing message (“a part” vs “apart”).

-      message: "You need to be apart of an organization to use this feature",
+      message: "You need to be a part of an organization to use this feature",

41-44: Fix grammar in user-facing message.

-      message: "You need to be apart of this organization to use this feature",
+      message: "You need to be a part of this organization to use this feature",
apps/web/lib/pages/auth/verify-email.ts (1)

48-52: Use Prisma select to limit returned fields

Per repo guidelines, add select to reads/updates to avoid returning full rows you don’t use.

Example diffs:

@@
-  const foundToken = await prisma.verificationToken.findFirst({
-    where: {
-      token,
-    },
-  });
+  const foundToken = await prisma.verificationToken.findFirst({
+    where: { token },
+    select: { id: true, expires: true, secondaryEmailId: true, identifier: true },
+  });
@@
-  const user = await prisma.user.findFirst({
-    where: {
-      email: foundToken?.identifier,
-    },
-  });
+  const user = await prisma.user.findFirst({
+    where: { email: foundToken?.identifier },
+    select: { id: true, email: true, emailVerified: true, metadata: true, completedOnboarding: true },
+  });
@@
-    await prisma.secondaryEmail.update({
+    await prisma.secondaryEmail.update({
       where: {
         id: foundToken.secondaryEmailId,
         email: foundToken?.identifier,
       },
-      data: {
-        emailVerified: new Date(),
-      },
+      data: { emailVerified: new Date() },
+      select: { id: true },
     });
@@
-    await prisma.user.update({
+    await prisma.user.update({
       where: { id: user.id },
       data: {
         email: updatedEmail,
         metadata: userMetadataParsed,
       },
+      select: { id: true },
     });
@@
-      await prisma.secondaryEmail.update({
+      await prisma.secondaryEmail.update({
         where: {
           id: existingSecondaryUser.id,
           userId: user.id,
         },
         data: {
           email: oldEmail,
           emailVerified: user.emailVerified,
         },
+        select: { id: true },
       });
@@
-  await prisma.user.update({
+  await prisma.user.update({
     where: { id: user.id },
-    data: {
-      emailVerified: new Date(),
-    },
+    data: { emailVerified: new Date() },
+    select: { id: true },
   });

Also applies to: 79-84, 93-98, 104-112, 123-131, 143-152, 162-169

packages/trpc/server/routers/viewer/attributes/create.handler.ts (1)

28-32: Fix user-facing grammar in error messages

“apart of” → “a part of”.

-      message: "You need to be apart of an organization to use this feature",
+      message: "You need to be a part of an organization to use this feature",
@@
-      message: "You need to be apart of this organization to use this feature",
+      message: "You need to be a part of this organization to use this feature",

Also applies to: 44-49

🧹 Nitpick comments (35)
packages/trpc/server/routers/viewer/me/checkForInvalidAppCredentials.ts (2)

27-31: Filter out potential null teamIds to avoid IN (NULL) and wasted OR branch.
If any memberships have teamId = null, the current in: [...] may be noisy. Filter before use.

Apply:

- 
+  const teamIds = userTeamIds.map((m) => m.teamId).filter((id): id is string => Boolean(id));
   const apps = await prisma.credential.findMany({
     where: {
-      OR: [{ userId }, { teamId: { in: userTeamIds.map((membership) => membership.teamId) } }],
+      OR: [{ userId }, { teamId: { in: teamIds } }],
       invalid: true,
     },
     select: {
       appId: true,
     },
   });

38-46: Parallelize app metadata fetches and de-duplicate appIds.
Avoid N serial awaits and duplicate banners if multiple invalid creds exist for the same app.

-  const appNamesAndSlugs: InvalidAppCredentialBannerProps[] = [];
-  for (const app of apps) {
-    if (app.appId) {
-      const appId = app.appId;
-      const appMeta = await getAppFromSlug(appId);
-      const name = appMeta ? appMeta.name : appId;
-      appNamesAndSlugs.push({ slug: appId, name });
-    }
-  }
+  const uniqueAppIds = Array.from(
+    new Set(apps.map((a) => a.appId).filter((id): id is string => Boolean(id)))
+  );
+  const appNamesAndSlugs: InvalidAppCredentialBannerProps[] = await Promise.all(
+    uniqueAppIds.map(async (appId) => {
+      const appMeta = await getAppFromSlug(appId);
+      return { slug: appId, name: appMeta?.name ?? appId };
+    })
+  );
packages/app-store/routing-forms/trpc/utils.ts (3)

166-184: Minor: compute scheduledAt once per batch

scheduledAt is identical for all items; compute once to avoid redundant Day.js work in the loop.

-      const promisesFormSubmittedNoEvent = webhooksFormSubmittedNoEvent.map((webhook) => {
-        const scheduledAt = dayjs().add(15, "minute").toDate();
-
-        return tasker.create(
+      const scheduledAt = dayjs().add(15, "minute").toDate();
+      const promisesFormSubmittedNoEvent = webhooksFormSubmittedNoEvent.map((webhook) =>
+        tasker.create(
           "triggerFormSubmittedNoEventWebhook",
           {
             responseId,
             form: {
               id: form.id,
               name: form.name,
               teamId: form.teamId ?? null,
             },
             responses: fieldResponsesByIdentifier,
             redirect: chosenAction,
             webhook,
           },
           { scheduledAt }
-        );
-      });
+        )
+      );

142-142: Consistency: use enum in payload too

Use WebhookTriggerEvents.FORM_SUBMITTED instead of the string literal to keep event values centralized. Covered in the diff above.


233-237: Nit: boolean naming vs. value type

isTeamForm holds number | null, not a boolean. Either coerce to boolean or rename.

-  const isTeamForm = form.teamId;
+  const isTeamForm = form.teamId != null;
packages/app-store/routing-forms/trpc/onFormSubmission.test.ts (1)

67-81: Add a test to ensure webhooks are awaited

Given the async fix in utils.ts, add a test that fails if webhook promises aren’t returned/awaited.

   describe("Webhooks", () => {
+    it("awaits FORM_SUBMITTED webhook promises", async () => {
+      const deferred: { resolve: () => void } = { resolve: () => {} };
+      vi.mocked(getWebhooks).mockResolvedValueOnce([{ id: "wh-1", secret: "secret" } as any]);
+      vi.mocked(sendGenericWebhookPayload).mockImplementation(
+        () =>
+          new Promise((res) => {
+            deferred.resolve = res as () => void;
+          })
+      );
+
+      const p = _onFormSubmission(mockForm as any, mockResponse, responseId);
+      // At this point, promise should still be pending
+      expect(vi.mocked(sendGenericWebhookPayload)).toHaveBeenCalledTimes(1);
+      // Resolve the deferred webhook send
+      deferred.resolve();
+      await expect(p).resolves.toBeUndefined();
+    });
apps/web/server/lib/[user]/[type]/getServerSideProps.ts (1)

153-154: Fix typos in comment.
Minor readability nit.

-// as well as to check if the event exist, so we c an show a 404 otherwise.
+// as well as to check if the event exists, so we can show a 404 otherwise.
apps/web/playwright/organization/organization-invitation.e2e.ts (3)

548-549: Replace arbitrary timeout with a deterministic wait.
Hard waits are flaky; prefer networkidle or UI readiness.

-      await page.waitForLoadState("domcontentloaded");
-      await page.waitForTimeout(500); // Add a small delay to ensure UI is fully loaded
+      await page.waitForLoadState("networkidle");

608-609: Ditto: avoid fixed sleep in team member check.

-  await page.waitForLoadState("domcontentloaded");
-  await page.waitForTimeout(1000); // Add a small delay to ensure UI is fully loaded
+  await page.waitForLoadState("networkidle");

500-503: Close browser context to free resources.
Prevents leakage across tests.

   await inviteLinkPage.locator("button[type=submit]").click();
   await inviteLinkPage.waitForURL("/getting-started");
+  await context.close();
   return { email };
apps/web/modules/settings/admin/components/UsersTable.tsx (2)

61-71: Localize action labels and alt text with t().

Per frontend guidelines, avoid hardcoded strings; use t() for actions and alt text.

       const actions = [
         {
           id: "unlock-sms",
-          label: smsLockState === SMSLockState.LOCKED ? "Unlock SMS sending" : "Lock SMS sending",
+          label:
+            smsLockState === SMSLockState.LOCKED
+              ? t("unlock_sms_sending")
+              : t("lock_sms_sending"),
           onClick: () =>
             setSMSLockState({
               userId: user ? user.id : undefined,
               teamId: team ? team.id : undefined,
               lock: smsLockState !== SMSLockState.LOCKED,
             }),
           icon: "lock" as IconName,
         },
       ];
       if (smsLockState === SMSLockState.REVIEW_NEEDED) {
         actions.push({
           id: "reviewed",
-          label: "Mark as Reviewed",
+          label: t("mark_as_reviewed"),
           onClick: () =>
             setSMSLockState({
               userId: user ? user.id : undefined,
               teamId: team ? team.id : undefined,
               lock: false,
             }),
           icon: "pencil" as IconName,
         });
       }
@@
-                    alt={`Avatar of ${user.username || "Nameless"}`}
+                    alt={t("avatar_of_name", { name: user.username || t("nameless") })}
@@
-                    alt={`Avatar of ${team.name}`}
+                    alt={t("avatar_of_name", { name: team.name })}

Also applies to: 73-85, 109-109, 133-133


153-153: Prefer named exports over default exports.

Improves tree-shaking and refactors.

-export default UsersTable;
+export { UsersTable };
apps/web/playwright/webhook.e2e.ts (1)

371-371: Remove redundant non-null assertion after await.

The ! here is a no-op on Promise and can mislead readers.

-    const newBooking = await prisma.booking.findFirst({ where: { fromReschedule: booking?.uid } })!;
+    const newBooking = await prisma.booking.findFirst({ where: { fromReschedule: booking?.uid } });
packages/trpc/server/routers/viewer/admin/setSMSLockState.handler.ts (1)

16-16: Prefer named exports over default exports (tree-shaking, refactors).

Convert to a named export.

-const setSMSLockState = async ({ input }: GetOptions) => {
+export const setSMSLockState = async ({ input }: GetOptions) => {
   ...
-};
-
-export default setSMSLockState;
+};

Also applies to: 88-88

apps/web/playwright/dynamic-booking-pages.e2e.ts (1)

85-86: Remove unnecessary await on Locator creation.

page.getByTestId(...) returns a Locator synchronously; awaiting it is redundant.

-  let listItemLocator = await page.getByTestId(listItemByDurationTestId(duration));
+  let listItemLocator = page.getByTestId(listItemByDurationTestId(duration));
...
-  listItemLocator = await page.getByTestId(listItemByDurationTestId(duration));
+  listItemLocator = page.getByTestId(listItemByDurationTestId(duration));
...
-  listItemLocator = await page.getByTestId(listItemByDurationTestId(15));
+  listItemLocator = page.getByTestId(listItemByDurationTestId(15));

Also applies to: 92-93, 98-99

packages/lib/server/repository/membership.ts (2)

479-491: Use enum values instead of string literals in role filter.

Prevents drift and benefits from type-safety.

-        role: {
-          in: ["ADMIN", "OWNER"],
-        },
+        role: {
+          in: [MembershipRole.ADMIN, MembershipRole.OWNER],
+        },

166-221: Broaden migration from include to select in this repository.

Multiple queries still rely on include. For consistency with our guideline and to reduce over-fetching, consider phasing them to select (pattern shown above). I can help generate targeted diffs per query if desired.

Also applies to: 292-303, 343-350, 429-445

apps/web/playwright/reschedule.e2e.ts (1)

6-7: Merge duplicate imports from the same module

Minor tidy-up: combine adjacent imports from @calcom/prisma/enums.

-import { MembershipRole } from "@calcom/prisma/enums";
-import { BookingStatus } from "@calcom/prisma/enums";
+import { BookingStatus, MembershipRole } from "@calcom/prisma/enums";
packages/features/ee/teams/components/RoundRobinSettings.tsx (1)

43-47: Fix typo in comment

Small spelling/grammar tweak in the inline comment.

-        // Rounb robin reset interval / basis governs host selection logic on the booking page.
+        // Round robin reset interval/basis govern host selection logic on the booking page.
apps/web/playwright/bookings-list.e2e.ts (1)

431-440: Prefer select over include in Prisma queries (tests too)

Follow repo guideline to select only needed fields; avoids unnecessary payload and keeps tests fast.

-    const host = await prisma.membership.findFirstOrThrow({
+    const host = await prisma.membership.findFirstOrThrow({
       where: {
         teamId: team.id,
         userId: {
           not: owner.id,
         },
       },
-      include: {
-        user: true,
-      },
+      select: {
+        user: {
+          select: {
+            id: true,
+            username: true,
+            name: true,
+          },
+        },
+      },
     });
apps/web/lib/team/[slug]/getServerSideProps.tsx (1)

118-138: Optional: prefer select over include for Prisma fetches

Not critical here (TSX file), but to stay consistent with our “select-only” guidance, consider switching to select and enumerating needed fields.

Example shape:

-    const unpublishedTeam = await prisma.team.findFirst({
-      where: { /* ... */ },
-      include: {
-        parent: {
-          select: { id: true, slug: true, name: true, isPrivate: true, isOrganization: true, metadata: true, logoUrl: true },
-        },
-      },
-    });
+    const unpublishedTeam = await prisma.team.findFirst({
+      where: { /* ... */ },
+      select: {
+        /* list fields from team you actually use ... */
+        parent: {
+          select: { id: true, slug: true, name: true, isPrivate: true, isOrganization: true, metadata: true, logoUrl: true },
+        },
+      },
+    });
packages/trpc/server/routers/viewer/attributes/delete.handler.ts (1)

21-26: Fix typo in user-facing error messages (“apart” → “a part”)

Small copy fix in API errors.

-      message: "You need to be apart of an organization to use this feature",
+      message: "You need to be a part of an organization to use this feature",
-      message: "You need to be apart of this organization to use this feature",
+      message: "You need to be a part of this organization to use this feature",

Also applies to: 38-43

packages/app-store/routing-forms/pages/route-builder/[...appPages].tsx (2)

111-114: Return a boolean from hasRules

Current code returns a number or undefined. Make it explicit.

-const hasRules = (route: EditFormRoute) => {
-  if (isRouter(route)) return false;
-  route.queryValue.children1 && Object.keys(route.queryValue.children1).length;
-};
+const hasRules = (route: EditFormRoute) => {
+  if (isRouter(route)) return false;
+  return !!(route.queryValue.children1 && Object.keys(route.queryValue.children1).length);
+};

533-533: Localize user-facing strings (use t())

Per guidelines for TSX, wrap visible strings with t(). Below are examples; adjust keys to your i18n catalog.

-        <span className="text-emphasis ml-2 text-sm font-medium">Conditions</span>
+        <span className="text-emphasis ml-2 text-sm font-medium">{t("conditions")}</span>
-            <span className="text-emphasis ml-2 text-sm font-medium">
-              And connect with specific team members
-            </span>
+            <span className="text-emphasis ml-2 text-sm font-medium">
+              {t("and_connect_with_specific_team_members")}
+            </span>
-          <span className="text-emphasis ml-2 text-sm font-medium">Fallback</span>
+          <span className="text-emphasis ml-2 text-sm font-medium">{t("fallback")}</span>
-      label={route.name ?? (route.isFallback ? "Otherwise" : `Route ${index + 1}`)}
+      label={route.name ?? (route.isFallback ? t("otherwise") : t("route_n", { n: index + 1 }))}
-            <p className="text-subtle mt-2 text-sm">
-              Fields available in <span className="font-bold">{route.name}</span> will be added to this form.
-            </p>
+            <p className="text-subtle mt-2 text-sm">
+              {t("fields_available_will_be_added_to_form", { routeName: route.name })}
+            </p>
-                          if (action.type === "customPageMessage") {
-                        action.value = "We are not ready for you yet :(";
+                          if (action.type === "customPageMessage") {
+                        action.value = t("not_ready_yet_message");
-                      placeholder="https://example.com"
+                      placeholder={t("example_url_placeholder")}
-                            placeholder="event-url"
+                            placeholder={t("event_url_placeholder")}
-          <EmptyState
-            icon="menu"
-            header="Create your first route"
-            text="Routes determine where your form responses will be sent based on the answers provided."
+          <EmptyState
+            icon="menu"
+            header={t("create_your_first_route")}
+            text={t("routes_determine_destination_helptext")}
             buttonText={t("add_a_new_route")}

Also applies to: 583-585, 611-612, 639-641, 498-500, 726-756, 860-892, 761-776, 897-925, 1326-1343

packages/trpc/server/routers/viewer/attributes/toggleActive.handler.ts (2)

57-61: Consider using “FORBIDDEN” for authorization failures.

User is authenticated but lacks permission; “FORBIDDEN” may be semantically clearer than “UNAUTHORIZED”. Verify client expectations before changing.

-    throw new TRPCError({
-      code: "UNAUTHORIZED",
+    throw new TRPCError({
+      code: "FORBIDDEN",
       message: "You don't have permission to modify attributes",
     });

100-100: Prefer named exports over default exports.

Improves tree-shaking and refactoring.

-export default toggleActiveHandler;
+export { toggleActiveHandler };
packages/trpc/server/routers/viewer/attributes/edit.handler.ts (3)

59-63: Consider “FORBIDDEN” for permission denials.

Semantically clearer if the user is authenticated but not permitted. Confirm consumer handling first.

-    throw new TRPCError({
-      code: "UNAUTHORIZED",
+    throw new TRPCError({
+      code: "FORBIDDEN",
       message: "You don't have permission to edit attributes",
     });

182-184: Consider “FORBIDDEN” here as well for ownership checks.

This is an authorization failure rather than authentication.

-    throw new TRPCError({
-      code: "UNAUTHORIZED",
+    throw new TRPCError({
+      code: "FORBIDDEN",
       message: "You can't edit options that are not owned by the attribute",
     });

188-189: Prefer named exports over default exports.

-export default editAttributesHandler;
+export { editAttributesHandler };
apps/web/playwright/booking-pages.e2e.ts (2)

719-735: Use Prisma select instead of include in tests, too.

Even in tests, prefer select per repo guidelines and to minimize payload.

-    const eventWithPrivateLink = await prisma.eventType.update({
+    const eventWithPrivateLink = await prisma.eventType.update({
       where: {
         id: eventType.id,
       },
       data: {
         hashedLink: {
           create: [
             {
               link: generateHashedLink(eventType.id),
             },
           ],
         },
       },
-      include: {
-        hashedLink: true,
-      },
+      select: {
+        slug: true,
+        hashedLink: {
+          select: { link: true }
+        }
+      },
     });

569-572: Remove duplicate assertion.

The success-page assertion is executed twice consecutively; keep one.

-    await expect(page.locator("[data-testid=success-page]")).toBeVisible();
-
     await expect(page.locator("[data-testid=success-page]")).toBeVisible();
apps/web/lib/pages/auth/verify-email.ts (1)

175-175: Avoid possible double slash in redirect URL

Remove the extra “/” before the path.

-return res.redirect(`${WEBAPP_URL}/${hasCompletedOnboarding ? "/event-types" : "/getting-started"}`);
+return res.redirect(`${WEBAPP_URL}${hasCompletedOnboarding ? "/event-types" : "/getting-started"}`);
packages/trpc/server/routers/viewer/attributes/create.handler.ts (3)

22-23: Avoid stringly-typed attribute types

Prefer enum constants over string literals to prevent drift.

-const typesWithOptions = ["SINGLE_SELECT", "MULTI_SELECT"];
+import { AttributeType } from "@calcom/prisma/enums";
+const typesWithOptions: ReadonlyArray<AttributeType> = [
+  AttributeType.SINGLE_SELECT,
+  AttributeType.MULTI_SELECT,
+];

87-91: Return a typed tRPC error on unique constraint violations

Use TRPCError({ code: "CONFLICT" }) instead of a generic Error.

-    if (error instanceof Prisma.PrismaClientKnownRequestError && error.code === "P2002") {
-      throw new Error("A record with that name already exists. Please choose another one.");
-    } else {
+    if (error instanceof Prisma.PrismaClientKnownRequestError && error.code === "P2002") {
+      throw new TRPCError({ code: "CONFLICT", message: "A record with that name already exists. Please choose another one." });
+    } else {
       throw error; // Re-throw the error if it's not a unique constraint violation
     }

110-110: Prefer named export over default export

Improves tree-shaking and refactorability.

-export default createAttributesHandler;
+export { createAttributesHandler };
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 6363b3e and 919ba60.

📒 Files selected for processing (43)
  • apps/api/v1/pages/api/event-types/_post.ts (1 hunks)
  • apps/web/app/(use-page-wrapper)/auth/error/page.tsx (1 hunks)
  • apps/web/app/api/auth/two-factor/totp/disable/route.ts (1 hunks)
  • apps/web/components/apps/installation/EventTypeConferencingAppSettings.tsx (1 hunks)
  • apps/web/lib/handleOrgRedirect.test.ts (1 hunks)
  • apps/web/lib/pages/auth/verify-email.test.ts (1 hunks)
  • apps/web/lib/pages/auth/verify-email.ts (1 hunks)
  • apps/web/lib/reschedule/[uid]/getServerSideProps.ts (1 hunks)
  • apps/web/lib/team/[slug]/[type]/getServerSideProps.tsx (1 hunks)
  • apps/web/lib/team/[slug]/getServerSideProps.tsx (1 hunks)
  • apps/web/modules/settings/admin/components/UsersTable.tsx (1 hunks)
  • apps/web/playwright/booking-limits.e2e.ts (1 hunks)
  • apps/web/playwright/booking-pages.e2e.ts (1 hunks)
  • apps/web/playwright/bookings-list.e2e.ts (1 hunks)
  • apps/web/playwright/dynamic-booking-pages.e2e.ts (1 hunks)
  • apps/web/playwright/embed-code-generator.e2e.ts (1 hunks)
  • apps/web/playwright/lib/orgMigration.ts (1 hunks)
  • apps/web/playwright/organization/organization-invitation.e2e.ts (1 hunks)
  • apps/web/playwright/reschedule.e2e.ts (1 hunks)
  • apps/web/playwright/webhook.e2e.ts (1 hunks)
  • apps/web/server/lib/[user]/[type]/getServerSideProps.ts (1 hunks)
  • apps/web/server/lib/[user]/getServerSideProps.ts (1 hunks)
  • apps/web/test/utils/bookingScenario/getSampleUserInSession.ts (1 hunks)
  • packages/app-store/routing-forms/pages/route-builder/[...appPages].tsx (1 hunks)
  • packages/app-store/routing-forms/trpc/onFormSubmission.test.ts (1 hunks)
  • packages/app-store/routing-forms/trpc/utils.ts (1 hunks)
  • packages/features/bookings/lib/handleNewRecurringBooking.ts (1 hunks)
  • packages/features/ee/billing/api/webhook/_customer.subscription.updated.ts (1 hunks)
  • packages/features/ee/organizations/pages/organization.tsx (1 hunks)
  • packages/features/ee/teams/components/RoundRobinSettings.tsx (1 hunks)
  • packages/lib/bookings/filterHostsByLeadThreshold.test.ts (1 hunks)
  • packages/lib/server/repository/membership.ts (1 hunks)
  • packages/lib/server/repository/workflow.ts (1 hunks)
  • packages/lib/service/attribute/utils.ts (1 hunks)
  • packages/trpc/server/routers/viewer/admin/getSMSLockStateTeamsUsers.handler.ts (1 hunks)
  • packages/trpc/server/routers/viewer/admin/setSMSLockState.handler.ts (1 hunks)
  • packages/trpc/server/routers/viewer/attributes/create.handler.ts (1 hunks)
  • packages/trpc/server/routers/viewer/attributes/delete.handler.ts (1 hunks)
  • packages/trpc/server/routers/viewer/attributes/edit.handler.ts (1 hunks)
  • packages/trpc/server/routers/viewer/attributes/toggleActive.handler.ts (1 hunks)
  • packages/trpc/server/routers/viewer/eventTypes/update.handler.ts (1 hunks)
  • packages/trpc/server/routers/viewer/me/checkForInvalidAppCredentials.ts (1 hunks)
  • packages/trpc/server/routers/viewer/slots/util.ts (1 hunks)
✅ Files skipped from review due to trivial changes (6)
  • packages/lib/bookings/filterHostsByLeadThreshold.test.ts
  • packages/trpc/server/routers/viewer/eventTypes/update.handler.ts
  • packages/features/bookings/lib/handleNewRecurringBooking.ts
  • apps/api/v1/pages/api/event-types/_post.ts
  • apps/web/lib/pages/auth/verify-email.test.ts
  • apps/web/playwright/lib/orgMigration.ts
🧰 Additional context used
📓 Path-based instructions (4)
**/*.ts

📄 CodeRabbit inference engine (.cursor/rules/review.mdc)

**/*.ts: For Prisma queries, only select data you need; never use include, always use select
Ensure the credential.key field is never returned from tRPC endpoints or APIs

Files:

  • packages/trpc/server/routers/viewer/attributes/edit.handler.ts
  • packages/trpc/server/routers/viewer/attributes/toggleActive.handler.ts
  • apps/web/playwright/embed-code-generator.e2e.ts
  • apps/web/playwright/webhook.e2e.ts
  • packages/trpc/server/routers/viewer/admin/setSMSLockState.handler.ts
  • packages/lib/service/attribute/utils.ts
  • packages/app-store/routing-forms/trpc/utils.ts
  • packages/trpc/server/routers/viewer/admin/getSMSLockStateTeamsUsers.handler.ts
  • apps/web/server/lib/[user]/getServerSideProps.ts
  • apps/web/app/api/auth/two-factor/totp/disable/route.ts
  • packages/trpc/server/routers/viewer/me/checkForInvalidAppCredentials.ts
  • packages/lib/server/repository/workflow.ts
  • packages/trpc/server/routers/viewer/slots/util.ts
  • packages/lib/server/repository/membership.ts
  • apps/web/playwright/booking-limits.e2e.ts
  • packages/features/ee/billing/api/webhook/_customer.subscription.updated.ts
  • packages/app-store/routing-forms/trpc/onFormSubmission.test.ts
  • packages/trpc/server/routers/viewer/attributes/create.handler.ts
  • apps/web/playwright/organization/organization-invitation.e2e.ts
  • apps/web/test/utils/bookingScenario/getSampleUserInSession.ts
  • apps/web/lib/handleOrgRedirect.test.ts
  • apps/web/server/lib/[user]/[type]/getServerSideProps.ts
  • apps/web/playwright/dynamic-booking-pages.e2e.ts
  • apps/web/playwright/reschedule.e2e.ts
  • packages/trpc/server/routers/viewer/attributes/delete.handler.ts
  • apps/web/lib/pages/auth/verify-email.ts
  • apps/web/playwright/bookings-list.e2e.ts
  • apps/web/playwright/booking-pages.e2e.ts
  • apps/web/lib/reschedule/[uid]/getServerSideProps.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/review.mdc)

Flag excessive Day.js use in performance-critical code; prefer native Date or Day.js .utc() in hot paths like loops

Files:

  • packages/trpc/server/routers/viewer/attributes/edit.handler.ts
  • packages/trpc/server/routers/viewer/attributes/toggleActive.handler.ts
  • apps/web/playwright/embed-code-generator.e2e.ts
  • apps/web/playwright/webhook.e2e.ts
  • apps/web/modules/settings/admin/components/UsersTable.tsx
  • apps/web/components/apps/installation/EventTypeConferencingAppSettings.tsx
  • packages/trpc/server/routers/viewer/admin/setSMSLockState.handler.ts
  • packages/lib/service/attribute/utils.ts
  • apps/web/lib/team/[slug]/getServerSideProps.tsx
  • packages/features/ee/organizations/pages/organization.tsx
  • packages/app-store/routing-forms/trpc/utils.ts
  • packages/trpc/server/routers/viewer/admin/getSMSLockStateTeamsUsers.handler.ts
  • apps/web/server/lib/[user]/getServerSideProps.ts
  • apps/web/app/api/auth/two-factor/totp/disable/route.ts
  • packages/trpc/server/routers/viewer/me/checkForInvalidAppCredentials.ts
  • packages/lib/server/repository/workflow.ts
  • packages/trpc/server/routers/viewer/slots/util.ts
  • apps/web/app/(use-page-wrapper)/auth/error/page.tsx
  • packages/lib/server/repository/membership.ts
  • apps/web/playwright/booking-limits.e2e.ts
  • packages/features/ee/teams/components/RoundRobinSettings.tsx
  • packages/features/ee/billing/api/webhook/_customer.subscription.updated.ts
  • packages/app-store/routing-forms/trpc/onFormSubmission.test.ts
  • packages/trpc/server/routers/viewer/attributes/create.handler.ts
  • apps/web/playwright/organization/organization-invitation.e2e.ts
  • apps/web/test/utils/bookingScenario/getSampleUserInSession.ts
  • apps/web/lib/handleOrgRedirect.test.ts
  • packages/app-store/routing-forms/pages/route-builder/[...appPages].tsx
  • apps/web/server/lib/[user]/[type]/getServerSideProps.ts
  • apps/web/playwright/dynamic-booking-pages.e2e.ts
  • apps/web/playwright/reschedule.e2e.ts
  • apps/web/lib/team/[slug]/[type]/getServerSideProps.tsx
  • packages/trpc/server/routers/viewer/attributes/delete.handler.ts
  • apps/web/lib/pages/auth/verify-email.ts
  • apps/web/playwright/bookings-list.e2e.ts
  • apps/web/playwright/booking-pages.e2e.ts
  • apps/web/lib/reschedule/[uid]/getServerSideProps.ts
**/*.{ts,tsx,js,jsx}

⚙️ CodeRabbit configuration file

Flag default exports and encourage named exports. Named exports provide better tree-shaking, easier refactoring, and clearer imports. Exempt main components like pages, layouts, and components that serve as the primary export of a module.

Files:

  • packages/trpc/server/routers/viewer/attributes/edit.handler.ts
  • packages/trpc/server/routers/viewer/attributes/toggleActive.handler.ts
  • apps/web/playwright/embed-code-generator.e2e.ts
  • apps/web/playwright/webhook.e2e.ts
  • apps/web/modules/settings/admin/components/UsersTable.tsx
  • apps/web/components/apps/installation/EventTypeConferencingAppSettings.tsx
  • packages/trpc/server/routers/viewer/admin/setSMSLockState.handler.ts
  • packages/lib/service/attribute/utils.ts
  • apps/web/lib/team/[slug]/getServerSideProps.tsx
  • packages/features/ee/organizations/pages/organization.tsx
  • packages/app-store/routing-forms/trpc/utils.ts
  • packages/trpc/server/routers/viewer/admin/getSMSLockStateTeamsUsers.handler.ts
  • apps/web/server/lib/[user]/getServerSideProps.ts
  • apps/web/app/api/auth/two-factor/totp/disable/route.ts
  • packages/trpc/server/routers/viewer/me/checkForInvalidAppCredentials.ts
  • packages/lib/server/repository/workflow.ts
  • packages/trpc/server/routers/viewer/slots/util.ts
  • apps/web/app/(use-page-wrapper)/auth/error/page.tsx
  • packages/lib/server/repository/membership.ts
  • apps/web/playwright/booking-limits.e2e.ts
  • packages/features/ee/teams/components/RoundRobinSettings.tsx
  • packages/features/ee/billing/api/webhook/_customer.subscription.updated.ts
  • packages/app-store/routing-forms/trpc/onFormSubmission.test.ts
  • packages/trpc/server/routers/viewer/attributes/create.handler.ts
  • apps/web/playwright/organization/organization-invitation.e2e.ts
  • apps/web/test/utils/bookingScenario/getSampleUserInSession.ts
  • apps/web/lib/handleOrgRedirect.test.ts
  • packages/app-store/routing-forms/pages/route-builder/[...appPages].tsx
  • apps/web/server/lib/[user]/[type]/getServerSideProps.ts
  • apps/web/playwright/dynamic-booking-pages.e2e.ts
  • apps/web/playwright/reschedule.e2e.ts
  • apps/web/lib/team/[slug]/[type]/getServerSideProps.tsx
  • packages/trpc/server/routers/viewer/attributes/delete.handler.ts
  • apps/web/lib/pages/auth/verify-email.ts
  • apps/web/playwright/bookings-list.e2e.ts
  • apps/web/playwright/booking-pages.e2e.ts
  • apps/web/lib/reschedule/[uid]/getServerSideProps.ts
**/*.tsx

📄 CodeRabbit inference engine (.cursor/rules/review.mdc)

Always use t() for text localization in frontend code; direct text embedding should trigger a warning

Files:

  • apps/web/modules/settings/admin/components/UsersTable.tsx
  • apps/web/components/apps/installation/EventTypeConferencingAppSettings.tsx
  • apps/web/lib/team/[slug]/getServerSideProps.tsx
  • packages/features/ee/organizations/pages/organization.tsx
  • apps/web/app/(use-page-wrapper)/auth/error/page.tsx
  • packages/features/ee/teams/components/RoundRobinSettings.tsx
  • packages/app-store/routing-forms/pages/route-builder/[...appPages].tsx
  • apps/web/lib/team/[slug]/[type]/getServerSideProps.tsx
🧠 Learnings (8)
📚 Learning: 2025-08-17T22:00:16.329Z
Learnt from: Udit-takkar
PR: calcom/cal.com#22995
File: packages/trpc/server/routers/viewer/aiVoiceAgent/_router.ts:117-126
Timestamp: 2025-08-17T22:00:16.329Z
Learning: In calcom/cal.com PR #22995, packages/trpc/server/routers/viewer/aiVoiceAgent/_router.ts, the enabled input parameter in the update endpoint is intentionally not forwarded to aiService.updateAgentConfiguration() as the enabled/disabled agent functionality is not required at the moment (per maintainer Udit-takkar). Future reviews should not flag this as missing functionality unless requirements change.

Applied to files:

  • packages/trpc/server/routers/viewer/attributes/toggleActive.handler.ts
📚 Learning: 2025-08-27T13:32:46.887Z
Learnt from: supalarry
PR: calcom/cal.com#23364
File: apps/api/v2/src/ee/event-types/event-types_2024_06_14/transformers/internal-to-api/internal-to-api.spec.ts:295-296
Timestamp: 2025-08-27T13:32:46.887Z
Learning: In calcom/cal.com, when transforming booking fields from internal to API format, tests in organizations-event-types.e2e-spec.ts already expect name field label and placeholder to be empty strings ("") rather than undefined. PR changes that set these to explicit empty strings are typically fixing implementation to match existing test expectations rather than breaking changes.

Applied to files:

  • apps/web/playwright/webhook.e2e.ts
  • apps/web/playwright/booking-limits.e2e.ts
  • packages/app-store/routing-forms/trpc/onFormSubmission.test.ts
  • apps/web/lib/handleOrgRedirect.test.ts
  • apps/web/playwright/dynamic-booking-pages.e2e.ts
  • apps/web/playwright/bookings-list.e2e.ts
  • apps/web/playwright/booking-pages.e2e.ts
📚 Learning: 2025-08-21T13:44:06.805Z
Learnt from: supalarry
PR: calcom/cal.com#23217
File: apps/api/v2/src/ee/event-types/event-types_2024_06_14/services/output-event-types.service.ts:93-94
Timestamp: 2025-08-21T13:44:06.805Z
Learning: In apps/api/v2/src/ee/event-types/event-types_2024_06_14/event-types.repository.ts, repository functions that use explicit Prisma select clauses (like getEventTypeWithSeats) are used for specific purposes and don't need to include all EventType fields like bookingRequiresAuthentication. These methods don't feed into the general OutputEventTypesService_2024_06_14 flow.

Applied to files:

  • packages/trpc/server/routers/viewer/slots/util.ts
  • apps/web/playwright/booking-pages.e2e.ts
  • apps/web/lib/reschedule/[uid]/getServerSideProps.ts
📚 Learning: 2025-09-03T11:54:05.409Z
Learnt from: supalarry
PR: calcom/cal.com#23514
File: apps/api/v2/src/ee/bookings/2024-08-13/services/bookings.service.ts:579-582
Timestamp: 2025-09-03T11:54:05.409Z
Learning: In calcom/cal.com bookings repository methods, when Prisma select uses `eventType: true`, all eventType fields including seatsShowAttendees are automatically included in the selection. Explicit field selection is not required when using `true` for nested relations.

Applied to files:

  • packages/lib/server/repository/membership.ts
  • apps/web/lib/reschedule/[uid]/getServerSideProps.ts
📚 Learning: 2025-08-21T16:34:10.839Z
Learnt from: Udit-takkar
PR: calcom/cal.com#22995
File: packages/trpc/server/routers/viewer/phoneNumber/delete.handler.ts:13-24
Timestamp: 2025-08-21T16:34:10.839Z
Learning: In calcom/cal.com PR #22995, the deletePhoneNumber function in packages/trpc/server/routers/viewer/phoneNumber/delete.handler.ts is only used for imported phone numbers that don't have active Stripe subscriptions. Purchased phone numbers with subscriptions use a separate cancellation flow first (per maintainer Udit-takkar).

Applied to files:

  • packages/features/ee/billing/api/webhook/_customer.subscription.updated.ts
📚 Learning: 2025-08-20T17:34:35.004Z
Learnt from: mdm317
PR: calcom/cal.com#23221
File: packages/features/schedules/components/NewScheduleButton.tsx:1-1
Timestamp: 2025-08-20T17:34:35.004Z
Learning: In the Cal.com codebase, server actions like `revalidateAvailabilityList()` from `app/(use-page-wrapper)/(main-nav)/availability/actions` are imported and called directly in client components within mutation `onSuccess` callbacks. This pattern is consistently used across availability-related components (both in availability-view.tsx for updates and NewScheduleButton.tsx for creates) to ensure the availability list cache is fresh after mutations.

Applied to files:

  • apps/web/lib/reschedule/[uid]/getServerSideProps.ts
📚 Learning: 2025-09-03T11:54:05.409Z
Learnt from: supalarry
PR: calcom/cal.com#23514
File: apps/api/v2/src/ee/bookings/2024-08-13/services/bookings.service.ts:579-582
Timestamp: 2025-09-03T11:54:05.409Z
Learning: In calcom/cal.com bookings repository methods, when Prisma include uses `eventType: true`, all eventType fields including seatsShowAttendees are automatically included in the selection. Explicit field selection is not required when using `true` for nested relations.

Applied to files:

  • apps/web/lib/reschedule/[uid]/getServerSideProps.ts
📚 Learning: 2025-08-19T09:47:49.478Z
Learnt from: eunjae-lee
PR: calcom/cal.com#23166
File: packages/prisma/migrations/20250818151914_routing_form_response_denormalized_backfill2/migration.sql:65-66
Timestamp: 2025-08-19T09:47:49.478Z
Learning: The Booking table has a unique constraint and index on the uid column (defined as `uid String unique` in schema.prisma), so JOINs on Booking.uid have optimal performance and don't require additional indexing.

Applied to files:

  • apps/web/lib/reschedule/[uid]/getServerSideProps.ts
⏰ Context from checks skipped due to timeout of 180000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (8)
  • GitHub Check: Production builds / Build Docs
  • GitHub Check: Production builds / Build Web App
  • GitHub Check: Production builds / Build API v2
  • GitHub Check: Production builds / Build Atoms
  • GitHub Check: Production builds / Build API v1
  • GitHub Check: Tests / Unit
  • GitHub Check: Linters / lint
  • GitHub Check: Type check / check-types

@keithwillcode keithwillcode enabled auto-merge (squash) September 4, 2025 11:16
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

Caution

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

⚠️ Outside diff range comments (3)
apps/api/v2/src/modules/workflows/workflows.repository.ts (3)

23-33: Replace include with select per Prisma query guidelines

Repository methods should avoid include and select only required fields. This reduces payloads and risk of leaking fields not needed downstream.

Would you like a follow-up PR to convert this to select with an explicit shape aligned to the API response?


42-45: Also switch this include to select

Same rationale as above: minimize fetched shape for steps and activeOn.


18-20: Add a valid unique selector or switch to deleteMany

The Prisma call in apps/api/v2/src/modules/workflows/workflows.repository.ts (lines 18–20) uses

delete({ where: { id: workflowId, teamId } })

but the Workflow model in your schema only has id as a unique key—there’s no @@unique([id, teamId]). This will fail at compile time.

• Add a compound unique on (id, teamId) in schema.prisma and update to:

where: { id_teamId: { id: workflowId, teamId } }

(adjusting the constraint name as needed).
• Or remove teamId from the delete selector (leaving where: { id: workflowId }) and enforce team ownership in code.
• Alternatively, use deleteMany({ where: { id: workflowId, teamId } }) if you intend to delete by both fields without a unique index.

🧹 Nitpick comments (3)
apps/api/v2/src/modules/workflows/workflows.repository.ts (3)

9-10: Prefer model types from @prisma/client (type-only) to avoid cross-package type drift

Enums from @calcom/prisma/enums are correct. For model types, using @prisma/client as a type-only import avoids accidental divergence between multiple Prisma client packages.

-import type { Workflow, WorkflowStep } from "@calcom/prisma/client";
+import type { Workflow, WorkflowStep } from "@prisma/client";

37-48: Add stable ordering for pagination determinism

skip/take without orderBy can yield non-deterministic pages across queries. Add a stable sort (e.g., by id).

   const workflows = await this.dbRead.prisma.workflow.findMany({
     where: {
       teamId: teamId,
     },
-    include: {
+    include: {
       steps: true,
       activeOn: { select: { eventTypeId: true } },
     },
+    orderBy: { id: "desc" },
     skip,
     take,
   });

72-76: Avoid double cast (unknown as PrismaClient); unify types or narrow required interface

The as unknown as PrismaClient cast is unsound. Prefer aligning the Prisma client type across packages or change updateWorkflow to accept a minimal interface (only the models it uses), avoiding cross-package nominal-type conflicts.

Happy to sketch the minimal PrismaLike interface and a small adapter if useful.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 919ba60 and 798477b.

📒 Files selected for processing (1)
  • apps/api/v2/src/modules/workflows/workflows.repository.ts (1 hunks)
🧰 Additional context used
📓 Path-based instructions (4)
**/*.{service,repository}.ts

📄 CodeRabbit inference engine (.cursor/rules/review.mdc)

Avoid dot-suffixes like .service.ts or .repository.ts for new files; reserve .test.ts, .spec.ts, .types.ts for their specific purposes

Files:

  • apps/api/v2/src/modules/workflows/workflows.repository.ts
**/*.ts

📄 CodeRabbit inference engine (.cursor/rules/review.mdc)

**/*.ts: For Prisma queries, only select data you need; never use include, always use select
Ensure the credential.key field is never returned from tRPC endpoints or APIs

Files:

  • apps/api/v2/src/modules/workflows/workflows.repository.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/review.mdc)

Flag excessive Day.js use in performance-critical code; prefer native Date or Day.js .utc() in hot paths like loops

Files:

  • apps/api/v2/src/modules/workflows/workflows.repository.ts
**/*.{ts,tsx,js,jsx}

⚙️ CodeRabbit configuration file

Flag default exports and encourage named exports. Named exports provide better tree-shaking, easier refactoring, and clearer imports. Exempt main components like pages, layouts, and components that serve as the primary export of a module.

Files:

  • apps/api/v2/src/modules/workflows/workflows.repository.ts
⏰ Context from checks skipped due to timeout of 180000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (7)
  • GitHub Check: Production builds / Build API v2
  • GitHub Check: Production builds / Build Atoms
  • GitHub Check: Tests / Unit
  • GitHub Check: Production builds / Build API v1
  • GitHub Check: Production builds / Build Web App
  • GitHub Check: Type check / check-types
  • GitHub Check: Linters / lint
🔇 Additional comments (1)
apps/api/v2/src/modules/workflows/workflows.repository.ts (1)

57-60: Enums migration LGTM

Using WorkflowTriggerEvents.BEFORE_EVENT and TimeUnit.HOUR from @calcom/prisma/enums matches the PR goal and avoids pulling the full Prisma client at runtime.

@github-actions
Copy link
Contributor

github-actions bot commented Sep 4, 2025

E2E results are ready!

@keithwillcode keithwillcode merged commit 7bf5d9c into main Sep 4, 2025
67 of 69 checks passed
@keithwillcode keithwillcode deleted the refactor/get-rid-of-imports-from-prisma-directly branch September 4, 2025 11:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

core area: core, team members only foundation platform Anything related to our platform plan ready-for-e2e 💻 refactor size/L

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants