@schandlergarcia/sf-web-components 2.3.17 → 2.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.a4drules/skills/command-center-builder/SKILL.md +3 -2
- package/.a4drules/skills/component-library/SKILL.md +50 -4
- package/.a4drules/skills/component-library/card-components.md +88 -0
- package/.a4drules/skills/component-library/when-to-use.md +1 -0
- package/CHANGELOG.md +40 -0
- package/CLAUDE.md +12 -13
- package/README.md +0 -15
- package/dist/components/library/cards/KanbanBoard.js +313 -0
- package/dist/components/library/cards/KanbanBoard.js.map +1 -0
- package/dist/components/library/index.js +60 -57
- package/dist/components/library/index.js.map +1 -1
- package/dist/components/workspace/ComponentRegistry.js +5 -2
- package/dist/components/workspace/ComponentRegistry.js.map +1 -1
- package/dist/index.js +84 -82
- package/dist/index.js.map +1 -1
- package/dist/styles/global.css +44 -57
- package/package.json +7 -2
- package/scripts/apply-brand.mjs +47 -30
- package/scripts/postinstall.mjs +1 -11
- package/src/components/library/cards/KanbanBoard.jsx +507 -0
- package/src/components/library/index.jsx +1 -0
- package/src/styles/global.css +44 -57
- package/brands/engine/PARTNER_HUB_PRD.md +0 -584
- package/brands/engine/agentApiConfig.ts +0 -36
- package/brands/engine/app/api/graphql-operations-types.ts +0 -11260
- package/brands/engine/app/api/graphqlClient.ts +0 -25
- package/brands/engine/app/api/partnerQueries.ts +0 -212
- package/brands/engine/app/appLayout.tsx +0 -5
- package/brands/engine/app/components/AgentPanel.tsx +0 -541
- package/brands/engine/app/components/AgentforceConversationClient.tsx +0 -201
- package/brands/engine/app/components/Data360Widget.tsx +0 -301
- package/brands/engine/app/components/__inherit_AgentforceConversationClient.tsx +0 -3
- package/brands/engine/app/components/alerts/status-alert.tsx +0 -49
- package/brands/engine/app/components/layouts/card-layout.tsx +0 -29
- package/brands/engine/app/components/workspace/CommandCenter.tsx +0 -16
- package/brands/engine/app/config/agentApi.ts +0 -36
- package/brands/engine/app/data/partner-hub-sample-data.js +0 -297
- package/brands/engine/app/features/object-search/__examples__/api/accountSearchService.ts +0 -46
- package/brands/engine/app/features/object-search/__examples__/api/query/distinctAccountIndustries.graphql +0 -19
- package/brands/engine/app/features/object-search/__examples__/api/query/distinctAccountTypes.graphql +0 -19
- package/brands/engine/app/features/object-search/__examples__/api/query/getAccountDetail.graphql +0 -121
- package/brands/engine/app/features/object-search/__examples__/api/query/searchAccounts.graphql +0 -51
- package/brands/engine/app/features/object-search/__examples__/pages/AccountObjectDetailPage.tsx +0 -357
- package/brands/engine/app/features/object-search/__examples__/pages/AccountSearch.tsx +0 -312
- package/brands/engine/app/features/object-search/__examples__/pages/Home.tsx +0 -34
- package/brands/engine/app/features/object-search/api/objectSearchService.ts +0 -84
- package/brands/engine/app/features/object-search/components/ActiveFilters.tsx +0 -89
- package/brands/engine/app/features/object-search/components/FilterContext.tsx +0 -83
- package/brands/engine/app/features/object-search/components/ObjectBreadcrumb.tsx +0 -66
- package/brands/engine/app/features/object-search/components/PaginationControls.tsx +0 -109
- package/brands/engine/app/features/object-search/components/SearchBar.tsx +0 -41
- package/brands/engine/app/features/object-search/components/SortControl.tsx +0 -143
- package/brands/engine/app/features/object-search/components/filters/BooleanFilter.tsx +0 -78
- package/brands/engine/app/features/object-search/components/filters/DateFilter.tsx +0 -128
- package/brands/engine/app/features/object-search/components/filters/DateRangeFilter.tsx +0 -70
- package/brands/engine/app/features/object-search/components/filters/FilterFieldWrapper.tsx +0 -33
- package/brands/engine/app/features/object-search/components/filters/MultiSelectFilter.tsx +0 -97
- package/brands/engine/app/features/object-search/components/filters/NumericRangeFilter.tsx +0 -163
- package/brands/engine/app/features/object-search/components/filters/SearchFilter.tsx +0 -50
- package/brands/engine/app/features/object-search/components/filters/SelectFilter.tsx +0 -97
- package/brands/engine/app/features/object-search/components/filters/TextFilter.tsx +0 -91
- package/brands/engine/app/features/object-search/hooks/useAsyncData.ts +0 -54
- package/brands/engine/app/features/object-search/hooks/useCachedAsyncData.ts +0 -184
- package/brands/engine/app/features/object-search/hooks/useDebouncedCallback.ts +0 -34
- package/brands/engine/app/features/object-search/hooks/useObjectSearchParams.ts +0 -252
- package/brands/engine/app/features/object-search/utils/debounce.ts +0 -25
- package/brands/engine/app/features/object-search/utils/fieldUtils.ts +0 -29
- package/brands/engine/app/features/object-search/utils/filterUtils.ts +0 -404
- package/brands/engine/app/features/object-search/utils/sortUtils.ts +0 -38
- package/brands/engine/app/hooks/useEngineLiveData.ts +0 -49
- package/brands/engine/app/hooks/useEvaAgent.ts +0 -288
- package/brands/engine/app/hooks/usePartnerDashboardData.ts +0 -141
- package/brands/engine/app/navigationMenu.tsx +0 -80
- package/brands/engine/app/pages/AccountObjectDetailPage.tsx +0 -361
- package/brands/engine/app/pages/AccountSearch.tsx +0 -305
- package/brands/engine/app/pages/BlankDashboard.tsx +0 -15
- package/brands/engine/app/pages/DataTest.tsx +0 -78
- package/brands/engine/app/pages/Home.tsx +0 -5
- package/brands/engine/app/pages/NotFound.tsx +0 -19
- package/brands/engine/app/pages/PartnerHubDashboard.tsx +0 -2760
- package/brands/engine/app/pages/Search.tsx +0 -13
- package/brands/engine/app/router-utils.tsx +0 -35
- package/brands/engine/app/routes.tsx +0 -39
- package/brands/engine/app/styles/global.css +0 -269
- package/brands/engine/brand.css +0 -40
- package/brands/engine/engine-command-center-prd.md +0 -575
- package/brands/engine/engine-live-data.js +0 -135
- package/brands/engine/engine-sample-data.js +0 -378
- package/brands/engine/engine_logo.png +0 -0
- package/brands/engine/global.css +0 -269
- package/brands/engine/partner-hub-sample-data.js +0 -281
- package/brands/engine/schema.graphql +0 -292
- package/brands/engine/useEngineLiveData.ts +0 -49
- package/brands/engine/useEvaAgent.ts +0 -288
|
@@ -1,584 +0,0 @@
|
|
|
1
|
-
# Engine Partner Hub — Product Requirements Document
|
|
2
|
-
|
|
3
|
-
**Org:** engine-prod (`admin@tdx26-keynote-org-1.com`)
|
|
4
|
-
**Last Updated:** 2026-03-31
|
|
5
|
-
**Status:** Deployed
|
|
6
|
-
|
|
7
|
-
---
|
|
8
|
-
|
|
9
|
-
## 1. Product Overview
|
|
10
|
-
|
|
11
|
-
The **Engine Partner Hub** extends the Engine corporate travel management platform with hotel partner operations — contracts, invoices, attrition penalties, and an AI agent that can catch billing errors humans miss.
|
|
12
|
-
|
|
13
|
-
Engine manages corporate travel at scale. When a company books a block of hotel rooms and doesn't fill them, the hotel can charge an **attrition penalty**. These penalties involve multi-step calculations with resale credits, threshold percentages, and three different calculation methods defined per-contract. Errors happen. The Partner Hub Agent finds them.
|
|
14
|
-
|
|
15
|
-
### Demo Context
|
|
16
|
-
|
|
17
|
-
This build supports a two-chapter TDX26 keynote demo:
|
|
18
|
-
|
|
19
|
-
| Chapter | What | Where |
|
|
20
|
-
|---------|------|-------|
|
|
21
|
-
| **Chapter 1** | Partner Hub React app built live with Vibes 2.0 | External to Salesforce |
|
|
22
|
-
| **Chapter 2** | Partner Hub Agent catches a miscalculated penalty | Salesforce Agentforce |
|
|
23
|
-
|
|
24
|
-
### The Hero Moment
|
|
25
|
-
|
|
26
|
-
A hotel partner is charged a **$9,000** attrition penalty. The correct amount is **$6,600**. The contract specifies a 50% Partial Credit resale policy — 8 rooms were resold, generating a $2,400 credit that was never applied. The Partner Hub Agent catches this, shows the math, and escalates to a case.
|
|
27
|
-
|
|
28
|
-
---
|
|
29
|
-
|
|
30
|
-
## 2. Existing Org Context
|
|
31
|
-
|
|
32
|
-
The engine-prod org already contains Engine's travel operations:
|
|
33
|
-
|
|
34
|
-
- Custom objects: `Trip__c`, `Booking__c`, `Flight__c`, `Hotel_Reservation__c`, `Car_Rental__c`, `Travel_Policy__c`, `Disruption__c`
|
|
35
|
-
- 46 Apex classes (Agent action classes for existing agents)
|
|
36
|
-
- 6 Agentforce agents (Eva, Vee, Sales Coach, Mae, Cloe, Travel Hub)
|
|
37
|
-
- Permission sets: `Engine_Travel_Operations`, `Agentforce_Agent_Access`
|
|
38
|
-
|
|
39
|
-
The Partner Hub objects are entirely new. Account already has 44 custom fields, but none overlap with Partner Hub fields.
|
|
40
|
-
|
|
41
|
-
---
|
|
42
|
-
|
|
43
|
-
## 3. Data Model
|
|
44
|
-
|
|
45
|
-
### 3.1 Custom Objects
|
|
46
|
-
|
|
47
|
-
Six new custom objects form the Partner Hub domain model:
|
|
48
|
-
|
|
49
|
-
| Object | Name Format | Relationship | Purpose |
|
|
50
|
-
|--------|------------|--------------|---------|
|
|
51
|
-
| `Property__c` | PROP-{00000} | Master-Detail → Account | Individual hotel properties owned by partners |
|
|
52
|
-
| `Contract__c` | CNTR-{00000} | Master-Detail → Account | Partner agreements with attrition clauses, resale credit policies |
|
|
53
|
-
| `Reservation__c` | RSV-{00000} | Master-Detail → Property__c | Room bookings by customer companies |
|
|
54
|
-
| `Invoice__c` | INV-{00000} | Master-Detail → Account | Monthly partner invoices |
|
|
55
|
-
| `Invoice_Line_Item__c` | ILI-{00000} | Master-Detail → Invoice__c | Granular invoice charges (commission, penalty, fees) |
|
|
56
|
-
| `Attrition_Penalty__c` | ATR-{00000} | Lookups to Property, Contract, Account | Penalty calculations — the hero object |
|
|
57
|
-
|
|
58
|
-
### 3.2 Object Relationship Map
|
|
59
|
-
|
|
60
|
-
```
|
|
61
|
-
Account (Hotel Partner)
|
|
62
|
-
├── Property__c (MD)
|
|
63
|
-
│ └── Reservation__c (MD)
|
|
64
|
-
├── Contract__c (MD)
|
|
65
|
-
├── Invoice__c (MD)
|
|
66
|
-
│ └── Invoice_Line_Item__c (MD)
|
|
67
|
-
└── (via lookups)
|
|
68
|
-
└── Attrition_Penalty__c
|
|
69
|
-
├── → Property__c (Lookup)
|
|
70
|
-
├── → Contract__c (Lookup)
|
|
71
|
-
├── → Account (Lookup: Customer Company)
|
|
72
|
-
└── → Invoice_Line_Item__c (Lookup)
|
|
73
|
-
```
|
|
74
|
-
|
|
75
|
-
### 3.3 Standard Object Extensions
|
|
76
|
-
|
|
77
|
-
**Account** — 10 new fields:
|
|
78
|
-
|
|
79
|
-
| Field | Type | Purpose |
|
|
80
|
-
|-------|------|---------|
|
|
81
|
-
| `Partner_Tier__c` | Picklist (Gold/Silver/Bronze) | Partner classification |
|
|
82
|
-
| `Commission_Rate__c` | Percent(5,2) | Default commission rate |
|
|
83
|
-
| `Contract_Start_Date__c` | Date | Current contract start |
|
|
84
|
-
| `Contract_End_Date__c` | Date | Current contract end |
|
|
85
|
-
| `Active_Contract__c` | Formula(Checkbox) | `Contract_End_Date__c >= TODAY()` |
|
|
86
|
-
| `Partner_Status__c` | Picklist | Active, Inactive, Pending, Suspended |
|
|
87
|
-
| `Primary_Contact__c` | Lookup(Contact) | Primary partner contact |
|
|
88
|
-
| `Total_Properties__c` | Number | Property count |
|
|
89
|
-
| `Total_Reservations__c` | Number | Reservation count |
|
|
90
|
-
| `Total_Revenue__c` | Currency | Revenue total |
|
|
91
|
-
|
|
92
|
-
**Case** — 5 new fields:
|
|
93
|
-
|
|
94
|
-
| Field | Type | Purpose |
|
|
95
|
-
|-------|------|---------|
|
|
96
|
-
| `Dispute_Type__c` | Picklist | Attrition Calculation, Resale Credit, Commission Rate, Invoice Amount, Other |
|
|
97
|
-
| `Disputed_Amount__c` | Currency | Dollar amount in dispute |
|
|
98
|
-
| `Agent_Handled__c` | Checkbox | Created or handled by Agentforce |
|
|
99
|
-
| `Escalation_Reason__c` | Text Area | Why the agent escalated |
|
|
100
|
-
| `Invoice_Line_Item__c` | Lookup | Related line item |
|
|
101
|
-
|
|
102
|
-
### 3.4 Record Types
|
|
103
|
-
|
|
104
|
-
| Object | Record Type | Purpose |
|
|
105
|
-
|--------|-------------|---------|
|
|
106
|
-
| Account | `Hotel_Partner` | Hotel partner companies (Marriott, Hilton, etc.) |
|
|
107
|
-
| Account | `Customer_Company` | Corporate customers booking through Engine |
|
|
108
|
-
| Case | `Partner_Dispute` | Attrition, invoice, and commission disputes |
|
|
109
|
-
| Case | `General_Support` | General partner support questions |
|
|
110
|
-
|
|
111
|
-
### 3.5 Validation Rules
|
|
112
|
-
|
|
113
|
-
| Rule | Object | Logic |
|
|
114
|
-
|------|--------|-------|
|
|
115
|
-
| `Reservation_Checkout_After_Checkin` | Reservation__c | Check-out must be after check-in |
|
|
116
|
-
| `Contract_End_After_Start` | Contract__c | End date must be after start date |
|
|
117
|
-
| `Invoice_Period_Valid` | Invoice__c | Period end must be after period start |
|
|
118
|
-
| `Attrition_Unused_Rooms_Valid` | Attrition_Penalty__c | Actual rooms cannot exceed original block |
|
|
119
|
-
| `Invoice_Due_Date_After_Invoice_Date` | Invoice__c | Due date must be on or after invoice date |
|
|
120
|
-
|
|
121
|
-
### 3.6 Key Formula Fields
|
|
122
|
-
|
|
123
|
-
| Object | Field | Formula |
|
|
124
|
-
|--------|-------|---------|
|
|
125
|
-
| `Reservation__c` | `Number_Of_Nights__c` | `Check_Out_Date__c - Check_In_Date__c` |
|
|
126
|
-
| `Attrition_Penalty__c` | `Unused_Rooms__c` | `Original_Room_Block__c - Actual_Rooms_Used__c` |
|
|
127
|
-
| `Attrition_Penalty__c` | `Final_Penalty_Amount__c` | `Penalty_Amount_Calculated__c - Resale_Credit_Applied__c` |
|
|
128
|
-
| `Invoice_Line_Item__c` | `Total_Amount__c` | `Quantity__c * Unit_Amount__c` |
|
|
129
|
-
| `Invoice_Line_Item__c` | `Is_Commissionable__c` | `Line_Item_Type__c = "Reservation Commission"` |
|
|
130
|
-
| `Account` | `Active_Contract__c` | `Contract_End_Date__c >= TODAY()` |
|
|
131
|
-
|
|
132
|
-
---
|
|
133
|
-
|
|
134
|
-
## 4. Attrition Penalty Domain
|
|
135
|
-
|
|
136
|
-
This is the core business logic of the Partner Hub and the foundation of the hero scenario.
|
|
137
|
-
|
|
138
|
-
### 4.1 What Is Attrition?
|
|
139
|
-
|
|
140
|
-
When a corporate customer books a block of hotel rooms (e.g., 50 rooms for a conference) and doesn't fill them all, the hotel partner may charge an **attrition penalty** for the unused rooms. The penalty calculation depends on the contract between Engine and the hotel partner.
|
|
141
|
-
|
|
142
|
-
### 4.2 Three Calculation Methods
|
|
143
|
-
|
|
144
|
-
**Per Night** (most common):
|
|
145
|
-
```
|
|
146
|
-
Base Penalty = Unused_Rooms × Room_Rate × Number_of_Nights
|
|
147
|
-
```
|
|
148
|
-
|
|
149
|
-
**Cumulative** (threshold-gated):
|
|
150
|
-
```
|
|
151
|
-
If (Actual_Rooms / Original_Block) < Threshold%:
|
|
152
|
-
Base Penalty = Unused_Rooms × Room_Rate × Number_of_Nights
|
|
153
|
-
Else:
|
|
154
|
-
No penalty (usage meets threshold)
|
|
155
|
-
```
|
|
156
|
-
|
|
157
|
-
**Revenue Based**:
|
|
158
|
-
```
|
|
159
|
-
Revenue_Shortfall = (Original_Block × Rate × Nights) - (Actual_Used × Rate × Nights)
|
|
160
|
-
Base Penalty = Revenue_Shortfall × Threshold%
|
|
161
|
-
```
|
|
162
|
-
|
|
163
|
-
### 4.3 Resale Credit Policies
|
|
164
|
-
|
|
165
|
-
When unused rooms are resold to other guests, the partner may owe a credit back:
|
|
166
|
-
|
|
167
|
-
| Policy | Formula | Example (8 rooms, $200/night, 3 nights) |
|
|
168
|
-
|--------|---------|----------------------------------------|
|
|
169
|
-
| **Full Credit** | `Rooms_Resold × Rate × Nights` | 8 × $200 × 3 = $4,800 |
|
|
170
|
-
| **Partial Credit** | `Rooms_Resold × Rate × Nights × Credit%` | 8 × $200 × 3 × 50% = $2,400 |
|
|
171
|
-
| **No Credit** | $0 | $0 |
|
|
172
|
-
|
|
173
|
-
### 4.4 The Hero Scenario: The Attrition Catch
|
|
174
|
-
|
|
175
|
-
This is the centerpiece of the Chapter 2 demo.
|
|
176
|
-
|
|
177
|
-
**The Data:**
|
|
178
|
-
|
|
179
|
-
| Field | Value |
|
|
180
|
-
|-------|-------|
|
|
181
|
-
| Record | ATR-00001 |
|
|
182
|
-
| Hotel Partner | Hilton Hotels Corporation |
|
|
183
|
-
| Property | Hilton Austin Convention Center Hotel |
|
|
184
|
-
| Contract | CNTR-00004 (Per Night, 80% threshold, 50% Partial Credit) |
|
|
185
|
-
| Customer | TechCorp Inc. |
|
|
186
|
-
| Original Room Block | 50 rooms |
|
|
187
|
-
| Actual Rooms Used | 35 rooms |
|
|
188
|
-
| Unused Rooms | 15 rooms |
|
|
189
|
-
| Room Rate | $200/night |
|
|
190
|
-
| Rooms Resold | 8 |
|
|
191
|
-
|
|
192
|
-
**The Error:**
|
|
193
|
-
|
|
194
|
-
| | Recorded | Correct |
|
|
195
|
-
|---|---------|---------|
|
|
196
|
-
| Base Penalty | $9,000 | $9,000 |
|
|
197
|
-
| Resale Credit | **$0** | **$2,400** |
|
|
198
|
-
| Final Penalty | **$9,000** | **$6,600** |
|
|
199
|
-
| Status | Approved | Should be disputed |
|
|
200
|
-
|
|
201
|
-
The `Resale_Credit_Applied__c` field is $0 when it should be $2,400. The contract specifies a 50% Partial Credit policy, and 8 rooms were resold: 8 × $200 × 3 nights × 50% = **$2,400** missing credit.
|
|
202
|
-
|
|
203
|
-
**Expected Agent Behavior:**
|
|
204
|
-
|
|
205
|
-
1. Partner asks: *"Why is this attrition penalty so high?"*
|
|
206
|
-
2. Agent retrieves contract terms (Per Night method, 50% Partial Credit policy)
|
|
207
|
-
3. Agent calculates the expected penalty:
|
|
208
|
-
- Base penalty: 15 rooms × $200 × 3 nights = $9,000
|
|
209
|
-
- Resale credit: 8 rooms × $200 × 3 nights × 50% = $2,400
|
|
210
|
-
- Expected final penalty: $9,000 - $2,400 = **$6,600**
|
|
211
|
-
4. Agent identifies the $2,400 discrepancy
|
|
212
|
-
5. Agent explains: *"The 50% resale credit for 8 resold rooms was not applied"*
|
|
213
|
-
6. Agent creates a Case with full context and provides the case number
|
|
214
|
-
|
|
215
|
-
---
|
|
216
|
-
|
|
217
|
-
## 5. Automation — Apex Invocable Classes
|
|
218
|
-
|
|
219
|
-
Three Apex classes power the Partner Hub Agent actions. All use `@InvocableMethod` with `@InvocableVariable` wrapper classes for Agent Script compatibility.
|
|
220
|
-
|
|
221
|
-
### 5.1 AttritionCalculator
|
|
222
|
-
|
|
223
|
-
**Target:** `apex://AttritionCalculator`
|
|
224
|
-
|
|
225
|
-
Implements all three calculation methods and applies resale credits. Returns a step-by-step explanation string the agent can relay to the partner.
|
|
226
|
-
|
|
227
|
-
| Input | Type | Required | Description |
|
|
228
|
-
|-------|------|----------|-------------|
|
|
229
|
-
| `contractId` | String | Yes | Contract__c ID (retrieves calculation method and resale policy) |
|
|
230
|
-
| `originalRoomBlock` | Integer | Yes | Rooms originally blocked |
|
|
231
|
-
| `actualRoomsUsed` | Integer | Yes | Rooms actually used |
|
|
232
|
-
| `roomRate` | Decimal | Yes | Nightly room rate |
|
|
233
|
-
| `numberOfNights` | Integer | Yes | Stay duration |
|
|
234
|
-
| `roomsResold` | Integer | No | Unused rooms resold to other guests |
|
|
235
|
-
|
|
236
|
-
| Output | Type | Description |
|
|
237
|
-
|--------|------|-------------|
|
|
238
|
-
| `penaltyAmount` | Decimal | Base penalty before resale credit |
|
|
239
|
-
| `resaleCreditAmount` | Decimal | Resale credit amount |
|
|
240
|
-
| `finalPenaltyAmount` | Decimal | Final penalty (base - credit) |
|
|
241
|
-
| `calculationExplanation` | String | Human-readable step-by-step breakdown |
|
|
242
|
-
|
|
243
|
-
### 5.2 ContractTermsRetriever
|
|
244
|
-
|
|
245
|
-
**Target:** `apex://ContractTermsRetriever`
|
|
246
|
-
|
|
247
|
-
Retrieves the active contract for a partner and formats terms in plain English.
|
|
248
|
-
|
|
249
|
-
| Input | Type | Required | Description |
|
|
250
|
-
|-------|------|----------|-------------|
|
|
251
|
-
| `partnerId` | String | No | Account ID (hotel partner) |
|
|
252
|
-
| `propertyId` | String | No | Property__c ID |
|
|
253
|
-
| `contractId` | String | No | Contract__c ID (if known) |
|
|
254
|
-
|
|
255
|
-
| Output | Type | Description |
|
|
256
|
-
|--------|------|-------------|
|
|
257
|
-
| `contractId` | String | Contract record ID |
|
|
258
|
-
| `commissionRate` | Decimal | Commission rate % |
|
|
259
|
-
| `attritionClauseIncluded` | Boolean | Whether attrition clause applies |
|
|
260
|
-
| `attritionCalculationMethod` | String | Per Night, Cumulative, or Revenue Based |
|
|
261
|
-
| `attritionThresholdPercentage` | Decimal | Threshold % |
|
|
262
|
-
| `resaleCreditPolicy` | String | Full Credit, Partial Credit, or No Credit |
|
|
263
|
-
| `resaleCreditPercentage` | Decimal | Resale credit % |
|
|
264
|
-
| `contractTermsSummary` | String | Human-readable summary |
|
|
265
|
-
|
|
266
|
-
### 5.3 CaseEscalationHandler
|
|
267
|
-
|
|
268
|
-
**Target:** `apex://CaseEscalationHandler`
|
|
269
|
-
|
|
270
|
-
Creates a Partner Dispute case with full context when the agent finds a discrepancy or the partner requests escalation.
|
|
271
|
-
|
|
272
|
-
| Input | Type | Required | Description |
|
|
273
|
-
|-------|------|----------|-------------|
|
|
274
|
-
| `attritionPenaltyId` | String | Yes | Attrition Penalty record ID |
|
|
275
|
-
| `partnerQuestion` | String | Yes | The partner's original question |
|
|
276
|
-
| `agentAnalysis` | String | Yes | The agent's findings |
|
|
277
|
-
| `escalationReason` | String | No | Why the case was escalated |
|
|
278
|
-
|
|
279
|
-
| Output | Type | Description |
|
|
280
|
-
|--------|------|-------------|
|
|
281
|
-
| `caseId` | String | Created case record ID |
|
|
282
|
-
| `caseNumber` | String | Created case number |
|
|
283
|
-
|
|
284
|
-
---
|
|
285
|
-
|
|
286
|
-
## 6. Agentforce: Partner Hub Agent
|
|
287
|
-
|
|
288
|
-
### 6.1 Agent Configuration
|
|
289
|
-
|
|
290
|
-
| Property | Value |
|
|
291
|
-
|----------|-------|
|
|
292
|
-
| **Developer Name** | `Partner_Hub_Agent` |
|
|
293
|
-
| **Type** | `AgentforceEmployeeAgent` |
|
|
294
|
-
| **Authoring Method** | Agent Script (AiAuthoringBundle) |
|
|
295
|
-
| **Status** | Published and Activated |
|
|
296
|
-
|
|
297
|
-
### 6.2 System Instructions
|
|
298
|
-
|
|
299
|
-
> You are the Partner Hub Agent for Engine, a corporate travel management platform. You assist hotel partners with questions about invoices, attrition penalties, and contract terms. Your primary expertise is explaining attrition penalty calculations. Always cite specific contract terms and show your calculations. Be precise with numbers. When you lack confidence or cannot answer, escalate to a human using the Escalate to Case action. You cannot modify invoices, waive penalties, or change contract terms — you can only explain and escalate.
|
|
300
|
-
|
|
301
|
-
### 6.3 Topics
|
|
302
|
-
|
|
303
|
-
| Topic | Label | Purpose |
|
|
304
|
-
|-------|-------|---------|
|
|
305
|
-
| `attrition_penalty` | Attrition Penalty Explanation | **Hero topic.** Explains calculations, finds discrepancies, escalates disputes. |
|
|
306
|
-
| `invoice_inquiry` | Invoice Inquiry | Answers questions about totals, due dates, line items, status. |
|
|
307
|
-
| `contract_terms` | Contract Terms | Retrieves and explains contract terms in plain English. |
|
|
308
|
-
| `general_support` | General Partner Support | Handles general questions, routes to appropriate topics. |
|
|
309
|
-
| `off_topic` | Off Topic | Redirects off-topic requests back to Partner Hub services. |
|
|
310
|
-
|
|
311
|
-
### 6.4 Actions Wired to Topics
|
|
312
|
-
|
|
313
|
-
The `attrition_penalty` topic (hero) has all three Apex actions:
|
|
314
|
-
|
|
315
|
-
| Reasoning Action | Target Action | Purpose |
|
|
316
|
-
|-----------------|---------------|---------|
|
|
317
|
-
| `retrieve_terms` | `@actions.retrieve_contract_terms` | Get contract terms (method, threshold, resale policy) |
|
|
318
|
-
| `calculate_penalty` | `@actions.calculate_attrition_penalty` | Calculate expected penalty with step-by-step math |
|
|
319
|
-
| `create_case` | `@actions.escalate_to_case` | Create case when discrepancy found |
|
|
320
|
-
| `set_penalty_id` / `set_partner_id` / `set_contract_id` | `@utils.setVariables` | Store IDs from conversation context |
|
|
321
|
-
|
|
322
|
-
The `contract_terms` topic has `retrieve_contract_terms` for standalone contract inquiries.
|
|
323
|
-
|
|
324
|
-
### 6.5 Agent Guardrails
|
|
325
|
-
|
|
326
|
-
**Can do:**
|
|
327
|
-
- Explain attrition penalties with specific contract terms and calculations
|
|
328
|
-
- Identify calculation errors by comparing expected vs. recorded penalties
|
|
329
|
-
- Retrieve and explain contract terms
|
|
330
|
-
- Answer invoice questions (totals, due dates, line items)
|
|
331
|
-
- Escalate disputes to Case with full context
|
|
332
|
-
|
|
333
|
-
**Cannot do:**
|
|
334
|
-
- Modify invoices or attrition penalties
|
|
335
|
-
- Waive attrition penalties
|
|
336
|
-
- Change contract terms
|
|
337
|
-
- Process payments
|
|
338
|
-
- Answer questions outside the Partner Hub domain
|
|
339
|
-
|
|
340
|
-
---
|
|
341
|
-
|
|
342
|
-
## 7. Security
|
|
343
|
-
|
|
344
|
-
### 7.1 Permission Sets
|
|
345
|
-
|
|
346
|
-
| Permission Set | Access Level | Assigned To |
|
|
347
|
-
|---------------|-------------|-------------|
|
|
348
|
-
| `Partner_Operations` | Full CRUD + View All / Modify All on all Partner Hub objects | System Administrators, Operations team |
|
|
349
|
-
| `Partner_Operations_ReadOnly` | Read + View All on all Partner Hub objects | Analysts, Executives |
|
|
350
|
-
| `Agentforce_Partner_Agent` | Read all + Create Case + Update Attrition_Penalty__c | Agent user |
|
|
351
|
-
|
|
352
|
-
### 7.2 Custom Tabs
|
|
353
|
-
|
|
354
|
-
All six custom objects have tabs deployed: `Property__c`, `Contract__c`, `Reservation__c`, `Invoice__c`, `Invoice_Line_Item__c`, `Attrition_Penalty__c`.
|
|
355
|
-
|
|
356
|
-
---
|
|
357
|
-
|
|
358
|
-
## 8. Sample Data (Deployed)
|
|
359
|
-
|
|
360
|
-
| Data | Count | Notes |
|
|
361
|
-
|------|-------|-------|
|
|
362
|
-
| Hotel Partner Accounts | 12 | Gold, Silver, Bronze tiers across major chains |
|
|
363
|
-
| Properties | 35 | Distributed across partners (1-5 per partner) |
|
|
364
|
-
| Contracts | 12 | All Active; mix of Per Night, Cumulative, Revenue Based |
|
|
365
|
-
| Reservations | 50 | Varied statuses (Confirmed, Checked Out, Cancelled) |
|
|
366
|
-
| Invoices | 24 | Monthly invoices for partners |
|
|
367
|
-
| Invoice Line Items | 50 | Reservation Commission and Attrition Penalty types |
|
|
368
|
-
| Attrition Penalties | 6 | Including hero scenario (ATR-00001) |
|
|
369
|
-
| Cases | 29 | Partner disputes and general support |
|
|
370
|
-
| Contacts | 110 | Partner contacts across all accounts |
|
|
371
|
-
|
|
372
|
-
### Key Partners
|
|
373
|
-
|
|
374
|
-
| Partner | Tier | Calculation Method | Resale Policy |
|
|
375
|
-
|---------|------|--------------------|---------------|
|
|
376
|
-
| Marriott International | Gold | Per Night | Full Credit |
|
|
377
|
-
| Hilton Hotels Corporation | Gold | Per Night | Partial Credit (50%) |
|
|
378
|
-
| Hyatt Hotels Corporation | Silver | Cumulative | Partial Credit (50%) |
|
|
379
|
-
| InterContinental Hotels Group | Gold | Revenue Based | No Credit |
|
|
380
|
-
| Wyndham Hotels & Resorts | Silver | Per Night | Full Credit |
|
|
381
|
-
| Best Western Hotels | Bronze | Cumulative | No Credit |
|
|
382
|
-
|
|
383
|
-
### Attrition Penalty Records
|
|
384
|
-
|
|
385
|
-
| ID | Status | Penalty | Resale Credit | Notes |
|
|
386
|
-
|----|--------|---------|---------------|-------|
|
|
387
|
-
| ATR-00001 | Approved | $9,000 | **$0** | **HERO SCENARIO** — $2,400 credit missing |
|
|
388
|
-
| ATR-00002 | Reviewed | $2,500 | $625 | Correctly calculated |
|
|
389
|
-
| ATR-00003 | Approved | $3,000 | $1,200 | Correctly calculated |
|
|
390
|
-
| ATR-00004 | Calculated | $1,925 | $275 | Correctly calculated |
|
|
391
|
-
| ATR-00005 | Disputed | $1,800 | $540 | Partner-initiated dispute |
|
|
392
|
-
| ATR-00006 | Approved | $2,800 | $525 | Correctly calculated |
|
|
393
|
-
|
|
394
|
-
---
|
|
395
|
-
|
|
396
|
-
## 9. Build Inventory
|
|
397
|
-
|
|
398
|
-
### Metadata Deployed
|
|
399
|
-
|
|
400
|
-
| Category | Items |
|
|
401
|
-
|----------|-------|
|
|
402
|
-
| Custom Objects | 6 (Property, Contract, Reservation, Invoice, Invoice_Line_Item, Attrition_Penalty) |
|
|
403
|
-
| Custom Fields (on custom objects) | ~90 |
|
|
404
|
-
| Custom Fields (on Account) | 10 |
|
|
405
|
-
| Custom Fields (on Case) | 5 |
|
|
406
|
-
| Validation Rules | 5 |
|
|
407
|
-
| Record Types | 4 (2 on Account, 2 on Case) |
|
|
408
|
-
| Business Processes | 2 (Case: Partner_Dispute, General_Support) |
|
|
409
|
-
| Apex Classes | 4 (AttritionCalculator, ContractTermsRetriever, CaseEscalationHandler, PartnerHubApexTest) |
|
|
410
|
-
| Permission Sets | 3 (Partner_Operations, Partner_Operations_ReadOnly, Agentforce_Partner_Agent) |
|
|
411
|
-
| Custom Tabs | 6 |
|
|
412
|
-
| AiAuthoringBundle | 1 (Partner_Hub_Agent) |
|
|
413
|
-
|
|
414
|
-
### Source Files
|
|
415
|
-
|
|
416
|
-
| Path | Contents |
|
|
417
|
-
|------|----------|
|
|
418
|
-
| `force-app/main/default/objects/` | All custom object and field metadata |
|
|
419
|
-
| `force-app/main/default/classes/` | Apex classes and test class |
|
|
420
|
-
| `force-app/main/default/permissionsets/` | Three permission sets |
|
|
421
|
-
| `force-app/main/default/tabs/` | Six custom tabs |
|
|
422
|
-
| `force-app/main/default/aiAuthoringBundles/Partner_Hub_Agent/` | Agent Script (.agent) and bundle metadata |
|
|
423
|
-
| `scripts/load-partner-hub-data.apex` | Anonymous Apex data loading script |
|
|
424
|
-
|
|
425
|
-
---
|
|
426
|
-
|
|
427
|
-
## 10. Partner Hub Dashboard
|
|
428
|
-
|
|
429
|
-
This section defines the Command Center dashboard for the Partner Hub. The agent building this dashboard should use the component library from `@/components/library` and wire all data through `useDataSource({ sample, live })`.
|
|
430
|
-
|
|
431
|
-
### 10.1 Sample Data File
|
|
432
|
-
|
|
433
|
-
Import from `@/data/partner-hub-sample-data.js`. Key exports:
|
|
434
|
-
|
|
435
|
-
| Export | Type | Use for |
|
|
436
|
-
|--------|------|---------|
|
|
437
|
-
| `PARTNERS` | Array | Partner list, tier breakdown |
|
|
438
|
-
| `CONTRACTS` | Array | Contract table, expiration tracking |
|
|
439
|
-
| `INVOICES` | Array | Invoice list, overdue tracking |
|
|
440
|
-
| `ATTRITION_PENALTIES` | Array | Penalty table (includes hero ATR-00001) |
|
|
441
|
-
| `DISPUTES` | Array | Open dispute cards |
|
|
442
|
-
| `RECENT_ACTIVITY` | Array | Activity feed |
|
|
443
|
-
| `METRICS` | Object | Pre-computed KPIs (activePartners, totalRevenue, openDisputes, etc.) |
|
|
444
|
-
| `PARTNER_TIER_CHART` | Array | Pie/bar chart data (Gold/Silver/Bronze) |
|
|
445
|
-
| `REVENUE_BY_PARTNER` | Array | Horizontal bar chart data |
|
|
446
|
-
| `INVOICE_TREND` | Array | Monthly line/area chart data |
|
|
447
|
-
| `PENALTY_TABLE_ITEMS` | Array | Pre-formatted table rows |
|
|
448
|
-
| `DISPUTE_CARDS` | Array | Pre-formatted dispute list items |
|
|
449
|
-
| `INVOICE_CARDS` | Array | Pre-formatted invoice list items |
|
|
450
|
-
| `EXPIRING_CONTRACTS` | Array | Contracts expiring within 6 months |
|
|
451
|
-
|
|
452
|
-
### 10.2 Layout Pattern
|
|
453
|
-
|
|
454
|
-
**Grid-first layout** (no hero map — this is a data-operations dashboard, not a geo dashboard).
|
|
455
|
-
|
|
456
|
-
```
|
|
457
|
-
┌─────────────────────────────────────────────────────────────┐
|
|
458
|
-
│ Header: Engine logo · "Partner Hub" · theme toggle │
|
|
459
|
-
├──────────┬──────────┬──────────┬──────────┬────────────────┤
|
|
460
|
-
│ Active │ Total │ Open │ Overdue │ Penalties │
|
|
461
|
-
│ Partners │ Revenue │ Disputes │ Invoices │ Under Review │
|
|
462
|
-
│ MetricCard MetricCard MetricCard MetricCard MetricCard │
|
|
463
|
-
├──────────────────────────────┬──────────────────────────────┤
|
|
464
|
-
│ Attrition Penalties │ Open Disputes │
|
|
465
|
-
│ TableCard │ ListCard │
|
|
466
|
-
│ (6 rows, status badges, │ (priority badges, amounts, │
|
|
467
|
-
│ highlight ATR-00001 hero) │ agent-handled indicator) │
|
|
468
|
-
├──────────────────────────────┬──────────────────────────────┤
|
|
469
|
-
│ Revenue by Partner │ Partner Tier Breakdown │
|
|
470
|
-
│ ChartCard (horizontal bar) │ ChartCard (donut/pie) │
|
|
471
|
-
├──────────────────────────────┬──────────────────────────────┤
|
|
472
|
-
│ Pending Invoices │ Expiring Contracts │
|
|
473
|
-
│ ListCard (overdue first, │ ListCard (sorted by date, │
|
|
474
|
-
│ status badges, amounts) │ warning badges) │
|
|
475
|
-
├──────────────────────────────┴──────────────────────────────┤
|
|
476
|
-
│ Invoice Trend │
|
|
477
|
-
│ ChartCard (area chart — monthly totals + commission) │
|
|
478
|
-
├─────────────────────────────────────────────────────────────┤
|
|
479
|
-
│ Recent Activity │
|
|
480
|
-
│ ActivityCard (feed of partner operations events) │
|
|
481
|
-
└─────────────────────────────────────────────────────────────┘
|
|
482
|
-
```
|
|
483
|
-
|
|
484
|
-
### 10.3 KPI Row (5 MetricCards)
|
|
485
|
-
|
|
486
|
-
| # | Title | Value Source | Subtitle | Icon |
|
|
487
|
-
|---|-------|-------------|----------|------|
|
|
488
|
-
| 1 | Active Partners | `METRICS.activePartners` | "hotel partners" | `BuildingOfficeIcon` |
|
|
489
|
-
| 2 | Total Revenue | `METRICS.totalRevenue` (format as $XXXk) | "all-time partner revenue" | `BanknotesIcon` |
|
|
490
|
-
| 3 | Open Disputes | `METRICS.openDisputes` | "need resolution" | `ExclamationTriangleIcon` |
|
|
491
|
-
| 4 | Overdue Invoices | `METRICS.overdueInvoices` | "past due date" | `ClockIcon` |
|
|
492
|
-
| 5 | Penalties | `METRICS.totalPenalties` (format as $XXk) | "total attrition penalties" | `ShieldCheckIcon` |
|
|
493
|
-
|
|
494
|
-
### 10.4 Panel Definitions
|
|
495
|
-
|
|
496
|
-
**Attrition Penalties Table** (`TableCard`)
|
|
497
|
-
- Data: `PENALTY_TABLE_ITEMS`
|
|
498
|
-
- Columns: Name, Partner, Customer, Method, Penalty ($), Credit ($), Status
|
|
499
|
-
- Highlight row where `isHero === true` (ATR-00001) with a subtle accent background or badge
|
|
500
|
-
- Status badges: Approved (green), Reviewed (blue), Calculated (gray), Disputed (red)
|
|
501
|
-
|
|
502
|
-
**Open Disputes** (`ListCard`)
|
|
503
|
-
- Data: `DISPUTE_CARDS`
|
|
504
|
-
- Show priority badge, disputed amount, and whether agent-handled (small indicator)
|
|
505
|
-
- Sort: High priority first
|
|
506
|
-
|
|
507
|
-
**Revenue by Partner** (`ChartCard` + `D3Chart`)
|
|
508
|
-
- Data: `REVENUE_BY_PARTNER`
|
|
509
|
-
- Chart type: Horizontal bar chart (`D3ChartTemplates.bar` with horizontal orientation)
|
|
510
|
-
- Shows top partners sorted by revenue
|
|
511
|
-
|
|
512
|
-
**Partner Tier Breakdown** (`ChartCard` + `D3Chart`)
|
|
513
|
-
- Data: `PARTNER_TIER_CHART`
|
|
514
|
-
- Chart type: Donut/pie chart
|
|
515
|
-
- Colors: Gold (#FFC107), Silver (#90A4AE), Bronze (#CD7F32)
|
|
516
|
-
|
|
517
|
-
**Pending Invoices** (`ListCard`)
|
|
518
|
-
- Data: `INVOICE_CARDS`
|
|
519
|
-
- Show amount, due date, status badge
|
|
520
|
-
- Overdue items should appear first with critical styling
|
|
521
|
-
|
|
522
|
-
**Expiring Contracts** (`ListCard`)
|
|
523
|
-
- Data: `EXPIRING_CONTRACTS`
|
|
524
|
-
- Show expiration date, calculation method, resale policy
|
|
525
|
-
- Warning badge for contracts expiring soon
|
|
526
|
-
|
|
527
|
-
**Invoice Trend** (`ChartCard` + `D3Chart`)
|
|
528
|
-
- Data: `INVOICE_TREND`
|
|
529
|
-
- Chart type: Area chart with two series (total invoiced, commission earned)
|
|
530
|
-
- Full width
|
|
531
|
-
|
|
532
|
-
**Recent Activity** (`ActivityCard`)
|
|
533
|
-
- Data: `RECENT_ACTIVITY`
|
|
534
|
-
- Status mapping: alert → red, warning → amber, success → green, info → blue
|
|
535
|
-
|
|
536
|
-
### 10.5 Brand Tokens
|
|
537
|
-
|
|
538
|
-
Use Engine brand colors from `global.css` (applied via `npm run brand:engine`):
|
|
539
|
-
|
|
540
|
-
| Token | Hex | Usage |
|
|
541
|
-
|-------|-----|-------|
|
|
542
|
-
| Engine Black | `#0D1117` | Dark backgrounds |
|
|
543
|
-
| Cyan | `#7DCBD9` | Primary accent, links, active states |
|
|
544
|
-
| Yellow/Orange | `#FD4B23` | Alerts, critical badges |
|
|
545
|
-
| Green | `#1E9D6D` | Success, approved status |
|
|
546
|
-
| Blue | `#157DE5` | Info badges, charts |
|
|
547
|
-
| Red | `#FFB200` | Warnings (amber) |
|
|
548
|
-
|
|
549
|
-
### 10.6 Dark Mode
|
|
550
|
-
|
|
551
|
-
All panels must support dark mode via `useThemeMode()`. Use slate scale colors (`text-slate-900 dark:text-slate-100`, `bg-slate-50 dark:bg-slate-900`) for any custom markup. Library components handle dark mode automatically.
|
|
552
|
-
|
|
553
|
-
### 10.7 Wiring Checklist
|
|
554
|
-
|
|
555
|
-
After building the dashboard:
|
|
556
|
-
1. Update `CommandCenter.tsx` to import `PartnerHubDashboard`
|
|
557
|
-
2. Rewrite `Home.tsx` to render `<CommandCenter />`
|
|
558
|
-
3. Update `routes.tsx` — set index route label to "Partner Hub"
|
|
559
|
-
|
|
560
|
-
---
|
|
561
|
-
|
|
562
|
-
## 11. Success Criteria
|
|
563
|
-
|
|
564
|
-
### Must Pass (Demo Blockers)
|
|
565
|
-
|
|
566
|
-
1. Agent correctly identifies the $2,400 discrepancy in ATR-00001
|
|
567
|
-
2. Agent explains that the 50% Partial Credit resale policy was not applied
|
|
568
|
-
3. Agent shows the math: 8 rooms x $200 x 3 nights x 50% = $2,400
|
|
569
|
-
4. Agent creates a Case with full context (partner question, analysis, penalty details)
|
|
570
|
-
5. Agent provides the Case number to the partner
|
|
571
|
-
|
|
572
|
-
### Should Pass (Agent Quality)
|
|
573
|
-
|
|
574
|
-
6. All three attrition calculation methods produce correct results
|
|
575
|
-
7. All three resale credit policies (Full, Partial, No Credit) apply correctly
|
|
576
|
-
8. Agent can retrieve and explain contract terms in plain English
|
|
577
|
-
9. Agent routes off-topic questions back to Partner Hub services
|
|
578
|
-
10. Agent transitions cleanly between topics (attrition → contract terms → escalation)
|
|
579
|
-
|
|
580
|
-
### Nice to Have
|
|
581
|
-
|
|
582
|
-
11. Invoice inquiry topic answers questions about totals, due dates, and line items
|
|
583
|
-
12. Agent handles edge cases gracefully (no contract found, zero unused rooms)
|
|
584
|
-
13. Permission sets enforce correct access boundaries
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Agentforce Agent API Configuration
|
|
3
|
-
*
|
|
4
|
-
* These values connect the ChatBar to the real Agentforce agent (Eva)
|
|
5
|
-
* via the REST-based Agent API instead of the iframe-based
|
|
6
|
-
* AgentforceConversationClient.
|
|
7
|
-
*
|
|
8
|
-
* Flow: OAuth token → create session → send messages → end session
|
|
9
|
-
*
|
|
10
|
-
* All requests are proxied through the Vite dev server to avoid CORS.
|
|
11
|
-
* See vite.config.ts proxy rules:
|
|
12
|
-
* /sf-oauth/* → myDomainUrl (for OAuth token)
|
|
13
|
-
* /sf-agent/* → agentApiBaseUrl (for Agent API calls)
|
|
14
|
-
*/
|
|
15
|
-
|
|
16
|
-
export const AGENT_API_CONFIG = {
|
|
17
|
-
myDomainUrl: "https://tdx26-keynote-org-1com.my.salesforce.com",
|
|
18
|
-
|
|
19
|
-
clientId:
|
|
20
|
-
"3MVG9Gm6vbdjgMWSOIAuIN3VSB5Rju6PgYQ5rl1yH3bVTTg9E2as4.C61Q0cyT.zqv2vUWNaxrm.A7SW5o3t7",
|
|
21
|
-
clientSecret:
|
|
22
|
-
"9ADF795A183A6B074A2E4B4CB1748B8DF7090C74191AF1C190213B512A733E03",
|
|
23
|
-
|
|
24
|
-
agentId: "0Xxa5000000rQlxCAE",
|
|
25
|
-
|
|
26
|
-
agentApiBaseUrl: "https://api.salesforce.com",
|
|
27
|
-
|
|
28
|
-
bypassUser: true,
|
|
29
|
-
|
|
30
|
-
demoTraveler: {
|
|
31
|
-
contactId: "003a500000mj4TlAAI",
|
|
32
|
-
email: "sarah.chen@arcline.ai",
|
|
33
|
-
firstName: "Sarah",
|
|
34
|
-
lastName: "Chen",
|
|
35
|
-
},
|
|
36
|
-
};
|