@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.
@@ -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. `CommandCenter.tsx` imports `EngineDashboard` (not `BlankDashboard`)
41
- 2. `Home.tsx` renders `CommandCenter`
42
- 3. `routes.tsx` has `Home` as index route, `Search` at `/search`
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
- This is a reference checklist. For build instructions, use the phase files in `.a4drules/phases/`.
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
- - [ ] `CommandCenter.tsx` imports your dashboard
24
- - [ ] `Home.tsx` renders `CommandCenter`
25
- - [ ] `routes.tsx` has correct routes
26
- - [ ] DO NOT run `npm run dev` or `npm run validate:dashboard`
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
- Before writing any code, read `.a4drules/features/pre-code-checklist.md` and verify all requirements. The most common mistakes are:
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
- <img src={engineLogo} alt="Engine" className="h-8 w-auto" />
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 & How to Wire Them
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
- Use `ChatBar` for dashboards, `ChatPanel` for full-page chat.
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 — permission sets, custom fields, flows, record types — write standard SFDX XML files and deploy with the Salesforce CLI.
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
- | Flow | `force-app/main/default/flows/{Name}.flow-meta.xml` |
525
- | Record Type | `force-app/main/default/objects/{Object}/recordTypes/{Name}.recordType-meta.xml` |
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 check whether the Salesforce org has the metadata needed for the features you're building. If something is missing a field isn't accessible, a record type doesn't exist, a flow would automate a manual process tell the user what's missing and ask before creating it. The PRD's build prompts include specific scripted moments for these interactions.
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
- - Permission set field permissions: set `readable` to `true`, `editable` to `false` for read-only dashboard fields
544
- - Flows: set `status` to `Draft` the user will activate after review
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
- See the PRD (engine-command-center-prd.md) section 13 for the 4-phase build process.
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
- ## Engine Travel Command Center
13
+ ## How to Build Efficiently
14
14
 
15
- The product spec is in `engine-command-center-prd.md` at the React app root (`force-app/main/default/uiBundles/reactcursor1/`). It defines the layout, components, data model, and brand tokens for the dashboard.
15
+ **Read these two files, then start building. Do not load other skills or explore component source files.**
16
16
 
17
- Sample data is pre-built in `src/data/engine-sample-data.js` with dashboard-ready exports.
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
- ## Skills
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
- | Skill | What it covers |
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
- ## Workflow
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
- 1. Read the PRD (`engine-command-center-prd.md`) for what to build
31
- 2. Reference **component-library** for component APIs
32
- 3. Follow **command-center-builder** conventions for layout and styling
33
- 4. Reference **command-center-project** for file locations and wiring
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 (`GlobeAltIcon` in `bg-brand-600` square) + "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) |
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 — ChatBar
255
+ ## 9. Eva — Agentforce Integration
250
256
 
251
- Eva renders as a full-width `ChatBar` below the hero map, between the map and the data panels. NOT in the header. NOT a FAB or sliding panel.
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
- > Build the Engine Travel Command Center dashboard. Read the PRD for the full spec. Create the visualization-hero layout with the sticky header, hero GeoMap, glass KPI overlays, flight status strip, and all 4 data panels — Escalations, Disruptions, Active Travelers, and Monthly Spend Trend. Wire up the sample data from `src/data/engine-sample-data.js` so we can see real travelers, flights, and map markers. Include the "Assign to Agent" buttons on open escalations, the "View in Salesforce" links in traveler details, the "Powered by Agentforce" badge in the header, and the Salesforce signal toasts. Skip the Eva ChatBar for now — we'll add that after we connect to live data.
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
- > Connect the dashboard to live Salesforce data. A second dataset already exists in `src/data/engine-live-data.js` with 12 travelers across global routes and different KPIs (distinct from the 8-traveler sample data). A hook already exists at `src/hooks/useEngineLiveData.ts` it imports the live data, simulates a 2-second loading delay, then calls `setMode("live")` to flip the global data mode.
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
- **Scripted metadata interaction Permission Set:**
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
- > "I notice the `External_Travel_Manager` permission set doesn't have read access to `Disruption__c.Severity__c`. This field is needed to display disruption severity in the dashboard. Would you like me to update the permission set?"
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
- When the user confirms, create:
355
+ **Reference — what the agent should say:**
338
356
 
