@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.
Files changed (94) hide show
  1. package/.a4drules/skills/command-center-builder/SKILL.md +3 -2
  2. package/.a4drules/skills/component-library/SKILL.md +50 -4
  3. package/.a4drules/skills/component-library/card-components.md +88 -0
  4. package/.a4drules/skills/component-library/when-to-use.md +1 -0
  5. package/CHANGELOG.md +40 -0
  6. package/CLAUDE.md +12 -13
  7. package/README.md +0 -15
  8. package/dist/components/library/cards/KanbanBoard.js +313 -0
  9. package/dist/components/library/cards/KanbanBoard.js.map +1 -0
  10. package/dist/components/library/index.js +60 -57
  11. package/dist/components/library/index.js.map +1 -1
  12. package/dist/components/workspace/ComponentRegistry.js +5 -2
  13. package/dist/components/workspace/ComponentRegistry.js.map +1 -1
  14. package/dist/index.js +84 -82
  15. package/dist/index.js.map +1 -1
  16. package/dist/styles/global.css +44 -57
  17. package/package.json +7 -2
  18. package/scripts/apply-brand.mjs +47 -30
  19. package/scripts/postinstall.mjs +1 -11
  20. package/src/components/library/cards/KanbanBoard.jsx +507 -0
  21. package/src/components/library/index.jsx +1 -0
  22. package/src/styles/global.css +44 -57
  23. package/brands/engine/PARTNER_HUB_PRD.md +0 -584
  24. package/brands/engine/agentApiConfig.ts +0 -36
  25. package/brands/engine/app/api/graphql-operations-types.ts +0 -11260
  26. package/brands/engine/app/api/graphqlClient.ts +0 -25
  27. package/brands/engine/app/api/partnerQueries.ts +0 -212
  28. package/brands/engine/app/appLayout.tsx +0 -5
  29. package/brands/engine/app/components/AgentPanel.tsx +0 -541
  30. package/brands/engine/app/components/AgentforceConversationClient.tsx +0 -201
  31. package/brands/engine/app/components/Data360Widget.tsx +0 -301
  32. package/brands/engine/app/components/__inherit_AgentforceConversationClient.tsx +0 -3
  33. package/brands/engine/app/components/alerts/status-alert.tsx +0 -49
  34. package/brands/engine/app/components/layouts/card-layout.tsx +0 -29
  35. package/brands/engine/app/components/workspace/CommandCenter.tsx +0 -16
  36. package/brands/engine/app/config/agentApi.ts +0 -36
  37. package/brands/engine/app/data/partner-hub-sample-data.js +0 -297
  38. package/brands/engine/app/features/object-search/__examples__/api/accountSearchService.ts +0 -46
  39. package/brands/engine/app/features/object-search/__examples__/api/query/distinctAccountIndustries.graphql +0 -19
  40. package/brands/engine/app/features/object-search/__examples__/api/query/distinctAccountTypes.graphql +0 -19
  41. package/brands/engine/app/features/object-search/__examples__/api/query/getAccountDetail.graphql +0 -121
  42. package/brands/engine/app/features/object-search/__examples__/api/query/searchAccounts.graphql +0 -51
  43. package/brands/engine/app/features/object-search/__examples__/pages/AccountObjectDetailPage.tsx +0 -357
  44. package/brands/engine/app/features/object-search/__examples__/pages/AccountSearch.tsx +0 -312
  45. package/brands/engine/app/features/object-search/__examples__/pages/Home.tsx +0 -34
  46. package/brands/engine/app/features/object-search/api/objectSearchService.ts +0 -84
  47. package/brands/engine/app/features/object-search/components/ActiveFilters.tsx +0 -89
  48. package/brands/engine/app/features/object-search/components/FilterContext.tsx +0 -83
  49. package/brands/engine/app/features/object-search/components/ObjectBreadcrumb.tsx +0 -66
  50. package/brands/engine/app/features/object-search/components/PaginationControls.tsx +0 -109
  51. package/brands/engine/app/features/object-search/components/SearchBar.tsx +0 -41
  52. package/brands/engine/app/features/object-search/components/SortControl.tsx +0 -143
  53. package/brands/engine/app/features/object-search/components/filters/BooleanFilter.tsx +0 -78
  54. package/brands/engine/app/features/object-search/components/filters/DateFilter.tsx +0 -128
  55. package/brands/engine/app/features/object-search/components/filters/DateRangeFilter.tsx +0 -70
  56. package/brands/engine/app/features/object-search/components/filters/FilterFieldWrapper.tsx +0 -33
  57. package/brands/engine/app/features/object-search/components/filters/MultiSelectFilter.tsx +0 -97
  58. package/brands/engine/app/features/object-search/components/filters/NumericRangeFilter.tsx +0 -163
  59. package/brands/engine/app/features/object-search/components/filters/SearchFilter.tsx +0 -50
  60. package/brands/engine/app/features/object-search/components/filters/SelectFilter.tsx +0 -97
  61. package/brands/engine/app/features/object-search/components/filters/TextFilter.tsx +0 -91
  62. package/brands/engine/app/features/object-search/hooks/useAsyncData.ts +0 -54
  63. package/brands/engine/app/features/object-search/hooks/useCachedAsyncData.ts +0 -184
  64. package/brands/engine/app/features/object-search/hooks/useDebouncedCallback.ts +0 -34
  65. package/brands/engine/app/features/object-search/hooks/useObjectSearchParams.ts +0 -252
  66. package/brands/engine/app/features/object-search/utils/debounce.ts +0 -25
  67. package/brands/engine/app/features/object-search/utils/fieldUtils.ts +0 -29
  68. package/brands/engine/app/features/object-search/utils/filterUtils.ts +0 -404
  69. package/brands/engine/app/features/object-search/utils/sortUtils.ts +0 -38
  70. package/brands/engine/app/hooks/useEngineLiveData.ts +0 -49
  71. package/brands/engine/app/hooks/useEvaAgent.ts +0 -288
  72. package/brands/engine/app/hooks/usePartnerDashboardData.ts +0 -141
  73. package/brands/engine/app/navigationMenu.tsx +0 -80
  74. package/brands/engine/app/pages/AccountObjectDetailPage.tsx +0 -361
  75. package/brands/engine/app/pages/AccountSearch.tsx +0 -305
  76. package/brands/engine/app/pages/BlankDashboard.tsx +0 -15
  77. package/brands/engine/app/pages/DataTest.tsx +0 -78
  78. package/brands/engine/app/pages/Home.tsx +0 -5
  79. package/brands/engine/app/pages/NotFound.tsx +0 -19
  80. package/brands/engine/app/pages/PartnerHubDashboard.tsx +0 -2760
  81. package/brands/engine/app/pages/Search.tsx +0 -13
  82. package/brands/engine/app/router-utils.tsx +0 -35
  83. package/brands/engine/app/routes.tsx +0 -39
  84. package/brands/engine/app/styles/global.css +0 -269
  85. package/brands/engine/brand.css +0 -40
  86. package/brands/engine/engine-command-center-prd.md +0 -575
  87. package/brands/engine/engine-live-data.js +0 -135
  88. package/brands/engine/engine-sample-data.js +0 -378
  89. package/brands/engine/engine_logo.png +0 -0
  90. package/brands/engine/global.css +0 -269
  91. package/brands/engine/partner-hub-sample-data.js +0 -281
  92. package/brands/engine/schema.graphql +0 -292
  93. package/brands/engine/useEngineLiveData.ts +0 -49
  94. package/brands/engine/useEvaAgent.ts +0 -288
