Skip to content

feat: implement comprehensive booking audit system #22854

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 6 commits into
base: main
Choose a base branch
from

Conversation

Vansh5632
Copy link
Contributor

What does this PR do?

This PR implements a comprehensive BookingAudit system that automatically logs booking lifecycle events to provide audit trails and analytics for Cal.com bookings.

Key Features:

  • Adds a new BookingAudit database table to track all booking operations
  • Implements strict Zod schema validation for audit data integrity
  • Creates a BookingAuditService for centralized audit logging
  • Integrates audit logging into booking creation, rescheduling, and cancellation flows
  • Includes comprehensive unit tests and schema validation tests
  • Provides optional actor metadata tracking for compliance and analytics

Database Changes:

  • Adds BookingAudit model with fields: id, bookingId, action, actor, version, data, createdAt
  • Includes proper indexing and foreign key relationships

Integration Points:

  • Hooks into createBooking.ts for booking creation and reschedule events
  • Hooks into handleCancelBooking.ts for cancellation events
  • Non-blocking implementation ensures main booking flows are not affected by audit failures

Database Schema Addition:

model BookingAudit {
  id        Int      @id @default(autoincrement())
  bookingId Int
  action    String
  actor     String?  // Optional, for metadata
  version   Int?     // For forward compatibility
  data      Json
  createdAt DateTime @default(now())
}

- Add BookingAudit database model with proper indexing
- Create Zod validation schemas for all booking audit actions
- Implement BookingAuditService with logging methods for lifecycle events
- Integrate audit logging into booking creation and cancellation flows
- Add comprehensive unit tests with 100% coverage
- Include actor metadata tracking and version compatibility
- Ensure graceful error handling without breaking booking flows

Features:
- Tracks booking creation, cancellation, rescheduling, confirmation, rejection
- Validates audit data with strict Zod schemas per action type
- Captures actor information (user ID, email, name, role)
- Supports optional metadata and version for forward compatibility
- Provides audit log retrieval functionality

Tests: 9/9 passing, verified working in real booking flows
@Vansh5632 Vansh5632 requested review from a team as code owners August 1, 2025 06:03
Copy link

vercel bot commented Aug 1, 2025

@Vansh5632 is attempting to deploy a commit to the cal Team on Vercel.

A member of the Team first needs to authorize it.

Copy link
Contributor

coderabbitai bot commented Aug 1, 2025

Walkthrough

Adds a booking audit capability. Introduces BookingAuditService with action-specific loggers (created, rescheduled, cancelled, confirmed, rejected, payment events, attendee changes), retrieval helpers, and actor serialization. Adds Zod-based booking audit schemas and related tests. Integrates audit logging into booking creation/reschedule (createBooking.ts) and cancellation flows (handleCancelBooking.ts); creation code paths updated to pass evt and eventType. Adds Prisma model BookingAudit and migrations creating the table and an index. Provides unit tests for the service and schema validation. Audit logging is best-effort with errors caught and not affecting main flows.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment

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.
    • Explain this complex logic.
    • 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. Examples:
    • @coderabbitai explain this code block.
  • 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 src/utils.ts and explain its main purpose.
    • @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 comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai generate unit tests to generate unit tests for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai 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.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • 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 added the community Created by Linear-GitHub Sync label Aug 1, 2025
@graphite-app graphite-app bot requested a review from a team August 1, 2025 06:03
@github-actions github-actions bot added the ❗️ migrations contains migration files label Aug 1, 2025
Copy link

graphite-app bot commented Aug 1, 2025

Graphite Automations

"Add consumer team as reviewer" took an action on this PR • (08/01/25)

1 reviewer was added to this PR based on Keith Williams's automation.

"Add community label" took an action on this PR • (08/01/25)

1 label was added to this PR based on Keith Williams's automation.

@dosubot dosubot bot added bookings area: bookings, availability, timezones, double booking ✨ feature New feature or request labels Aug 1, 2025
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: 5

🧹 Nitpick comments (2)
packages/features/bookings/lib/audit/booking-audit-schemas.test.ts (1)

1-91: Enhance test coverage for more comprehensive validation.

