@salesforce/afv-skills 1.49.0 → 1.51.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/skills/experience-ui-bundle-deploy/SKILL.md +43 -2
- package/skills/experience-ui-bundle-deploy/references/config-scaffold.md +16 -3
- package/skills/experience-ui-bundle-deploy/references/logout-url.md +97 -0
- package/skills/experience-ui-bundle-deploy/scripts/set-logout-url.mjs +304 -0
- package/skills/experience-ui-bundle-localize/SKILL.md +107 -90
- package/skills/experience-ui-bundle-localize/references/angular/check-i18n-wired.sh +159 -0
- package/skills/experience-ui-bundle-localize/references/angular/i18n-setup.md +250 -0
- package/skills/experience-ui-bundle-localize/references/angular/interpolation.md +156 -0
- package/skills/experience-ui-bundle-localize/references/angular/localize.md +111 -0
- package/skills/experience-ui-bundle-localize/references/{gotchas.md → common/gotchas.md} +27 -43
- package/skills/experience-ui-bundle-localize/references/{label-xml.md → common/label-xml.md} +27 -17
- package/skills/experience-ui-bundle-localize/references/common/platform-sdk-i18n.md +169 -0
- package/skills/experience-ui-bundle-localize/references/{verifying.md → common/verifying.md} +26 -16
- package/skills/experience-ui-bundle-localize/{scripts → references/react}/check-i18n-wired.sh +8 -3
- package/skills/experience-ui-bundle-localize/references/{i18n-setup.md → react/i18n-setup.md} +48 -10
- package/skills/experience-ui-bundle-localize/references/{interpolation.md → react/interpolation.md} +4 -4
- package/skills/experience-ui-bundle-localize/references/react/localize.md +76 -0
- package/skills/experience-ui-bundle-localize/scripts/check-manifest-registered.sh +92 -24
- package/skills/experience-ui-bundle-localize/scripts/detect-framework.sh +73 -0
- package/skills/experience-ui-bundle-site-generate/SKILL.md +1 -1
- package/skills/field-service-data-capture-form-deployer-configure/SKILL.md +180 -0
- package/skills/field-service-data-capture-form-deployer-configure/examples/inventory-transfer-spec.json +135 -0
- package/skills/field-service-data-capture-form-deployer-configure/examples/sample-spec.json +140 -0
- package/skills/field-service-data-capture-form-deployer-configure/examples/sectioned-spec.json +64 -0
- package/skills/field-service-data-capture-form-deployer-configure/references/field-types.md +297 -0
- package/skills/field-service-data-capture-form-deployer-configure/references/flow-metadata-json.md +243 -0
- package/skills/field-service-data-capture-form-deployer-configure/references/post-screen-automation.md +127 -0
- package/skills/field-service-data-capture-form-designer-configure/SKILL.md +110 -0
- package/skills/field-service-data-capture-form-designer-configure/references/extraction-from-image.md +244 -0
- package/skills/field-service-data-capture-form-designer-configure/references/extraction-from-prompt.md +222 -0
- package/skills/field-service-data-capture-form-editor-configure/SKILL.md +134 -0
- package/skills/field-service-data-capture-reference-configure/SKILL.md +762 -0
- package/skills/field-service-data-capture-reference-configure/examples/DataCapture_Showcase.flow-meta.xml +2022 -0
- package/skills/field-service-data-capture-reference-configure/examples/Data_Capture_All_Components.flow-meta.xml +2170 -0
- package/skills/field-service-data-capture-reference-configure/examples/Repeater_with_prepopulation.flow-meta.xml +231 -0
- package/skills/field-service-foundation-setup-designer-get/SKILL.md +135 -0
- package/skills/field-service-mobile-branding-configure/SKILL.md +133 -0
- package/skills/field-service-mobile-branding-configure/examples/dark-blue-scheme.json +16 -0
- package/skills/field-service-mobile-branding-configure/examples/salesforce-default-scheme.json +16 -0
- package/skills/field-service-mobile-branding-configure/references/color-fields.md +66 -0
- package/skills/field-service-mobile-branding-configure/references/contrast-validation.md +55 -0
- package/skills/field-service-mobile-branding-configure/references/derivation-methodology.md +83 -0
- package/skills/field-service-objective-designer-configure/SKILL.md +342 -0
- package/skills/field-service-prework-brief-deployer-configure/SKILL.md +83 -0
- package/skills/field-service-scheduling-policy-designer-query/SKILL.md +121 -0
- package/skills/field-service-setup-orchestrator-get/SKILL.md +48 -0
- package/skills/field-service-sobject-create-configure/SKILL.md +56 -0
- package/skills/field-service-voice-to-form-configure/SKILL.md +650 -0
- package/skills/field-service-work-rule-designer-configure/SKILL.md +303 -0
- package/skills/service-digital-engagement-channel-configure/SKILL.md +20 -37
- package/skills/service-digital-engagement-channel-configure/assets/messaging_channel_template.xml +3 -2
- package/skills/service-digital-engagement-channel-configure/examples/asa_agent_channel.xml +4 -4
- package/skills/service-helpagent-coordinate/SKILL.md +37 -29
- package/skills/service-helpagent-coordinate/assets/help-agent-spec.md +33 -28
- package/skills/service-helpagent-coordinate/references/agent-script.md +4 -1
- package/skills/service-helpagent-coordinate/references/channel-voice.md +1 -1
- package/skills/service-helpagent-coordinate/references/channel-web-chat.md +10 -12
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
# Extraction rules — visual sources (PDF / image)
|
|
2
|
+
|
|
3
|
+
These are the rules to follow when given a `.pdf`, `.png`, `.jpg`, or `.jpeg` and asked to produce the intermediate JSON spec for a Data Capture Flow.
|
|
4
|
+
|
|
5
|
+
The spec schema is the input contract of the build skill — see [field-types.md](../../fs-data-capture-form-deployer/reference/field-types.md) and [post-screen-automation.md](../../fs-data-capture-form-deployer/reference/post-screen-automation.md). This file covers extraction *behavior*; that file covers what the converter accepts.
|
|
6
|
+
|
|
7
|
+
## Output schema
|
|
8
|
+
|
|
9
|
+
```json
|
|
10
|
+
{
|
|
11
|
+
"formTitle": "string",
|
|
12
|
+
"formType": "string",
|
|
13
|
+
"screens": {
|
|
14
|
+
"PascalCaseScreenName1": [ /* fields */ ],
|
|
15
|
+
"PascalCaseScreenName2": [ /* fields */ ]
|
|
16
|
+
},
|
|
17
|
+
"postScreen": { /* optional — see post-screen-automation.md */ }
|
|
18
|
+
}
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Each field has these properties (only `fieldName`, `fieldLabel`, and `fieldType` are required):
|
|
22
|
+
|
|
23
|
+
| Property | Type | Notes |
|
|
24
|
+
|----------|------|-------|
|
|
25
|
+
| `fieldName` | string | camelCase or PascalCase, English, unique across the form, valid Salesforce API name. |
|
|
26
|
+
| `fieldLabel` | string | Exact label from the source. Preserve original language, units, special characters. Strip required indicators (`*`, `(required)`). |
|
|
27
|
+
| `fieldType` | string | One of the supported types in `field-types.md`. Case-sensitive. |
|
|
28
|
+
| `isRequired` | boolean | true if the source had `*`, "required", "mandatory", "Pflichtfeld", "obligatoire", etc. |
|
|
29
|
+
| `defaultValue` | string \| null | null for input fields; for `DisplayText`, the static body text. |
|
|
30
|
+
| `options` | array \| null | Required for `Radio`, `Picklist`, `CheckboxGroup`, `Matrix` (column choices). null otherwise. |
|
|
31
|
+
| `repeaterFields` | array | Required for `Repeater`. List of nested field objects with the same shape. |
|
|
32
|
+
| `matrixRows` | array | Required for `Matrix`. List of row labels. |
|
|
33
|
+
| `min` / `max` / `value` | number | Optional for `Counter` — initial/min/max for the +/- counter. |
|
|
34
|
+
| `visibility` | object | Optional. `{ "field": "<fieldName>", "operator": "EqualTo", "value": "<choice display>" }` — show this field only when the referenced choice is selected. |
|
|
35
|
+
| `lookupObject` | string | Required for `Lookup`. Salesforce object API name (e.g. `"Asset"`, `"WorkOrder"`). |
|
|
36
|
+
| `lookupSearchFields` | string | Optional for `Lookup`. Comma-separated field API names searched by typeahead (e.g. `"Name, SerialNumber"`). |
|
|
37
|
+
| `lookupMulti` | boolean | Optional for `Lookup`. true to allow selecting multiple records. |
|
|
38
|
+
| `fileName` | string | Required for `FileView`. Static-asset filename without extension. |
|
|
39
|
+
|
|
40
|
+
## Output requirements
|
|
41
|
+
|
|
42
|
+
1. Output **only** the JSON object.
|
|
43
|
+
2. No markdown, no code fences, no explanation before or after.
|
|
44
|
+
3. Use `null` for null, `true`/`false` for booleans, double-quoted strings.
|
|
45
|
+
4. Stop immediately after the closing `}`.
|
|
46
|
+
|
|
47
|
+
## Field-type classification — control evidence over labels
|
|
48
|
+
|
|
49
|
+
Pick a field type from what the *control* does, not from what the *label* says. A field labeled "Signature" that's just a text line is `ShortText`, not `Signature`. A field labeled "Photo of damage" that's a description box is `LongText`, not `UploadImage`. The label is a hint; the rendered UI control is the answer.
|
|
50
|
+
|
|
51
|
+
Use the **most specific** type the visual evidence supports. Default to `ShortText` when in doubt.
|
|
52
|
+
|
|
53
|
+
| Type | Control evidence required (PDF/image) |
|
|
54
|
+
|---|---|
|
|
55
|
+
| `Name` | A text input whose label is an unambiguous person role: Inspector, Operator, Technician, Employee, Customer Name, Reported By. Plain "Name" alone is fine. **A dropdown control with a person-role label (e.g. "--Select Inspector--", "Choose Operator ▼") is still `Name`, not `Picklist`** — the data captured is a person, and the runtime treatment of person fields is what matters. |
|
|
56
|
+
| `Email` | Text input with `@` placeholder, label "Email", or input attribute hints. |
|
|
57
|
+
| `Phone` | Text input with phone formatting, label "Phone", "Tel", "Mobile". |
|
|
58
|
+
| `Numeric` | Numeric input, often with units (°C, mm, kg, bar, %). |
|
|
59
|
+
| `Counter` | A `+` / `-` stepper widget *or* explicit "Quantity" with stepper UI. Default `min: 1, value: 1`. |
|
|
60
|
+
| `Date` | A date picker (calendar icon, `MM/DD/YYYY` placeholder). |
|
|
61
|
+
| `DateTime` | A date+time picker. |
|
|
62
|
+
| `Checkbox` | A single standalone checkbox with one label. |
|
|
63
|
+
| `CheckboxGroup` | Multiple checkboxes under one heading or "select all that apply". |
|
|
64
|
+
| `Radio` | Radio buttons / "(circle one)" / mutually exclusive options visible on the form. |
|
|
65
|
+
| `Picklist` | A combo box / dropdown indicator (▼ ▾ ⌄, "Select…"). For person-name dropdowns, prefer `Name`. Supply 3–5 sample options. |
|
|
66
|
+
| `Toggle` | An on/off switch UI element (rounded slider). |
|
|
67
|
+
| `UploadFile` | A file-picker control: "Choose file", paperclip icon, drag-drop zone, attachment slot. **Not** a label that mentions a file. |
|
|
68
|
+
| `UploadImage` | An image-upload control: camera icon, "Add photo" button, image drop zone. **Not** a label like "Photo" on a text line. |
|
|
69
|
+
| `FileView` | A read-only image preview / pre-attached image. |
|
|
70
|
+
| `Signature` | A signature pad (a labeled empty box sized for handwriting, with "Sign here" / "Signature" inside the box, often with an X-line). **Not** a one-line text field labeled "Signature". |
|
|
71
|
+
| `Matrix` | A grid where each row asks the same question with shared answer columns (e.g. row=item, columns=OK/NOK/N/A). ONE field with `matrixRows` + `options`. |
|
|
72
|
+
| `Repeater` | A table with input columns where the user adds N rows (e.g. Part Number / Quantity / Description). ONE field with `repeaterFields`. |
|
|
73
|
+
| `Address` | A compound address widget with separate sub-inputs (street + city + state + zip + country). |
|
|
74
|
+
| `LongText` | A multi-line text box (textarea, ≥3 lines tall, "Notes" / "Comments" / "Remarks"). |
|
|
75
|
+
| `ShortText` | A single-line text input. **This is the default** when no other evidence applies. |
|
|
76
|
+
| `DisplayText` | Static instructional text with no input control. Set `defaultValue` to the body. |
|
|
77
|
+
| `Lookup` | A typeahead/record-search input bound to a Salesforce object (search-as-you-type that resolves to a record). Requires `lookupObject` (the Salesforce object API name) supplied via the spec. |
|
|
78
|
+
|
|
79
|
+
**Multi-part fields** (e.g. "D0: ___ Ref.-Dim.: ___") → extract each part as its own field with its own classification.
|
|
80
|
+
|
|
81
|
+
### Repeater extraction rules
|
|
82
|
+
|
|
83
|
+
A `Repeater` is for tables where each row is a **user-added item** with **input columns** (the user types/picks per cell). Distinct from `Matrix`, which is a fixed set of rows that share **selection columns** (OK / NOK / N/A — pick one).
|
|
84
|
+
|
|
85
|
+
| Pattern | Type |
|
|
86
|
+
|---|---|
|
|
87
|
+
| Table: `Parameter \| Old Value \| New Value` (user types in each cell) | `Repeater` |
|
|
88
|
+
| Table: `Component \| OK \| NOK \| N/A \| Repair` (user picks one per row) | `Matrix` |
|
|
89
|
+
|
|
90
|
+
When emitting a `Repeater`, populate `repeaterFields` with one nested field per **input column**, classified using the same evidence rules above. Skip any selection-only "OK/NOK" columns — those mean it's a `Matrix`.
|
|
91
|
+
|
|
92
|
+
**Merge side-by-side / stacked repeaters with the same columns.** If the source visually splits one logical table into two blocks (top half / bottom half, left / right) because of page-space constraints, but both blocks have the same column structure — emit **one** Repeater. Two Repeater fields with identical `repeaterFields` is almost always a mistake.
|
|
93
|
+
|
|
94
|
+
**Dedupe columns with the same label.** If a table has the same column label appearing twice and the data captured is the same kind of thing, include the column **once** in `repeaterFields`.
|
|
95
|
+
|
|
96
|
+
**Skip symbol-only columns.** Single-character or symbol headers (`Δ`, `Σ`, `→`, blank) are typically separators or change indicators, not data inputs.
|
|
97
|
+
|
|
98
|
+
### Anti-patterns (do NOT do these)
|
|
99
|
+
|
|
100
|
+
- ❌ Label contains "signature" → automatically `Signature`. The control might be a single-line text field where the inspector types their name. Only emit `Signature` if you can see a sign-here pad.
|
|
101
|
+
- ❌ Label contains "photo" / "image" / "picture" → automatically `UploadImage`. The control might be a description text box. Only emit `UploadImage` when you see a camera/upload widget.
|
|
102
|
+
- ❌ Label contains "attach" / "file" / "document" → automatically `UploadFile`. Same rule — needs an actual file picker.
|
|
103
|
+
- ❌ Label contains "address" → automatically `Address`. A single text line for address is `ShortText` or `LongText`. Only emit `Address` for a compound widget with separate sub-inputs.
|
|
104
|
+
- ❌ Any table → `Repeater`. A table where each row is a fixed inspection point (with shared OK/NOK columns) is `Matrix`, not `Repeater`.
|
|
105
|
+
- ❌ Any list of options → `Picklist`. If the source explicitly shows radio buttons or "circle one", use `Radio`.
|
|
106
|
+
|
|
107
|
+
When the evidence is ambiguous, **fall back to the simplest type** (`ShortText`, `LongText`, `Numeric`) and call it out in the confirmation step so the user can correct it before deploy.
|
|
108
|
+
|
|
109
|
+
## Conditional fields
|
|
110
|
+
|
|
111
|
+
If a field on the form is preceded by something like "If Work Order, also fill: WO#" or only makes sense given a previous answer, attach a `visibility` block:
|
|
112
|
+
|
|
113
|
+
```json
|
|
114
|
+
{
|
|
115
|
+
"fieldName": "WorkOrderNumber",
|
|
116
|
+
"fieldLabel": "WO#",
|
|
117
|
+
"fieldType": "ShortText",
|
|
118
|
+
"isRequired": true,
|
|
119
|
+
"visibility": { "field": "To", "operator": "EqualTo", "value": "Work Order" }
|
|
120
|
+
}
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
The `value` must match one of the parent field's `options` exactly (display text, not the api-sanitized name).
|
|
124
|
+
|
|
125
|
+
## Naming rules
|
|
126
|
+
|
|
127
|
+
- `fieldName`: camelCase or PascalCase, English even if the label is in another language. No spaces, no special characters (underscore allowed). Unique within the form. ≤ 80 chars.
|
|
128
|
+
- Screen keys: `PascalCase` describing the section (`HeaderInformation`, `OperatingParameters`, `VisualInspection`). Never `Screen1`, `Screen2`.
|
|
129
|
+
- `formTitle`: human-readable, original language allowed. The Flow's API name is derived from this by the deploy step.
|
|
130
|
+
- `formType`: short descriptor (e.g. `Inspection Report`, `Service Log`, `Inventory Transfer`).
|
|
131
|
+
|
|
132
|
+
## Label rules
|
|
133
|
+
|
|
134
|
+
- **Preserve** original language, umlauts/accents, units, bilingual text exactly as shown (`"Kennwort: / Job name:"`).
|
|
135
|
+
- **Strip** leading `*`, `(required)`, `(mandatory)`, `Pflichtfeld` from the label and set `isRequired: true` instead.
|
|
136
|
+
- **Do not** translate or rephrase.
|
|
137
|
+
|
|
138
|
+
## Screen grouping
|
|
139
|
+
|
|
140
|
+
- 8–12 fields per screen, max.
|
|
141
|
+
- A form with a single section and a repeater can be a single screen — don't fabricate sections.
|
|
142
|
+
- Group by logical sections in the source (header info, measurements, inspection, attachments, signatures…).
|
|
143
|
+
- Use the source's section breaks where they exist.
|
|
144
|
+
- Use descriptive PascalCase screen names — never `Screen1`.
|
|
145
|
+
|
|
146
|
+
## Sections within a screen
|
|
147
|
+
|
|
148
|
+
A Section is a *visual grouping inside one screen* — distinct from splitting fields across multiple screens. Emit a section **only when the source visibly shows a labeled group header** (a banner/heading like "Asset Details", "Inspection Notes", a colored separator with a title, or a visibly bordered group).
|
|
149
|
+
|
|
150
|
+
When you emit a section, insert a `{ "section": "Header Label" }` item into the screen's field list before the fields belonging to that group:
|
|
151
|
+
|
|
152
|
+
```json
|
|
153
|
+
{
|
|
154
|
+
"screens": {
|
|
155
|
+
"AssetInspection": [
|
|
156
|
+
{ "section": "Asset Details" },
|
|
157
|
+
{ "fieldName": "AssetName", "fieldLabel": "Asset Name", "fieldType": "ShortText" },
|
|
158
|
+
{ "fieldName": "Manufacturer", "fieldLabel": "Manufacturer", "fieldType": "Picklist", "options": ["Demag","Konecranes"] },
|
|
159
|
+
|
|
160
|
+
{ "section": "Inspection" },
|
|
161
|
+
{ "fieldName": "Condition", "fieldLabel": "Condition", "fieldType": "Picklist", "options": ["Pass","Fail"] }
|
|
162
|
+
]
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
**When NOT to use sections:**
|
|
168
|
+
- The source has no visible group headers — emit a flat field list.
|
|
169
|
+
- The source uses one heading per screen (these are *screen names*, not within-screen sections).
|
|
170
|
+
- You'd be inventing groupings the source doesn't show.
|
|
171
|
+
|
|
172
|
+
**One-section screens are usually wrong.** A single section spanning the whole screen is just a screen with a redundant header bar. Either emit no sections, or emit ≥ 2 sections per screen.
|
|
173
|
+
|
|
174
|
+
## Post-screen automation — determine the desired outcome
|
|
175
|
+
|
|
176
|
+
A data capture form is rarely just a form. The captured data almost always needs to **do** something in Salesforce: create a record, update a record, look something up. That "do something" is the desired outcome.
|
|
177
|
+
|
|
178
|
+
You **must** determine the desired outcome before finalizing the spec. A form that captures perfect data but never writes anything to Salesforce is a broken flow.
|
|
179
|
+
|
|
180
|
+
### Outcome-elicitation rules
|
|
181
|
+
|
|
182
|
+
For every form, ask yourself:
|
|
183
|
+
|
|
184
|
+
1. **What Salesforce object should be created or updated when the user finishes the form?** (e.g. ProductTransfer, WorkOrderLineItem, Case, Asset, ServiceAppointment.)
|
|
185
|
+
2. **Are any rows in a Repeater supposed to become individual records?** If yes, you need a `loop` over `<Repeater>.AddedItems` and a `recordCreate` per iteration.
|
|
186
|
+
3. **Does any captured value need to be resolved to a record Id before writing?** If yes, you need a `recordLookup`.
|
|
187
|
+
4. **Is the user picking a branch that determines which lookup or write to do?** If yes, you need a `decision`.
|
|
188
|
+
5. **Is there a parent record passed in via `parentRecordId` / `parentObjectType` that should be referenced or updated?** This is the standard Field Service entry-point pattern.
|
|
189
|
+
|
|
190
|
+
### How to decide whether to emit `postScreen`
|
|
191
|
+
|
|
192
|
+
| Signal | Action |
|
|
193
|
+
|---|---|
|
|
194
|
+
| The form's name or purpose strongly implies a single object — Inventory Transfer, Work Order Completion, Asset Inspection, Damage Report, Time Entry | **Emit `postScreen`** with your best-guess object/field mapping AND list every `valueRef` / `field` in the confirmation step so the user can correct names. |
|
|
195
|
+
| The form has a Repeater whose rows obviously become rows in Salesforce (parts, line items, time entries, photos with metadata) | **Emit `postScreen`** with a loop + recordCreate. State the assumption explicitly. |
|
|
196
|
+
| You're refining an existing flow the user pointed you at | **Mirror the existing flow's `postScreen`** (same object, same field shape). |
|
|
197
|
+
| You truly cannot infer what the data should do | Surface a question to the user in the confirmation step ("What should happen when this form is submitted?") and emit no `postScreen` until they answer. |
|
|
198
|
+
|
|
199
|
+
### Common outcome patterns
|
|
200
|
+
|
|
201
|
+
- **Inventory Transfer** (form has a parts repeater) → loop over `Part.AddedItems` → create one `ProductTransfer` per row, mapping `Product2Id`, `QuantitySent`, `QuantityReceived`, `DestinationLocationId`.
|
|
202
|
+
- **Inspection / Checklist** → create one `WorkOrderLineItem` or `Asset__History` record summarizing the inspection.
|
|
203
|
+
- **Time Entry** → create a `ResourceAbsence` or custom time-entry record tied to `parentRecordId`.
|
|
204
|
+
- **Damage Report** → update the parent Work Order and/or create child Case records.
|
|
205
|
+
|
|
206
|
+
### Validation for `postScreen`
|
|
207
|
+
|
|
208
|
+
When you emit a `postScreen` block, every reference must point at a real thing:
|
|
209
|
+
|
|
210
|
+
- Every `valueRef` is either: a `<fieldName>.value` from a screen field, a `<RepeaterName>.<ChildName>.value` inside a loop, a non-input variable you declared, or a global like `$User.Id`.
|
|
211
|
+
- Every `field` in `inputAssignments` and `outputAssignments` is the API name of a field on the named `object`. If you don't know the exact API name, use your best guess and list it in the confirmation step.
|
|
212
|
+
- Every `next` connector targets the name of an element you actually defined.
|
|
213
|
+
- The decision's branch `when.field` is a screen field, and `when.value` exactly matches one of that field's `options`.
|
|
214
|
+
|
|
215
|
+
## Validation checklist
|
|
216
|
+
|
|
217
|
+
Before returning, verify:
|
|
218
|
+
|
|
219
|
+
- [ ] Every screen key is PascalCase.
|
|
220
|
+
- [ ] Every `fieldName` is a valid API name, unique across the form (including inside repeaters).
|
|
221
|
+
- [ ] Every `fieldType` is one of the supported types in [field-types.md](../../fs-data-capture-form-deployer/reference/field-types.md) (case-sensitive).
|
|
222
|
+
- [ ] `Radio`, `Picklist`, `CheckboxGroup` have non-empty `options`.
|
|
223
|
+
- [ ] `Matrix` has both `options` (columns) and `matrixRows`.
|
|
224
|
+
- [ ] `Repeater` has `repeaterFields` (each child has its own valid `fieldType`).
|
|
225
|
+
- [ ] Any `visibility.value` exactly matches one of the referenced field's `options`.
|
|
226
|
+
- [ ] No required indicators (`*`, "(required)") left in any label.
|
|
227
|
+
- [ ] No translations of original labels.
|
|
228
|
+
- [ ] No fabricated fields the source doesn't have.
|
|
229
|
+
- [ ] **Outcome is determined.** Either a `postScreen` block is emitted, or the confirmation step will explicitly ask the user what to do with the data.
|
|
230
|
+
- [ ] If `postScreen` is emitted: every `valueRef` resolves, every `field` belongs to the named `object` (or is flagged for user review), every `next` connector targets a defined element, and decision branch `value`s match a parent field's `options`.
|
|
231
|
+
- [ ] **Specialized types are evidence-backed.** For every `Signature`, `UploadFile`, `UploadImage`, `Images`, `FileView`, `Address`, `Matrix`, `Lookup`, and `Repeater` in the output, name the visual evidence (camera-icon button, sign-here pad, +/- stepper, table with row-add button, typeahead picker). If you can only point to the field's *label*, downgrade the type per the table above. (These deploy as **real functional components** — `dcSignature`, `dcUpImage`, `dcMatrix`, etc. — so emitting them when the source only shows a text line is the most common extraction bug.)
|
|
232
|
+
- [ ] **Lookup has `lookupObject`.** Every `Lookup` field has a `lookupObject` (Salesforce object API name). If the source doesn't make it explicit, pick a best-guess and flag it in the confirmation step.
|
|
233
|
+
- [ ] **FileView has `fileName`.** Every `FileView` field has a `fileName` (static asset filename, no extension). If unknown, surface a question.
|
|
234
|
+
- [ ] **Repeaters are not duplicated.** No two `Repeater` fields have identical `repeaterFields` (merge side-by-side or stacked tables that share columns). No `repeaterFields` entries for symbol-only headers (`Δ`, `Σ`).
|
|
235
|
+
- [ ] **Sections only where the source shows them.** Every `{ "section": "..." }` item corresponds to a visible group header in the source. No invented sections, and no screens with exactly one section.
|
|
236
|
+
|
|
237
|
+
---
|
|
238
|
+
|
|
239
|
+
## Source design docs
|
|
240
|
+
|
|
241
|
+
This rule sheet is informed by two upstream design docs. Don't paste the full prompts from those docs into the user-facing flow — they're internal source-of-truth references.
|
|
242
|
+
|
|
243
|
+
- **Form-To-Flow AI HLD** ([doc](https://docs.google.com/document/d/1XlDRQE1gVrux8Iyz5LDupN9xV7i1IKpczLbsvMq5Tc4)) — the Flow Builder team's architecture for PDF-to-DC-Flow generation.
|
|
244
|
+
- **Field Service POC HLD** ([doc](https://docs.google.com/document/d/10TO6CC983AcclXY7Ixp3I3hY5R7TagUMWP9VRqXOFoc)) — Field Service team's Apex+Agentforce POC. Source for the intermediate JSON contract and the extraction prompt rules.
|
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
# Extraction rules — natural-language sources
|
|
2
|
+
|
|
3
|
+
These are the rules to follow when given a prose description of a form (no PDF or image) and asked to produce the intermediate JSON spec for a Data Capture Flow.
|
|
4
|
+
|
|
5
|
+
The spec schema is the input contract of the build skill — see [field-types.md](../../fs-data-capture-form-deployer/reference/field-types.md) and [post-screen-automation.md](../../fs-data-capture-form-deployer/reference/post-screen-automation.md). This file covers extraction *behavior*; that file covers what the converter accepts.
|
|
6
|
+
|
|
7
|
+
## Output schema
|
|
8
|
+
|
|
9
|
+
```json
|
|
10
|
+
{
|
|
11
|
+
"formTitle": "string",
|
|
12
|
+
"formType": "string",
|
|
13
|
+
"screens": {
|
|
14
|
+
"PascalCaseScreenName1": [ /* fields */ ],
|
|
15
|
+
"PascalCaseScreenName2": [ /* fields */ ]
|
|
16
|
+
},
|
|
17
|
+
"postScreen": { /* optional — see post-screen-automation.md */ }
|
|
18
|
+
}
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Each field has these properties (only `fieldName`, `fieldLabel`, and `fieldType` are required):
|
|
22
|
+
|
|
23
|
+
| Property | Type | Notes |
|
|
24
|
+
|----------|------|-------|
|
|
25
|
+
| `fieldName` | string | camelCase or PascalCase, English, unique across the form, valid Salesforce API name. |
|
|
26
|
+
| `fieldLabel` | string | The label the user gave (or a faithful summary if they didn't give an explicit label). Strip required indicators (`*`, `(required)`). |
|
|
27
|
+
| `fieldType` | string | One of the supported types in `field-types.md`. Case-sensitive. |
|
|
28
|
+
| `isRequired` | boolean | true if the user said "required", "mandatory", "must enter", etc. |
|
|
29
|
+
| `defaultValue` | string \| null | null for input fields; for `DisplayText`, the static body text. |
|
|
30
|
+
| `options` | array \| null | Required for `Radio`, `Picklist`, `CheckboxGroup`, `Matrix` (column choices). null otherwise. |
|
|
31
|
+
| `repeaterFields` | array | Required for `Repeater`. List of nested field objects with the same shape. |
|
|
32
|
+
| `matrixRows` | array | Required for `Matrix`. List of row labels. |
|
|
33
|
+
| `min` / `max` / `value` | number | Optional for `Counter` — initial/min/max for the +/- counter. |
|
|
34
|
+
| `visibility` | object | Optional. `{ "field": "<fieldName>", "operator": "EqualTo", "value": "<choice display>" }` — show this field only when the referenced choice is selected. |
|
|
35
|
+
| `lookupObject` | string | Required for `Lookup`. Salesforce object API name (e.g. `"Asset"`, `"WorkOrder"`). |
|
|
36
|
+
| `lookupSearchFields` | string | Optional for `Lookup`. Comma-separated field API names searched by typeahead (e.g. `"Name, SerialNumber"`). |
|
|
37
|
+
| `lookupMulti` | boolean | Optional for `Lookup`. true to allow selecting multiple records. |
|
|
38
|
+
| `fileName` | string | Required for `FileView`. Static-asset filename without extension. |
|
|
39
|
+
|
|
40
|
+
## Output requirements
|
|
41
|
+
|
|
42
|
+
1. Output **only** the JSON object.
|
|
43
|
+
2. No markdown, no code fences, no explanation before or after.
|
|
44
|
+
3. Use `null` for null, `true`/`false` for booleans, double-quoted strings.
|
|
45
|
+
4. Stop immediately after the closing `}`.
|
|
46
|
+
|
|
47
|
+
## Field-type classification — explicit vocabulary required
|
|
48
|
+
|
|
49
|
+
For prose input (no visual reference), only choose specialized types (`Signature`, `UploadFile`, `UploadImage`, `FileView`, `Matrix`, `Address`, `Repeater`) when the user **explicitly** describes that control. The user saying "captures the inspector's signature" with no other context isn't enough — that could be a typed name or a real signature pad. Default to the simpler text/number/date type unless the user uses control vocabulary.
|
|
50
|
+
|
|
51
|
+
Use the **most specific** type the prose evidence supports. Default to `ShortText` when in doubt.
|
|
52
|
+
|
|
53
|
+
| Type | Prose evidence required |
|
|
54
|
+
|---|---|
|
|
55
|
+
| `Name` | User says the field captures a person's name (inspector, operator, technician, customer, employee). |
|
|
56
|
+
| `Email` | User says "email". |
|
|
57
|
+
| `Phone` | User says "phone", "phone number", "mobile", "contact number". |
|
|
58
|
+
| `Numeric` | User says "number", "count", or gives a numeric measurement (pressure, temperature, weight). |
|
|
59
|
+
| `Counter` | User says "counter", "stepper", "+/- quantity", "quantity field". |
|
|
60
|
+
| `Date` | User says "date". |
|
|
61
|
+
| `DateTime` | User says "date and time", "timestamp". |
|
|
62
|
+
| `Checkbox` | User says "checkbox" (singular). |
|
|
63
|
+
| `CheckboxGroup` | User says "select multiple", "all that apply", "checkbox group". |
|
|
64
|
+
| `Radio` | User says "radio", "single choice", "pick one", "select one". |
|
|
65
|
+
| `Picklist` | User says "dropdown", "picklist", "select from a list". For person-name dropdowns, prefer `Name`. |
|
|
66
|
+
| `Toggle` | User says "toggle" or "on/off switch". |
|
|
67
|
+
| `UploadFile` | User says "upload a file" / "attach a document" / explicitly describes a file picker. |
|
|
68
|
+
| `UploadImage` | User says "upload an image" / "add a photo" / "camera capture" / explicitly describes an image picker. |
|
|
69
|
+
| `FileView` | User explicitly asks for a read-only image viewer. |
|
|
70
|
+
| `Signature` | User says "signature pad" / "captures a signature" / explicitly describes a sign-here widget. |
|
|
71
|
+
| `Matrix` | User explicitly describes a same-question-per-row table (rows share OK/NOK columns). |
|
|
72
|
+
| `Repeater` | User says "add multiple rows" / "list of parts" / "repeat for each item" / "repeater". |
|
|
73
|
+
| `Address` | User explicitly says "compound address" or lists street/city/state/zip as a single block. |
|
|
74
|
+
| `LongText` | User says "notes", "comments", "long text", "description", "remarks". |
|
|
75
|
+
| `ShortText` | User just lists a label with no other vocabulary. **This is the default.** |
|
|
76
|
+
| `DisplayText` | User explicitly says "show static text" / "instructions". |
|
|
77
|
+
| `Lookup` | User says "lookup", "select a record", "pick an existing X". Requires `lookupObject` (the Salesforce object API name). |
|
|
78
|
+
|
|
79
|
+
### Anti-patterns (do NOT do these)
|
|
80
|
+
|
|
81
|
+
- ❌ User mentions "signature" → automatically `Signature`. They might mean a typed name. Only emit `Signature` when they say "signature pad", "sign-here widget", or similar control vocabulary.
|
|
82
|
+
- ❌ User mentions "photo" / "image" → automatically `UploadImage`. They might mean a description field. Only emit `UploadImage` when they say "upload an image", "add a photo", "camera capture".
|
|
83
|
+
- ❌ User mentions "address" → automatically `Address`. Single text line is fine for most addresses. Only emit `Address` for an explicit compound widget.
|
|
84
|
+
- ❌ User says "table" → automatically `Repeater` or `Matrix`. Ask for clarification: rows-the-user-adds (Repeater) vs. fixed-rows-with-shared-columns (Matrix).
|
|
85
|
+
- ❌ Inventing fields the user didn't mention. If the user says "asset id, condition rating, photos, and remarks", emit four fields. Don't add an "Inspector" or "Date Inspected" field just because forms usually have those.
|
|
86
|
+
|
|
87
|
+
When the evidence is ambiguous, **fall back to the simplest type** (`ShortText`, `LongText`, `Numeric`) and call it out in the confirmation step so the user can correct it before deploy.
|
|
88
|
+
|
|
89
|
+
## Conditional fields
|
|
90
|
+
|
|
91
|
+
If the user describes a field that depends on a previous answer ("if they pick Work Order, then ask for the WO number"), attach a `visibility` block:
|
|
92
|
+
|
|
93
|
+
```json
|
|
94
|
+
{
|
|
95
|
+
"fieldName": "WorkOrderNumber",
|
|
96
|
+
"fieldLabel": "WO Number",
|
|
97
|
+
"fieldType": "ShortText",
|
|
98
|
+
"isRequired": true,
|
|
99
|
+
"visibility": { "field": "To", "operator": "EqualTo", "value": "Work Order" }
|
|
100
|
+
}
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
The `value` must match one of the parent field's `options` exactly (display text, not the api-sanitized name).
|
|
104
|
+
|
|
105
|
+
## Naming rules
|
|
106
|
+
|
|
107
|
+
- `fieldName`: camelCase or PascalCase, English. No spaces, no special characters (underscore allowed). Unique within the form. ≤ 80 chars.
|
|
108
|
+
- Screen keys: `PascalCase` describing the section (`HeaderInformation`, `OperatingParameters`, `VisualInspection`). Never `Screen1`, `Screen2`.
|
|
109
|
+
- `formTitle`: human-readable. The Flow's API name is derived from this by the deploy step.
|
|
110
|
+
- `formType`: short descriptor (e.g. `Inspection Report`, `Service Log`, `Inventory Transfer`).
|
|
111
|
+
|
|
112
|
+
## Label rules
|
|
113
|
+
|
|
114
|
+
- Use the user's words verbatim where possible. If the user gave a label, keep it. If they only described the field ("the inspector's name"), summarize concisely as the label ("Inspector Name").
|
|
115
|
+
- **Strip** any `*`, `(required)`, `(mandatory)` from the label and set `isRequired: true` instead.
|
|
116
|
+
|
|
117
|
+
## Screen grouping
|
|
118
|
+
|
|
119
|
+
- 8–12 fields per screen, max.
|
|
120
|
+
- A small form (≤ 8 fields) can be a single screen — don't fabricate sections.
|
|
121
|
+
- If the user described multiple sections ("first ask for header info, then measurements, then the parts list"), respect their grouping.
|
|
122
|
+
- If the user just listed fields with no sections, group them into one screen unless there are more than 12 fields. Then split logically.
|
|
123
|
+
- Use descriptive PascalCase screen names — never `Screen1`.
|
|
124
|
+
|
|
125
|
+
## Sections within a screen
|
|
126
|
+
|
|
127
|
+
A Section is a *visual grouping inside one screen* — distinct from splitting fields across multiple screens. **Default to a flat field list.** Emit sections only when the user explicitly describes named sub-groups within a single screen ("on the inspection screen, group fields under 'Asset Details' and 'Inspection Notes'"). Don't infer sections from a list of field topics — a list of fields is just a list of fields.
|
|
128
|
+
|
|
129
|
+
When you emit a section, insert a `{ "section": "Header Label" }` item into the screen's field list before the fields belonging to that group:
|
|
130
|
+
|
|
131
|
+
```json
|
|
132
|
+
{
|
|
133
|
+
"screens": {
|
|
134
|
+
"AssetInspection": [
|
|
135
|
+
{ "section": "Asset Details" },
|
|
136
|
+
{ "fieldName": "AssetName", "fieldLabel": "Asset Name", "fieldType": "ShortText" },
|
|
137
|
+
{ "fieldName": "Manufacturer", "fieldLabel": "Manufacturer", "fieldType": "Picklist", "options": ["Demag","Konecranes"] },
|
|
138
|
+
|
|
139
|
+
{ "section": "Inspection" },
|
|
140
|
+
{ "fieldName": "Condition", "fieldLabel": "Condition", "fieldType": "Picklist", "options": ["Pass","Fail"] }
|
|
141
|
+
]
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
**When NOT to use sections:**
|
|
147
|
+
- The user didn't explicitly name within-screen sub-groups.
|
|
148
|
+
- The user described separate steps (those become separate *screens*, not sections).
|
|
149
|
+
- You'd be inventing groupings the user didn't describe.
|
|
150
|
+
|
|
151
|
+
**Single-column only.** Sections render as full-width single-column groups. Don't try to express multi-column layouts.
|
|
152
|
+
|
|
153
|
+
**One-section screens are usually wrong.** A single section spanning the whole screen is just a screen with a redundant header bar. Either emit no sections, or emit ≥ 2 sections per screen.
|
|
154
|
+
|
|
155
|
+
## Post-screen automation — determine the desired outcome
|
|
156
|
+
|
|
157
|
+
A data capture form is rarely just a form. The captured data almost always needs to **do** something in Salesforce: create a record, update a record, look something up.
|
|
158
|
+
|
|
159
|
+
You **must** determine the desired outcome before finalizing the spec. A form that captures perfect data but never writes anything to Salesforce is a broken flow.
|
|
160
|
+
|
|
161
|
+
### Outcome-elicitation rules
|
|
162
|
+
|
|
163
|
+
For every form, ask yourself:
|
|
164
|
+
|
|
165
|
+
1. **What Salesforce object should be created or updated when the user finishes?** (e.g. ProductTransfer, WorkOrderLineItem, Case, Asset, ServiceAppointment.)
|
|
166
|
+
2. **Are any rows in a Repeater supposed to become individual records?** If yes, you need a `loop` over `<Repeater>.AddedItems` and a `recordCreate` per iteration.
|
|
167
|
+
3. **Does any captured value need to be resolved to a record Id before writing?** If yes, you need a `recordLookup`.
|
|
168
|
+
4. **Is the user picking a branch that determines which lookup or write to do?** If yes, you need a `decision`.
|
|
169
|
+
5. **Is there a parent record passed in via `parentRecordId` / `parentObjectType`?** This is the standard Field Service entry-point pattern.
|
|
170
|
+
|
|
171
|
+
### How to decide whether to emit `postScreen`
|
|
172
|
+
|
|
173
|
+
| Signal | Action |
|
|
174
|
+
|---|---|
|
|
175
|
+
| The user explicitly says what to create/update ("create a ProductTransfer for each part") | **Emit `postScreen`** with the named object and field mappings. |
|
|
176
|
+
| The user gives a form name or purpose that strongly implies a single object — Inventory Transfer, Work Order Completion, Asset Inspection, Damage Report, Time Entry | **Emit `postScreen`** with your best-guess object/field mapping AND list every `valueRef` / `field` in the confirmation step so the user can correct names. |
|
|
177
|
+
| The user describes a Repeater whose rows obviously become rows in Salesforce | **Emit `postScreen`** with a loop + recordCreate. State the assumption explicitly. |
|
|
178
|
+
| You truly cannot infer what the data should do, AND the user gave no hint | Surface a question in the confirmation step ("What should happen when this form is submitted?") with concrete options. Don't deploy a screens-only flow without flagging that the data goes nowhere. |
|
|
179
|
+
|
|
180
|
+
### Common outcome patterns
|
|
181
|
+
|
|
182
|
+
- **Inventory Transfer** (form has a parts repeater) → loop over `Part.AddedItems` → create one `ProductTransfer` per row, mapping `Product2Id`, `QuantitySent`, `QuantityReceived`, `DestinationLocationId`.
|
|
183
|
+
- **Inspection / Checklist** → create one `WorkOrderLineItem` or `Asset__History` record summarizing the inspection.
|
|
184
|
+
- **Time Entry** → create a `ResourceAbsence` or custom time-entry record tied to `parentRecordId`.
|
|
185
|
+
- **Damage Report** → update the parent Work Order and/or create child Case records.
|
|
186
|
+
|
|
187
|
+
### Validation for `postScreen`
|
|
188
|
+
|
|
189
|
+
When you emit a `postScreen` block, every reference must point at a real thing:
|
|
190
|
+
|
|
191
|
+
- Every `valueRef` is either: a `<fieldName>.value` from a screen field, a `<RepeaterName>.<ChildName>.value` inside a loop, a non-input variable you declared, or a global like `$User.Id`.
|
|
192
|
+
- Every `field` in `inputAssignments` and `outputAssignments` is the API name of a field on the named `object`. If you don't know the exact API name, use your best guess and list it in the confirmation step.
|
|
193
|
+
- Every `next` connector targets the name of an element you actually defined.
|
|
194
|
+
- The decision's branch `when.field` is a screen field, and `when.value` exactly matches one of that field's `options`.
|
|
195
|
+
|
|
196
|
+
## Validation checklist
|
|
197
|
+
|
|
198
|
+
Before returning, verify:
|
|
199
|
+
|
|
200
|
+
- [ ] Every screen key is PascalCase.
|
|
201
|
+
- [ ] Every `fieldName` is a valid API name, unique across the form (including inside repeaters).
|
|
202
|
+
- [ ] Every `fieldType` is one of the supported types in [field-types.md](../../fs-data-capture-form-deployer/reference/field-types.md) (case-sensitive).
|
|
203
|
+
- [ ] `Radio`, `Picklist`, `CheckboxGroup` have non-empty `options` (use 3–5 plausible options if the user didn't list specific ones, and surface that you guessed).
|
|
204
|
+
- [ ] `Matrix` has both `options` (columns) and `matrixRows`.
|
|
205
|
+
- [ ] `Repeater` has `repeaterFields` (each child has its own valid `fieldType`).
|
|
206
|
+
- [ ] Any `visibility.value` exactly matches one of the referenced field's `options`.
|
|
207
|
+
- [ ] **No fabricated fields the user didn't mention.** This is the most common prose-extraction bug — don't pad the form with "usual" fields.
|
|
208
|
+
- [ ] **Outcome is determined.** Either a `postScreen` block is emitted, or the confirmation step will explicitly ask the user what to do with the data.
|
|
209
|
+
- [ ] If `postScreen` is emitted: every `valueRef` resolves, every `field` belongs to the named `object` (or is flagged for user review), every `next` connector targets a defined element.
|
|
210
|
+
- [ ] **Specialized types are evidence-backed.** For every `Signature`, `UploadFile`, `UploadImage`, `Images`, `Matrix`, `Address`, `Lookup`, `FileView`, and `Repeater` in the output, name the prose evidence ("user said 'add multiple parts'"). If the user only used the *label* not the *control vocabulary*, downgrade the type per the table above. (These are real components that deploy as functional widgets — emitting them when the user only meant a text field is the most common bug.)
|
|
211
|
+
- [ ] **Lookup has `lookupObject`.** Every `Lookup` field has a `lookupObject` (Salesforce object API name). If the user didn't say which object, surface a question in the confirmation step or pick a best-guess and flag it.
|
|
212
|
+
- [ ] **FileView has `fileName`.** Every `FileView` field has a `fileName` (static asset filename, no extension). If unknown, surface a question.
|
|
213
|
+
- [ ] **Sections only where the user described them.** Every `{ "section": "..." }` item corresponds to a named sub-group the user actually mentioned. No invented sections, and no screens with exactly one section.
|
|
214
|
+
|
|
215
|
+
---
|
|
216
|
+
|
|
217
|
+
## Source design docs
|
|
218
|
+
|
|
219
|
+
This rule sheet is informed by two upstream design docs. Don't paste the full prompts from those docs into the user-facing flow — they're internal source-of-truth references.
|
|
220
|
+
|
|
221
|
+
- **Form-To-Flow AI HLD** ([doc](https://docs.google.com/document/d/1XlDRQE1gVrux8Iyz5LDupN9xV7i1IKpczLbsvMq5Tc4)) — the Flow Builder team's architecture for prose/PDF-to-DC-Flow generation.
|
|
222
|
+
- **Field Service POC HLD** ([doc](https://docs.google.com/document/d/10TO6CC983AcclXY7Ixp3I3hY5R7TagUMWP9VRqXOFoc)) — Field Service team's Apex+Agentforce POC. Source for the intermediate JSON contract and the extraction prompt rules.
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: field-service-data-capture-form-editor-configure
|
|
3
|
+
description: "Patch an existing Data Capture Flow that's already deployed in a connected Salesforce org. Retrieves the live Flow Metadata JSON via the Tooling API, applies the user's requested change, and PATCHes it back. Use when the user names an existing flow and asks to add/remove/rename a field, change visibility, fix a bug, add visual polish, or swap a placeholder for a real component ('add a Notes field to Inventory_Transfer', 'fix the visibility rule on Work_Order_Number', 'make the parts repeater optional', 'replace the Signature placeholder with the real dcSignature component'). Do NOT use this skill to build a brand-new flow — that's fs-data-capture-form-designer followed by fs-data-capture-form-deployer."
|
|
4
|
+
user-invocable: false
|
|
5
|
+
metadata:
|
|
6
|
+
version: "1.0"
|
|
7
|
+
domains: ["Field Service"]
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# Edit a Data Capture Form (in an org)
|
|
11
|
+
|
|
12
|
+
This skill patches a flow that already exists in a connected org. The source of truth is the deployed flow's `Metadata` JSON, retrieved live from the Tooling `Flow` sObject — there is no spec file, no `.flow-meta.xml`, no zip, no SFDX project. The skill retrieves the JSON, edits it in memory, and PATCHes it back.
|
|
13
|
+
|
|
14
|
+
> **Runtime contract:** every org interaction in this skill is a REST call
|
|
15
|
+
> dispatched through the Codey runtime (`execute_api` locally / the hosted
|
|
16
|
+
> Headless 360 MCP in shared surfaces). This skill has **no dependency on the
|
|
17
|
+
> execution environment** — no `sf` CLI, no local Python, no temp files, no
|
|
18
|
+
> scratch SFDX project. Auth probes, the flow retrieve, and the redeploy are
|
|
19
|
+
> single REST calls; the JSON patch is authored by the agent inline. Do not
|
|
20
|
+
> shell out.
|
|
21
|
+
|
|
22
|
+
## When this skill fires
|
|
23
|
+
|
|
24
|
+
- The user names an existing flow (`Inventory_Transfer`, `Asset_Inspection`, etc.) and asks for a change.
|
|
25
|
+
- The user pastes a Flow Builder URL and asks for a change.
|
|
26
|
+
- The user describes a deploy error or runtime bug in a deployed flow.
|
|
27
|
+
|
|
28
|
+
If the user is starting from scratch (prose, PDF, image), route to a `design-*` skill instead.
|
|
29
|
+
|
|
30
|
+
## Workflow
|
|
31
|
+
|
|
32
|
+
### 1. Verify org auth
|
|
33
|
+
|
|
34
|
+
Confirm the connected org is reachable with a cheap auth probe — dispatch `SELECT Id FROM Organization LIMIT 1` (`GET /services/data/vXX.0/query`):
|
|
35
|
+
|
|
36
|
+
- 2xx with `totalSize=1` → the session token is live; continue.
|
|
37
|
+
- 401/403 → the org needs re-authentication. Surface that to the user and **stop**. (The Codey runtime resolves and refreshes the connected org — this skill does not manage org aliases.)
|
|
38
|
+
|
|
39
|
+
### 2. Retrieve the live flow's Metadata JSON
|
|
40
|
+
|
|
41
|
+
The Tooling `Flow` sObject exposes the flow definition as a JSON `Metadata` field — the same shape the deployer assembles and POSTs. Retrieving is a two-call round-trip, no CLI and no file:
|
|
42
|
+
|
|
43
|
+
1. **Resolve the latest version id from the API name.** Dispatch `GET /services/data/vXX.0/tooling/query` with:
|
|
44
|
+
|
|
45
|
+
```sql
|
|
46
|
+
SELECT Id, ActiveVersionId, LatestVersionId FROM FlowDefinition WHERE DeveloperName = '<FlowApiName>'
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Edit the **latest** version (`LatestVersionId`) so the patch builds on the newest draft, not a stale active version. If `LatestVersionId` is null, fall back to `ActiveVersionId`.
|
|
50
|
+
|
|
51
|
+
2. **Read the Metadata blob.** Dispatch `GET /services/data/vXX.0/tooling/sobjects/Flow/<versionId>` and take the `Metadata` object from the response. This JSON is the flow — screens, choices, decisions, variables, and the post-screen chain. See [../fs-data-capture-form-deployer/reference/flow-metadata-json.md](../fs-data-capture-form-deployer/reference/flow-metadata-json.md) for the shape.
|
|
52
|
+
|
|
53
|
+
If the FlowDefinition query returns zero rows, the API name is wrong or the user is pointed at the wrong org. Confirm with the user before retrying. List the candidate flows in the org if useful — dispatch `GET /services/data/vXX.0/tooling/query` with `SELECT DeveloperName FROM FlowDefinition ORDER BY DeveloperName`.
|
|
54
|
+
|
|
55
|
+
### 3. Read the retrieved Metadata JSON and the rule sheet
|
|
56
|
+
|
|
57
|
+
Before patching, **read** the retrieved `Metadata` JSON to understand the current structure, then read [fs-data-capture-reference/SKILL.md](../fs-data-capture-reference/SKILL.md) for the platform's hard constraints. The constraints are identical whether the flow is expressed as XML or JSON — a repeated XML element is a JSON array, so "grouping" becomes "the array" (see the JSON↔XML mapping rule in [../fs-data-capture-form-deployer/reference/flow-metadata-json.md](../fs-data-capture-form-deployer/reference/flow-metadata-json.md)). Pay particular attention to:
|
|
58
|
+
|
|
59
|
+
- **Element arrays**: `screens`, `choices`, `decisions`, `recordLookups`, `recordCreates`, `recordUpdates`, `loops`, `assignments`, `variables` are each a single JSON array. Add a new element by appending to the right array — never introduce a duplicate top-level key.
|
|
60
|
+
- **CUD ordering**: no record-lookup or screen after any CUD (recordCreate/recordUpdate/recordDelete) in the connector chain. No decision between sequential CUDs.
|
|
61
|
+
- **`.AllItems` vs `.AddedItems` Repeater accessor** — use what the deployed flow uses, don't change it.
|
|
62
|
+
- **Visibility rules**: in a `visibilityRule.conditions` entry, `leftValueReference` is the *choice* api-name, not the parent field's name.
|
|
63
|
+
- **Required-field behind visibility-rule** anti-pattern (see `fs-data-capture-reference` SKILL.md).
|
|
64
|
+
- **`isLlmTargetable`**: carried as a `{ "stringValue": "true" }`-style wrapper, not a raw JSON boolean — match whatever the retrieved flow uses.
|
|
65
|
+
|
|
66
|
+
The prohibited-patterns table at the bottom of [fs-data-capture-reference/SKILL.md](../fs-data-capture-reference/SKILL.md) is the fastest reference for "what would break this patch".
|
|
67
|
+
|
|
68
|
+
### 4. Plan the patch and confirm with the user
|
|
69
|
+
|
|
70
|
+
Before editing, tell the user:
|
|
71
|
+
|
|
72
|
+
1. **What you're going to change** — specific element, specific lines (cite `path:line` references), and what the result will look like.
|
|
73
|
+
2. **Whether the change requires schema reordering** — e.g. adding a new `<recordLookups>` element when none exist requires placing it in the right group. Call this out.
|
|
74
|
+
3. **Activation status risk** — patches deploy as a new draft version of the flow. The active version (if any) keeps running until the user activates the new draft in Flow Builder. Tell the user this.
|
|
75
|
+
4. **Anything you noticed that's worth flagging** — pre-existing issues, deprecated patterns, validation rules that look broken. Don't auto-fix unrelated issues; surface them.
|
|
76
|
+
|
|
77
|
+
Use `AskUserQuestion` to gate the edit. Options:
|
|
78
|
+
- **Apply and deploy** — proceed.
|
|
79
|
+
- **Show me the change first** — present the before/after of just the edited JSON subtree (the specific field, screen, or rule you're touching) inline in the chat, then ask again. No file is written; the patch lives in memory until the user approves the PATCH.
|
|
80
|
+
- **Cancel** — stop without deploying.
|
|
81
|
+
|
|
82
|
+
Do not proceed to step 5 without explicit approval.
|
|
83
|
+
|
|
84
|
+
### 5. Apply the patch
|
|
85
|
+
|
|
86
|
+
Edit the in-memory `Metadata` JSON object retrieved in step 2. Some specific guidelines:
|
|
87
|
+
|
|
88
|
+
- **Append to the right array.** If you're adding a screen, append to the `screens` array; a choice, to `choices`; a variable, to `variables`. Never create a second top-level key of the same name.
|
|
89
|
+
- **Booleans and numbers stay JSON scalars.** `"isRequired": true`, `"locationX": 0` — not strings. Typed value wrappers keep their key (`{ "stringValue": "X" }`, `{ "booleanValue": true }`, `{ "elementReference": "Foo" }`).
|
|
90
|
+
- **Preserve `locationX` / `locationY`** for existing elements. For new elements set both to `0` — Flow Builder re-layouts on open.
|
|
91
|
+
- **If the change touches a Repeater, preserve the existing `.AllItems` / `.AddedItems` accessor in any loops** — switching accessors will break runtime behavior.
|
|
92
|
+
- **If you add a new field, copy the shape from a sibling field** in the same flow (label inputParameter, `inputsOnNextNavToAssocScrn`, `storeOutputAutomatically`, `styleProperties`, `isRequired`). Don't compose from memory — the rules at [fs-data-capture-reference/SKILL.md](../fs-data-capture-reference/SKILL.md) show what's required per component, but the deployed flow already has working examples.
|
|
93
|
+
- **If the change requires a new `choices` entry**, dedupe — check whether a choice with the same `value` already exists in the `choices` array.
|
|
94
|
+
- **Never emit a `required` inputParameter** on a screen component — some `dc*` components (`dcName`, `dcSignature`) reject it. Carry requiredness via the field's `isRequired` key only.
|
|
95
|
+
|
|
96
|
+
### 6. Redeploy via a Tooling PATCH
|
|
97
|
+
|
|
98
|
+
Push the edited flow back as a new draft version with a single Tooling API call — dispatch `PATCH /services/data/vXX.0/tooling/sobjects/Flow/<versionId>` with body:
|
|
99
|
+
|
|
100
|
+
```json
|
|
101
|
+
{ "Metadata": { "...the full edited Metadata object..." } }
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
- Send the **complete** `Metadata` object, not a partial patch — Tooling replaces the whole blob.
|
|
105
|
+
- A 204 (No Content) is success. On a 400, the response body's `message` carries the Flow validation error — diagnose against step 7's table.
|
|
106
|
+
- This creates a new **draft** version of the flow. Existing active versions keep running until the user activates the new draft in Flow Builder. (To activate on save instead, set `Metadata.status: "Active"` — default is to leave it Draft.)
|
|
107
|
+
|
|
108
|
+
### 7. Report back
|
|
109
|
+
|
|
110
|
+
On success:
|
|
111
|
+
- State plainly what changed (e.g. "Added `Notes` ShortText field to `Header_Information` screen").
|
|
112
|
+
- Print the Flow Builder URL so the user can review and activate. Look up the FlowDefinition Id with a Tooling API query — dispatch `GET /services/data/vXX.0/tooling/query` with `SELECT Id, ActiveVersionId FROM FlowDefinition WHERE DeveloperName = '<FlowApiName>'` → `<instanceUrl>/builder_platform_interaction/flowBuilder.app?flowId=<id>`
|
|
113
|
+
- Remind the user the active version hasn't changed yet — they need to activate the new draft in Flow Builder.
|
|
114
|
+
|
|
115
|
+
On failure (the `PATCH` returned a 400 — read the error from the response body's `message`):
|
|
116
|
+
- Cross-reference the prohibited-patterns table at [fs-data-capture-reference/SKILL.md](../fs-data-capture-reference/SKILL.md). Common diagnoses for edits: element-array grouping violation, CUD ordering, `Element X doesn't exist` (typo'd reference), `extension not found` (wrong component name), `'Range' is not a valid value` (slider not supported), `We can't find this input attribute: 'required'` (drop the `required` inputParameter — use `isRequired`).
|
|
117
|
+
- If the error is about an element you didn't touch, the retrieved flow might have been in a broken state already. Re-read the current version's Metadata and compare against the active version (`GET /tooling/sobjects/Flow/<ActiveVersionId>`).
|
|
118
|
+
- Don't loop more than twice without showing the user.
|
|
119
|
+
|
|
120
|
+
## Out of scope
|
|
121
|
+
|
|
122
|
+
- Building a new flow — `fs-data-capture-form-designer` + `fs-data-capture-form-deployer`.
|
|
123
|
+
- Bulk migrations across many flows.
|
|
124
|
+
- Replacing a flow with a wholly different structure (delete + rebuild is cleaner).
|
|
125
|
+
- Editing flows that aren't `processType=DataCaptureFlow` — this skill assumes the FSL Mobile runtime.
|
|
126
|
+
|
|
127
|
+
## Related skills
|
|
128
|
+
|
|
129
|
+
- **`fs-data-capture-reference`** (library) — read this *before* every edit. Source of truth for valid flow patterns, prohibited patterns + exact deploy errors, visual polish HTML, supporting CustomObject/PermissionSet/CustomTab deploy.
|
|
130
|
+
- **`fs-data-capture-form-deployer`** — creates flows via the same Tooling `Flow` JSON round-trip this skill uses to patch them. Its [reference/flow-metadata-json.md](../fs-data-capture-form-deployer/reference/flow-metadata-json.md) is the authoritative `Metadata` shape for both skills.
|
|
131
|
+
|
|
132
|
+
## Files in this skill
|
|
133
|
+
|
|
134
|
+
This skill has **no executable scripts**. The auth probe, the flow retrieve (`GET /tooling/sobjects/Flow/{id}`), and the redeploy (`PATCH /tooling/sobjects/Flow/{id}`) are all single REST calls dispatched through the Codey runtime. The JSON patch is authored by the agent inline against [../fs-data-capture-form-deployer/reference/flow-metadata-json.md](../fs-data-capture-form-deployer/reference/flow-metadata-json.md).
|