339
- `force-app/main/default/permissionsets/External_Travel_Manager.permissionset-meta.xml`
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
- ```xml
342
- <?xml version="1.0" encoding="UTF-8"?>
343
- <PermissionSet xmlns="http://soap.sforce.com/2006/04/metadata">
344
- <label>External Travel Manager</label>
345
- <description>Field access for the Engine Travel Command Center dashboard</description>
346
- <fieldPermissions>
347
- <editable>false</editable>
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
- Then run: `sf project deploy start --source-dir force-app/main/default/permissionsets/External_Travel_Manager.permissionset-meta.xml`
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
- **Scripted metadata interaction Custom Field:**
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
- > "There's no `Weather_Impact__c` field on `Flight__c` to track weather-related disruptions. This would help the dashboard filter storm-affected flights. Want me to create it?"
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
- When the user confirms, create:
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
- Then run: `sf project deploy start --source-dir force-app/main/default/objects/Flight__c/fields/Weather_Impact__c.field-meta.xml`
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
- > "Since the dashboard handles weather disruptions, I can create a Flow that automatically sends weather delay alerts to affected travelers. It would query `Disruption__c` records where `Disruption_Type__c = 'Weather Event'`, match them to `Contact` records via `Flight__c`, and send a notification email. Want me to build it?"
410
+ ### 14b. Platform Event `Travel_Disruption_Alert__e`
421
411
 
422
- When the user confirms, create:
412
+ Create the event object and its fields:
423
413
 
424
- `force-app/main/default/flows/Travel_Weather_Alert_Notification.flow-meta.xml`
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
- <Flow xmlns="http://soap.sforce.com/2006/04/metadata">
429
- <apiVersion>62.0</apiVersion>
430
- <label>Travel Weather Alert Notification</label>
431
- <description>Sends weather delay alerts to travelers affected by disruptions. Triggered when a Disruption__c record is created or updated with Disruption_Type__c = Weather Event.</description>
432
- <status>Draft</status>
433
- <processType>AutoLaunchedFlow</processType>
434
- <start>
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
- Then run: `sf project deploy start --source-dir force-app/main/default/flows/Travel_Weather_Alert_Notification.flow-meta.xml`
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
- <RecordType xmlns="http://soap.sforce.com/2006/04/metadata">
463
- <fullName>Travel_Support</fullName>
464
- <label>Travel Support</label>
465
- <description>Support cases for travel disruptions, rebookings, and weather events</description>
466
- <active>true</active>
467
- </RecordType>
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
- Then run: `sf project deploy start --source-dir force-app/main/default/objects/Case/recordTypes/Travel_Support.recordType-meta.xml`
440
+ `force-app/main/default/objects/Travel_Disruption_Alert__e/fields/Severity__c.field-meta.xml`
471
441
 
472
- **Scripted metadata interaction — Email Template:**
473
- Finally, tell the user:
474
-
475
- > "I'll also create an email template for weather delay notifications — the Flow can use it to send branded alerts with flight details and alternate routing options."
476
-
477
- Create:
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/email/Travel_Alerts/Weather_Delay_Notification.email-meta.xml`
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
- <EmailTemplate xmlns="http://soap.sforce.com/2006/04/metadata">
484
- <name>Weather Delay Notification</name>
485
- <available>true</available>
486
- <description>Sent to travelers when their flight is affected by a weather disruption</description>
487
- <encodingKey>UTF-8</encodingKey>
488
- <style>freeForm</style>
489
- <subject>Weather Alert: Your flight {!Flight__c.Flight_Number__c} is affected</subject>
490
- <type>custom</type>
491
- <textOnly>Hi {!Contact.FirstName},
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
- Current delay: {!Disruption__c.Description__c}
496
- Eva is monitoring the situation and will notify you of any changes.
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
- If you need immediate assistance, reply to this email or ask Eva in the Engine Travel app.
502
+ `force-app/main/default/classes/TravelDisruptionEventService.cls-meta.xml`
499
503
 
500
- — Engine Travel Team</textOnly>
501
- </EmailTemplate>
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
- Then run: `sf project deploy start --source-dir force-app/main/default/email/`
512
+ Deploy: `sf project deploy start --source-dir force-app/main/default/classes/TravelDisruptionEventService.cls --test-level NoTestRun`
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@schandlergarcia/sf-web-components",
3
- "version": "1.9.74",
3
+ "version": "1.9.76",
4
4
  "description": "Reusable Salesforce web components library with Tailwind CSS v4 and shadcn/ui",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",