* chore: upgrade Vitest to 4.0.16 and Vite to 6.4.1 - Update vitest from 2.1.9 to 4.0.16 - Update @vitest/ui from 2.1.9 to 4.0.16 - Update vitest-fetch-mock from 0.3.0 to 0.4.5 - Update vitest-mock-extended from 2.0.2 to 3.1.0 - Update vite from 4.5.14/5.4.21 to 6.4.1 across all packages - Update @vitejs/plugin-react to 5.1.2 - Update @vitejs/plugin-react-swc to 4.2.2 - Update @vitejs/plugin-basic-ssl to 2.1.0 - Update vite-plugin-dts to 4.5.4 - Rename vitest.config.ts to vitest.config.mts for ESM compatibility - Add globals: true to vitest config Co-Authored-By: Volnei Munhoz <volnei.munhoz@gmail.com> * fix: address Vitest 4.0 and Vite 6 breaking changes - Convert arrow function mockImplementation patterns to regular functions (Vitest 4.0 breaking change: arrow functions can't be constructor mocks) - Fix CSS imports with ?inline suffix for Vite 6 compatibility - Add biome override to disable useArrowFunction rule for test files - Fix syntax errors in test files introduced by regex replacements Co-Authored-By: Volnei Munhoz <volnei.munhoz@gmail.com> * fix: fix remaining Vitest 4.0 constructor mock patterns Co-Authored-By: Volnei Munhoz <volnei.munhoz@gmail.com> * fix: fix more Vitest 4.0 constructor mock patterns and exclude API v2 spec files Co-Authored-By: Volnei Munhoz <volnei.munhoz@gmail.com> * fix: convert more arrow function mocks to regular functions for Vitest 4.0 Co-Authored-By: Volnei Munhoz <volnei.munhoz@gmail.com> * fix: convert more arrow function mocks to regular functions for Vitest 4.0 - Fix CrmService.integration.test.ts jsforce.Connection mock - Fix RetellSDKClient.test.ts Retell mock - Fix RetellAIService.test.ts CreditService mocks - Fix GoogleCalendarSubscriptionAdapter.test.ts CalendarAuth mock Co-Authored-By: Volnei Munhoz <volnei.munhoz@gmail.com> * fix: convert Google Calendar and OAuthManager arrow function mocks for Vitest 4.0 - Fix googleapis.ts Calendar, OAuth2Client, and JWT mocks - Fix utils.ts JWT mock - Fix OAuthManager.ts defaultMockOAuthManager mock Co-Authored-By: Volnei Munhoz <volnei.munhoz@gmail.com> * fix: add React plugin, jsdom environment, and fix more constructor mocks for Vitest 4.0 Co-Authored-By: Volnei Munhoz <volnei.munhoz@gmail.com> * fix: convert HostRepository PrismaClient mock to regular function for Vitest 4.0 Co-Authored-By: Volnei Munhoz <volnei.munhoz@gmail.com> * fix: add useOrgBranding mock to React component tests for Vitest 4.0 Co-Authored-By: Volnei Munhoz <volnei.munhoz@gmail.com> * fix: update TestFunction type for Vitest 4.0 compatibility Co-Authored-By: Volnei Munhoz <volnei.munhoz@gmail.com> * fix: convert listBookingReports constructor mocks to regular functions for Vitest 4.0 Co-Authored-By: Volnei Munhoz <volnei.munhoz@gmail.com> * fix: convert UserRepository constructor mock to regular function for Vitest 4.0 Co-Authored-By: Volnei Munhoz <volnei.munhoz@gmail.com> * fix: convert OrganizationPaymentService constructor mock to regular function for Vitest 4.0 Co-Authored-By: Volnei Munhoz <volnei.munhoz@gmail.com> * fix: convert more constructor mocks to regular functions for Vitest 4.0 Co-Authored-By: Volnei Munhoz <volnei.munhoz@gmail.com> * fix: add apps/web path aliases to vitest config Co-Authored-By: Volnei Munhoz <volnei.munhoz@gmail.com> * fix: fix test issues for Vitest 4.0 compatibility - Fix Response constructor 204 status code issue in testUtils.ts - Fix FeaturesRepository mock persistence in handleNotificationWhenNoSlots.test.ts - Add @vitest-environment node directive to formSubmissionUtils.test.ts - Fix document.querySelector mock in embed.test.ts Co-Authored-By: Volnei Munhoz <volnei.munhoz@gmail.com> * fix: clear EventManager spy between tests for Vitest 4.0 compatibility Co-Authored-By: Volnei Munhoz <volnei.munhoz@gmail.com> * fix: update TeamRepository mock pattern for Vitest 4.0 compatibility Co-Authored-By: Volnei Munhoz <volnei.munhoz@gmail.com> * fix: convert RoutingFormResponseRepository mock to regular function for Vitest 4.0 Co-Authored-By: Volnei Munhoz <volnei.munhoz@gmail.com> * fix: convert more constructor mocks to regular functions for Vitest 4.0 Co-Authored-By: Volnei Munhoz <volnei.munhoz@gmail.com> * fix: fix mock reset and spy clear issues for Vitest 4.0 Co-Authored-By: Volnei Munhoz <volnei.munhoz@gmail.com> * fix: fix remaining test failures for Vitest 4.0 upgrade - Fix booking-validations.test.ts: convert UserRepository mock to regular function - Fix route.test.ts: update 500 error test to mock ImageResponse instead of fetch - Fix users-public-view.test.tsx: add missing mocks for getOrgFullOrigin and useRouterQuery - Add @calcom/web path alias to vitest config Co-Authored-By: Volnei Munhoz <volnei.munhoz@gmail.com> * fix: add vitest-mocks for generated files that don't exist in CI - Add svg-hashes.json mock for route.test.ts - Add tailwind.generated.css mock for embed.test.ts - Update vitest config to use mock files Co-Authored-By: Volnei Munhoz <volnei.munhoz@gmail.com> * fix: update vitest config aliases for CI compatibility - Use array format for aliases to ensure proper ordering - Add @calcom/platform-constants alias to resolve from source - Add @calcom/embed-react alias to resolve from source - Ensure svg-hashes.json mock alias is matched before @calcom/web Co-Authored-By: Volnei Munhoz <volnei.munhoz@gmail.com> * fix: add @calcom/embed-snippet alias for CI compatibility Co-Authored-By: Volnei Munhoz <volnei.munhoz@gmail.com> * Fix wrong test * fix: migrate from CLI flags to VITEST_MODE env var for Vitest 4.0 Vitest 4.0 no longer allows custom CLI flags like --packaged-embed-tests-only. This change migrates to using VITEST_MODE environment variable instead: - VITEST_MODE=packaged-embed for packaged embed tests - VITEST_MODE=integration for integration tests - VITEST_MODE=timezone for timezone-dependent tests Updated vitest.config.mts to handle mode-based include/exclude patterns. Updated CI workflows and package scripts to use the new env var approach. Co-Authored-By: Volnei Munhoz <volnei.munhoz@gmail.com> * fix: return default include pattern instead of undefined in vitest config The getTestInclude() function was returning undefined for the default case, but Vitest 4.0 expects an array. This caused 'resolved.include is not iterable' error in CI. Co-Authored-By: Volnei Munhoz <volnei.munhoz@gmail.com> * fix: always set INTEGRATION_TEST_MODE for jsdom environment The getBookingFields.ts file checks for INTEGRATION_TEST_MODE to allow server-side imports in the jsdom environment. Without this, tests fail with 'getBookingFields must not be imported on the client side' error. Co-Authored-By: Volnei Munhoz <volnei.munhoz@gmail.com> * fix: support legacy CLI flags for backwards compatibility with main workflow The CI runs workflows from main branch, which uses the old CLI flag approach (yarn test -- --integrationTestsOnly). This commit adds backwards compatibility by checking both VITEST_MODE env var and process.argv for the legacy flags. Co-Authored-By: Volnei Munhoz <volnei.munhoz@gmail.com> --------- Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Booking Audit System
Overview
The Booking Audit System tracks all actions and changes related to bookings in Cal.com. The architecture is built around two core tables (AuditActor and BookingAudit) that work together to maintain a complete, immutable audit trail.
Database Architecture
Core Tables
- AuditActor: Stores information about entities that perform actions on bookings. Maintains historical records even after users are deleted.
- BookingAudit: Stores audit records for all booking-related actions.
Key Design Decisions
AuditActor Table:
- Uses UUID primary keys for distributed system compatibility
- Soft references to
User(viauserUuid) andAttendee(viaattendeeId) without foreign key constraints - Audit trail persists independently even after users/attendees are deleted
- Unique constraints prevent duplicate audit actors
- Supports actor types: USER, GUEST, ATTENDEE, SYSTEM, APP
- Identity fields (email, phone, name) can be anonymized when source records are deleted
BookingAudit Table:
- Uses UUID v7 primary keys for time-sortable IDs
bookingUidstored as plain string (no foreign key) to preserve audit trail after booking deletiononDelete: Restrictprevents actor deletion if audit records exist- Explicit
timestampfield represents business event time (may differ fromcreatedAtif processed asynchronously) operationIdrequired field for correlating audit logs from a single user action across different audit types (BookingAudit, UserAudit, etc.)- JSON
datafield stores action-specific contextual data - Indexed for efficient queries by
bookingUid,actorId,timestamp, andoperationId
Protecting the Audit Trail:
- Database rejects deletion of
AuditActorrecords with associatedBookingAuditrecords - When a
Useris deleted, theirAuditActorrecord persists withuserUuidset to null
Actor Types
- USER: Registered Cal.com users
- GUEST: Non-registered users (typically booking guests)
- ATTENDEE: Guests who have an Attendee record associated with a booking
- SYSTEM: Automated system actions
Source and Actor Design Pattern
The booking audit system uses two complementary fields:
Source: The Channel
source identifies how the action was initiated:
- WEBAPP: Cal.com web application
- API_V1: API v1 endpoint
- API_V2: API v2 endpoint
- WEBHOOK: External webhook (e.g., Stripe)
- UNKNOWN: Source cannot be determined
Actor: The Entity
actor identifies who or what performed the action:
- User Actor: Registered Cal.com user
- Guest Actor: Non-registered guest
- Attendee Actor: Attendee associated with a booking
- System Actor: Automated system action (generic or named for specific webhooks/services)
This separation enables clear compliance trails, easier debugging, better analytics, and security by distinguishing user-initiated vs automated actions.
Audit Actions
The system tracks various booking actions including:
- CREATED: Initial booking creation
- RESCHEDULED: Booking time/date changed
- ACCEPTED: Booking request approved
- CANCELLED: Booking cancelled
- REJECTED: Booking request declined
- RESCHEDULE_REQUESTED: Request to reschedule
- ATTENDEE_ADDED: New attendee added
- ATTENDEE_REMOVED: Attendee removed
- REASSIGNMENT: Booking reassigned to different host
- LOCATION_CHANGED: Meeting location updated
- HOST_NO_SHOW_UPDATED: Host no-show status changed
- ATTENDEE_NO_SHOW_UPDATED: Attendee no-show status changed
- SEAT_BOOKED: Seat reserved in group booking
- SEAT_RESCHEDULED: Seat rescheduled in group booking
Data Structure Pattern
Most audit actions track changes using a consistent structure:
- Each field tracks both old and new values:
{ old: T | null, new: T } old: Previous value (null if field didn't exist before)new: New value after the change- Complete before/after state captured in every record
Exception: The CREATED action captures initial booking state at creation using a flat object with initial values.
Schema Versioning
The audit system uses per-action versioning. Each action maintains its own schema version independently.
Benefits:
- Update one action's schema without affecting others
- Old records handled via discriminated unions (no migration required)
- Strongly-typed schemas for input and storage
Storage Structure:
Version stored separately from audit data: { version, data: {} }
Table Relationships
AuditActor (1) ──────< (many) BookingAudit
↑
│ (soft reference, no FK)
├──────────── User (via userUuid)
│ (soft reference, no FK)
└──────────── Attendee (via attendeeId)
Relationship Details:
- AuditActor → BookingAudit: One-to-Many with FK constraint and
onDelete: Restrict - AuditActor → User: Soft reference (no FK) - nullable to preserve audits after user deletion
- AuditActor → Attendee: Soft reference (no FK) - nullable to preserve audits after attendee deletion
Indexing Strategy
AuditActor Table:
- Indexed on
email,userUuid,attendeeIdfor fast lookups - Indexed on
pseudonymizedAtfor compliance cleanup jobs
BookingAudit Table:
- Indexed on
bookingUid(primary query pattern) - Indexed on
actorId(secondary query pattern) - Indexed on
timestamp(time-based sorting and filtering) - Indexed on
operationId(correlating multi-booking operations)
Special Actors
SYSTEM Actor:
- Fixed UUID representing automated actions
- Used for automated status changes, system-generated meeting URLs, scheduled operations
- Single instance across the entire system
- No userUuid, attendeeId, email, or phone
Design Principles
1. Immutability
Audit records are append-only. Once created, they are never modified or deleted. This ensures complete historical accuracy and a tamper-proof audit trail.
2. Historical Preservation
Actor information is preserved even after source records are deleted. AuditActor records persist with anonymized identity fields. The audit trail remains complete and queryable even after user/attendee deletion.
3. Flexibility
The JSON data field provides schema flexibility for action-specific context without database schema changes. Backward compatible with versioning.
4. Traceability
Every action is fully traceable with who (actor), what (action), when (timestamp), and contextual data.
5. Integrity
Database constraints ensure data quality through foreign keys, onDelete: Restrict protection, unique constraints, and strategic indexes.
6. Reality Over Enforcement
The audit system records actual state, not expected state. It captures what actually happened without enforcing business rules:
- Store actual values from the database
- Record all actions, including anomalies
- Business logic layer enforces rules; audit layer records faithfully
Benefits:
- Shows real system behavior including anomalies
- Easier debugging
- No silent failures
7. Compliance & Data Privacy
GDPR & HIPAA Compliance:
- AuditActor records persist with PII fields nullified when users are deleted
- Maintains immutable audit trail as required by HIPAA §164.312(b)
- GDPR Article 17 compliance through anonymization:
userUuid,email,phone,nameset to null - Application-level logic handles retention policies
8. Queue Privacy
Zero PII in Queue: The audit system works with third-party queue providers without exposing PII:
- UserActor: Only
userUuidis queued - AttendeeActor: Only
attendeeIdis queued - GuestActor: Actor record created before queueing; only
actorIdis queued
Benefits:
- Safe to use third-party queue providers
- GDPR and HIPAA compliant
- Audit trail remains complete even if queue is compromised
Service Architecture
BookingEventHandlerService is the primary entry point for tracking booking changes. It:
- Receives booking events from various parts of the application
- Queues audit tasks via BookingAuditProducerService
- Handles other side effects such as webhooks and notifications
Queue Payload Structure:
bookingUid: String identifier for the bookingactor: ID-only actor object (userUuid,attendeeId, oractorId)organizationId: Number (for feature flag checks)action: Enum value (e.g., "CREATED", "CANCELLED")operationId: Required string for correlating related audit logsdata: Action-specific datatimestamp: Number (milliseconds since epoch)source: Action source (API_V1, API_V2, WEBAPP, WEBHOOK, UNKNOWN)
BookingAuditTaskConsumer processes audit records:
- Validates queue payload structure
- Resolves actor IDs to AuditActor records
- Routes to appropriate action service for data validation and formatting
- Creates immutable audit records in BookingAudit table
Operation ID
The operationId field correlates audit logs that result from a single user action affecting multiple bookings or across different audit types (BookingAudit, UserAudit, etc.).
Benefits:
- Easy to identify all audits from a single user action
- Track bulk vs individual operations
- Improved debugging and understanding of action scope
- Indexed field for fast lookups
Summary
The Booking Audit System provides a robust, scalable architecture for tracking all booking-related actions:
- Complete Audit Trail: Every action tracked with full context
- Historical Preservation: Data retained even after deletions through PII anonymization
- Flexible Schema: JSON data supports evolution without migrations
- Strong Integrity: Database constraints ensure data quality
- Performance: Strategic indexes, UUID v7 for time-sortable IDs
- HIPAA & GDPR Compliant: Immutable audit records, anonymized actors
- Reality-Based Recording: Captures actual state for debugging
- Independent Audit Trail: Persists after booking deletion
- Operation Correlation: Links related audit logs across different audit types
This architecture supports compliance requirements, debugging, analytics, and provides transparency for users and administrators.