@schandlergarcia/sf-web-components 1.9.48 → 1.9.52

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.
@@ -0,0 +1,353 @@
1
+ # Salesforce Data Access
2
+
3
+ - **Fetch or display Salesforce data** — Query records (Account, Contact, Opportunity, custom objects) to show in a component
4
+ - **Create, update, or delete records** — Perform mutations on Salesforce data
5
+ - **Add data fetching to a component** — Wire up a React component to Salesforce data
6
+ - **Call REST APIs** — Use Connect REST, Apex REST, or UI API endpoints
7
+ - **Explore the org schema** — Discover available objects, fields, or relationships
8
+
9
+ ## Data SDK Requirement
10
+
11
+ > **All Salesforce data access MUST use the Data SDK** (`@salesforce/sdk-data`). The SDK handles authentication, CSRF, and base URL resolution. Never use `fetch()` or `axios` directly.
12
+
13
+ ```typescript
14
+ import { createDataSDK, gql } from "@salesforce/sdk-data";
15
+
16
+ const sdk = await createDataSDK();
17
+
18
+ // GraphQL for record queries/mutations (PREFERRED)
19
+ const response = await sdk.graphql?.<ResponseType>(query, variables);
20
+
21
+ // REST for Connect REST, Apex REST, UI API (when GraphQL insufficient)
22
+ const res = await sdk.fetch?.("/services/apexrest/my-resource");
23
+ ```
24
+
25
+ **Always use optional chaining** (`sdk.graphql?.()`, `sdk.fetch?.()`) — these methods may be undefined in some surfaces.
26
+
27
+ ## Supported APIs
28
+
29
+ **Only the following APIs are permitted.** Any endpoint not listed here must not be used.
30
+
31
+ | API | Method | Endpoints / Use Case |
32
+ |-----|--------|----------------------|
33
+ | GraphQL | `sdk.graphql` | All record queries and mutations via `uiapi { }` namespace |
34
+ | UI API REST | `sdk.fetch` | `/services/data/v{ver}/ui-api/records/{id}` — record metadata when GraphQL is insufficient |
35
+ | Apex REST | `sdk.fetch` | `/services/apexrest/{resource}` — custom server-side logic, aggregates, multi-step transactions |
36
+ | Connect REST | `sdk.fetch` | `/services/data/v{ver}/connect/file/upload/config` — file upload config |
37
+ | Einstein LLM | `sdk.fetch` | `/services/data/v{ver}/einstein/llm/prompt/generations` — AI text generation |
38
+
39
+ **Not supported:**
40
+
41
+ - **Enterprise REST query endpoint** (`/services/data/v*/query` with SOQL) — blocked at the proxy level. Use GraphQL for record reads; use Apex REST if server-side SOQL aggregates are required.
42
+ - **Aura-enabled Apex** (`@AuraEnabled`) — an LWC/Aura pattern with no invocation path from React webapps.
43
+ - **Chatter API** (`/chatter/users/me`) — use `uiapi { currentUser { ... } }` in a GraphQL query instead.
44
+ - **Any other Salesforce REST endpoint** not listed in the supported table above.
45
+
46
+ ## Decision: GraphQL vs REST
47
+
48
+ | Need | Method | Example |
49
+ |------|--------|---------|
50
+ | Query/mutate records | `sdk.graphql` | Account, Contact, custom objects |
51
+ | Current user info | `sdk.graphql` | `uiapi { currentUser { Id Name { value } } }` |
52
+ | UI API record metadata | `sdk.fetch` | `/ui-api/records/{id}` |
53
+ | Connect REST | `sdk.fetch` | `/connect/file/upload/config` |
54
+ | Apex REST | `sdk.fetch` | `/services/apexrest/auth/login` |
55
+ | Einstein LLM | `sdk.fetch` | `/einstein/llm/prompt/generations` |
56
+
57
+ **GraphQL is preferred** for record operations. Use REST only when GraphQL doesn't cover the use case.
58
+
59
+ ---
60
+
61
+ ## GraphQL Workflow
62
+
63
+ ### Step 1: Acquire Schema
64
+
65
+ The `schema.graphql` file is **already checked into the repo** at the SFDX project root. **Never open or parse it directly.**
66
+
67
+ - Pre-built from sample data, contains Engine objects (Contact, Trip__c, Flight__c, etc.)
68
+ - No generation needed — just use it
69
+ - If you ever need to regenerate (after adding fields to sample data): `npm run graphql:schema:sample` from webapp dir
70
+
71
+ ### Step 2: Look Up Entity Schema
72
+
73
+ Map user intent to PascalCase names ("accounts" → `Account`), then **run the search script from the project root**:
74
+
75
+ ```bash
76
+ # From project root — look up all relevant schema info for one or more entities
77
+ bash scripts/graphql-search.sh Account
78
+
79
+ # Multiple entities at once
80
+ bash scripts/graphql-search.sh Account Contact Opportunity
81
+ ```
82
+
83
+ The script outputs five sections per entity:
84
+ 1. **Type definition** — all queryable fields and relationships
85
+ 2. **Filter options** — available fields for `where:` conditions
86
+ 3. **Sort options** — available fields for `orderBy:`
87
+ 4. **Create input** — fields accepted by create mutations
88
+ 5. **Update input** — fields accepted by update mutations
89
+
90
+ Use this output to determine exact field names before writing any query or mutation. **Maximum 2 script runs.** If the entity still can't be found, ask the user — the object may not be deployed.
91
+
92
+ ### Step 3: Generate Query
93
+
94
+ Use the templates below. Every field name **must** be verified from the script output in Step 2.
95
+
96
+ #### Read Query Template
97
+
98
+ ```graphql
99
+ query GetAccounts {
100
+ uiapi {
101
+ query {
102
+ Account(where: { Industry: { eq: "Technology" } }, first: 10) {
103
+ edges {
104
+ node {
105
+ Id
106
+ Name @optional { value }
107
+ Industry @optional { value }
108
+ # Parent relationship
109
+ Owner @optional { Name { value } }
110
+ # Child relationship
111
+ Contacts @optional {
112
+ edges { node { Name @optional { value } } }
113
+ }
114
+ }
115
+ }
116
+ }
117
+ }
118
+ }
119
+ }
120
+ ```
121
+
122
+ **FLS Resilience**: Apply `@optional` to all record fields. The server omits inaccessible fields instead of failing. Consuming code must use optional chaining:
123
+
124
+ ```typescript
125
+ const name = node.Name?.value ?? "";
126
+ ```
127
+
128
+ #### Mutation Template
129
+
130
+ ```graphql
131
+ mutation CreateAccount($input: AccountCreateInput!) {
132
+ uiapi {
133
+ AccountCreate(input: $input) {
134
+ Record { Id Name { value } }
135
+ }
136
+ }
137
+ }
138
+ ```
139
+
140
+ **Mutation constraints:**
141
+ - Create: Include required fields, only `createable` fields, no child relationships
142
+ - Update: Include `Id`, only `updateable` fields
143
+ - Delete: Include `Id` only
144
+
145
+ #### Object Metadata & Picklist Values
146
+
147
+ Use `uiapi { objectInfos(...) }` to fetch field metadata or picklist values. Pass **either** `apiNames` or `objectInfoInputs` — never both in the same query.
148
+
149
+ **Object metadata** (field labels, data types, CRUD flags):
150
+
151
+ ```typescript
152
+ const GET_OBJECT_INFO = gql`
153
+ query GetObjectInfo($apiNames: [String!]!) {
154
+ uiapi {
155
+ objectInfos(apiNames: $apiNames) {
156
+ ApiName
157
+ label
158
+ labelPlural
159
+ fields {
160
+ ApiName
161
+ label
162
+ dataType
163
+ updateable
164
+ createable
165
+ }
166
+ }
167
+ }
168
+ }
169
+ `;
170
+
171
+ const sdk = await createDataSDK();
172
+ const response = await sdk.graphql?.(GET_OBJECT_INFO, { apiNames: ["Account"] });
173
+ const objectInfos = response?.data?.uiapi?.objectInfos ?? [];
174
+ ```
175
+
176
+ **Picklist values** (use `objectInfoInputs` + `... on PicklistField` inline fragment):
177
+
178
+ ```typescript
179
+ const GET_PICKLIST_VALUES = gql`
180
+ query GetPicklistValues($objectInfoInputs: [ObjectInfoInput!]!) {
181
+ uiapi {
182
+ objectInfos(objectInfoInputs: $objectInfoInputs) {
183
+ ApiName
184
+ fields {
185
+ ApiName
186
+ ... on PicklistField {
187
+ picklistValuesByRecordTypeIDs {
188
+ recordTypeID
189
+ picklistValues {
190
+ label
191
+ value
192
+ }
193
+ }
194
+ }
195
+ }
196
+ }
197
+ }
198
+ }
199
+ `;
200
+
201
+ const response = await sdk.graphql?.(GET_PICKLIST_VALUES, {
202
+ objectInfoInputs: [{ objectApiName: "Account" }],
203
+ });
204
+ const fields = response?.data?.uiapi?.objectInfos?.[0]?.fields ?? [];
205
+ ```
206
+
207
+ ### Step 4: Validate & Test
208
+
209
+ 1. **Lint**: `npx eslint <file>` from webapp dir
210
+ 2. **Test**: Ask user before testing. For mutations, request input values — never fabricate data.
211
+
212
+ **If ESLint reports a GraphQL error** (e.g. `Cannot query field`, `Unknown type`, `Unknown argument`), the field or type name is wrong. Re-run the schema search script to find the correct name — do not guess:
213
+
214
+ ```bash
215
+ # From project root — re-check the entity that caused the error
216
+ bash scripts/graphql-search.sh <EntityName>
217
+ ```
218
+
219
+ Then fix the query using the exact names from the script output.
220
+
221
+ ---
222
+
223
+ ## Webapp Integration (React)
224
+
225
+ ```typescript
226
+ import { createDataSDK, gql } from "@salesforce/sdk-data";
227
+
228
+ const GET_ACCOUNTS = gql`
229
+ query GetAccounts {
230
+ uiapi {
231
+ query {
232
+ Account(first: 10) {
233
+ edges {
234
+ node {
235
+ Id
236
+ Name @optional { value }
237
+ Industry @optional { value }
238
+ }
239
+ }
240
+ }
241
+ }
242
+ }
243
+ }
244
+ `;
245
+
246
+ const sdk = await createDataSDK();
247
+ const response = await sdk.graphql?.(GET_ACCOUNTS);
248
+
249
+ if (response?.errors?.length) {
250
+ throw new Error(response.errors.map(e => e.message).join("; "));
251
+ }
252
+
253
+ const accounts = response?.data?.uiapi?.query?.Account?.edges?.map(e => e.node) ?? [];
254
+
255
+ ---
256
+
257
+ ## REST API Patterns
258
+
259
+ Use `sdk.fetch` when GraphQL is insufficient. See the [Supported APIs](#supported-apis) table for the full allowlist.
260
+
261
+ ```typescript
262
+ declare const __SF_API_VERSION__: string;
263
+ const API_VERSION = typeof __SF_API_VERSION__ !== "undefined" ? __SF_API_VERSION__ : "65.0";
264
+
265
+ // Connect — file upload config
266
+ const res = await sdk.fetch?.(`/services/data/v${API_VERSION}/connect/file/upload/config`);
267
+
268
+ // Apex REST (no version in path)
269
+ const res = await sdk.fetch?.("/services/apexrest/auth/login", {
270
+ method: "POST",
271
+ body: JSON.stringify({ email, password }),
272
+ headers: { "Content-Type": "application/json" },
273
+ });
274
+
275
+ // UI API — record with metadata (prefer GraphQL for simple reads)
276
+ const res = await sdk.fetch?.(`/services/data/v${API_VERSION}/ui-api/records/${recordId}`);
277
+
278
+ // Einstein LLM
279
+ const res = await sdk.fetch?.(`/services/data/v${API_VERSION}/einstein/llm/prompt/generations`, {
280
+ method: "POST",
281
+ body: JSON.stringify({ promptTextorId: prompt }),
282
+ });
283
+ ```
284
+
285
+ **Current user**: Do not use Chatter (`/chatter/users/me`). Use GraphQL instead:
286
+
287
+ ```typescript
288
+ const GET_CURRENT_USER = gql`
289
+ query CurrentUser {
290
+ uiapi { currentUser { Id Name { value } } }
291
+ }
292
+ `;
293
+ const response = await sdk.graphql?.(GET_CURRENT_USER);
294
+ ```
295
+
296
+ ---
297
+
298
+ ## Directory Structure
299
+
300
+ ```
301
+ <project-root>/ ← SFDX project root
302
+ ├── schema.graphql ← grep target (lives here)
303
+ ├── sfdx-project.json
304
+ └── force-app/main/default/webapplications/<app-name>/ ← webapp dir
305
+ ├── package.json ← npm scripts
306
+ └── src/
307
+ ```
308
+
309
+ | Command | Run From | Why |
310
+ |---------|----------|-----|
311
+ | `npm run graphql:schema:sample` | webapp dir | Regenerate schema (rarely needed) |
312
+ | `npx eslint <file>` | webapp dir | Reads eslint.config.js |
313
+ | `bash scripts/graphql-search.sh <Entity>` | project root | Schema lookup |
314
+ | `sf api request rest` | project root | Needs sfdx-project.json |
315
+
316
+ ---
317
+
318
+ ## Quick Reference
319
+
320
+ ### Schema Lookup (from project root)
321
+
322
+ Run the search script to get all relevant schema info in one step:
323
+
324
+ ```bash
325
+ bash scripts/graphql-search.sh <EntityName>
326
+ ```
327
+
328
+ | Script Output Section | Used For |
329
+ |-----------------------|----------|
330
+ | Type definition | Field names, parent/child relationships |
331
+ | Filter options | `where:` conditions |
332
+ | Sort options | `orderBy:` |
333
+ | CreateRepresentation | Create mutation field list |
334
+ | UpdateRepresentation | Update mutation field list |
335
+
336
+ ### Error Categories
337
+
338
+ | Error Contains | Resolution |
339
+ |----------------|------------|
340
+ | `Cannot query field` | Field name is wrong — run `graphql-search.sh <Entity>` and use the exact name from the Type definition section |
341
+ | `Unknown type` | Type name is wrong — run `graphql-search.sh <Entity>` to confirm the correct PascalCase entity name |
342
+ | `Unknown argument` | Argument name is wrong — run `graphql-search.sh <Entity>` and check Filter or OrderBy sections |
343
+ | `invalid syntax` | Fix syntax per error message |
344
+ | `validation error` | Field name is wrong — run `graphql-search.sh <Entity>` to verify |
345
+ | `VariableTypeMismatch` | Correct argument type from schema |
346
+ | `invalid cross reference id` | Entity deleted — ask for valid Id |
347
+
348
+ ### Checklist
349
+
350
+ - [ ] All field names verified via search script (Step 2)
351
+ - [ ] `@optional` applied to record fields (reads)
352
+ - [ ] Optional chaining in consuming code
353
+ - [ ] Lint passes: `npx eslint <file>`
@@ -0,0 +1,16 @@
1
+ # UI Platform Rule
2
+
3
+ **All new UI must be built as a Salesforce Web Application.**
4
+
5
+ When any task involves creating a new UI, frontend, page, dashboard, form, or user-facing feature:
6
+
7
+ 1. Use `sf webapp generate` to scaffold the web app inside the SFDX project — do not use `create-react-app`, standalone Vite, or any other scaffold.
8
+ 2. The app must live under `<sfdx-source>/webapplications/<AppName>/` as a WebApplication bundle.
9
+ 3. Do not build new UIs as LWC components, Aura components, or Visualforce pages.
10
+
11
+ For setup from the project root, use `node scripts/setup-cli.mjs --help` and the options documented there.
12
+
13
+ ## Data Access (MUST FOLLOW)
14
+
15
+ - **Never hardcode data in the app.** All data displayed in the UI must come from live Salesforce data fetching — no static arrays, mock objects, or placeholder values in production code.
16
+ - **Follow `.a4drules/webapp-data.md`** before writing any data access code. All implementation must match those rules (Data SDK, supported APIs, GraphQL workflow).
package/CHANGELOG.md CHANGED
@@ -5,6 +5,264 @@ 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.52] - 2026-04-01
9
+
10
+ ### Added
11
+ - **data/engine-command-center-prd.md** - Complete PRD for Engine Travel Command Center
12
+ - Issue: PRD was external documentation, not part of package
13
+ - Solution: Include PRD in package data, install to webapp root automatically
14
+ - Enables agents to reference PRD directly without external files
15
+ - Location after install: `engine-command-center-prd.md` (webapp root)
16
+ - Sections: Product overview, users, brand tokens, architecture, layout, components, data model, build prompts, anti-patterns
17
+
18
+ ### Changed
19
+ - **scripts/postinstall.mjs** - Now installs Engine PRD to webapp root
20
+ - Copies `engine-command-center-prd.md` from package data/
21
+ - Accessible at same level as schema.graphql for easy reference
22
+ - Updated summary count to include PRD
23
+
24
+ - **scripts/reset-command-center.sh** - Now restores Engine PRD during reset
25
+ - Added restoration of `engine-command-center-prd.md`
26
+ - Updated success message to mention PRD restoration
27
+
28
+ - **.a4drules/** - Synced all skill files from reactapp4
29
+ - Updated existing skills: command-center-builder, command-center-project, component-library, outer-app
30
+ - Added new feature rules:
31
+ - `features/phase2-data-pattern.md` - Data patterns for Phase 2
32
+ - `features/pre-code-checklist.md` - Pre-code verification checklist
33
+ - Added root-level documentation:
34
+ - `validation-requirements.md` - Validation rules
35
+ - `webapp-data.md` - Data access patterns
36
+ - `webapp-ui.md` - UI component patterns
37
+ - Updated troubleshooting: `troubleshooting/graphql-introspection-failure.md`
38
+ - Updated dashboard rules: `features/engine-dashboard-rule.md`, `features/command-center-dashboard-rule.md`
39
+
40
+ ### Rationale
41
+ **The Problem:** Engine PRD was maintained separately (in docs/ or at repo root in other projects). Agents had to search for it, and different projects had different versions.
42
+
43
+ **The Solution:** Include PRD in the package just like sample data and schema:
44
+ 1. PRD ships with package in `data/`
45
+ 2. Postinstall copies to webapp root
46
+ 3. Reset restores it if modified
47
+ 4. All projects get the canonical PRD version
48
+
49
+ **Benefits:**
50
+ - ✅ PRD is always available at `engine-command-center-prd.md`
51
+ - ✅ Agents can reference it without searching
52
+ - ✅ Single source of truth for Engine dashboard specs
53
+ - ✅ Phase 1-4 build prompts included
54
+ - ✅ Anti-patterns documented
55
+ - ✅ Consistent across all projects using the package
56
+
57
+ **What Gets Installed:**
58
+ ```
59
+ webapp-root/
60
+ ├── schema.graphql (6KB - GraphQL schema)
61
+ ├── engine-command-center-prd.md (20KB - Complete PRD)
62
+ ├── src/
63
+ │ └── data/
64
+ │ └── engine-sample-data.js (31KB - Sample data)
65
+ └── scripts/
66
+ └── generate-schema-from-sample.mjs (Generator)
67
+ ```
68
+
69
+ ### Files Synced from reactapp4
70
+ All .a4drules files updated to latest versions:
71
+ - `skills/command-center-builder/SKILL.md`
72
+ - `skills/command-center-project/SKILL.md`
73
+ - `skills/component-library/SKILL.md`
74
+ - `skills/outer-app/SKILL.md`
75
+ - `features/command-center-dashboard-rule.md`
76
+ - `features/engine-dashboard-rule.md`
77
+ - `features/phase2-data-pattern.md` (new)
78
+ - `features/pre-code-checklist.md` (new)
79
+ - `troubleshooting/graphql-introspection-failure.md`
80
+ - `validation-requirements.md` (new)
81
+ - `webapp-data.md` (new)
82
+ - `webapp-ui.md` (new)
83
+
84
+ ### Migration
85
+ No breaking changes. When users update to v1.9.52:
86
+ - Postinstall automatically copies PRD to webapp root
87
+ - Reset script now restores PRD
88
+ - All .a4drules skills updated to latest versions
89
+ - Existing projects continue working
90
+
91
+ ---
92
+
93
+ ## [1.9.51] - 2026-04-01
94
+
95
+ ### Added
96
+ - **data/schema.graphql** - Pre-built GraphQL schema for Engine Travel Command Center
97
+ - Issue: Org introspection fails due to null data types in some fields
98
+ - Solution: Pre-generate schema from sample data field names
99
+ - Enables GraphQL skills to work without org access
100
+ - Schema includes: Contact, Trip__c, Flight__c, Booking__c, Disruption__c, Rebooking_Action__c, Travel_Policy__c
101
+ - All field names match sample data for consistency
102
+ - Works in CI/CD, no org dependency
103
+ - 6KB pre-built schema with proper UIAPI structure
104
+
105
+ - **scripts/generate-schema-from-sample.mjs** - Schema generator script
106
+ - Creates minimal GraphQL schema from sample data field names
107
+ - Infers types from field names (String, Float, Boolean, ID)
108
+ - Generates proper UIAPI structure with connections, filters, pagination
109
+ - Writes to webapp root: `schema.graphql`
110
+ - Enables regeneration when sample data fields change
111
+
112
+ - **.a4drules/troubleshooting/graphql-introspection-failure.md** - Comprehensive troubleshooting guide
113
+ - Documents org introspection bug and workaround
114
+ - Explains what still works (queries) vs what's broken (introspection)
115
+ - Step-by-step manual workaround if needed
116
+ - Decision tree for when to regenerate schema
117
+
118
+ - **.a4drules/features/engine-dashboard-rule.md** - Phase 3 implementation rules
119
+ - Updated to use pre-built schema (no generation needed)
120
+ - GraphQL skills work out of the box
121
+ - Sample data as fallback pattern documented
122
+
123
+ ### Changed
124
+ - **scripts/postinstall.mjs** - Now installs GraphQL schema and generator
125
+ - Copies `schema.graphql` to webapp root
126
+ - Copies `generate-schema-from-sample.mjs` to webapp scripts/
127
+ - Adds `graphql:schema:sample` npm script to package.json
128
+ - Updated summary to show scripts installed
129
+
130
+ - **scripts/reset-command-center.sh** - Now restores GraphQL schema
131
+ - Added step 10: restore schema.graphql from package
132
+ - Handles both installed package and source package locations
133
+ - Updated success message to mention schema restoration
134
+
135
+ - **engine-command-center-prd.md** - Simplified Phase 3 prompt
136
+ - Before: Long explanation about schema generation and fallbacks
137
+ - After: "Schema is already pre-built - use GraphQL skills normally"
138
+ - 4-step process instead of complex troubleshooting
139
+ - Removed DataModeToggle requirement (automatic fallback)
140
+
141
+ ### Rationale
142
+ **The Problem:** Org introspection fails with "cannot invoke FieldDataType.equals(Object) because the return value of Field.getDataType() is null". This breaks:
143
+ - `npm run graphql:schema` (introspection query)
144
+ - IDE autocomplete that queries org directly
145
+ - GraphQL codegen from org schema
146
+
147
+ But **queries still work** - introspection is just metadata.
148
+
149
+ **The Solution:** Pre-generate schema from sample data field names:
150
+ 1. Sample data already has correct Salesforce field names
151
+ 2. Generate schema.graphql from those field names
152
+ 3. Check schema into repo (or package)
153
+ 4. GraphQL skills use the pre-built schema
154
+ 5. Queries execute normally using the same field names
155
+
156
+ **Benefits:**
157
+ - ✅ Agents don't troubleshoot - schema is ready
158
+ - ✅ Works without org access (CI/CD, offline dev)
159
+ - ✅ GraphQL skills work normally (exploring, generating, using)
160
+ - ✅ IDE tooling works (autocomplete, validation)
161
+ - ✅ Consistent with sample-first approach in Phase 2
162
+ - ✅ Simpler Phase 3 experience
163
+
164
+ **When to Regenerate:**
165
+ Only when adding new fields to sample data:
166
+ ```bash
167
+ npm run graphql:schema:sample # Updates schema.graphql
168
+ git commit -m "Add new fields to schema"
169
+ ```
170
+
171
+ ### Files Included in Package
172
+ New files that ship with sf-web-components:
173
+ - `data/schema.graphql` (6KB)
174
+ - `scripts/generate-schema-from-sample.mjs`
175
+ - `.a4drules/troubleshooting/graphql-introspection-failure.md`
176
+ - `.a4drules/features/engine-dashboard-rule.md`
177
+
178
+ ### Migration
179
+ No breaking changes. When users update to v1.9.51:
180
+ - Postinstall automatically copies schema.graphql and generator script
181
+ - Adds `graphql:schema:sample` to package.json scripts
182
+ - Existing projects continue working
183
+ - Phase 3 builds become simpler (no schema troubleshooting)
184
+
185
+ ---
186
+
187
+ ## [1.9.50] - 2026-04-01
188
+
189
+ ### Added
190
+ - **scripts/postinstall.mjs** - Now copies engine-sample-data.js to src/data/ on installation
191
+ - Issue: Phase 2 of Engine PRD required manually creating sample data file
192
+ - Solution: Automatically install pre-built sample data during package setup
193
+ - Sample data includes all Salesforce-shaped records and dashboard-ready derivatives
194
+ - File location: `src/data/engine-sample-data.js` (31KB of ready-to-use data)
195
+ - Eliminates manual data creation step from Phase 2 build process
196
+
197
+ - **scripts/reset-command-center.sh** - Now restores engine-sample-data.js during reset
198
+ - Issue: Reset could leave app with modified or missing sample data
199
+ - Solution: Added step 10 that copies fresh engine-sample-data.js from package
200
+ - Handles both installed package and source package locations
201
+ - Ensures consistent data state across resets
202
+
203
+ ### Changed
204
+ - **engine-command-center-prd.md** - Updated Phase 2 prompt to use pre-installed data
205
+ - Before: "Create `src/data/engine-sample-data.js` with travelers, flights..."
206
+ - After: "Build components using the pre-installed sample data at `src/data/engine-sample-data.js`"
207
+ - Simplified Phase 2: just import and use, no data creation needed
208
+
209
+ - **Postinstall summary** - Now reports data files installed
210
+ - Added line: "Installed X sample data files"
211
+
212
+ - **Reset success message** - Now highlights sample data restoration
213
+ - Added: "Engine sample data (engine-sample-data.js)"
214
+
215
+ ### Rationale
216
+ The engine-sample-data.js file (31KB) contains complete, dashboard-ready data for all Engine Travel Command Center components:
217
+ - Raw Salesforce records (Contact, Trip__c, Flight__c, Booking__c, Disruption__c, etc.)
218
+ - Pre-computed dashboard derivatives (MAP_MARKERS, MAP_ARCS, TRAVELER_CARDS, etc.)
219
+ - All field names match the org schema for easy live-data swap in Phase 3
220
+
221
+ Installing this automatically:
222
+ - Eliminates a 30+ minute manual data-creation step from Phase 2
223
+ - Ensures all developers use the same sample data
224
+ - Makes the Phase 2 prompt simpler and faster
225
+ - Consistent with how we handle other templates (Home.tsx, routes.tsx, etc.)
226
+
227
+ Restoring on reset:
228
+ - Prevents issues where modified sample data breaks demo builds
229
+ - Keeps data in sync with global.css, templates, and structure
230
+ - Allows developers to experiment with data changes and easily revert
231
+
232
+ ---
233
+
234
+ ## [1.9.49] - 2026-04-01
235
+
236
+ ### Added
237
+ - **scripts/reset-command-center.sh** - Now restores Engine-branded global.css during reset
238
+ - Issue: Reset didn't touch global.css, leaving inconsistent styling state
239
+ - Solution: Added step 9 that writes complete Engine-branded global.css template
240
+ - Includes all Engine brand tokens:
241
+ - `--color-engine-*` tokens (teal, coral, green, savings, etc.)
242
+ - `--color-brand-*` palette (12 teal shades from 50-950)
243
+ - Inter font stack (`--font-sans`)
244
+ - JetBrains Mono (`--font-mono`)
245
+ - Engine border radius tokens (`--radius-pill`, `--radius-card`)
246
+ - Complete `.heroui-scope` theme overrides with Engine colors
247
+ - Ensures consistent Engine branding across all reset operations
248
+ - Template sourced from enginewebexperience production configuration
249
+
250
+ ### Changed
251
+ - **Reset success message** - Updated to highlight Engine branding restoration
252
+ - Before: "Everything preserved: Theme (global.css + initialMode)"
253
+ - After: "Restored: Engine brand theme (global.css)" with brand details
254
+ - Clarifies that reset actively restores Engine branding, not just preserves it
255
+
256
+ ### Rationale
257
+ The reset script is tooling specifically for Engine Travel Command Center development. Making it restore Engine branding by default is consistent with:
258
+ - The script's existing opinionated behavior (specific templates for Home, Search, routes)
259
+ - The engine-command-center-prd.md PRD section 3 which specifies Engine brand tokens
260
+ - The fact that the script lives in sf-web-components package used for Engine dashboards
261
+
262
+ This eliminates a common source of confusion where developers would reset the app structure but be left with mismatched or baseline styling.
263
+
264
+ ---
265
+
8
266
  ## Critical History: Component Naming Crisis (v1.9.29 - v1.9.42)
9
267
 
10
268
  ### The Problem