The test structure is good, but consider expanding the test coverage:

   describe("CANCELLED action schema", () => {
     it("should validate valid booking cancellation data", () => {
       // ... existing test
     });
+
+    it("should reject invalid booking cancellation data", () => {
+      const invalidData = {
+        bookingId: -1, // Invalid
+        action: BookingAuditAction.CANCELLED,
+        data: {
+          eventTypeId: "invalid", // Invalid type
+          startTime: "invalid-date", // Invalid
+          endTime: "invalid-date", // Invalid
+          cancellationReason: "", // Invalid if required
+        },
+      };
+
+      const schema = getBookingAuditSchema(BookingAuditAction.CANCELLED);
+      const result = schema.safeParse(invalidData);
+
+      expect(result.success).toBe(false);
+    });
   });

   describe("RESCHEDULED action schema", () => {
     it("should validate valid booking reschedule data", () => {
       // ... existing test
     });
+
+    it("should reject invalid booking reschedule data", () => {
+      const invalidData = {
+        bookingId: -1, // Invalid
+        action: BookingAuditAction.RESCHEDULED,
+        data: {
+          eventTypeId: "invalid", // Invalid type
+          startTime: "invalid-date", // Invalid
+          endTime: "invalid-date", // Invalid
+          oldStartTime: "invalid-date", // Invalid
+          oldEndTime: "invalid-date", // Invalid
+          organizerChanged: "no", // Invalid type
+        },
+      };
+
+      const schema = getBookingAuditSchema(BookingAuditAction.RESCHEDULED);
+      const result = schema.safeParse(invalidData);
+
+      expect(result.success).toBe(false);
+    });
   });
+
+  describe("Edge cases", () => {
+    it("should handle unknown action gracefully", () => {
+      expect(() => getBookingAuditSchema("UNKNOWN_ACTION" as any)).toThrow();
+    });
+
+    it("should validate with minimal required fields", () => {
+      const minimalData = {
+        bookingId: 1,
+        action: BookingAuditAction.CREATED,
+        data: {
+          eventTypeId: 1,
+          eventTypeName: "Test",
+          organizerId: 123,
+          startTime: "2025-08-01T10:00:00.000Z",
+          endTime: "2025-08-01T11:00:00.000Z",
+        },
+      };
+
+      const schema = getBookingAuditSchema(BookingAuditAction.CREATED);
+      const result = schema.safeParse(minimalData);
+
+      expect(result.success).toBe(true);
+    });
+  });
packages/features/bookings/lib/handleCancelBooking.ts (1)

403-403: Consider making actor role determination more flexible.

Both audit logging calls hardcode the role as "organizer", but cancelledBy might represent different types of users (attendees, admins, etc.).

Consider determining the role based on the context or making it configurable:

-          actor: cancelledBy ? { userId: parseInt(cancelledBy), role: "organizer" } : undefined,
+          actor: cancelledBy && !isNaN(parseInt(cancelledBy)) ? { 
+            userId: parseInt(cancelledBy), 
+            role: userId === parseInt(cancelledBy) ? "organizer" : "attendee" 
+          } : undefined,

Also applies to: 455-455

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6e3de84 and 6f62d1c.

