@schandlergarcia/sf-web-components 1.9.74 → 1.9.76
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/features/command-center-dashboard-rule.md +16 -7
- package/.a4drules/features/engine-dashboard-rule.md +11 -5
- package/.a4drules/features/pre-code-checklist.md +29 -6
- package/.a4drules/skills/command-center-builder/SKILL.md +159 -89
- package/.a4drules/skills/command-center-builder/improved-build-process.md +32 -1
- package/.a4drules/skills/command-center-guide/SKILL.md +25 -17
- package/CHANGELOG.md +37 -0
- package/data/engine-command-center-prd.md +151 -143
- package/package.json +1 -1
|
@@ -8,6 +8,22 @@ paths:
|
|
|
8
8
|
|
|
9
9
|
These rules apply to all dashboard files. For Engine-specific rules, see `engine-dashboard-rule.md`.
|
|
10
10
|
|
|
11
|
+
**Read `.a4drules/skills/command-center-builder/SKILL.md` before building any dashboard.** It has the full conventions, component rules, and wiring steps.
|
|
12
|
+
|
|
13
|
+
## Wiring — MANDATORY (do not skip)
|
|
14
|
+
|
|
15
|
+
After creating a dashboard, you MUST update all 3 files or the dashboard will never appear:
|
|
16
|
+
|
|
17
|
+
1. **`CommandCenter.tsx`** — import and render your dashboard (change only the import line)
|
|
18
|
+
2. **`Home.tsx`** — REWRITE to render `CommandCenter` (it ships as Account Search by default):
|
|
19
|
+
```tsx
|
|
20
|
+
import CommandCenter from "@/components/workspace/CommandCenter";
|
|
21
|
+
export default function HomePage() { return <CommandCenter />; }
|
|
22
|
+
```
|
|
23
|
+
3. **`routes.tsx`** — set `Home` as index route with label "Dashboard", move Search to `/search`
|
|
24
|
+
|
|
25
|
+
**If you skip this, the user sees the Account Search page instead of your dashboard.**
|
|
26
|
+
|
|
11
27
|
## Core Constraints
|
|
12
28
|
|
|
13
29
|
1. Dashboard files: `.tsx` in `src/pages/` — never `.jsx`, never `src/components/pages/`
|
|
@@ -21,13 +37,6 @@ These rules apply to all dashboard files. For Engine-specific rules, see `engine
|
|
|
21
37
|
9. DO NOT run `npm run dev`, `npm run validate:dashboard`, or `npm run build` during builds
|
|
22
38
|
10. DO NOT `npm install` any packages — everything needed is already installed
|
|
23
39
|
|
|
24
|
-
## Wiring
|
|
25
|
-
|
|
26
|
-
After creating a dashboard, update all 3 files:
|
|
27
|
-
1. `CommandCenter.tsx` — import and render your dashboard
|
|
28
|
-
2. `Home.tsx` — render `CommandCenter`
|
|
29
|
-
3. `routes.tsx` — set `Home` as index route
|
|
30
|
-
|
|
31
40
|
## Component API
|
|
32
41
|
|
|
33
42
|
For full component props and data shapes, read `.a4drules/skills/component-library/SKILL.md`.
|
|
@@ -33,13 +33,19 @@ These rules load automatically when editing Engine dashboard files. For full bui
|
|
|
33
33
|
|
|
34
34
|
Complete each phase fully before starting the next. Read the relevant phase file for detailed instructions and code templates.
|
|
35
35
|
|
|
36
|
-
## Wiring Checklist
|
|
36
|
+
## Wiring Checklist — MANDATORY
|
|
37
37
|
|
|
38
|
-
After creating or updating `EngineDashboard.tsx
|
|
38
|
+
After creating or updating `EngineDashboard.tsx`, update ALL 3 files:
|
|
39
39
|
|
|
40
|
-
1.
|
|
41
|
-
2.
|
|
42
|
-
|
|
40
|
+
1. **`CommandCenter.tsx`** — imports `EngineDashboard` (not `BlankDashboard`)
|
|
41
|
+
2. **`Home.tsx`** — REWRITE to render `CommandCenter` (it ships as Account Search by default):
|
|
42
|
+
```tsx
|
|
43
|
+
import CommandCenter from "@/components/workspace/CommandCenter";
|
|
44
|
+
export default function HomePage() { return <CommandCenter />; }
|
|
45
|
+
```
|
|
46
|
+
3. **`routes.tsx`** — has `Home` as index route with label "Dashboard", `Search` at `/search`
|
|
47
|
+
|
|
48
|
+
**If you skip steps 2-3, the user sees the Account Search page instead of the dashboard.**
|
|
43
49
|
|
|
44
50
|
## Component Quick Reference
|
|
45
51
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Pre-Code Checklist
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Read `.a4drules/skills/command-center-builder/SKILL.md` before building. It has the full conventions and wiring steps.
|
|
4
4
|
|
|
5
5
|
## Before creating a dashboard file
|
|
6
6
|
|
|
@@ -18,9 +18,32 @@ This is a reference checklist. For build instructions, use the phase files in `.
|
|
|
18
18
|
| `text-black` | `text-slate-900` | Body text (light mode) |
|
|
19
19
|
| `bg-black` | `bg-slate-900` or `bg-black/40` (with opacity) | Backgrounds |
|
|
20
20
|
|
|
21
|
-
## After creating the dashboard
|
|
21
|
+
## After creating the dashboard — WIRE IT (MANDATORY)
|
|
22
22
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
- [ ]
|
|
26
|
-
|
|
23
|
+
**All 3 steps are required or the dashboard will never render on screen.**
|
|
24
|
+
|
|
25
|
+
- [ ] **`CommandCenter.tsx`** — change the import to your dashboard:
|
|
26
|
+
```tsx
|
|
27
|
+
// src/components/workspace/CommandCenter.tsx
|
|
28
|
+
import MyDashboard from "../../pages/MyDashboard"; // ← your dashboard
|
|
29
|
+
// ... render <MyDashboard /> inside the existing providers
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
- [ ] **`Home.tsx`** — REPLACE the entire file (it ships as Account Search by default):
|
|
33
|
+
```tsx
|
|
34
|
+
// src/pages/Home.tsx — REPLACE EVERYTHING
|
|
35
|
+
import CommandCenter from "@/components/workspace/CommandCenter";
|
|
36
|
+
export default function HomePage() {
|
|
37
|
+
return <CommandCenter />;
|
|
38
|
+
}
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
- [ ] **`routes.tsx`** — set Home as the index route with label "Dashboard":
|
|
42
|
+
```tsx
|
|
43
|
+
{ index: true, element: <Home />, handle: { showInNavigation: true, showNavBar: true, label: "Dashboard" } },
|
|
44
|
+
{ path: "search", element: <Search />, handle: { showInNavigation: true, showNavBar: true, label: "Search" } },
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
- [ ] DO NOT run `npm run dev` or `npm run validate:dashboard` during builds
|
|
48
|
+
|
|
49
|
+
**If you skip the wiring steps, the user will see the Account Search page instead of your dashboard.**
|
|
@@ -13,15 +13,131 @@ description: >-
|
|
|
13
13
|
|
|
14
14
|
These rules apply when building dashboards rendered by `CommandCenter.tsx`. For full component API details, read the **component-library** skill.
|
|
15
15
|
|
|
16
|
+
## WIRING — DO THIS FIRST (before building the dashboard)
|
|
17
|
+
|
|
18
|
+
**Building a dashboard requires updating 4 files. If you only create the dashboard file, the user will never see it — they'll see the old Account Search page instead.**
|
|
19
|
+
|
|
20
|
+
Read the existing `Home.tsx`, `CommandCenter.tsx`, and `routes.tsx` BEFORE you start building. Plan all 4 file changes up front:
|
|
21
|
+
|
|
22
|
+
1. `src/pages/YourDashboard.tsx` — the dashboard component
|
|
23
|
+
2. `src/components/workspace/CommandCenter.tsx` — import and render your dashboard
|
|
24
|
+
3. `src/pages/Home.tsx` — **MUST be rewritten** to render CommandCenter (it ships as Account Search)
|
|
25
|
+
4. `src/routes.tsx` — set Home as index route with label "Dashboard"
|
|
26
|
+
|
|
27
|
+
**Home.tsx ships as an Account Search page by default.** You MUST replace its entire contents:
|
|
28
|
+
|
|
29
|
+
```tsx
|
|
30
|
+
// src/pages/Home.tsx — REPLACE the entire file
|
|
31
|
+
import CommandCenter from "@/components/workspace/CommandCenter";
|
|
32
|
+
|
|
33
|
+
export default function HomePage() {
|
|
34
|
+
return <CommandCenter />;
|
|
35
|
+
}
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
**CommandCenter.tsx** — only change the dashboard import. Preserve the `heroui-scope` wrapper and `Toast.Provider`:
|
|
39
|
+
|
|
40
|
+
```tsx
|
|
41
|
+
// src/components/workspace/CommandCenter.tsx
|
|
42
|
+
import AppThemeProvider from "@/components/library/theme/AppThemeProvider";
|
|
43
|
+
import DataModeProvider from "@/components/library/data/DataModeProvider";
|
|
44
|
+
import { Toast } from "@heroui/react";
|
|
45
|
+
import MyDashboard from "../../pages/MyDashboard"; // ← change ONLY this import
|
|
46
|
+
|
|
47
|
+
export default function CommandCenter() {
|
|
48
|
+
return (
|
|
49
|
+
<div className="heroui-scope">
|
|
50
|
+
<AppThemeProvider initialMode="light">
|
|
51
|
+
<DataModeProvider initialMode="sample">
|
|
52
|
+
<MyDashboard />
|
|
53
|
+
<Toast.Provider placement="bottom end" />
|
|
54
|
+
</DataModeProvider>
|
|
55
|
+
</AppThemeProvider>
|
|
56
|
+
</div>
|
|
57
|
+
);
|
|
58
|
+
}
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
**routes.tsx** — make Home the index route, move Search to `/search`:
|
|
62
|
+
|
|
63
|
+
```tsx
|
|
64
|
+
{
|
|
65
|
+
index: true,
|
|
66
|
+
element: <Home />,
|
|
67
|
+
handle: { showInNavigation: true, showNavBar: true, label: "Dashboard" }
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
path: "search",
|
|
71
|
+
element: <Search />,
|
|
72
|
+
handle: { showInNavigation: true, showNavBar: true, label: "Search" }
|
|
73
|
+
},
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
**After writing all files, verify:**
|
|
77
|
+
1. Your dashboard `.tsx` file exists in `src/pages/`
|
|
78
|
+
2. `CommandCenter.tsx` imports your dashboard (not `BlankDashboard`)
|
|
79
|
+
3. `Home.tsx` imports and renders `CommandCenter` (NOT the Account Search interface)
|
|
80
|
+
4. `routes.tsx` has `Home` as the index route with label "Dashboard"
|
|
81
|
+
|
|
82
|
+
**If any of these are missing, the dashboard will not render.** This is the #1 cause of "I built the dashboard but I can't see it."
|
|
83
|
+
|
|
84
|
+
---
|
|
85
|
+
|
|
86
|
+
## Quick Import Reference
|
|
87
|
+
|
|
88
|
+
Use these exact imports. Do NOT read component source files to discover imports — this list is authoritative.
|
|
89
|
+
|
|
90
|
+
```tsx
|
|
91
|
+
// Library components — named imports from barrel
|
|
92
|
+
import {
|
|
93
|
+
BaseCard, MetricCard, ChartCard, TableCard, ListCard, ActivityCard,
|
|
94
|
+
StatusCard, WidgetCard, SectionCard, FeedPanel, CalloutCard, ActionList,
|
|
95
|
+
MetricsStrip, D3Chart, D3ChartTemplates, GeoMap, Avatar, UIButton,
|
|
96
|
+
UIChip, UIText, EmptyState, Spinner, ChatBar, FilterBar,
|
|
97
|
+
FormModal, toast,
|
|
98
|
+
} from "@/components/library";
|
|
99
|
+
|
|
100
|
+
// Theme — named export
|
|
101
|
+
import { useThemeMode } from "@/components/library/theme/AppThemeProvider";
|
|
102
|
+
|
|
103
|
+
// Data — DEFAULT export (no braces)
|
|
104
|
+
import useDataSource from "@/components/library/data/useDataSource";
|
|
105
|
+
|
|
106
|
+
// Icons — Heroicons ONLY (not Lucide) — use 24/outline by default
|
|
107
|
+
import {
|
|
108
|
+
UsersIcon, BellIcon, SunIcon, MoonIcon, SparklesIcon,
|
|
109
|
+
CheckCircleIcon, ArrowPathIcon, ClockIcon, BanknotesIcon,
|
|
110
|
+
ShieldCheckIcon, ChevronDownIcon, ChevronUpIcon,
|
|
111
|
+
ExclamationTriangleIcon, PaperAirplaneIcon, BuildingOfficeIcon,
|
|
112
|
+
MapPinIcon, GlobeAltIcon, UserIcon,
|
|
113
|
+
} from "@heroicons/react/24/outline";
|
|
114
|
+
|
|
115
|
+
// Sample data
|
|
116
|
+
import {
|
|
117
|
+
MAP_MARKERS, MAP_ARCS, MAP_OVERLAYS, FLIGHT_STATUS_LIST,
|
|
118
|
+
TRAVELER_CARDS, DISRUPTION_CARDS, ESCALATION_CARDS,
|
|
119
|
+
MONTHLY_SPEND, METRICS,
|
|
120
|
+
} from "@/data/engine-sample-data.js";
|
|
121
|
+
|
|
122
|
+
// Logo
|
|
123
|
+
import engineLogo from "@/assets/images/engine_logo.png";
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
**Common mistakes:** `PlaneIcon` doesn't exist (use `PaperAirplaneIcon`), `HotelIcon` doesn't exist (use `BuildingOfficeIcon`), `import { useDataSource }` fails (it's a default export — no braces).
|
|
127
|
+
|
|
128
|
+
---
|
|
129
|
+
|
|
16
130
|
## Core Conventions
|
|
17
131
|
|
|
18
132
|
The following conventions apply to all dashboard development in this project.
|
|
19
133
|
|
|
20
|
-
|
|
134
|
+
The most common mistakes are:
|
|
135
|
+
- **Forgetting to update Home.tsx and routes.tsx** (dashboard exists but never renders)
|
|
21
136
|
- Creating `.jsx` instead of `.tsx` files
|
|
22
137
|
- Creating files in `src/components/pages/` instead of `src/pages/`
|
|
23
138
|
- Using forbidden colors (`text-white`, `bg-black`)
|
|
24
139
|
- Hand-rolling HTML cards instead of using library components
|
|
140
|
+
- Reading component source files instead of using this skill's documentation
|
|
25
141
|
|
|
26
142
|
1. **Write `.tsx` files** in `src/pages/` and update `CommandCenter.tsx` to import the dashboard. This is a TypeScript project — all React components use `.tsx` extension.
|
|
27
143
|
|
|
@@ -89,9 +205,15 @@ The company logo is at `src/assets/images/engine_logo.png`. Import it as a modul
|
|
|
89
205
|
```jsx
|
|
90
206
|
import engineLogo from "@/assets/images/engine_logo.png";
|
|
91
207
|
|
|
92
|
-
|
|
208
|
+
// On light backgrounds:
|
|
209
|
+
<img src={engineLogo} alt="Engine" className="h-5 w-auto" />
|
|
210
|
+
|
|
211
|
+
// On dark backgrounds (slate-900 header, dark mode):
|
|
212
|
+
<img src={engineLogo} alt="Engine" className="h-5 w-auto brightness-0 invert" />
|
|
93
213
|
```
|
|
94
214
|
|
|
215
|
+
The logo is black — use `brightness-0 invert` to make it white when placed on dark surfaces.
|
|
216
|
+
|
|
95
217
|
- **Do not use external image URLs** (Unsplash, placeholder services, etc.) unless the user explicitly requests images.
|
|
96
218
|
- **Do not use other asset images** (codey-*.png, etc.) unless the user asks for them.
|
|
97
219
|
- **Preserve aspect ratio** — always use `w-auto` with a fixed height, or `h-auto` with a fixed width. Never set both `w-*` and `h-*` to fixed values on the logo or any image, as this distorts the aspect ratio.
|
|
@@ -100,85 +222,12 @@ import engineLogo from "@/assets/images/engine_logo.png";
|
|
|
100
222
|
|
|
101
223
|
No `<nav>`, header bar, tab bar, or content-swapping via `useState("activeTab")` inside dashboard pages. The app shell handles navigation. Dashboards are single scrollable pages — all content visible by scrolling.
|
|
102
224
|
|
|
103
|
-
## Where Dashboards Live
|
|
225
|
+
## Where Dashboards Live
|
|
104
226
|
|
|
105
227
|
- Dashboard page files: `src/pages/` (e.g. `EngineDashboard.tsx`, `FleetDashboard.tsx`) — **NOT** `src/components/pages/`
|
|
106
228
|
- File format: `.tsx` (MUST be TypeScript) — this is a TypeScript project, all React components use `.tsx`, NEVER `.jsx`.
|
|
107
229
|
- `CommandCenter.tsx` wraps with `heroui-scope` div + `AppThemeProvider` + `DataModeProvider` + `Toast.Provider` from `@heroui/react`. **Never recreate these providers in dashboard pages.** When wiring a new dashboard, only change the import — preserve the `heroui-scope` wrapper and `Toast.Provider` exactly as-is. For toasts inside dashboards, import `toast` from `@heroui/react` (or `@/components/library`) — NOT from `sonner`.
|
|
108
|
-
|
|
109
|
-
### Wiring a new dashboard (REQUIRED STEPS)
|
|
110
|
-
|
|
111
|
-
All three steps are required for the dashboard to render:
|
|
112
|
-
|
|
113
|
-
**Step 1:** Create the dashboard file in `src/pages/` (NOT `src/components/pages/`):
|
|
114
|
-
```tsx
|
|
115
|
-
// src/pages/MyDashboard.tsx (NOTE: .tsx NOT .jsx, in src/pages/ NOT src/components/pages/)
|
|
116
|
-
import React from "react";
|
|
117
|
-
import { MetricCard, ListCard, ChartCard, D3Chart } from "@/components/library";
|
|
118
|
-
|
|
119
|
-
export default function MyDashboard() {
|
|
120
|
-
return (
|
|
121
|
-
<div className="space-y-6 p-6">
|
|
122
|
-
{/* dashboard content using library components */}
|
|
123
|
-
</div>
|
|
124
|
-
);
|
|
125
|
-
}
|
|
126
|
-
```
|
|
127
|
-
|
|
128
|
-
**Step 2:** Update `CommandCenter.tsx` to import and render it. Only change the import line — preserve `heroui-scope` and `Toast.Provider`:
|
|
129
|
-
```tsx
|
|
130
|
-
// src/components/workspace/CommandCenter.tsx
|
|
131
|
-
import AppThemeProvider from "@/components/library/theme/AppThemeProvider";
|
|
132
|
-
import DataModeProvider from "@/components/library/data/DataModeProvider";
|
|
133
|
-
import { Toast } from "@heroui/react";
|
|
134
|
-
import MyDashboard from "../../pages/MyDashboard"; // ← change ONLY this import
|
|
135
|
-
|
|
136
|
-
export default function CommandCenter() {
|
|
137
|
-
return (
|
|
138
|
-
<div className="heroui-scope"> {/* ← preserve this wrapper */}
|
|
139
|
-
<AppThemeProvider initialMode="light">
|
|
140
|
-
<DataModeProvider initialMode="sample">
|
|
141
|
-
<MyDashboard /> {/* ← change this */}
|
|
142
|
-
<Toast.Provider placement="bottom end" /> {/* ← preserve this */}
|
|
143
|
-
</DataModeProvider>
|
|
144
|
-
</AppThemeProvider>
|
|
145
|
-
</div>
|
|
146
|
-
);
|
|
147
|
-
}
|
|
148
|
-
```
|
|
149
|
-
|
|
150
|
-
**Step 2.5:** Update `Home.tsx` to render `CommandCenter`:
|
|
151
|
-
```tsx
|
|
152
|
-
// src/pages/Home.tsx
|
|
153
|
-
import CommandCenter from "@/components/workspace/CommandCenter";
|
|
154
|
-
|
|
155
|
-
export default function HomePage() {
|
|
156
|
-
return <CommandCenter />;
|
|
157
|
-
}
|
|
158
|
-
```
|
|
159
|
-
|
|
160
|
-
**Step 3:** Update `src/routes.tsx` to make the dashboard the home page. Replace the Search page index route with the Home/CommandCenter route:
|
|
161
|
-
```tsx
|
|
162
|
-
// src/routes.tsx — change the index route
|
|
163
|
-
{
|
|
164
|
-
index: true,
|
|
165
|
-
element: <SuspenseWrap><Home /></SuspenseWrap>,
|
|
166
|
-
handle: { showInNavigation: true, label: 'Dashboard' }
|
|
167
|
-
},
|
|
168
|
-
{
|
|
169
|
-
path: "search",
|
|
170
|
-
element: <SuspenseWrap><Search /></SuspenseWrap>,
|
|
171
|
-
handle: { showInNavigation: true, label: 'Search' }
|
|
172
|
-
},
|
|
173
|
-
```
|
|
174
|
-
|
|
175
|
-
The `Home` page renders `CommandCenter`, which renders your dashboard. The Search page moves to `/search`.
|
|
176
|
-
|
|
177
|
-
**Verify:** After writing all files, confirm:
|
|
178
|
-
1. Your dashboard `.tsx` file exists in `src/pages/`
|
|
179
|
-
2. `CommandCenter.tsx` (in `src/components/workspace/`) imports your dashboard (not `BlankDashboard`)
|
|
180
|
-
3. `Home.tsx` (in `src/pages/`) imports and renders `CommandCenter` (not search interface)
|
|
181
|
-
4. `src/routes.tsx` has `Home` as the index route and `Search` at `/search`
|
|
230
|
+
- **Wiring is covered at the top of this file** — see "WIRING — DO THIS FIRST".
|
|
182
231
|
|
|
183
232
|
## Page Structure
|
|
184
233
|
|
|
@@ -346,10 +395,17 @@ Define schemas outside component body. Always `required: true` on mandatory fiel
|
|
|
346
395
|
|
|
347
396
|
## AI Chat & Agent
|
|
348
397
|
|
|
349
|
-
|
|
398
|
+
Two components for agent integration:
|
|
399
|
+
|
|
400
|
+
- **`ChatBar`** — command-palette strip for suggested prompts. Place between the hero map and data panels (full-width, `px-4 pt-4`), NOT in the header. Always provide 3–5 `suggestions`.
|
|
401
|
+
- **`AgentforceConversationClient`** — the real Salesforce agent. Import from `@/components/AgentforceConversationClient` and pass the agent ID. Renders as a floating widget.
|
|
402
|
+
|
|
403
|
+
```tsx
|
|
404
|
+
import { AgentforceConversationClient } from "@/components/AgentforceConversationClient";
|
|
405
|
+
|
|
406
|
+
<AgentforceConversationClient agentId="0Xxa5000000relhCAA" agentLabel="Eva" />
|
|
407
|
+
```
|
|
350
408
|
|
|
351
|
-
- Place `ChatBar` between the hero map and data panels (full-width, `px-4 pt-4`), NOT in the header
|
|
352
|
-
- Always provide 3–5 `suggestions` for starter prompts
|
|
353
409
|
- Return `components` for structured data — never markdown tables in text
|
|
354
410
|
- Always set height on `ChatPanel`
|
|
355
411
|
- Extract `onSend` handlers to module scope when shared
|
|
@@ -513,17 +569,15 @@ Instead, verify correctness by reviewing the code against the Pre-Completion Che
|
|
|
513
569
|
|
|
514
570
|
## Salesforce Metadata Patterns
|
|
515
571
|
|
|
516
|
-
This is an SFDX project (`force-app/main/default/`). When the build requires metadata changes
|
|
572
|
+
This is an SFDX project (`force-app/main/default/`). When the build requires metadata changes, write standard SFDX XML files and deploy with the Salesforce CLI.
|
|
517
573
|
|
|
518
574
|
### File locations
|
|
519
575
|
|
|
520
576
|
| Metadata type | Path pattern |
|
|
521
577
|
|---|---|
|
|
522
|
-
| Permission Set | `force-app/main/default/permissionsets/{Name}.permissionset-meta.xml` |
|
|
523
578
|
| Custom Field | `force-app/main/default/objects/{Object}/fields/{Field}.field-meta.xml` |
|
|
524
|
-
|
|
|
525
|
-
|
|
|
526
|
-
| Email Template | `force-app/main/default/email/{Folder}/{Name}.email-meta.xml` |
|
|
579
|
+
| Platform Event | `force-app/main/default/objects/{Name}__e/{Name}__e.object-meta.xml` + `fields/` |
|
|
580
|
+
| Apex Class | `force-app/main/default/classes/{Name}.cls` + `{Name}.cls-meta.xml` |
|
|
527
581
|
|
|
528
582
|
### Deploy command
|
|
529
583
|
|
|
@@ -531,16 +585,32 @@ This is an SFDX project (`force-app/main/default/`). When the build requires met
|
|
|
531
585
|
sf project deploy start --source-dir force-app/main/default/permissionsets/MyPermSet.permissionset-meta.xml
|
|
532
586
|
```
|
|
533
587
|
|
|
534
|
-
Use `--source-dir` to deploy individual files. For multiple files, point to the parent directory.
|
|
588
|
+
Use `--source-dir` to deploy individual files. For multiple files, point to the parent directory. For Apex, use `--test-level NoTestRun` during development.
|
|
589
|
+
|
|
590
|
+
### Platform Events
|
|
591
|
+
|
|
592
|
+
Platform events are structured like custom objects under `objects/{Name}__e/`. The object file defines the event (`eventType: HighVolume`), and each field gets its own file under `fields/`. Deploy the whole directory at once:
|
|
593
|
+
|
|
594
|
+
```bash
|
|
595
|
+
sf project deploy start --source-dir force-app/main/default/objects/Travel_Disruption_Alert__e
|
|
596
|
+
```
|
|
597
|
+
|
|
598
|
+
### Apex Classes
|
|
599
|
+
|
|
600
|
+
Apex classes need two files: the `.cls` source and a `.cls-meta.xml` with API version and status. Always use `with sharing` for security. Deploy with `--test-level NoTestRun` for development:
|
|
601
|
+
|
|
602
|
+
```bash
|
|
603
|
+
sf project deploy start --source-dir force-app/main/default/classes/TravelDisruptionEventService.cls --test-level NoTestRun
|
|
604
|
+
```
|
|
535
605
|
|
|
536
606
|
### When to create metadata
|
|
537
607
|
|
|
538
|
-
During the build, proactively
|
|
608
|
+
During the build, proactively create the Salesforce metadata needed for the features you're building. If the dashboard needs field access, create a permission set. If a new field would improve the data model, create it. If automation would enhance a workflow, create a flow. Tell the user what you're creating and ask before doing it. The PRD's build prompts (section 13) include specific instructions for these interactions, with XML templates in section 14.
|
|
539
609
|
|
|
540
610
|
### Key rules
|
|
541
611
|
|
|
542
612
|
- Always use API version `62.0` or higher
|
|
543
|
-
-
|
|
544
|
-
-
|
|
613
|
+
- Platform events: use `HighVolume` event type
|
|
614
|
+
- Apex: use `with sharing`, handle `Database.SaveResult` errors when publishing events
|
|
545
615
|
- Never deploy destructive changes without explicit confirmation
|
|
546
616
|
- Never modify standard Salesforce objects' core fields — only add custom fields
|
|
@@ -1 +1,32 @@
|
|
|
1
|
-
|
|
1
|
+
# Efficient Build Process
|
|
2
|
+
|
|
3
|
+
## Speed Rules
|
|
4
|
+
|
|
5
|
+
1. **Load only 2 files before building:** the PRD and this skill (command-center-builder). Do NOT load component-library, command-center-project, or outer-app skills — they add latency and aren't needed for the initial build.
|
|
6
|
+
|
|
7
|
+
2. **Do NOT read component source files.** The props for every component (GeoMap, BaseCard, Avatar, ChartCard, D3Chart, etc.) are documented in this skill and the PRD. Reading `GeoMap.jsx`, `BaseCard.jsx`, etc. wastes time and produces no new information.
|
|
8
|
+
|
|
9
|
+
3. **Write the dashboard in one pass.** Plan the full file before writing. Do not write a partial dashboard and iterate — write the complete component with all imports, data, and JSX in a single Write call.
|
|
10
|
+
|
|
11
|
+
4. **Write all 4 files without stopping.** After the dashboard, immediately write CommandCenter.tsx, Home.tsx, and edit routes.tsx. Do not run build commands between files.
|
|
12
|
+
|
|
13
|
+
5. **Do NOT run `npm run build`, `npm run dev`, `tsc`, or `npm run validate:dashboard` during the build.** These waste time. The Vite build handles JSX/TSX regardless of TypeScript errors, and pre-existing TS7016 errors (from untyped .jsx library files) are normal.
|
|
14
|
+
|
|
15
|
+
## File Write Order
|
|
16
|
+
|
|
17
|
+
```
|
|
18
|
+
1. src/pages/EngineDashboard.tsx ← full dashboard, one pass
|
|
19
|
+
2. src/components/workspace/CommandCenter.tsx ← import dashboard
|
|
20
|
+
3. src/pages/Home.tsx ← REPLACE with CommandCenter wrapper
|
|
21
|
+
4. src/routes.tsx ← edit index route label to "Dashboard"
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Common Time Wasters
|
|
25
|
+
|
|
26
|
+
| Waste | Fix |
|
|
27
|
+
|-------|-----|
|
|
28
|
+
| Loading 4-5 skills before starting | Load only command-center-builder + PRD |
|
|
29
|
+
| Reading GeoMap.jsx, Avatar.jsx, BaseCard.jsx source | Props are in this skill — trust the docs |
|
|
30
|
+
| Running `npm run build` after writing | Don't — Vite handles it, TS errors are pre-existing |
|
|
31
|
+
| Fixing imports iteratively (wrong icon names, wrong exports) | Check the PRD and this skill for exact import names before writing |
|
|
32
|
+
| Writing Home.tsx with Account Search content | REPLACE it with the 3-line CommandCenter wrapper (see WIRING section) |
|
|
@@ -10,37 +10,45 @@ description: >-
|
|
|
10
10
|
|
|
11
11
|
# Command Center Development Guide
|
|
12
12
|
|
|
13
|
-
##
|
|
13
|
+
## How to Build Efficiently
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
**Read these two files, then start building. Do not load other skills or explore component source files.**
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
1. **`.a4drules/skills/command-center-builder/SKILL.md`** — has the wiring steps, conventions, component APIs, and everything you need
|
|
18
|
+
2. **`engine-command-center-prd.md`** — the product spec (layout, data model, brand tokens)
|
|
18
19
|
|
|
19
|
-
|
|
20
|
+
That's it. The builder skill already contains the component API reference inline. Do NOT separately load `component-library`, `command-center-project`, or `outer-app` skills — they add latency and you don't need them for the initial build. Do NOT read individual component source files (GeoMap.jsx, Avatar.jsx, etc.) — the builder skill documents all the props.
|
|
20
21
|
|
|
21
|
-
|
|
22
|
-
|-------|---------------|
|
|
23
|
-
| **component-library** | Component API reference — props, data shapes, import patterns |
|
|
24
|
-
| **command-center-builder** | Dashboard conventions — layout, styling, component selection, dark mode |
|
|
25
|
-
| **command-center-project** | Project structure — routing, file locations, tech stack, wiring |
|
|
26
|
-
| **outer-app** | Outer app — navigation, shadcn/ui, non-dashboard pages |
|
|
22
|
+
## Build Order (write files in this exact order)
|
|
27
23
|
|
|
28
|
-
|
|
24
|
+
1. **Read** the PRD and builder skill
|
|
25
|
+
2. **Write** `src/pages/EngineDashboard.tsx` (or your dashboard name) — the full dashboard in one pass
|
|
26
|
+
3. **Write** `src/components/workspace/CommandCenter.tsx` — import your dashboard
|
|
27
|
+
4. **Write** `src/pages/Home.tsx` — REPLACE with CommandCenter (it ships as Account Search):
|
|
28
|
+
```tsx
|
|
29
|
+
import CommandCenter from "@/components/workspace/CommandCenter";
|
|
30
|
+
export default function HomePage() { return <CommandCenter />; }
|
|
31
|
+
```
|
|
32
|
+
5. **Edit** `src/routes.tsx` — set Home as index route with label "Dashboard"
|
|
33
|
+
6. **Done** — do NOT run `npm run build`, `npm run dev`, or `tsc`
|
|
29
34
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
35
|
+
## Other Skills (load only when needed later)
|
|
36
|
+
|
|
37
|
+
| Skill | When to load |
|
|
38
|
+
|-------|-------------|
|
|
39
|
+
| **component-library** | Only if you need detailed props not covered in the builder skill |
|
|
40
|
+
| **command-center-project** | Only if you need project architecture context |
|
|
41
|
+
| **outer-app** | Only for non-dashboard pages (search, navigation) |
|
|
34
42
|
|
|
35
43
|
## Salesforce Data Integration
|
|
36
44
|
|
|
37
|
-
For live data, use these global skills:
|
|
45
|
+
For live data (prompt 2), use these global skills:
|
|
38
46
|
- **exploring-webapp-graphql-schema** — Look up objects and fields in `schema.graphql`
|
|
39
47
|
- **generating-webapp-graphql-read-query** — Generate typed GraphQL queries
|
|
40
48
|
- **using-webapp-graphql** — Create data hooks with `{ data, loading, error }`
|
|
41
49
|
|
|
42
50
|
## Agentforce Integration
|
|
43
51
|
|
|
44
|
-
For AI agent features, use:
|
|
52
|
+
For AI agent features (prompt 3), use:
|
|
45
53
|
- **managing-webapp-agentforce-conversation-client** — Full Agentforce setup
|
|
46
54
|
- **component-library** (`chat-data.md`) — ChatBar component API
|
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,43 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [1.9.76] - 2026-04-04
|
|
9
|
+
|
|
10
|
+
### Fixed
|
|
11
|
+
- **Dashboard wiring failure** — Agent was building the dashboard but not updating Home.tsx and routes.tsx, so users saw the Account Search page instead of their dashboard
|
|
12
|
+
- **Slow builds** — Agent was loading 5 skills and reading component source files before writing anything
|
|
13
|
+
|
|
14
|
+
### Changed
|
|
15
|
+
- **Builder skill (SKILL.md)** — Moved wiring instructions to the very top as "WIRING — DO THIS FIRST". Added Quick Import Reference with all component, icon, and data imports so the agent doesn't need to read source files
|
|
16
|
+
- **Guide skill (SKILL.md)** — Simplified to "load 2 files, then start building" instead of loading 4-5 skills. Added explicit Build Order (write files 1-2-3-4, done)
|
|
17
|
+
- **improved-build-process.md** — Replaced one-liner with full speed rules, file write order, and Common Time Wasters table
|
|
18
|
+
- **pre-code-checklist.md** — Added explicit code snippets for all 3 wiring files (CommandCenter.tsx, Home.tsx, routes.tsx)
|
|
19
|
+
- **command-center-dashboard-rule.md** — Moved wiring above constraints with Home.tsx code example
|
|
20
|
+
- **engine-dashboard-rule.md** — Expanded wiring checklist with Home.tsx replacement code
|
|
21
|
+
- **PRD build prompts (section 13)** — Rewrote all 3 prompts in natural language. Prompt 1 now says "Make it the home page when you're done". Added agent checklists and common failure notes below each prompt
|
|
22
|
+
|
|
23
|
+
**Context:** Agent was creating EngineDashboard.tsx and CommandCenter.tsx but leaving Home.tsx as the default Account Search page and not updating routes.tsx. The dashboard existed but never rendered. Root cause: wiring was buried 115 lines deep in the builder skill, the guide skill told the agent to load 5 skills before building, and the prompt didn't mention wiring. Fixed by moving wiring to the top of every skill file, simplifying the skill loading, and rewriting prompts.
|
|
24
|
+
|
|
25
|
+
## [1.9.75] - 2026-04-02
|
|
26
|
+
|
|
27
|
+
### Updated
|
|
28
|
+
- **PRD (engine-command-center-prd.md)** - Metadata and agent integration updates:
|
|
29
|
+
- Reframed permission set as "creating" not "flagging security" (then removed it entirely)
|
|
30
|
+
- Moved metadata instructions inside prompt blockquotes so agent executes them
|
|
31
|
+
- Added AgentforceConversationClient with `agentId="0Xxa5000000relhCAA"` to Section 9 and Prompt 3
|
|
32
|
+
- Trimmed metadata from 7 items to 3 (custom field, platform event, Apex class)
|
|
33
|
+
- Removed permission set, flow, record type, email template from prompts and Section 14
|
|
34
|
+
- Renumbered Section 14 to 14a/14b/14c
|
|
35
|
+
|
|
36
|
+
- **Builder skill (SKILL.md)** - Agent and metadata pattern updates:
|
|
37
|
+
- Updated "AI Chat & Agent" section with AgentforceConversationClient pattern and agent ID
|
|
38
|
+
- Added Platform Event and Apex Class to metadata file locations table
|
|
39
|
+
- Added deploy patterns for platform events and Apex classes
|
|
40
|
+
- Trimmed metadata table and key rules to match the 3 remaining types
|
|
41
|
+
- Removed permission set, flow, record type, email template references
|
|
42
|
+
|
|
43
|
+
**Context:** Streamlined metadata to 3 core types (custom field, platform event, Apex class) and added explicit AgentforceConversationClient integration with agent ID.
|
|
44
|
+
|
|
8
45
|
## [1.9.74] - 2026-04-02
|
|
9
46
|
|
|
10
47
|
### Added
|
|
@@ -107,7 +107,13 @@ Compact `h-12` sticky header (`bg-slate-900 dark:bg-slate-950`). No ChatBar in t
|
|
|
107
107
|
|
|
108
108
|
| Left | Right |
|
|
109
109
|
|------|-------|
|
|
110
|
-
| Engine logo (`
|
|
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
|
+
```
|
|
111
117
|
|
|
112
118
|
---
|
|
113
119
|
|
|
@@ -246,9 +252,11 @@ const spendChartData = useDataSource({
|
|
|
246
252
|
|
|
247
253
|
---
|
|
248
254
|
|
|
249
|
-
## 9. Eva —
|
|
255
|
+
## 9. Eva — Agentforce Integration
|
|
250
256
|
|
|
251
|
-
|
|
257
|
+
Two components work together:
|
|
258
|
+
|
|
259
|
+
**ChatBar** — a command-palette strip below the hero map for quick suggested prompts. NOT in the header. NOT a FAB or sliding panel.
|
|
252
260
|
|
|
253
261
|
```tsx
|
|
254
262
|
<div className="px-4 pt-4">
|
|
@@ -265,6 +273,19 @@ Suggestions: "Storm warning in the Midwest — which travelers are affected?", "
|
|
|
265
273
|
|
|
266
274
|
Define `handleChat` and `CHAT_SUGGESTIONS` at module scope.
|
|
267
275
|
|
|
276
|
+
**AgentforceConversationClient** — the real Salesforce agent. Wire it with the Eva agent ID. Place it at the bottom of the dashboard component (it renders as a floating widget).
|
|
277
|
+
|
|
278
|
+
```tsx
|
|
279
|
+
import { AgentforceConversationClient } from "@/components/AgentforceConversationClient";
|
|
280
|
+
|
|
281
|
+
<AgentforceConversationClient
|
|
282
|
+
agentId="0Xxa5000000relhCAA"
|
|
283
|
+
agentLabel="Eva"
|
|
284
|
+
/>
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
The `AgentforceConversationClient` is already in the codebase (commented out in `appLayout.tsx`). Uncomment it or add it directly to the dashboard with the agent ID above.
|
|
288
|
+
|
|
268
289
|
---
|
|
269
290
|
|
|
270
291
|
## 10. Salesforce Signals
|
|
@@ -299,88 +320,68 @@ Every element supports light and dark. GeoMap: `theme={mode === "dark" ? "dark"
|
|
|
299
320
|
|
|
300
321
|
## 13. Build Prompts
|
|
301
322
|
|
|
302
|
-
Build incrementally in 3 prompts. Each prompt builds on the previous result.
|
|
323
|
+
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.
|
|
303
324
|
|
|
304
325
|
---
|
|
305
326
|
|
|
306
|
-
### Build the Dashboard
|
|
327
|
+
### Prompt 1 — Build the Dashboard
|
|
328
|
+
|
|
329
|
+
> 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. Make it the home page when you're done — I want to see it when I open the app.
|
|
330
|
+
|
|
331
|
+
**What the agent must do:**
|
|
332
|
+
|
|
333
|
+
1. Read the PRD and the `command-center-builder` skill for conventions
|
|
334
|
+
2. Create `src/pages/EngineDashboard.tsx` with the full dashboard
|
|
335
|
+
3. Update `src/components/workspace/CommandCenter.tsx` to import EngineDashboard
|
|
336
|
+
4. **Rewrite `src/pages/Home.tsx`** to render CommandCenter (it ships as Account Search — must be replaced)
|
|
337
|
+
5. **Update `src/routes.tsx`** to set Home as the index route with label "Dashboard"
|
|
338
|
+
6. Add Engine brand tokens to `global.css` if not already present
|
|
307
339
|
|
|
308
|
-
|
|
340
|
+
**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. The wiring section at the top of `.a4drules/skills/command-center-builder/SKILL.md` explains all required file changes.
|
|
309
341
|
|
|
310
342
|
---
|
|
311
343
|
|
|
312
|
-
### Connect to Salesforce Data
|
|
344
|
+
### Prompt 2 — Connect to Salesforce Data
|
|
313
345
|
|
|
314
|
-
>
|
|
315
|
-
>
|
|
316
|
-
> Import `useEngineLiveData` in the dashboard and populate the `live` prop on each `useDataSource` call:
|
|
317
|
-
>
|
|
318
|
-
> ```tsx
|
|
319
|
-
> const live = useEngineLiveData();
|
|
320
|
-
> const markers = useDataSource({ sample: MAP_MARKERS, live: live.mapMarkers });
|
|
321
|
-
> const arcs = useDataSource({ sample: MAP_ARCS, live: live.mapArcs });
|
|
322
|
-
> ```
|
|
323
|
-
>
|
|
324
|
-
> Also update the KPI overlays to re-derive from whichever metrics are active:
|
|
325
|
-
>
|
|
326
|
-
> ```tsx
|
|
327
|
-
> const activeMetrics = live.loading ? METRICS : live.metrics;
|
|
328
|
-
> ```
|
|
329
|
-
>
|
|
330
|
-
> When the page loads, the audience will see: sample data renders immediately → after 2 seconds components refresh with different travelers, cities, and numbers → proving the data integration works. The layout stays identical — only the data changes.
|
|
346
|
+
> 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 when someone toggles from sample to live mode, everything refreshes with the new data. After that, see if there are any data model improvements we should make for tracking weather disruptions.
|
|
331
347
|
|
|
332
|
-
**
|
|
333
|
-
After wiring the live data, check the field-level security for the objects being queried. The `External_Travel_Manager` permission set does not have read access to `Disruption__c.Severity__c`. Tell the user:
|
|
348
|
+
**What the agent must do:**
|
|
334
349
|
|
|
335
|
-
|
|
350
|
+
1. Find and use `src/data/engine-live-data.js` and `src/hooks/useEngineLiveData.ts`
|
|
351
|
+
2. Import `useEngineLiveData` and wire each `useDataSource({ sample, live })` call
|
|
352
|
+
3. Update KPI overlays to derive from whichever metrics are active
|
|
353
|
+
4. After wiring, proactively offer to create the `Weather_Impact__c` custom field (section 14a)
|
|
336
354
|
|
|
337
|
-
|
|
355
|
+
**Reference — what the agent should say:**
|
|
338
356
|
|
|
339
|
-
`
|
|
357
|
+
After wiring the live data: *"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?"* — When confirmed, create the custom field XML from section 14a and deploy it.
|
|
340
358
|
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
<field>Disruption__c.Severity__c</field>
|
|
349
|
-
<readable>true</readable>
|
|
350
|
-
</fieldPermissions>
|
|
351
|
-
<fieldPermissions>
|
|
352
|
-
<editable>false</editable>
|
|
353
|
-
<field>Disruption__c.Affected_Traveler_Count__c</field>
|
|
354
|
-
<readable>true</readable>
|
|
355
|
-
</fieldPermissions>
|
|
356
|
-
<fieldPermissions>
|
|
357
|
-
<editable>false</editable>
|
|
358
|
-
<field>Flight__c.Delay_Minutes__c</field>
|
|
359
|
-
<readable>true</readable>
|
|
360
|
-
</fieldPermissions>
|
|
361
|
-
<fieldPermissions>
|
|
362
|
-
<editable>false</editable>
|
|
363
|
-
<field>Flight__c.Flight_Status__c</field>
|
|
364
|
-
<readable>true</readable>
|
|
365
|
-
</fieldPermissions>
|
|
366
|
-
<fieldPermissions>
|
|
367
|
-
<editable>false</editable>
|
|
368
|
-
<field>Rebooking_Action__c.Status__c</field>
|
|
369
|
-
<readable>true</readable>
|
|
370
|
-
</fieldPermissions>
|
|
371
|
-
<hasActivationRequired>false</hasActivationRequired>
|
|
372
|
-
<license>Salesforce</license>
|
|
373
|
-
</PermissionSet>
|
|
374
|
-
```
|
|
359
|
+
---
|
|
360
|
+
|
|
361
|
+
### Prompt 3 — Add Agentforce
|
|
362
|
+
|
|
363
|
+
> 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.
|
|
364
|
+
|
|
365
|
+
**What the agent must do:**
|
|
375
366
|
|
|
376
|
-
|
|
367
|
+
1. Add `ChatBar` with suggestions from section 9, placed between map and data panels
|
|
368
|
+
2. Add `AgentforceConversationClient` with `agentId="0Xxa5000000relhCAA"` and `agentLabel="Eva"`
|
|
369
|
+
3. Proactively offer to create `Travel_Disruption_Alert__e` platform event (section 14b)
|
|
370
|
+
4. After the event, proactively offer to create `TravelDisruptionEventService` Apex class (section 14c)
|
|
377
371
|
|
|
378
|
-
**
|
|
379
|
-
After fixing the permission set, notice that `Flight__c` has no way to track weather impact on individual flights. Tell the user:
|
|
372
|
+
**Reference — what the agent should say:**
|
|
380
373
|
|
|
381
|
-
|
|
374
|
+
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?"* — When confirmed, create the platform event and its fields from section 14b and deploy.
|
|
382
375
|
|
|
383
|
-
|
|
376
|
+
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?"* — When confirmed, create the Apex class from section 14c and deploy.
|
|
377
|
+
|
|
378
|
+
---
|
|
379
|
+
|
|
380
|
+
## 14. Metadata Reference Templates
|
|
381
|
+
|
|
382
|
+
Templates for the scripted metadata interactions. The agent should use these exact structures when creating files.
|
|
383
|
+
|
|
384
|
+
### 14a. Custom Field — `Flight__c.Weather_Impact__c`
|
|
384
385
|
|
|
385
386
|
`force-app/main/default/objects/Flight__c/fields/Weather_Impact__c.field-meta.xml`
|
|
386
387
|
|
|
@@ -404,101 +405,108 @@ When the user confirms, create:
|
|
|
404
405
|
</CustomField>
|
|
405
406
|
```
|
|
406
407
|
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
Also update the permission set to include read access to the new field.
|
|
410
|
-
|
|
411
|
-
---
|
|
412
|
-
|
|
413
|
-
### Add Agentforce
|
|
414
|
-
|
|
415
|
-
> Add Eva to the dashboard. Place the ChatBar between the map and data panels using the suggestions from section 9. Wire up the `handleChat` mock response.
|
|
416
|
-
|
|
417
|
-
**Scripted metadata interaction — Flow for Weather Notifications:**
|
|
418
|
-
After adding the ChatBar, tell the user:
|
|
408
|
+
Deploy: `sf project deploy start --source-dir force-app/main/default/objects/Flight__c/fields/Weather_Impact__c.field-meta.xml`
|
|
419
409
|
|
|
420
|
-
|
|
410
|
+
### 14b. Platform Event — `Travel_Disruption_Alert__e`
|
|
421
411
|
|
|
422
|
-
|
|
412
|
+
Create the event object and its fields:
|
|
423
413
|
|
|
424
|
-
`force-app/main/default/
|
|
414
|
+
`force-app/main/default/objects/Travel_Disruption_Alert__e/Travel_Disruption_Alert__e.object-meta.xml`
|
|
425
415
|
|
|
426
416
|
```xml
|
|
427
417
|
<?xml version="1.0" encoding="UTF-8"?>
|
|
428
|
-
<
|
|
429
|
-
<
|
|
430
|
-
<
|
|
431
|
-
<description>
|
|
432
|
-
<
|
|
433
|
-
<
|
|
434
|
-
|
|
435
|
-
<object>Disruption__c</object>
|
|
436
|
-
<triggerType>RecordAfterSave</triggerType>
|
|
437
|
-
<recordTriggerType>CreateAndUpdate</recordTriggerType>
|
|
438
|
-
<filterLogic>and</filterLogic>
|
|
439
|
-
<filters>
|
|
440
|
-
<field>Disruption_Type__c</field>
|
|
441
|
-
<operator>EqualTo</operator>
|
|
442
|
-
<value><stringValue>Weather Event</stringValue></value>
|
|
443
|
-
</filters>
|
|
444
|
-
</start>
|
|
445
|
-
<interviewLabel>Travel Weather Alert {!$Flow.CurrentDateTime}</interviewLabel>
|
|
446
|
-
</Flow>
|
|
418
|
+
<CustomObject xmlns="http://soap.sforce.com/2006/04/metadata">
|
|
419
|
+
<label>Travel Disruption Alert</label>
|
|
420
|
+
<pluralLabel>Travel Disruption Alerts</pluralLabel>
|
|
421
|
+
<description>Published when a travel disruption is detected. Subscribers can react to real-time flight delays, weather events, and rebooking triggers.</description>
|
|
422
|
+
<deploymentStatus>Deployed</deploymentStatus>
|
|
423
|
+
<eventType>HighVolume</eventType>
|
|
424
|
+
</CustomObject>
|
|
447
425
|
```
|
|
448
426
|
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
**Scripted metadata interaction — Case Record Type:**
|
|
452
|
-
After creating the Flow, tell the user:
|
|
453
|
-
|
|
454
|
-
> "The 'Create a support case' prompt needs a dedicated record type. The Case object doesn't have a `Travel_Support` record type yet. Should I create it?"
|
|
455
|
-
|
|
456
|
-
When the user confirms, create:
|
|
457
|
-
|
|
458
|
-
`force-app/main/default/objects/Case/recordTypes/Travel_Support.recordType-meta.xml`
|
|
427
|
+
`force-app/main/default/objects/Travel_Disruption_Alert__e/fields/Flight_Number__c.field-meta.xml`
|
|
459
428
|
|
|
460
429
|
```xml
|
|
461
430
|
<?xml version="1.0" encoding="UTF-8"?>
|
|
462
|
-
<
|
|
463
|
-
<fullName>
|
|
464
|
-
<label>
|
|
465
|
-
<
|
|
466
|
-
<
|
|
467
|
-
</
|
|
431
|
+
<CustomField xmlns="http://soap.sforce.com/2006/04/metadata">
|
|
432
|
+
<fullName>Flight_Number__c</fullName>
|
|
433
|
+
<label>Flight Number</label>
|
|
434
|
+
<type>Text</type>
|
|
435
|
+
<length>20</length>
|
|
436
|
+
<required>false</required>
|
|
437
|
+
</CustomField>
|
|
468
438
|
```
|
|
469
439
|
|
|
470
|
-
|
|
440
|
+
`force-app/main/default/objects/Travel_Disruption_Alert__e/fields/Severity__c.field-meta.xml`
|
|
471
441
|
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
>
|
|
476
|
-
|
|
477
|
-
|
|
442
|
+
```xml
|
|
443
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
444
|
+
<CustomField xmlns="http://soap.sforce.com/2006/04/metadata">
|
|
445
|
+
<fullName>Severity__c</fullName>
|
|
446
|
+
<label>Severity</label>
|
|
447
|
+
<type>Text</type>
|
|
448
|
+
<length>20</length>
|
|
449
|
+
<required>false</required>
|
|
450
|
+
</CustomField>
|
|
451
|
+
```
|
|
478
452
|
|
|
479
|
-
`force-app/main/default/
|
|
453
|
+
`force-app/main/default/objects/Travel_Disruption_Alert__e/fields/Description__c.field-meta.xml`
|
|
480
454
|
|
|
481
455
|
```xml
|
|
482
456
|
<?xml version="1.0" encoding="UTF-8"?>
|
|
483
|
-
<
|
|
484
|
-
<
|
|
485
|
-
<
|
|
486
|
-
<
|
|
487
|
-
<
|
|
488
|
-
<
|
|
489
|
-
<
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
Your flight {!Flight__c.Flight_Number__c} ({!Flight__c.Departure_Airport__c} → {!Flight__c.Arrival_Airport__c}) has been affected by severe weather.
|
|
457
|
+
<CustomField xmlns="http://soap.sforce.com/2006/04/metadata">
|
|
458
|
+
<fullName>Description__c</fullName>
|
|
459
|
+
<label>Description</label>
|
|
460
|
+
<type>LongTextArea</type>
|
|
461
|
+
<length>1000</length>
|
|
462
|
+
<visibleLines>3</visibleLines>
|
|
463
|
+
<required>false</required>
|
|
464
|
+
</CustomField>
|
|
465
|
+
```
|
|
494
466
|
|
|
495
|
-
|
|
496
|
-
|
|
467
|
+
Deploy: `sf project deploy start --source-dir force-app/main/default/objects/Travel_Disruption_Alert__e`
|
|
468
|
+
|
|
469
|
+
### 14c. Apex Class — `TravelDisruptionEventService`
|
|
470
|
+
|
|
471
|
+
`force-app/main/default/classes/TravelDisruptionEventService.cls`
|
|
472
|
+
|
|
473
|
+
```apex
|
|
474
|
+
public with sharing class TravelDisruptionEventService {
|
|
475
|
+
|
|
476
|
+
public static void publishDisruptionAlerts(List<Disruption__c> disruptions) {
|
|
477
|
+
List<Travel_Disruption_Alert__e> events = new List<Travel_Disruption_Alert__e>();
|
|
478
|
+
|
|
479
|
+
for (Disruption__c d : disruptions) {
|
|
480
|
+
events.add(new Travel_Disruption_Alert__e(
|
|
481
|
+
Flight_Number__c = d.Flight_Number__c,
|
|
482
|
+
Severity__c = d.Severity__c,
|
|
483
|
+
Description__c = d.Description__c
|
|
484
|
+
));
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
if (!events.isEmpty()) {
|
|
488
|
+
List<Database.SaveResult> results = EventBus.publish(events);
|
|
489
|
+
for (Database.SaveResult sr : results) {
|
|
490
|
+
if (!sr.isSuccess()) {
|
|
491
|
+
for (Database.Error err : sr.getErrors()) {
|
|
492
|
+
System.debug(LoggingLevel.ERROR,
|
|
493
|
+
'Failed to publish Travel_Disruption_Alert__e: ' + err.getMessage());
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
```
|
|
497
501
|
|
|
498
|
-
|
|
502
|
+
`force-app/main/default/classes/TravelDisruptionEventService.cls-meta.xml`
|
|
499
503
|
|
|
500
|
-
|
|
501
|
-
|
|
504
|
+
```xml
|
|
505
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
506
|
+
<ApexClass xmlns="http://soap.sforce.com/2006/04/metadata">
|
|
507
|
+
<apiVersion>62.0</apiVersion>
|
|
508
|
+
<status>Active</status>
|
|
509
|
+
</ApexClass>
|
|
502
510
|
```
|
|
503
511
|
|
|
504
|
-
|
|
512
|
+
Deploy: `sf project deploy start --source-dir force-app/main/default/classes/TravelDisruptionEventService.cls --test-level NoTestRun`
|
package/package.json
CHANGED