@@ -1,575 +0,0 @@
1
- # Engine Travel Command Center
2
-
3
- Product Requirements Document
4
-
5
- ---
6
-
7
- ## 1. Product Overview
8
-
9
- The Engine Travel Command Center is a real-time operations dashboard for corporate travel managers who use Engine (engine.com). It gives a single-screen view of every active traveler, booking, flight, policy flag, and agent interaction — built on Salesforce Data Cloud.
10
-
11
- **Build approach:** Incremental — PRD → dashboard → data → agent.
12
-
13
- ---
14
-
15
- ## 2. Users
16
-
17
- **Primary — Sarah Chen, Travel Manager at Acme Corp**
18
- Manages Acme's travel program: bookings, policy enforcement, exceptions, traveler monitoring.
19
-
20
- **Secondary — Eva (Agentforce Agent)**
21
- Engine's Agentforce-powered AI agent. Handles traveler requests autonomously — booking changes, policy questions, itinerary lookups. Resolves ~30% of requests without human involvement. Surfaces via `ChatBar` below the hero map.
22
-
23
- ---
24
-
25
- ## 3. Brand Tokens
26
-
27
- Update `src/styles/global.css` — replace the existing `--color-brand-*` palette inside the `@theme inline` block:
28
-
29
- ```css
30
- --color-brand-50: #ECFDF9;
31
- --color-brand-100: #D1FAF0;
32
- --color-brand-200: #A7F3E1;
33
- --color-brand-300: #6EE7C8;
34
- --color-brand-400: #34D3AB;
35
- --color-brand-500: #5BC8C8;
36
- --color-brand-600: #0D9488;
37
- --color-brand-700: #0F766E;
38
- --color-brand-800: #115E59;
39
- --color-brand-900: #134E4A;
40
- --color-brand-950: #042F2E;
41
- --color-engine-savings: #16A34A;
42
- ```
43
-
44
- Use `brand-*` Tailwind classes for brand elements. Tailwind built-in colors (green, amber, red) for status. No hardcoded hex in components.
45
-
46
- **Typography:** Inter (already `--font-sans`). **Icons:** Heroicons 2 (`@heroicons/react`).
47
-
48
- ---
49
-
50
- ## 4. Architecture
51
-
52
- - **Dashboard file:** `src/pages/EngineDashboard.tsx`
53
- - **Wiring:** `CommandCenter.tsx` imports and renders `EngineDashboard` inside the existing provider stack. Never recreate providers in the dashboard. When updating `CommandCenter.tsx`, only change the dashboard import line — preserve the `heroui-scope` wrapper div and `Toast.Provider` from `@heroui/react` exactly as-is.
54
- - **Toasts:** Import `toast` from `@heroui/react` in dashboard pages. Use `toast.success("message")` for success toasts and `toast("message")` for informational ones. The `Toast.Provider` in CommandCenter handles rendering — do not add a second `Toaster` or replace the existing provider.
55
- - **Imports:** Components from `@/components/library`. Theme from `@/components/library/theme/AppThemeProvider`.
56
- - **Salesforce metadata:** This is an SFDX project. Metadata lives in `force-app/main/default/`. When creating permission sets, custom fields, flows, or other metadata, write standard SFDX XML files and deploy with `sf project deploy start`.
57
-
58
- ---
59
-
60
- ## 5. Layout
61
-
62
- Visualization-hero layout. Full-page scroll (no `h-screen`).
63
-
64
- ```
65
- ┌──────────────────────────────────────────────────────────────┐
66
- │ HEADER (h-12, sticky, bg-slate-900) │
67
- │ Engine logo + "Travel Command Center" + badge | actions │
68
- ├──────────────────────────────────────────────────────────────┤
69
- │ HERO MAP (h-[520px], GeoMap, relative) │
70
- │ ┌─ glass KPI overlays (absolute top-left) ───────────────┐ │
71
- │ │ Active Travelers | Spend MTD | Compliance | Eva Resolved│ │
72
- │ └────────────────────────────────────────────────────────┘ │
73
- │ ┌─ flight status strip (absolute bottom) ────────────────┐ │
74
- │ │ BA 286 · In Air | NH 109 · In Air | LH 431 · Delayed │ │
75
- │ └────────────────────────────────────────────────────────┘ │
76
- ├──────────────────────────────────────────────────────────────┤
77
- │ EVA CHATBAR (px-4 pt-4, full-width command palette strip) │
78
- ├──────────────────────────────────────────────────────────────┤
79
- │ DATA PANELS (px-4 py-5 space-y-6) │
80
- │ │
81
- │ Row 1: grid grid-cols-1 items-start gap-4 lg:grid-cols-3 │
82
- │ ┌── 2/3 (lg:col-span-2) ──────┐ ┌── 1/3 ───────────────┐ │
83
- │ │ Escalations (custom panel) │ │ Disruptions (custom) │ │
84
- │ └───────────────────────────────┘ └──────────────────────┘ │
85
- │ │
86
- │ Row 2: grid grid-cols-1 items-start gap-4 lg:grid-cols-3 │
87
- │ ┌── 2/3 (lg:col-span-2) ──────┐ ┌── 1/3 ───────────────┐ │
88
- │ │ Active Travelers (expandable) │ │ Travel Spend (chart) │ │
89
- │ └───────────────────────────────┘ └──────────────────────┘ │
90
- └──────────────────────────────────────────────────────────────┘
91
- ```
92
-
93
- ### Layout classes
94
-
95
- - **Outer:** `<div className="flex flex-col bg-slate-50 dark:bg-slate-950">`
96
- - **Map:** `<div className="relative h-[520px]">`
97
- - **Eva:** `<div className="px-4 pt-4"><ChatBar ... /></div>`
98
- - **Panels:** `<div className="px-4 py-5"><div className="space-y-6">...</div></div>`
99
- - **Row 1:** `grid grid-cols-1 items-start gap-4 lg:grid-cols-3` — Escalations `lg:col-span-2`, Disruptions auto
100
- - **Row 2:** `grid grid-cols-1 items-start gap-4 lg:grid-cols-3` — Travelers `lg:col-span-2`, Spend auto
101
-
102
- ---
103
-
104
- ## 6. Header
105
-
106
- Compact `h-12` sticky header (`bg-slate-900 dark:bg-slate-950`). No ChatBar in the header — Eva lives below the map.
107
-
108
- | Left | Right |
109
- |------|-------|
110
- | Engine logo (`engine_logo.png`, `h-5 w-auto brightness-0 invert` to make it white on the dark header) + "ENGINE" wordmark + separator + "Travel Command Center" + "Powered by Agentforce" badge (`bg-brand-900/40 text-brand-400 rounded-full text-[10px]`) | Notification bell (badge count) + theme toggle (sun/moon) |
111
-
112
- ```tsx
113
- import engineLogo from "@/assets/images/engine_logo.png";
114
-
115
- <img src={engineLogo} alt="Engine" className="h-5 w-auto brightness-0 invert" />
116
- ```
117
-
118
- ---
119
-
120
- ## 7. Hero Map
121
-
122
- **Component:** `GeoMap` from `@/components/library`
123
-
124
- ```tsx
125
- <GeoMap
126
- width={960}
127
- height={520}
128
- theme={mode === "dark" ? "dark" : "light"}
129
- markers={useDataSource({ sample: MAP_MARKERS, live: live.mapMarkers })}
130
- arcs={useDataSource({ sample: MAP_ARCS, live: live.mapArcs })}
131
- overlays={useDataSource({ sample: MAP_OVERLAYS, live: live.mapOverlays })}
132
- zoomable
133
- className="h-full w-full"
134
- />
135
- ```
136
-
137
- - **Markers:** One per city. `{ id, lon, lat, label, active: true }`
138
- - **Arcs:** One per flight route. `{ id, from: [lon, lat], to: [lon, lat], progress: 0–1, danger: boolean }`. `danger: true` on disrupted routes.
139
- - **Overlays:** Weather zones. `{ id, center: [lon, lat], radius: number }`
140
-
141
- **Glass KPI overlays** — 4 pills, `absolute left-3 top-3`:
142
- Active Travelers (count), Spend MTD (`fmtK()`), Compliance %, Eva Resolved (count + "resolved").
143
-
144
- Label styling: `text-[10px] font-medium uppercase tracking-wide text-slate-300`
145
- Value styling: `text-sm font-semibold text-slate-50`
146
- Pill styling: `bg-black/40 backdrop-blur-md border border-white/10 rounded-lg px-3 py-1.5`
147
- Icon: `h-4 w-4 text-brand-400`
148
-
149
- **Flight status strip** — `absolute bottom-3 left-3 right-3`, horizontal scroll. One pill per flight: flight number + status chip (green=On Time, amber=Delayed, sky=Boarding). Same glass styling.
150
-
151
- ---
152
-
153
- ## 8. Data Panels
154
-
155
- 4 panels in 2 rows. Sample data imported from `src/data/engine-sample-data.js`.
156
-
157
- ### 8a. Escalations (Row 1, 2/3 width)
158
-
159
- Custom inline panel in BaseCard. Do NOT use ActivityCard — this panel has per-item "Assign to Agent" buttons.
160
-
161
- Each escalation row:
162
- - Status icon: `CheckCircleIcon` (complete, green), `ArrowPathIcon` (working, brand), `ClockIcon` (pending, amber)
163
- - Title + subtitle + timestamp
164
- - **"Assign to Agent" button** on items where status is NOT `"complete"`: teal button (`bg-brand-600`) with `SparklesIcon` + "Assign to Agent" text. On click: `toast.success("Assigned to Eva")` via `@heroui/react`.
165
-
166
- ```tsx
167
- <BaseCard>
168
- <div className="p-4">
169
- <h3 className="mb-3 text-sm font-semibold text-slate-900 dark:text-slate-50">
170
- Escalations
171
- </h3>
172
- <div className="divide-y divide-slate-100 dark:divide-slate-800">
173
- {escalations.map((e) => {
174
- const isOpen = e.status !== "complete";
175
- return (
176
- <div key={e.id} className="flex items-start gap-3 py-3">
177
- <StatusIcon className={`mt-0.5 h-5 w-5 shrink-0 ${statusColor}`} />
178
- <div className="min-w-0 flex-1">
179
- <div className="text-sm font-medium text-slate-900 dark:text-slate-50">{e.title}</div>
180
- <div className="mt-0.5 text-xs text-slate-500 dark:text-slate-400">
181
- {e.subtitle} · {e.timestamp}
182
- </div>
183
- </div>
184
- {isOpen && (
185
- <button onClick={() => toast.success("Assigned to Eva")}
186
- className="shrink-0 rounded-md bg-brand-600 px-2.5 py-1 text-xs font-medium text-slate-50 hover:bg-brand-700">
187
- <span className="flex items-center gap-1">
188
- <SparklesIcon className="h-3 w-3" /> Assign to Agent
189
- </span>
190
- </button>
191
- )}
192
- </div>
193
- );
194
- })}
195
- </div>
196
- </div>
197
- </BaseCard>
198
- ```
199
-
200
- Data: `ESCALATION_CARDS` from sample data.
201
-
202
- ### 8b. Disruptions (Row 1, 1/3 width)
203
-
204
- Custom inline component in BaseCard. Shows flights delayed 60+ min or grounded.
205
-
206
- Each disruption card:
207
- - Severity dot (rose=grounded, amber=delayed) + flight number + delay minutes
208
- - Route + traveler name
209
- - Reason text
210
- - Eva action line with `SparklesIcon`
211
-
212
- Data: `DISRUPTION_CARDS` from sample data.
213
-
214
- ### 8c. Active Travelers (Row 2, 2/3 width)
215
-
216
- BaseCard with `maxBodyHeight={420}`. Expandable traveler cards.
217
-
218
- Each row: `Avatar` (initials) + name + department + origin → destination + policy chip (compliant=green, exception=amber).
219
- Expand: 4-col grid — Flight, Hotel, Return, Destination + "View in Salesforce" link.
220
-
221
- Data: `TRAVELER_CARDS` from sample data.
222
-
223
- ### 8d. Monthly Spend Trend (Row 2, 1/3 width)
224
-
225
- ```tsx
226
- const spendChartData = useDataSource({
227
- sample: MONTHLY_SPEND.map(m => ({ x: m.month, spend: m.amount })),
228
- live: live.monthlySpend.map(m => ({ x: m.month, spend: m.amount })),
229
- });
230
-
231
- <ChartCard
232
- title="Travel Spend"
233
- subtitle="Monthly trend (6 months)"
234
- chart={
235
- <D3Chart
236
- data={spendChartData}
237
- renderChart={D3ChartTemplates.groupedBarChart}
238
- options={{
239
- xKey: "x",
240
- groups: ["spend"],
241
- colors: ["#5BC8C8"],
242
- barRadius: 6,
243
- margin: { top: 20, right: 20, bottom: 40, left: 60 },
244
- showGrid: true,
245
- }}
246
- responsive
247
- height={320}
248
- />
249
- }
250
- />
251
- ```
252
-
253
- ---
254
-
255
- ## 9. Eva — Agentforce Integration
256
-
257
- Two pieces work together: a **ChatBar** for user input and the **`useEvaAgent` hook** which talks to the Agentforce Agent REST API.
258
-
259
- > **Important:** We do NOT use `AgentforceConversationClient` (the iframe widget). All agent communication goes through the REST-based Agent API via the `useEvaAgent` hook. The Vite dev server proxies the requests to avoid CORS issues.
260
-
261
- ### ChatBar
262
-
263
- A command-palette strip below the hero map. NOT in the header. NOT a FAB or sliding panel.
264
-
265
- ```tsx
266
- <div className="px-4 pt-4">
267
- <ChatBar
268
- title="Eva"
269
- placeholder="Ask Eva anything about travelers, bookings, policy, or spend…"
270
- suggestions={CHAT_SUGGESTIONS}
271
- onSend={handleChat}
272
- />
273
- </div>
274
- ```
275
-
276
- Suggestions: "Storm warning in the Midwest — which travelers are affected?", "What's our severe weather rebooking policy?", "Notify Anna and Sofia about the Chicago delays", "Create a support case for Anna Johansson's flight"
277
-
278
- ### useEvaAgent Hook
279
-
280
- The hook manages the full Agent API lifecycle — OAuth, session, messaging, cleanup.
281
-
282
- ```tsx
283
- import useEvaAgent from "@/hooks/useEvaAgent";
284
-
285
- // Inside the component:
286
- const { messages, isReady, isSending, connect, sendMessage } = useEvaAgent();
287
-
288
- // Connect on mount (or on first ChatBar focus):
289
- useEffect(() => { connect(); }, [connect]);
290
-
291
- // Wire to ChatBar:
292
- const handleChat = (text: string) => {
293
- sendMessage(text);
294
- return { text: `Looking into: "${text}"…` };
295
- };
296
- ```
297
-
298
- The hook:
299
- 1. **Authenticates** via OAuth client-credentials (`POST /sf-oauth/services/oauth2/token`)
300
- 2. **Creates a session** (`POST /sf-agent/einstein/ai-agent/v1/agents/{agentId}/sessions`)
301
- 3. **Sends messages** (`POST /sf-agent/…/messages`) — returns agent response text
302
- 4. **Ends the session** (`DELETE /sf-agent/…`) on unmount
303
-
304
- Config is in `src/config/agentApi.ts`. Proxy rules are in `vite.config.ts` (`/sf-oauth` and `/sf-agent`).
305
-
306
- Define `CHAT_SUGGESTIONS` at module scope.
307
-
308
- ---
309
-
310
- ## 10. Salesforce Signals
311
-
312
- Subtle indicators throughout the dashboard — not banners.
313
-
314
- | Signal | Location |
315
- |--------|----------|
316
- | "Powered by Agentforce" | Header, next to "Travel Command Center" (small rounded badge) |
317
- | "View in Salesforce" | Traveler expanded view (micro-link, muted text) |
318
- | "Salesforce updated" | After rebook/approve actions — `toast("Opening in Salesforce…")` via `@heroui/react` |
319
- | "Assigned to Eva" | After "Assign to Agent" button click — `toast.success("Assigned to Eva")` via `@heroui/react` |
320
-
321
- ---
322
-
323
- ## 11. Dark Mode
324
-
325
- Every element supports light and dark. GeoMap: `theme={mode === "dark" ? "dark" : "light"}`. Glass overlays work in both modes. Use slate scale (no `text-white` or `text-black`). Theme toggle in header.
326
-
327
- ---
328
-
329
- ## 12. Data Model
330
-
331
- - **Traveler** — `id`, `name`, `department`, `destination`, `origin`, `hotel`, `flight`, `return`, `policyStatus` (compliant | exception)
332
- - **Flight** — `id`, `flight`, `route`, `dep`, `status` (On Time | Delayed | Boarding | In Air | Landed), `traveler`, `delayMin`
333
- - **Disruption** — `id`, `flight`, `route`, `traveler`, `severity` (grounded | delayed), `delayMin`, `reason`, `evaAction`
334
- - **Escalation** — `id`, `title`, `subtitle`, `status` (complete | working | pending), `timestamp`
335
- - **Monthly Spend** — `{ month, amount }` array, 6 months (Oct–Mar), $98K–$156K range
336
- - **Sample data:** Pre-built in `src/data/engine-sample-data.js`. 8 travelers, 8 flights, 4 disruptions, 8 escalations, 6 months spend. All deterministic.
337
-
338
- ---
339
-
340
- ## 13. Build Prompts
341
-
342
- Build incrementally in 3 prompts. Each prompt builds on the previous result. The user prompt (blockquote) is what you copy-paste. The agent instructions below each prompt are guidance for the AI — not shown to the user.
343
-
344
- > **CRITICAL — Rules for ALL prompts:**
345
- > - Do NOT read any file inside `src/components/library/` (GeoMap.jsx, ChatBar.jsx, BaseCard.jsx, useDataSource.jsx, DataModeProvider.jsx, etc.) — all props/patterns are documented here and in the build guide.
346
- > - Do NOT load unnecessary skills — only `command-center-builder` is needed.
347
- > - Do NOT run `npm run build` during the build — Vite handles it.
348
- > - Do NOT create files not listed in the instructions below.
349
-
350
- ---
351
-
352
- ### Prompt 1 — Build the Dashboard
353
-
354
- > Build me a travel command center for Engine. There's a PRD with the full spec. I want the big hero map showing where all our travelers are with flight arcs, glass KPI overlays on top of the map, a flight status ticker, and then below that the main panels — escalations that need attention, active disruptions, our traveler roster with expandable details, and a spend trend chart. Hook it all up to the sample data so it looks real. Don't worry about the AI assistant or live data yet — we'll layer those on after. Make it the home page when you're done — I want to see it when I open the app.
355
-
356
- **What the agent must do:**
357
-
358
- 1. Load ONLY the `command-center-builder` skill (no other skills)
359
- 2. Read ONLY the PRD and `src/data/engine-sample-data.js` — no other files before writing
360
- 3. Create `src/pages/EngineDashboard.tsx` with the full dashboard in ONE write
361
- 4. Update `src/components/workspace/CommandCenter.tsx` to import EngineDashboard
362
- 5. **Rewrite `src/pages/Home.tsx`** to render CommandCenter (it ships as Account Search — must be replaced with a 3-line wrapper)
363
- 6. **Update `src/routes.tsx`** to set Home as the index route with label "Dashboard"
364
-
365
- **FORBIDDEN in Prompt 1:**
366
- - ❌ ChatBar, Eva, or any Agentforce integration (Prompt 3)
367
- - ❌ `useEngineLiveData` or live data wiring (Prompt 2)
368
- - ❌ Salesforce metadata — custom fields, platform events, Apex (Prompts 2-3)
369
- - ❌ Reading library component source files (GeoMap.jsx, BaseCard.jsx, etc.)
370
- - ❌ Loading `outer-app`, `component-library`, `command-center-project`, or other skills
371
-
372
- **Common failure:** The agent creates the dashboard file but forgets to update `Home.tsx` and `routes.tsx`, so the user still sees the Account Search page.
373
-
374
- ---
375
-
376
- ### Prompt 2 — Connect to Salesforce Data
377
-
378
- > Now let's connect this to real data. There's a second dataset with different travelers and metrics — hook that up as the "live" data source so the dashboard can pull from either dataset depending on the backend config. After that, see if there are any data model improvements we should make for tracking weather disruptions.
379
-
380
- **What the agent must do (exactly 5 edits + 1 suggestion):**
381
-
382
- 1. Read ONLY `EngineDashboard.tsx` and `src/hooks/useEngineLiveData.ts` — no other files
383
- 2. **Edit 1:** Add `useEngineLiveData` import to EngineDashboard.tsx
384
- 3. **Edit 2:** Add `const live = useEngineLiveData()` hook call
385
- 4. **Edit 3:** Update every `useDataSource({ sample, live: [] })` to pass `live: live.xxx`
386
- 5. **Edit 4:** Update KPI derivations to use reactive metrics
387
- 6. **Edit 5:** ⚠️ **CRITICAL — Flip `ENABLE_SAMPLE_DATA_CACHE` from `true` to `false` in `src/lib/dataStrategy.ts`** — without this, the data never switches and the demo fails
388
- 7. After all edits, **STOP and suggest** ONLY `Weather_Impact__c` — do NOT create it until the user says yes
389
-
390
- **FORBIDDEN in Prompt 2:**
391
- - ❌ **`DataModeToggle`** — do NOT add it to the UI. There is NO UI toggle. The switch is `dataStrategy.ts`. This is the most common agent mistake.
392
- - ❌ Rewriting `EngineDashboard.tsx` from scratch (make 5 targeted edits)
393
- - ❌ Renaming existing imports with `SAMPLE_` prefix (leave variable names alone, just fill in `live:` props)
394
- - ❌ Reading library source files (`useDataSource.jsx`, `DataModeProvider.jsx`, `DataModeToggle.jsx`)
395
- - ❌ ChatBar, Eva, or Agentforce (Prompt 3)
396
- - ❌ Running `npm run build` between edits
397
- - ❌ Suggesting more than one custom field (only `Weather_Impact__c`)
398
- - ❌ Creating extra files not listed above
399
-
400
- **Reference — what the agent should say after wiring:**
401
-
402
- *"I notice `Flight__c` doesn't have a field to track weather impact on individual flights. A `Weather_Impact__c` picklist would help the dashboard filter storm-affected flights. Want me to create it?"* — Only create the custom field XML from section 14a AFTER the user confirms.
403
-
404
- ---
405
-
406
- ### Prompt 3 — Add Agentforce
407
-
408
- > Last piece — let's add Eva, the AI travel assistant. I want a chat bar right below the map where people can ask her questions about travelers and disruptions. Also hook up the real Agentforce agent so she can actually do things. Then let's set up the backend so disruption alerts can flow through the platform in real time.
409
-
410
- **Pre-installed files (already in the project — do NOT recreate):**
411
- - `src/hooks/useEvaAgent.ts` — Agent API hook (OAuth → session → messages → cleanup)
412
- - `src/config/agentApi.ts` — hardcoded credentials and endpoints
413
- - `vite.config.ts` — already has `/sf-oauth` and `/sf-agent` proxy rules
414
-
415
- **What the agent must do (exactly 4 edits + 2 suggestions):**
416
-
417
- 1. Read ONLY `src/pages/EngineDashboard.tsx` — no other files
418
- 2. **Edit 1:** Add `ChatBar` and `useEvaAgent` imports
419
- 3. **Edit 2:** Add `CHAT_SUGGESTIONS` constant at module scope
420
- 4. **Edit 3:** Add `useEvaAgent` hook call + `handleChat` handler inside component
421
- 5. **Edit 4:** Insert `<ChatBar />` JSX between map and data panels
422
- 6. After adding Eva, **STOP and suggest** the platform event — wait for user confirmation
423
- 7. After platform event, **STOP and suggest** the Apex class — wait for user confirmation
424
-
425
- **FORBIDDEN in Prompt 3:**
426
- - ❌ **`AgentforceConversationClient`** — do NOT use the iframe widget. We use the Agent REST API via `useEvaAgent`.
427
- - ❌ **Wrapper hooks** — do NOT create `useEvaChatAdapter.ts`, `useDisruptionAlerts.ts`, or any extra hook file. Use `useEvaAgent` directly.
428
- - ❌ **`.env` or `.env.local` files** — config is hardcoded in `src/config/agentApi.ts`
429
- - ❌ **Recreating `useEvaAgent.ts`, `agentApi.ts`, or proxy config** — these are pre-installed
430
- - ❌ Rewriting `EngineDashboard.tsx` from scratch
431
- - ❌ Reading library source files (including `ChatBar.jsx`)
432
- - ❌ Creating platform events or Apex without user confirmation
433
- - ❌ Loading `agentforce-test`, `agentforce-observability`, or `outer-app` skills
434
-
435
- **Reference — what the agent should say (in sequence, stopping after each):**
436
-
437
- 1. After adding Eva: *"The dashboard tracks disruptions in real time. I can create a `Travel_Disruption_Alert__e` platform event so disruption data can be published to the Salesforce event bus — other systems and automation can subscribe to it. Want me to set it up?"* — Only create the platform event (section 14b) AFTER the user confirms.
438
-
439
- 2. After the platform event: *"Now I'll write an Apex service class to publish disruption records to that event bus. `TravelDisruptionEventService` will take a list of disruptions and fire platform events with the flight number, severity, and description. Want me to create it?"* — Only create the Apex class (section 14c) AFTER the user confirms.
440
-
441
- ---
442
-
443
- ## 14. Metadata Reference Templates
444
-
445
- Templates for the scripted metadata interactions. The agent should use these exact structures when creating files.
446
-
447
- ### 14a. Custom Field — `Flight__c.Weather_Impact__c`
448
-
449
- `force-app/main/default/objects/Flight__c/fields/Weather_Impact__c.field-meta.xml`
450
-
451
- ```xml
452
- <?xml version="1.0" encoding="UTF-8"?>
453
- <CustomField xmlns="http://soap.sforce.com/2006/04/metadata">
454
- <fullName>Weather_Impact__c</fullName>
455
- <label>Weather Impact</label>
456
- <type>Picklist</type>
457
- <required>false</required>
458
- <valueSet>
459
- <restricted>true</restricted>
460
- <valueSetDefinition>
461
- <sorted>false</sorted>
462
- <value><fullName>None</fullName><default>true</default><label>None</label></value>
463
- <value><fullName>Minor</fullName><default>false</default><label>Minor</label></value>
464
- <value><fullName>Moderate</fullName><default>false</default><label>Moderate</label></value>
465
- <value><fullName>Severe</fullName><default>false</default><label>Severe</label></value>
466
- </valueSetDefinition>
467
- </valueSet>
468
- </CustomField>
469
- ```
470
-
471
- Deploy: `sf project deploy start --source-dir force-app/main/default/objects/Flight__c/fields/Weather_Impact__c.field-meta.xml`
472
-
473
- ### 14b. Platform Event — `Travel_Disruption_Alert__e`
474
-
475
- Create the event object and its fields:
476
-
477
- `force-app/main/default/objects/Travel_Disruption_Alert__e/Travel_Disruption_Alert__e.object-meta.xml`
478
-
479
- ```xml
480
- <?xml version="1.0" encoding="UTF-8"?>
481
- <CustomObject xmlns="http://soap.sforce.com/2006/04/metadata">
482
- <label>Travel Disruption Alert</label>
483
- <pluralLabel>Travel Disruption Alerts</pluralLabel>
484
- <description>Published when a travel disruption is detected. Subscribers can react to real-time flight delays, weather events, and rebooking triggers.</description>
485
- <deploymentStatus>Deployed</deploymentStatus>
486
- <eventType>HighVolume</eventType>
487
- </CustomObject>
488
- ```
489
-
490
- `force-app/main/default/objects/Travel_Disruption_Alert__e/fields/Flight_Number__c.field-meta.xml`
491
-
492
- ```xml
493
- <?xml version="1.0" encoding="UTF-8"?>
494
- <CustomField xmlns="http://soap.sforce.com/2006/04/metadata">
495
- <fullName>Flight_Number__c</fullName>
496
- <label>Flight Number</label>
497
- <type>Text</type>
498
- <length>20</length>
499
- <required>false</required>
500
- </CustomField>
501
- ```
502
-
503
- `force-app/main/default/objects/Travel_Disruption_Alert__e/fields/Severity__c.field-meta.xml`
504
-
505
- ```xml
506
- <?xml version="1.0" encoding="UTF-8"?>
507
- <CustomField xmlns="http://soap.sforce.com/2006/04/metadata">
508
- <fullName>Severity__c</fullName>
509
- <label>Severity</label>
510
- <type>Text</type>
511
- <length>20</length>
512
- <required>false</required>
513
- </CustomField>
514
- ```
515
-
516
- `force-app/main/default/objects/Travel_Disruption_Alert__e/fields/Description__c.field-meta.xml`
517
-
518
- ```xml
519
- <?xml version="1.0" encoding="UTF-8"?>
520
- <CustomField xmlns="http://soap.sforce.com/2006/04/metadata">
521
- <fullName>Description__c</fullName>
522
- <label>Description</label>
523
- <type>LongTextArea</type>
524
- <length>1000</length>
525
- <visibleLines>3</visibleLines>
526
- <required>false</required>
527
- </CustomField>
528
- ```
529
-
530
- Deploy: `sf project deploy start --source-dir force-app/main/default/objects/Travel_Disruption_Alert__e`
531
-
532
- ### 14c. Apex Class — `TravelDisruptionEventService`
533
-
534
- `force-app/main/default/classes/TravelDisruptionEventService.cls`
535
-
536
- ```apex
537
- public with sharing class TravelDisruptionEventService {
538
-
539
- public static void publishDisruptionAlerts(List<Disruption__c> disruptions) {
540
- List<Travel_Disruption_Alert__e> events = new List<Travel_Disruption_Alert__e>();
541
-
542
- for (Disruption__c d : disruptions) {
543
- events.add(new Travel_Disruption_Alert__e(
544
- Flight_Number__c = d.Flight_Number__c,
545
- Severity__c = d.Severity__c,
546
- Description__c = d.Description__c
547
- ));
548
- }
549
-
550
- if (!events.isEmpty()) {
551
- List<Database.SaveResult> results = EventBus.publish(events);
552
- for (Database.SaveResult sr : results) {
553
- if (!sr.isSuccess()) {
554
- for (Database.Error err : sr.getErrors()) {
555
- System.debug(LoggingLevel.ERROR,
556
- 'Failed to publish Travel_Disruption_Alert__e: ' + err.getMessage());
557
- }
558
- }
559
- }
560
- }
561
- }
562
- }
563
- ```
564
-
565
- `force-app/main/default/classes/TravelDisruptionEventService.cls-meta.xml`
566
-
567
- ```xml
568
- <?xml version="1.0" encoding="UTF-8"?>
569
- <ApexClass xmlns="http://soap.sforce.com/2006/04/metadata">
570
- <apiVersion>62.0</apiVersion>
571
- <status>Active</status>
572
- </ApexClass>
573
- ```
574
-
575
- Deploy: `sf project deploy start --source-dir force-app/main/default/classes/TravelDisruptionEventService.cls --test-level NoTestRun`