📒 Files selected for processing (8)
  • packages/features/bookings/lib/audit/booking-audit-schemas.test.ts (1 hunks)
  • packages/features/bookings/lib/audit/booking-audit-schemas.ts (1 hunks)
  • packages/features/bookings/lib/audit/booking-audit-service.test.ts (1 hunks)
  • packages/features/bookings/lib/audit/booking-audit-service.ts (1 hunks)
  • packages/features/bookings/lib/handleCancelBooking.ts (3 hunks)
  • packages/features/bookings/lib/handleNewBooking/createBooking.ts (4 hunks)
  • packages/prisma/migrations/20250801050105_add_booking_audit_table/migration.sql (1 hunks)
  • packages/prisma/schema.prisma (1 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
**/*.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/features/bookings/lib/audit/booking-audit-schemas.test.ts
  • packages/features/bookings/lib/audit/booking-audit-service.test.ts
  • packages/features/bookings/lib/handleCancelBooking.ts
  • packages/features/bookings/lib/handleNewBooking/createBooking.ts
  • packages/features/bookings/lib/audit/booking-audit-schemas.ts
  • packages/features/bookings/lib/audit/booking-audit-service.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/features/bookings/lib/audit/booking-audit-schemas.test.ts
  • packages/features/bookings/lib/audit/booking-audit-service.test.ts
  • packages/features/bookings/lib/handleCancelBooking.ts
  • packages/features/bookings/lib/handleNewBooking/createBooking.ts
  • packages/features/bookings/lib/audit/booking-audit-schemas.ts
  • packages/features/bookings/lib/audit/booking-audit-service.ts
🧠 Learnings (4)
📓 Common learnings
Learnt from: eunjae-lee
PR: calcom/cal.com#22702
File: packages/lib/server/service/insightsBooking.ts:120-124
Timestamp: 2025-07-24T08:39:06.185Z
Learning: In the InsightsBookingService (packages/lib/server/service/insightsBooking.ts), the constructor stores null for invalid options or filters but this is handled safely through null checks in buildFilterConditions() and buildAuthorizationConditions() methods. The service uses defensive programming to return safe fallback conditions (null or NOTHING_CONDITION) rather than throwing errors on invalid inputs.
📚 Learning: in the insightsbookingservice (packages/lib/server/service/insightsbooking.ts), the constructor stor...
Learnt from: eunjae-lee
PR: calcom/cal.com#22702
File: packages/lib/server/service/insightsBooking.ts:120-124
Timestamp: 2025-07-24T08:39:06.185Z
Learning: In the InsightsBookingService (packages/lib/server/service/insightsBooking.ts), the constructor stores null for invalid options or filters but this is handled safely through null checks in buildFilterConditions() and buildAuthorizationConditions() methods. The service uses defensive programming to return safe fallback conditions (null or NOTHING_CONDITION) rather than throwing errors on invalid inputs.

Applied to files:

  • packages/features/bookings/lib/audit/booking-audit-service.test.ts
  • packages/features/bookings/lib/audit/booking-audit-service.ts
📚 Learning: the office365calendar webhook handler in packages/app-store/office365calendar/api/webhook.ts is spec...
Learnt from: vijayraghav-io
PR: calcom/cal.com#21072
File: packages/app-store/office365calendar/api/webhook.ts:120-123
Timestamp: 2025-07-18T17:57:16.395Z
Learning: The office365calendar webhook handler in packages/app-store/office365calendar/api/webhook.ts is specifically designed for Office365 calendar integration, not as a generic webhook handler. Therefore, it's safe to assume that fetchAvailabilityAndSetCache method will be implemented in the Office365CalendarService, making explicit validation checks unnecessary.

Applied to files:

  • packages/features/bookings/lib/handleCancelBooking.ts
📚 Learning: in the failedbookingsbyfield component (packages/features/insights/components/failedbookingsbyfield....
Learnt from: eunjae-lee
PR: calcom/cal.com#22106
File: packages/features/insights/components/FailedBookingsByField.tsx:65-71
Timestamp: 2025-07-15T12:59:34.389Z
Learning: In the FailedBookingsByField component (packages/features/insights/components/FailedBookingsByField.tsx), although routingFormId is typed as optional in useInsightsParameters, the system automatically enforces a routing form filter, so routingFormId is always present in practice. This means the data always contains only one entry, making the single-entry destructuring approach safe.

Applied to files:

  • packages/features/bookings/lib/handleNewBooking/createBooking.ts
🧬 Code Graph Analysis (2)
packages/features/bookings/lib/audit/booking-audit-service.test.ts (1)
packages/features/bookings/lib/audit/booking-audit-service.ts (1)
  • BookingAuditService (16-399)
packages/features/bookings/lib/handleCancelBooking.ts (1)
packages/features/bookings/lib/audit/booking-audit-service.ts (1)
  • BookingAuditService (16-399)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Install dependencies / Yarn install & cache
  • GitHub Check: Codacy Static Code Analysis
🔇 Additional comments (27)
packages/features/bookings/lib/handleCancelBooking.ts (2)

40-40: LGTM! Clean integration of audit service.

The import addition is well-placed and follows the existing import organization.


397-411: Excellent non-blocking audit integration.

The audit logging implementation follows best practices:

  • Wrapped in try-catch blocks to prevent disrupting the main booking flow
  • Logs errors appropriately without throwing
  • Called after the booking operations are completed
  • Uses appropriate service methods with relevant booking data

Also applies to: 450-462

packages/features/bookings/lib/audit/booking-audit-service.test.ts (6)

1-34: Excellent test setup with proper mocking.

The test setup correctly mocks both Prisma client and logger dependencies, with proper cleanup in beforeEach. The use of vi.clearAllMocks() ensures test isolation.


37-67: Comprehensive test coverage for booking creation audit.

The test properly validates the audit logging for booking creation, checking that Prisma's create method is called with the expected data structure and booking action.


69-96: Good coverage for booking cancellation audit.

Test correctly verifies cancellation audit logging with appropriate mock data and assertions.


98-126: Thorough testing of booking rescheduling audit.

The test includes both original and new timestamps, which properly validates the rescheduling audit data structure.


128-157: Well-structured audit log retrieval test.

Test properly verifies both the returned data and the query parameters passed to Prisma's findMany method, including the correct ordering.


159-178: Critical error handling test ensures robustness.

This test is essential - it verifies that audit failures don't break the main booking flow by ensuring the service methods don't throw errors even when database operations fail.

packages/features/bookings/lib/handleNewBooking/createBooking.ts (4)

14-14: Clean import addition.

The BookingAuditService import is appropriately placed with other feature imports.


113-116: Necessary function signature update for audit logging.

The additional parameters (organizerUser, evt, eventType) are required for the audit logging functionality and are passed appropriately.


191-240: Comprehensive and well-structured audit logging implementation.

The audit logging implementation is excellent:

  • Proper placement: Called after successful booking creation within the transaction
  • Conditional logic: Correctly differentiates between new bookings and reschedules
  • Rich data capture: Includes all relevant booking details for both scenarios
  • Actor metadata: Properly constructs actor information from organizer user data
  • Error handling: Wrapped in try-catch that doesn't disrupt the main booking flow
  • Data mapping: Correctly maps booking and event type data to audit parameters

The reschedule audit includes both old and new timestamps, and the creation audit captures comprehensive booking metadata including payment requirements and recurring event details.


142-144: Function signature appropriately updated.

The saveBooking function signature correctly adds the required parameters for audit logging while maintaining backward compatibility through the internal function structure.

packages/features/bookings/lib/audit/booking-audit-schemas.ts (7)

6-16: Comprehensive and well-organized audit action enum.

The BookingAuditAction enum covers all essential booking lifecycle events and is organized logically. The inclusion of payment and attendee management actions shows good forward-thinking for audit requirements.


21-27: Well-designed base audit schema.

The base schema captures essential common fields with appropriate validation:

  • Datetime strings for consistent timestamp handling
  • Optional location for flexibility
  • Default attendee count with sensible fallback
  • Required eventTypeId for proper categorization

32-39: Comprehensive creation audit schema.

The creation schema appropriately extends the base with creation-specific fields like eventTypeName, organizerId, and booking configuration details. Good use of optional fields for non-universal properties.


44-50: Thorough rescheduling audit schema.

The reschedule schema correctly captures both old and new timestamps, essential for understanding the change. Optional fields for reason and organizer changes provide good audit trail details.


102-110: Flexible and comprehensive actor metadata schema.

The actor schema design is excellent:

  • Covers various user identification methods (userId, email, name)
  • Includes role-based categorization
  • Captures technical details (userAgent, ipAddress) for security auditing
  • Supports platform integration with platformClientId
  • All fields appropriately optional for flexibility

115-160: Excellent schema factory pattern implementation.

The getBookingAuditSchema function provides type-safe validation based on action type:

  • Uses literal types for action validation
  • Properly maps actions to their corresponding data schemas
  • Groups related actions (payment, attendee) efficiently
  • Includes fallback with passthrough for extensibility
  • Default version and createdAt provide good defaults

165-181: Complete type exports for TypeScript integration.

The exported types provide excellent TypeScript integration, making the schemas usable throughout the codebase with proper type safety.

packages/features/bookings/lib/audit/booking-audit-service.ts (8)

20-64: Excellent core audit creation method with robust error handling.

The create method implementation is exemplary:

  • Schema validation: Uses the appropriate schema based on action type
  • Database persistence: Properly handles Prisma JSON input types
  • Error handling: Catches and logs errors without throwing, preventing disruption to main booking flows
  • Structured logging: Provides detailed success and error logs with relevant context
  • Type safety: Properly casts data to Prisma.InputJsonValue

This follows the non-blocking design pattern perfectly for audit systems.


69-106: Comprehensive booking creation audit method.

The logBookingCreated method properly handles:

  • Flexible timestamp input (string or Date)
  • Comprehensive booking metadata capture
  • Proper actor serialization
  • Sensible defaults (attendeeCount = 1)

111-142: Thorough rescheduling audit implementation.

The reschedule method captures both old and new booking details, essential for understanding the full context of the change. The timestamp handling and optional parameters provide good flexibility.


147-170: Well-designed cancellation audit method.

The cancellation method properly handles optional parameters since some booking details might not be available during cancellation scenarios.


315-335: Robust audit log retrieval with proper error handling.

The retrieval method follows the same error handling pattern as the creation method - logs errors and returns safe fallbacks (empty array) rather than throwing exceptions.


347-374: Efficient multiple booking audit retrieval.

The multiple booking query uses proper SQL optimization with IN clause and sensible ordering (by bookingId first, then by creation time descending). Good performance consideration.


379-398: Safe JSON serialization utilities.

Both serializeActor and deserializeActor methods include proper error handling with fallback behaviors, ensuring the audit system remains robust even with malformed data.


250-273: Smart action determination for payment events.

The payment method intelligently maps payment status to appropriate audit actions, showing good design consideration for the audit trail requirements.

Vansh5632 and others added 4 commits August 2, 2025 11:31
- Add null checks before parseInt(cancelledBy) to prevent TypeScript errors
- Fixes TS2345 errors where 'string | undefined' is not assignable to 'string'
- Ensures userId is set to NaN when cancelledBy is undefined, maintaining existing logic
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: 6

🧹 Nitpick comments (1)
packages/features/bookings/lib/audit/bookingAudit.schemas.ts (1)

95-95: Consider renaming the 'action' field to avoid confusion

The attendeeAuditDataSchema contains an 'action' field that could be confused with the top-level audit action. Consider renaming it to something more specific like 'attendeeAction' or 'operation'.

-  action: z.enum(["added", "removed"]),
+  attendeeAction: z.enum(["added", "removed"]),

Note: This would require corresponding changes in the BookingAuditService.logAttendeeEvent method.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e2c6903 and 57d450b.

📒 Files selected for processing (6)
  • packages/features/bookings/lib/audit/BookingAuditService.test.ts (1 hunks)
  • packages/features/bookings/lib/audit/BookingAuditService.ts (1 hunks)
  • packages/features/bookings/lib/audit/bookingAudit.schemas.test.ts (1 hunks)
  • packages/features/bookings/lib/audit/bookingAudit.schemas.ts (1 hunks)
  • packages/features/bookings/lib/handleCancelBooking.ts (3 hunks)
  • packages/features/bookings/lib/handleNewBooking/createBooking.ts (4 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/features/bookings/lib/handleCancelBooking.ts
🧰 Additional context used
📓 Path-based instructions (3)
**/*.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/features/bookings/lib/audit/BookingAuditService.test.ts
  • packages/features/bookings/lib/audit/bookingAudit.schemas.ts
  • packages/features/bookings/lib/audit/bookingAudit.schemas.test.ts
  • packages/features/bookings/lib/handleNewBooking/createBooking.ts
  • packages/features/bookings/lib/audit/BookingAuditService.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/features/bookings/lib/audit/BookingAuditService.test.ts
  • packages/features/bookings/lib/audit/bookingAudit.schemas.ts
  • packages/features/bookings/lib/audit/bookingAudit.schemas.test.ts
  • packages/features/bookings/lib/handleNewBooking/createBooking.ts
  • packages/features/bookings/lib/audit/BookingAuditService.ts
**/*Service.ts

📄 CodeRabbit Inference Engine (.cursor/rules/review.mdc)

Service files must include Service suffix, use PascalCase matching exported class, and avoid generic names (e.g., MembershipService.ts)

Files:

  • packages/features/bookings/lib/audit/BookingAuditService.ts
🧬 Code Graph Analysis (4)
packages/features/bookings/lib/audit/BookingAuditService.test.ts (1)
packages/features/bookings/lib/audit/BookingAuditService.ts (1)
  • BookingAuditService (16-399)
packages/features/bookings/lib/audit/bookingAudit.schemas.test.ts (1)
packages/features/bookings/lib/audit/bookingAudit.schemas.ts (1)
  • getBookingAuditSchema (115-160)
packages/features/bookings/lib/handleNewBooking/createBooking.ts (2)
packages/types/Calendar.d.ts (1)
  • CalendarEvent (163-224)
packages/features/bookings/lib/audit/BookingAuditService.ts (1)
  • BookingAuditService (16-399)
packages/features/bookings/lib/audit/BookingAuditService.ts (1)
packages/features/bookings/lib/audit/bookingAudit.schemas.ts (3)
  • BookingAuditInput (173-173)
  • getBookingAuditSchema (115-160)
  • ActorMetadata (174-174)
⏰ Context from checks skipped due to timeout of 90000ms. 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 (1)
packages/features/bookings/lib/handleNewBooking/createBooking.ts (1)

226-226: Add null check for paymentAppData.price

The expression paymentAppData.price > 0 might throw if price is undefined. Consider using a safer check.

-          paymentRequired: paymentAppData.price > 0,
+          paymentRequired: typeof paymentAppData.price === "number" && paymentAppData.price > 0,

Likely an incorrect or invalid review comment.

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

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 57d450b and 09607b6.

📒 Files selected for processing (3)
  • packages/features/bookings/lib/handleCancelBooking.ts (5 hunks)
  • packages/prisma/migrations/20250811202009_add_index_to_booking_audit/migration.sql (1 hunks)
  • packages/prisma/schema.prisma (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • packages/features/bookings/lib/handleCancelBooking.ts
  • packages/prisma/schema.prisma
🔇 Additional comments (1)
packages/prisma/migrations/20250811202009_add_index_to_booking_audit/migration.sql (1)

2-2: LGTM: bookingId index is appropriate and complements FK lookups

This index is a good baseline for frequent WHERE bookingId filters and joins.

@@ -0,0 +1,2 @@
-- CreateIndex
CREATE INDEX "BookingAudit_bookingId_idx" ON "BookingAudit"("bookingId");
Copy link
Contributor

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

Optional: add composite index for common timeline queries

If your audit retrievals frequently do WHERE bookingId = ? ORDER BY createdAt DESC, a composite index (bookingId, createdAt DESC) will eliminate extra sorts and improve pagination.

Check for such usage to justify the composite index:

If confirmed, add this additional index in a follow-up migration:

-- Postgres: composite index optimizing WHERE bookingId + ORDER BY createdAt DESC
CREATE INDEX CONCURRENTLY IF NOT EXISTS "BookingAudit_bookingId_createdAt_desc_idx"
  ON "BookingAudit"("bookingId", "createdAt" DESC);

🏁 Script executed:

#!/bin/bash
# Find BookingAudit queries that filter by bookingId and order by createdAt
rg -n -A3 -i 'BookingAudit|bookingAudit' | rg -n -i 'orderBy.*createdAt|ORDER BY[[:space:]]+"?createdAt' -A3 -B6

Length of output: 114


🏁 Script executed:

#!/bin/bash
set -eux

echo "1. Locate all Prisma BookingAudit queries (findMany/findFirst) with context:"
rg -n "prisma\.bookingAudit\.(findMany|findFirst)" -A5 -B5

echo "2. Look for WHERE bookingId + ORDER BY createdAt in the same snippet:"
rg -n -i "where.*bookingId.*orderBy.*createdAt" -A3 -B3 .

echo "3. Fallback: any ORDER BY createdAt usage (to catch raw SQL or other clients):"
rg -n "orderBy.*createdAt" -A3 -B3 .

Length of output: 2407


Add composite index to optimize BookingAudit pagination

We’ve confirmed that getBookingAuditLogs uses

prisma.bookingAudit.findMany({
  where: { bookingId },
  orderBy: { createdAt: "desc" },})

Adding a composite index on (bookingId, createdAt DESC) will remove the need for an extra sort and speed up pagination.

• Create a new migration (e.g. packages/prisma/migrations/202508XX_add_composite_index_booking_audit/migration.sql) with:

-- Postgres: composite index optimizing WHERE bookingId + ORDER BY createdAt DESC
CREATE INDEX CONCURRENTLY IF NOT EXISTS "BookingAudit_bookingId_createdAt_desc_idx"
  ON "BookingAudit"("bookingId", "createdAt" DESC);
🤖 Prompt for AI Agents
In
packages/prisma/migrations/20250811202009_add_index_to_booking_audit/migration.sql
around line 2, the current migration only creates a single-column index on
bookingId; add a new migration file (e.g.
packages/prisma/migrations/202508XX_add_composite_index_booking_audit/migration.sql)
that creates a composite index on (bookingId, createdAt DESC) using CREATE INDEX
CONCURRENTLY IF NOT EXISTS "BookingAudit_bookingId_createdAt_desc_idx" ON
"BookingAudit"("bookingId", "createdAt" DESC) so the DB can use the index for
the WHERE bookingId + ORDER BY createdAt DESC pattern and speed up pagination,
then run/apply the migration.

💡 Verification agent

🧩 Analysis chain

Prefer CREATE INDEX CONCURRENTLY (Postgres) to avoid write locks on large tables

On production-sized tables, plain CREATE INDEX can block writes. If your provider is PostgreSQL, consider using CONCURRENTLY and IF NOT EXISTS. Prisma migrate will run the migration outside a transaction when it detects non-transactional statements like CONCURRENTLY.

Proposed change:

-CREATE INDEX "BookingAudit_bookingId_idx" ON "BookingAudit"("bookingId");
+-- Postgres only: create index without blocking writes
+CREATE INDEX CONCURRENTLY IF NOT EXISTS "BookingAudit_bookingId_idx" ON "BookingAudit"("bookingId");

Verify provider (should be "postgresql"):


🏁 Script executed:

#!/bin/bash
# Show Prisma provider for datasource `db`
fd -a schema.prisma | while read -r f; do
  echo "==> $f"
  awk '
    /datasource[[:space:]]+db[[:space:]]*\{/ { in=1 }
    in && /provider[[:space:]]*=/ { print; in=0 }
  ' "$f"
done

Length of output: 990


Let’s reliably detect each Prisma schema’s provider with a simpler approach:


🏁 Script executed:

#!/bin/bash
find . -type f -name 'schema.prisma' | while read f; do
  echo "==> $f"
  # Print the datasource block, then extract the provider line
  sed -n '/^datasource/,/^}/p' "$f" | grep -E 'provider\s*=' || echo "  ⚠️ no provider found"
done

Length of output: 519


Use CREATE INDEX CONCURRENTLY for PostgreSQL-only migrations

  • Verified that packages/prisma/schema.prisma uses provider = "postgresql" (the example schema is SQLite).
  • Update the migration at packages/prisma/migrations/20250811202009_add_index_to_booking_audit/migration.sql:
--- a/packages/prisma/migrations/20250811202009_add_index_to_booking_audit/migration.sql
+++ b/packages/prisma/migrations/20250811202009_add_index_to_booking_audit/migration.sql
@@ -1,2 +1,4 @@
-  CREATE INDEX "BookingAudit_bookingId_idx" ON "BookingAudit"("bookingId");
+  -- PostgreSQL only: avoid write locks on large tables
+  CREATE INDEX CONCURRENTLY IF NOT EXISTS "BookingAudit_bookingId_idx"
+    ON "BookingAudit"("bookingId");

Prisma Migrate will detect the non‐transactional CONCURRENTLY statement and run this migration outside a transaction.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
CREATE INDEX "BookingAudit_bookingId_idx" ON "BookingAudit"("bookingId");
-- PostgreSQL only: avoid write locks on large tables
CREATE INDEX CONCURRENTLY IF NOT EXISTS "BookingAudit_bookingId_idx"
ON "BookingAudit"("bookingId");
🤖 Prompt for AI Agents
In
packages/prisma/migrations/20250811202009_add_index_to_booking_audit/migration.sql
around line 2, the migration creates a standard index which can lock large
tables; update the SQL to use PostgreSQL's non-blocking form by replacing the
statement with a CREATE INDEX CONCURRENTLY "BookingAudit_bookingId_idx" ON
"BookingAudit"("bookingId"); and save—note that Prisma Migrate will detect the
CONCURRENTLY statement and run this migration outside a transaction.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bookings area: bookings, availability, timezones, double booking community Created by Linear-GitHub Sync ✨ feature New feature or request ❗️ migrations contains migration files
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants