* Add DB schema * Init zod schema * Init RoutingTrace and PendingRoutingTrace repository interfaces * Create PrismaPendingRoutingTraceRepository * Init RoutingTraceService * Create RoutingTraceService container * User routing trace service in routing * Create RoutingTraceRepository and PrismaRoutingTraceRepoistory * Add findByFormResponseId and findByQueuedFormResponseId to PendingRoutingTraceRepository * Update DI containers * RoutingTraceService create process booking method * Use pending routing trace rather than URL params * Fix schema * Fix writing assignment reason for routed booking * Remove from service * Refactor RoutingTraceService to not rely on async local storage * Pass RoutingTraceService through routing call * Add attribute-logic-evaluated to routing trace step * Add routing trace to trpc endpoint * Add CRM routing trace step * Fix extracting routing trace to assignment reason * Add back CRM params to prevent refetching * test: Add unit tests for RoutingTraceService and repositories Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com> * test: Add missing mock for RoutingTraceService in getRoutedUrl tests Also fix pre-existing lint issues in the test file: - Add explicit types to mockForm and mockSerializableForm variables - Add explicit type to url parameter in mockContext - Replace 'as any' with 'as unknown as InstanceType<typeof UserRepository>' Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com> * Link pending form submission to routing trace * Clean up * Add lookup field assignment reasons * Rename to PendingRoutingTrace * Add migration file * fix: Update RoutingTraceService tests to use assignmentReasonRepository mock - Add getStepsCount() method back to RoutingTraceService - Add queuedFormResponseId support to processForBooking method - Update tests to use mockAssignmentReasonRepository instead of prisma mock - Remove test for missing routingTraceRepository (all deps now required) Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com> * fix: Remove PII (organizer email) from log payload in RoutingTraceService Addresses Cubic AI review feedback with confidence 9/10. Logging PII violates sensitive information logging rules. Co-Authored-By: unknown <> * Write field values at the time of routing * Write attributes used to route * feat: add CRM routing trace service Add CrmRoutingTraceService as a reusable wrapper around RoutingTraceService for CRM-specific tracing. Also adds CrmRoutingTraceServiceInterface type to support passing trace services through the CRM call chain. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * feat: add Salesforce routing trace infrastructure Add SalesforceRoutingTrace static class with 19 trace methods covering: - Account resolution (SOQL path): searching by website, contact domain - Lookup field queries - Owner lookups (contact, lead, account) - Validation and skip scenarios - GraphQL three-tier resolution Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * feat: wire CRM trace service through call chain Pass crmTrace parameter through the CRM call chain: - routerGetCrmContactOwnerEmail creates CrmRoutingTraceService - Passes to app booking form handlers and CRM round robin skip - CrmManager.getContacts accepts and forwards crmTrace - All handlers accept optional crmTrace parameter Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * feat: add trace instrumentation to Salesforce CRM service Instrument Salesforce CRM methods with routing trace steps: - getContacts: trace owner lookups for contact/lead/account - getAccountIdBasedOnEmailDomainOfContacts: trace website and domain searches - findUserEmailFromLookupField: trace lookup field queries - GetAccountRecordsForRRSkip (GraphQL): trace three-tier resolution Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * refactor: rename SalesforceRoutingTrace to SalesforceRoutingTraceService Consistent naming with CrmRoutingTraceService. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * test: add unit tests for CrmRoutingTraceService and SalesforceRoutingTraceService Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com> * refactor: use AsyncLocalStorage for CRM routing trace Replace explicit crmTrace parameter passing with AsyncLocalStorage: - Add AsyncLocalStorage to RoutingTraceService with getCurrent() and runAsync() - Update SalesforceRoutingTraceService to auto-resolve trace from AsyncLocalStorage - Remove CrmRoutingTraceService wrapper (no longer needed) - Remove crmTrace parameter from all CRM method signatures - Wrap CRM operations in routingTraceService.runAsync() context This is cleaner than threading crmTrace through 5+ function layers. The trace context is available within the withReporting wrapper. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * Use async local storage for `CrmRoutingTraceService` * fix: correct template literal syntax in RoutingTraceService Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com> * fix: use narrowed eventTypeId variable in nested async function Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com> * fix: update SalesforceRoutingTraceService tests to use AsyncLocalStorage API Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com> * refactor: rename crmTrace to crmRoutingTraceService for consistency Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com> --------- Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> Co-authored-by: Volnei Munhoz <volnei@cal.com>
Creating a Salesforce test org
You must have the Salesforce CLI installed to create a test org. Once installed, you can create a test org using the following command yarn scratch-org:create
This will create a scratch org with the configuration specified in the project-scratch-def.json file.
To open a browser tab to the org, run yarn scratch-org:start
Working With GraphQL
This package utilizes GraphQL Codegen to generate types and queries from the Salesforce schema.
Generating GraphQL Schema
Currently v63 of the Salesforce graphql endpoint throws an error when trying to generate files. This is due to the Setup__JoinInput type not generating any fields. To work around this, the schema.json file comes from the Salesforce graphql introspection query. This file is then converted to a SDL file using the graphql-introspection-json-to-sdl package. You can generate the SDL file by running yarn generate:schema.
Generating Queries
When working with graphql files ensure that yarn codegen:watch is running in the background. This will generate the types and queries from the SDL file.
Developing the SFDC package
The SFDC package is written using Apex. To develop this package, you need to have the Salesforce CLI installed. Then you can run yarn sfdc:deploy:preview to see what changes will be deployed to the scratch org. Running yarn sfdc:deploy will deploy the changes to the scratch org.
Note that if you want to call your local development instances you need to change the "Named Credential" on the scratch org settings to point the CalCom_Development credential to the local instance.
Publishing the SFDC Package
All commands should be run from the sfdc-package directory:
cd packages/app-store/salesforce/sfdc-package
Initial Setup (One-time)
If the package doesn't exist yet in the Dev Hub, create it:
sf package create \
--name "calcom-sfdc-package" \
--package-type Unlocked \
--path force-app \
--target-dev-hub team@cal.com
This registers the package and updates sfdx-project.json with the package ID.
Creating a New Package Version
Each time you want to release changes, create a new version:
sf package version create \
--package "calcom-sfdc-package" \
--installation-key-bypass \
--wait 20 \
--target-dev-hub team@cal.com
Options:
--installation-key-bypass: Allows installation without a password--wait 20: Waits up to 20 minutes for completion--code-coverage: Add this flag when ready to promote (requires 75% Apex test coverage)
Viewing Packages and Installation URLs
List all package versions:
sf package version list --target-dev-hub team@cal.com
The installation URL format is:
https://login.salesforce.com/packaging/installPackage.apexp?p0=<04t_SUBSCRIBER_PACKAGE_VERSION_ID>
Promoting for Production
Beta versions can only be installed in sandboxes/scratch orgs. To allow installation in production orgs, promote the version:
sf package version promote \
--package "calcom-sfdc-package@X.X.X-X" \
--target-dev-hub team@cal.com
Replace X.X.X-X with the version number (e.g., 0.1.0-1).
Running Tests
To run Apex tests and check code coverage:
sf project deploy start --target-org <org-alias>
sf apex run test --test-level RunLocalTests --wait 10 --target-org <org-alias>