-
Notifications
You must be signed in to change notification settings - Fork 11.7k
feat: Use RoutingTraceService to write assignment reasons
#27225
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
base: main
Are you sure you want to change the base?
Conversation
…tingTraceRepository
Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>
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>
| @@ -10,10 +11,12 @@ export default async function routerGetCrmContactOwnerEmail({ | |||
| attributeRoutingConfig, | |||
| identifierKeyedResponse, | |||
| action, | |||
| routingTraceService, | |||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We need to pass the routingTraceService down from getRoutedURL down to the actual functions that handle the routing. getRoutedMembers is wrapped using Sentry's withReporting which creates it's own async context so we cannot rely on AsyncLocalStorage for the RoutingTraceService
| if (!eventType.hosts.some((host) => host.user.email === contactOwner.email)) | ||
| return null; | ||
|
|
||
| if (routingTraceService && contactOwner.email && contactOwner.crmAppSlug) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Change to the file is here, we're recording the routing trace step. With these values stored, we don't have to rely on these values being passed through URL params to generate the assignment reason.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since we're using the PendingRoutingTrace we don't need to rely on URL params being passed.
| routingTraceService.addStep({ | ||
| domain: "routing_form", | ||
| step: "attribute-logic-evaluated", | ||
| data: { | ||
| routeName, | ||
| routeIsFallback, | ||
| attributeRoutingDetails, | ||
| }, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
With this data stored, we don't need to do the calculation to get the name value pairs of the attributes used to route in RegularBookingService when recording the assignment reason.
| /** | ||
| * Process pending routing trace for a booking. | ||
| * Looks up the pending trace, extracts assignment reason, creates permanent trace. | ||
| */ | ||
| async processForBooking(args: { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Phase 1 of the routing trace project is to replace how we're recording the assignment reason with the stored pending routing trace.
This method will change as we continue to work on the routing trace.
| reasonString: this.buildSalesforceReasonString({ | ||
| email, | ||
| recordType: recordType ?? "Contact", // Default to Contact if not specified | ||
| recordId, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One advantage of taking this approach is we can pass the Salesforce record id around without exposing it in URL params
E2E results are ready! |
What does this PR do?
This PR introduces a
RoutingTraceServiceto track routing decisions and write assignment reasons for bookings, replacing the previous approach that relied on URL params or post-processing after booking creation.Key Changes
New Database Models:
PendingRoutingTraces- Stores routing trace data temporarily between form submission and booking creationRoutingTrace- Permanent storage linked to bookings, form responses, and assignment reasonsNew Service Architecture:
RoutingTraceService- Core service that collects routing steps and processes them into assignment reasonsIPendingRoutingTraceRepositoryandIRoutingTraceRepositoryinterfacesRoutingTraceService.container.tsIntegration Points:
handleResponsenow accepts atraceServiceparameter to track routing form decisionsfindTeamMembersMatchingAttributeLogicrecords attribute logic evaluation stepsrouterGetCrmContactOwnerEmailrecords CRM assignment stepsRegularBookingServiceusesRoutingTraceService.processForBooking()instead ofAssignmentReasonRecorderTrace Steps Recorded:
routing_formdomain:attribute-logic-evaluatedstep with route name, fallback status, and attribute detailssalesforce):{appSlug}_assignmentstep with contact owner detailsUpdates since last revision
RoutingTraceService.test.ts- 20 tests covering step tracking, pending trace saving, and assignment reason extractionPrismaPendingRoutingTraceRepository.test.ts- 7 tests for pending trace CRUD operationsPrismaRoutingTraceRepository.test.ts- 5 tests for permanent trace creationMandatory Tasks (DO NOT REMOVE)
How should this be tested?
PendingRoutingTracesrecord is created after form submissionRoutingTracerecord is created after booking completionAssignmentReasonis correctly populated based on the routing traceFor CRM routing:
Human Review Checklist
extractAssignmentReasonFromTracelogic correctly prioritizes CRM over routing form assignmentRegularBookingService- failures are logged as warnings but don't block bookingPendingRoutingTracesandRoutingTracetablesAssignmentReasonRecorderlogicChecklist
Link to Devin run: https://app.devin.ai/sessions/1f674b7b8e4747249113cc2da6142b24
Requested by: joe@cal.com (@joeauyeung)