@salesforce/afv-skills 1.48.0 → 1.50.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (31) hide show
  1. package/package.json +1 -1
  2. package/skills/education-cloud-multi-campus-configure/SKILL.md +0 -5
  3. package/skills/field-service-data-capture-form-deployer-configure/SKILL.md +180 -0
  4. package/skills/field-service-data-capture-form-deployer-configure/examples/inventory-transfer-spec.json +135 -0
  5. package/skills/field-service-data-capture-form-deployer-configure/examples/sample-spec.json +140 -0
  6. package/skills/field-service-data-capture-form-deployer-configure/examples/sectioned-spec.json +64 -0
  7. package/skills/field-service-data-capture-form-deployer-configure/references/field-types.md +297 -0
  8. package/skills/field-service-data-capture-form-deployer-configure/references/flow-metadata-json.md +243 -0
  9. package/skills/field-service-data-capture-form-deployer-configure/references/post-screen-automation.md +127 -0
  10. package/skills/field-service-data-capture-form-designer-configure/SKILL.md +110 -0
  11. package/skills/field-service-data-capture-form-designer-configure/references/extraction-from-image.md +244 -0
  12. package/skills/field-service-data-capture-form-designer-configure/references/extraction-from-prompt.md +222 -0
  13. package/skills/field-service-data-capture-form-editor-configure/SKILL.md +134 -0
  14. package/skills/field-service-data-capture-reference-configure/SKILL.md +762 -0
  15. package/skills/field-service-data-capture-reference-configure/examples/DataCapture_Showcase.flow-meta.xml +2022 -0
  16. package/skills/field-service-data-capture-reference-configure/examples/Data_Capture_All_Components.flow-meta.xml +2170 -0
  17. package/skills/field-service-data-capture-reference-configure/examples/Repeater_with_prepopulation.flow-meta.xml +231 -0
  18. package/skills/field-service-foundation-setup-designer-get/SKILL.md +135 -0
  19. package/skills/field-service-mobile-branding-configure/SKILL.md +133 -0
  20. package/skills/field-service-mobile-branding-configure/examples/dark-blue-scheme.json +16 -0
  21. package/skills/field-service-mobile-branding-configure/examples/salesforce-default-scheme.json +16 -0
  22. package/skills/field-service-mobile-branding-configure/references/color-fields.md +66 -0
  23. package/skills/field-service-mobile-branding-configure/references/contrast-validation.md +55 -0
  24. package/skills/field-service-mobile-branding-configure/references/derivation-methodology.md +83 -0
  25. package/skills/field-service-objective-designer-configure/SKILL.md +342 -0
  26. package/skills/field-service-prework-brief-deployer-configure/SKILL.md +83 -0
  27. package/skills/field-service-scheduling-policy-designer-query/SKILL.md +121 -0
  28. package/skills/field-service-setup-orchestrator-get/SKILL.md +48 -0
  29. package/skills/field-service-sobject-create-configure/SKILL.md +56 -0
  30. package/skills/field-service-voice-to-form-configure/SKILL.md +650 -0
  31. package/skills/field-service-work-rule-designer-configure/SKILL.md +303 -0
@@ -0,0 +1,762 @@
1
+ ---
2
+ name: field-service-data-capture-reference-configure
3
+ description: "Build, edit, and deploy Salesforce Data Capture Flows (processType DataCaptureFlow) — Field Service mobile / offline forms. Use when authoring flow-meta.xml with runtime_service_fieldservice:dc* components, Repeater loops (.AllItems), master-detail child record persistence, visual polish (gradient banners, progress bars, callouts), supporting objects with FLS/permsets, debugging DataCaptureFlow deploy errors, or troubleshooting why a deployed form doesn't appear on the FSL Mobile Forms tab (DDC/WorkPlan OWD + AssignedResource sharing prerequisites)."
4
+ user-invocable: false
5
+ metadata:
6
+ version: "1.0"
7
+ domains: ["Field Service"]
8
+ cliTools:
9
+ - tool: ["python3"]
10
+ semver: ">=3.9.0"
11
+ - tool: ["sf"]
12
+ semver: ">=2.0.0"
13
+ ---
14
+
15
+ # Salesforce Data Capture Flow Skill
16
+
17
+ Build, edit, and deploy Salesforce Flows with `processType: DataCaptureFlow` (Field Service mobile / offline forms).
18
+
19
+ ---
20
+
21
+ ## Required metadata (every flow)
22
+
23
+ ```xml
24
+ <processType>DataCaptureFlow</processType>
25
+ <areMetricsLoggedToDataCloud>false</areMetricsLoggedToDataCloud>
26
+ <environments>Offline</environments>
27
+ <!-- NO <apiVersion> tag -->
28
+ ```
29
+
30
+ Optional `IsLlmTargetable` custom property — if you include it, it must be a JSON string, not a boolean:
31
+
32
+ ```xml
33
+ <customProperties>
34
+ <name>IsLlmTargetable</name>
35
+ <value><stringValue>{&quot;value&quot;:&quot;false&quot;}</stringValue></value>
36
+ </customProperties>
37
+ ```
38
+
39
+ The `<booleanValue>false</booleanValue>` form deploys but blocks activation — error: `The value of the IsLlmTargetable custom property's value field must be a string in JSON format`. Omitting the property entirely is also fine.
40
+
41
+ Required input variables:
42
+ ```xml
43
+ <variables><name>recordId</name><dataType>String</dataType><isInput>true</isInput><isOutput>false</isOutput><isCollection>false</isCollection></variables>
44
+ <variables><name>parentRecordId</name><dataType>String</dataType><isInput>true</isInput><isOutput>false</isOutput><isCollection>false</isCollection></variables>
45
+ <variables><name>parentObjectType</name><dataType>String</dataType><isInput>true</isInput><isOutput>false</isOutput><isCollection>false</isCollection></variables>
46
+ ```
47
+
48
+ ---
49
+
50
+ ## XML structure rules
51
+
52
+ Salesforce's Flow schema enforces grouping — all elements of the same type must appear in a single contiguous block. Deploy fails with `Element X is duplicated at this location` when violated.
53
+
54
+ Group order doesn't matter, but within each group elements must be adjacent:
55
+ - all `<choices>` together
56
+ - all `<dynamicChoiceSets>` together
57
+ - all `<screens>` together
58
+ - all `<decisions>` together
59
+ - all `<recordLookups>` together
60
+ - all `<recordCreates>` together
61
+ - all `<recordUpdates>` together
62
+ - all `<loops>` together
63
+ - all `<assignments>` together
64
+ - all `<variables>` together
65
+
66
+ Connector references determine execution order, not XML order.
67
+
68
+ ---
69
+
70
+ ## Component reference
71
+
72
+ All extensions: prefix `runtime_service_fieldservice:`
73
+
74
+ | Component | Extension | fieldType |
75
+ |-----------|-----------|-----------|
76
+ | Short Text | `dcTextInput` | `ComponentInstance` |
77
+ | Long Text | `dcLongText` | `ComponentInstance` |
78
+ | Email | `dcEmail` | `ComponentInstance` |
79
+ | Phone | `dcPhone` | `ComponentInstance` |
80
+ | Name | `dcName` | `ComponentInstance` |
81
+ | Numeric | `dcNumeric` | `ComponentInstance` |
82
+ | Counter | `dcCounter` | `ComponentInstance` |
83
+ | Date | `dcDate` | `ComponentInstance` |
84
+ | Date & Time | `dcDateTime` | `ComponentInstance` |
85
+ | Checkbox | `dcCheckbox` | `ComponentInstance` |
86
+ | Toggle | `dcToggle` | `ComponentInstance` |
87
+ | Address / GPS | `dcAddress` | `ComponentInstance` |
88
+ | Lookup | `dcLookup` | `ComponentInstance` |
89
+ | Static image | `dcFileView` | `ComponentInstance` |
90
+ | Upload image (mobile) | `dcUpImage` | `ComponentInstance` |
91
+ | Upload file (mobile) | `dcUpFile` | `ComponentInstance` |
92
+ | Signature (mobile) | `dcSignature` | `ComponentInstance` |
93
+ | Picklist single | `dcPicklist` | `ComponentChoice` |
94
+ | Picklist multi | `dcPicklist` | `ComponentMultiChoice` |
95
+ | Radio buttons | `dcRbGroup` | `ComponentChoice` |
96
+ | Checkbox group | `dcCbGroup` | `ComponentMultiChoice` |
97
+ | Matrix | `dcMatrix` | `ComponentMultiChoice` |
98
+ | Display text | *(none)* | `DisplayText` |
99
+ | Section | *(none)* | `RegionContainer` + `Region` |
100
+ | Repeater | *(none)* | `Repeater` |
101
+
102
+ Note: `<fieldType>Range</fieldType>` is NOT a valid slider fieldType in DataCaptureFlow (despite "Range/Slider" appearing in Builder UI lists). Sliders aren't available as pure metadata in this process type — use `dcNumeric` or `dcCounter`. `forceContent:repeater` (Lightning generic) ≠ `<fieldType>Repeater</fieldType>` (FSL offline). They share a concept, not XML.
103
+
104
+ ### Setting the label
105
+
106
+ | fieldType | How |
107
+ |-----------|-----|
108
+ | `ComponentInstance` | `<inputParameters><name>label</name><value><stringValue>…</stringValue></value></inputParameters>` |
109
+ | `ComponentChoice` / `ComponentMultiChoice` | `<fieldText>Label</fieldText>` |
110
+ | `DisplayText` | `<fieldText>HTML</fieldText>` |
111
+
112
+ All ComponentInstance extensions (including `dcAddress` and `dcToggle`) accept the `label` inputParameter — no wrapping DisplayText needed.
113
+
114
+ ### Required flag
115
+
116
+ Every input field needs `<isRequired>true/false</isRequired>` at field level. That single flag is sufficient for every `dc*` component — no extra `required` / `isRequired` inputParameter is needed.
117
+
118
+ `dcLookup` additionally accepts an `isRequired` inputParameter (boolean), but the field-level `<isRequired>` drives enforcement.
119
+
120
+ `dcCheckbox` and `dcToggle` accept `<isRequired>true</isRequired>` syntactically but don't enforce it at runtime.
121
+
122
+ ### Every input field must also have
123
+
124
+ ```xml
125
+ <inputsOnNextNavToAssocScrn>UseStoredValues</inputsOnNextNavToAssocScrn>
126
+ <storeOutputAutomatically>true</storeOutputAutomatically>
127
+ <styleProperties>
128
+ <verticalAlignment><stringValue>top</stringValue></verticalAlignment>
129
+ <width><stringValue>12</stringValue></width>
130
+ </styleProperties>
131
+ ```
132
+
133
+ **Exception:** `<fieldType>Repeater</fieldType>` explicitly rejects `storeOutputAutomatically` (`"the storeOutputAutomatically field isn't supported"`). Repeater output is always available as `.AllItems` — no opt-in needed.
134
+
135
+ ---
136
+
137
+ ## Screen rules
138
+
139
+ Every screen needs ALL THREE of these or the Next/Finish button won't render:
140
+ - `<allowFinish>true</allowFinish>` (even on non-final screens)
141
+ - `<showFooter>true</showFooter>`
142
+ - `<nextOrFinishButtonLabel>Next</nextOrFinishButtonLabel>`
143
+
144
+ Plus:
145
+ - First element after `<start>` must always be a `<screens>` element
146
+ - All `<screens>` elements must be grouped together in the XML
147
+
148
+ ---
149
+
150
+ ## Repeater — iterating rows and creating child records
151
+
152
+ The Repeater's output collection is exposed as `.AllItems`. Confirmed working on API v66.
153
+
154
+ ```xml
155
+ <!-- On the screen: -->
156
+ <fields>
157
+ <name>MyRepeater</name>
158
+ <fieldType>Repeater</fieldType>
159
+ <!-- NO storeOutputAutomatically on the Repeater itself -->
160
+ <fields>
161
+ <name>Row_PartName</name>
162
+ <extensionName>runtime_service_fieldservice:dcTextInput</extensionName>
163
+ <fieldType>ComponentInstance</fieldType>
164
+ <storeOutputAutomatically>true</storeOutputAutomatically>
165
+ <!-- … -->
166
+ </fields>
167
+ <fields>
168
+ <name>Row_PartQty</name>
169
+ <extensionName>runtime_service_fieldservice:dcCounter</extensionName>
170
+ <fieldType>ComponentInstance</fieldType>
171
+ <storeOutputAutomatically>true</storeOutputAutomatically>
172
+ <!-- … -->
173
+ </fields>
174
+ <isRequired>false</isRequired>
175
+ </fields>
176
+
177
+ <!-- At end of flow: -->
178
+ <loops>
179
+ <name>Loop_Parts</name>
180
+ <collectionReference>MyRepeater.AllItems</collectionReference> <!-- ← THE KEY -->
181
+ <iterationOrder>Asc</iterationOrder>
182
+ <nextValueConnector>
183
+ <targetReference>Create_Part</targetReference>
184
+ </nextValueConnector>
185
+ </loops>
186
+ <recordCreates>
187
+ <name>Create_Part</name>
188
+ <object>CustomFormPart__c</object>
189
+ <connector>
190
+ <targetReference>Loop_Parts</targetReference> <!-- loops back -->
191
+ </connector>
192
+ <inputAssignments>
193
+ <field>PartName__c</field>
194
+ <value>
195
+ <elementReference>Loop_Parts.Row_PartName.value</elementReference>
196
+ <!-- ↑ LOOP name + nested field name + .value -->
197
+ </value>
198
+ </inputAssignments>
199
+ <inputAssignments>
200
+ <field>Quantity__c</field>
201
+ <value>
202
+ <elementReference>Loop_Parts.Row_PartQty.value</elementReference>
203
+ </value>
204
+ </inputAssignments>
205
+ <storeOutputAutomatically>true</storeOutputAutomatically>
206
+ </recordCreates>
207
+ ```
208
+
209
+ **Don'ts:**
210
+ - `<collectionReference>MyRepeater</collectionReference>` → `Element "MyRepeater" doesn't exist`
211
+ - `<collectionReference>MyRepeater.items</collectionReference>` → generic server error
212
+ - `<collectionReference>MyRepeater.data</collectionReference>` → generic server error
213
+ - Inside the loop body, `MyRepeater.Row_PartName.value` won't work — must use the **loop's name**, not the repeater's name.
214
+
215
+ **Cross-row validation does NOT compile.** Formula refs like `r_GR4.AllItems[$Items].field.value` and `r_GR4.AllItems[$Items - 1].field.value` fail with *Syntax error*. Per-row validation works via plain `fieldName.value` inside the nested field's own `validationRule`. For cross-row rules, use a post-screen `loops + decisions`.
216
+
217
+ **Other Repeater accessors don't resolve today.** Only `.AllItems` works. `AddedItems`, `PrepopulatedItems`, `RemovedItems` all fail deploy with `doesn't exist`.
218
+
219
+ ### Prepopulating a Repeater from an existing collection
220
+
221
+ Bind an existing SObject collection to the Repeater so it renders one pre-filled row per source record. The user can then edit, add, or remove rows before submit.
222
+
223
+ Pattern: `recordLookups` (get source collection, `getFirstRecordOnly=false`, `storeOutputAutomatically=true`) → screen with `Repeater` bound via the `collection` inputParameter → nested fields use `SourceCollection[$EachItem].FieldApiName` as their `value` default.
224
+
225
+ ```xml
226
+ <recordLookups>
227
+ <name>Get_Source</name>
228
+ <object>ServiceResource</object>
229
+ <getFirstRecordOnly>false</getFirstRecordOnly>
230
+ <storeOutputAutomatically>true</storeOutputAutomatically>
231
+ <connector><targetReference>Screen_Repeater</targetReference></connector>
232
+ <!-- optional <limit>, <filters> … -->
233
+ </recordLookups>
234
+
235
+ <!-- On the screen: -->
236
+ <fields>
237
+ <name>accountRepeater</name>
238
+ <fieldType>Repeater</fieldType>
239
+ <inputParameters>
240
+ <name>collection</name> <!-- ← binds source rows -->
241
+ <value><elementReference>Get_Source</elementReference></value>
242
+ </inputParameters>
243
+ <fields>
244
+ <name>account_info</name>
245
+ <fieldType>DisplayText</fieldType>
246
+ <fieldText>&lt;p&gt;Id: {!Get_Source[$EachItem].Id}&lt;/p&gt;</fieldText>
247
+ <!-- DisplayText inside the Repeater merges via SourceCollection[$EachItem].Field -->
248
+ </fields>
249
+ <fields>
250
+ <name>name</name>
251
+ <extensionName>runtime_service_fieldservice:dcTextInput</extensionName>
252
+ <fieldType>ComponentInstance</fieldType>
253
+ <inputParameters>
254
+ <name>label</name>
255
+ <value><stringValue>Name</stringValue></value>
256
+ </inputParameters>
257
+ <inputParameters>
258
+ <name>value</name>
259
+ <value><elementReference>Get_Source[$EachItem].Name</elementReference></value>
260
+ <!-- ↑ prepopulates the editable field with the source record's value -->
261
+ </inputParameters>
262
+ <isRequired>true</isRequired>
263
+ <storeOutputAutomatically>true</storeOutputAutomatically>
264
+ <inputsOnNextNavToAssocScrn>UseStoredValues</inputsOnNextNavToAssocScrn>
265
+ <styleProperties>…</styleProperties>
266
+ </fields>
267
+ <isRequired>false</isRequired>
268
+ <styleProperties>…</styleProperties>
269
+ </fields>
270
+ ```
271
+
272
+ Key points:
273
+ - The binding inputParameter is named `collection`, not `value` or `source`.
274
+ - Inside the Repeater, reference a source row via `SourceCollectionName[$EachItem].FieldApiName` — use the **record-lookup's name**, not the Repeater's name. Works in both `DisplayText.fieldText` (as `{!Get_Source[$EachItem].Id}`) and in component `value` defaults (as `<elementReference>Get_Source[$EachItem].Name</elementReference>`).
275
+ - `$EachItem` is the per-row iterator Salesforce injects while rendering the Repeater. It only resolves inside Repeater-nested fields.
276
+ - Downstream loops still iterate `Repeater_Name.AllItems` as normal — prepopulation changes the input, not the output accessor.
277
+ - Prepopulated rows appear as regular `.AllItems` entries after submit; there is no `PrepopulatedItems` / `AddedItems` split (those accessors fail deploy).
278
+
279
+ ### Displaying Repeater entries to the user (post-Repeater Loop screen)
280
+
281
+ To show the user what they captured (e.g. review / confirmation / per-row detail), put a Loop **after** the Repeater screen whose body connects to a display screen; the display screen then connects back to the Loop. The end connector of the Loop moves on to the next step.
282
+
283
+ ```xml
284
+ <loops>
285
+ <name>Loop_Through_Repeater</name>
286
+ <collectionReference>accountRepeater.AllItems</collectionReference>
287
+ <iterationOrder>Asc</iterationOrder>
288
+ <nextValueConnector>
289
+ <targetReference>Repeater_Output_Screen</targetReference> <!-- body = display screen -->
290
+ </nextValueConnector>
291
+ <!-- <noMoreValuesConnector> → next step after the review is done -->
292
+ </loops>
293
+
294
+ <screens>
295
+ <name>Repeater_Output_Screen</name>
296
+ <connector><targetReference>Loop_Through_Repeater</targetReference></connector> <!-- back to loop -->
297
+ <fields>
298
+ <name>display_info</name>
299
+ <fieldType>DisplayText</fieldType>
300
+ <fieldText>&lt;p&gt;Source Id: {!Loop_Through_Repeater.UniqueField__Id}&lt;/p&gt;
301
+ &lt;p&gt;Name: {!Loop_Through_Repeater.name.value}&lt;/p&gt;
302
+ &lt;p&gt;Type: {!Loop_Through_Repeater.description.value}&lt;/p&gt;</fieldText>
303
+ <styleProperties>…</styleProperties>
304
+ </fields>
305
+ <allowFinish>true</allowFinish>
306
+ <showFooter>true</showFooter>
307
+ <nextOrFinishButtonLabel>Next</nextOrFinishButtonLabel>
308
+ </screens>
309
+ ```
310
+
311
+ Accessor rules inside the loop body:
312
+ - User-captured values — `{!LoopName.nestedFieldName.value}` (same `.value` / `.selectedChoiceValues` / `.isActive` / etc. accessors as elsewhere).
313
+ - Source record Id for **prepopulated** rows — `{!LoopName.UniqueField__Id}`. This is a synthetic field the Repeater exposes on each iteration; it only carries a value for rows that came from the bound `collection` (new rows the user added will be blank).
314
+ - Use the **loop's name**, not the Repeater's name, inside the loop body — same rule as the canonical `.AllItems` + Create pattern above.
315
+
316
+ This loop-over-`.AllItems` display pattern composes with the Create/Update patterns: one loop for rendering a review screen, a later loop (or the same one, if ordering permits) for CUD. Remember the CUD rule — nothing (screens, gets, decisions) may sit between sequential CUD nodes, so any review loop must fully complete before the CUD chain starts.
317
+
318
+ ---
319
+
320
+ ## CUD rules (hard platform constraints)
321
+
322
+ - **A Decision can choose which CUD chain starts** (e.g. Create vs Update branches of a save-mode decision). But **once a CUD chain begins, no Decision may appear between sequential CUD nodes** — deploy fails with `Append multiple Create, Update, or Delete operations only at the end of the flow, in any order`.
323
+ - Workaround for "create only if filled" → always-create (accept blank rows), or move the conditional logic before the CUD chain begins.
324
+ - **All CUDs at end of flow.** No Get Records or screens after any CUD. No subflows containing CUD.
325
+ - **Assignment-after-CUD inside a loop was bugged in v260.** Fixed in v262 / API 66. Safe to use now.
326
+
327
+ ---
328
+
329
+ ## Counter params
330
+
331
+ ```xml
332
+ <inputParameters><name>min</name><value><numberValue>1.0</numberValue></value></inputParameters>
333
+ <inputParameters><name>max</name><value><numberValue>10.0</numberValue></value></inputParameters>
334
+ <inputParameters><name>step</name><value><numberValue>1.0</numberValue></value></inputParameters>
335
+ <inputParameters><name>minCustomErrorMessage</name><value><stringValue>…</stringValue></value></inputParameters>
336
+ <inputParameters><name>maxCustomErrorMessage</name><value><stringValue>…</stringValue></value></inputParameters>
337
+ ```
338
+
339
+ ## Date params
340
+
341
+ ```xml
342
+ <inputParameters><name>minDate</name><value><elementReference>$Flow.CurrentDate</elementReference></value></inputParameters>
343
+ <inputParameters><name>maxDate</name><value><dateValue>2027-12-31</dateValue></value></inputParameters>
344
+ ```
345
+
346
+ ## Picklist compact mode
347
+
348
+ Only use `isCompact=true` when ALL labels ≤8 characters AND ≤5 options.
349
+
350
+ ## Lookup params
351
+
352
+ ```xml
353
+ <inputParameters><name>objectApiName</name><value><stringValue>Asset</stringValue></value></inputParameters>
354
+ <inputParameters><name>searchedFields</name><value><stringValue>Name, SerialNumber</stringValue></value></inputParameters>
355
+ <inputParameters><name>isMultiSelection</name><value><booleanValue>true</booleanValue></value></inputParameters>
356
+ <inputParameters><name>recordIdCollection</name><value><elementReference>v_Ids</elementReference></value></inputParameters>
357
+ ```
358
+
359
+ ### `recordIdCollection` — scoping the searchable set
360
+
361
+ - **Builder label:** *Record IDs Collection*. **XML attribute:** `recordIdCollection` (singular `recordId` + `Collection` suffix). `recordIds` fails deploy with `We can't find this input attribute: "recordIds"`.
362
+ - **It is a scoping filter, not a default pre-selection.** Constrains the lookup to only search within the provided String collection of Ids.
363
+ - **Only takes effect when `isMultiSelection=true`.** In single-select mode it is silently ignored — the user sees the full unfiltered object.
364
+ - Canonical pattern: `recordLookups` (scoped subset) → `loops` + `assignments` (build String collection of Ids) → screen with `dcLookup recordIdCollection=v_Ids`. Works offline against Briefcase-primed data; target < 1s over ~60k records.
365
+ - Output in multi-select mode is `{!Lookup.recordIds}` (String collection); visibility rules and DML that previously used `{!Lookup.recordId}` (singular) must iterate the collection or take the first element.
366
+
367
+ ### `dcLookup` displayed label
368
+
369
+ `dcLookup` has **no input parameter** for the displayed field (no `displayField`/`primaryField`). The label in search results and the selected chip is driven by the object's **Primary Compact Layout** — first field in that layout wins. To change it: Setup → Object Manager → *Object* → Compact Layouts → reorder → assign as Primary (org-wide change). `searchedFields` controls matching, not display.
370
+
371
+ Flow-local alternative: swap `dcLookup` for `dcPicklist` backed by a `dynamicChoiceSets` with `<displayField>` / `<valueField>`.
372
+
373
+ ## Address with GPS
374
+
375
+ ```xml
376
+ <inputParameters><name>useCoordinates</name><value><booleanValue>true</booleanValue></value></inputParameters>
377
+ ```
378
+
379
+ ## Matrix
380
+
381
+ ```xml
382
+ <inputParameters><name>questions</name><value><stringValue>["Q1","Q2","Q3"]</stringValue></value></inputParameters>
383
+ ```
384
+
385
+ Escape `&` as `&amp;` inside the JSON string.
386
+
387
+ ## 2-column section
388
+
389
+ ```xml
390
+ <fields>
391
+ <name>MySection</name>
392
+ <fieldText>Section Header</fieldText>
393
+ <fieldType>RegionContainer</fieldType>
394
+ <fields>
395
+ <name>MySection_Col1</name>
396
+ <fieldType>Region</fieldType>
397
+ <fields><!-- components here --></fields>
398
+ <inputParameters><name>width</name><value><stringValue>6</stringValue></value></inputParameters>
399
+ <isRequired>false</isRequired>
400
+ </fields>
401
+ <fields>
402
+ <name>MySection_Col2</name>
403
+ <fieldType>Region</fieldType>
404
+ <fields><!-- components here --></fields>
405
+ <inputParameters><name>width</name><value><stringValue>6</stringValue></value></inputParameters>
406
+ <isRequired>false</isRequired>
407
+ </fields>
408
+ <isRequired>false</isRequired>
409
+ <regionContainerType>SectionWithHeader</regionContainerType>
410
+ …styleProperties…
411
+ </fields>
412
+ ```
413
+
414
+ ## Visibility rule
415
+
416
+ ```xml
417
+ <visibilityRule>
418
+ <conditionLogic>and</conditionLogic>
419
+ <conditions>
420
+ <leftValueReference>componentName.value</leftValueReference>
421
+ <operator>GreaterThan</operator>
422
+ <rightValue><numberValue>0.0</numberValue></rightValue>
423
+ </conditions>
424
+ </visibilityRule>
425
+ ```
426
+
427
+ Property accessors: `.value` (input components, including `dcCheckbox`), `.selectedChoiceValues` (choice components), `.isActive` (toggle), `.firstName` / `.lastName` (Name component), `.recordId` / `.recordIds` (Lookup single / multi).
428
+
429
+ The same accessors are also used inside `recordCreates` / `recordUpdates` `inputAssignments` — e.g. `<elementReference>new_Reading.value</elementReference>`.
430
+
431
+ ### Conditionally-hidden required fields — use `validationRule`, not `isRequired`
432
+
433
+ Never mark a field `isRequired=true` if it's behind a `visibilityRule`. The required check still fires while the field is hidden, so users can't proceed. Instead, set the field `isRequired=false` and wrap the rule:
434
+
435
+ ```text
436
+ IF(TriggerField.selectedChoiceValues = "Yes",
437
+ AND(NOT(ISBLANK(value)), value >= 0, value <= 100000),
438
+ TRUE)
439
+ ```
440
+
441
+ ### Canonical Decision IsNull pattern
442
+
443
+ `IsNull` takes a `booleanValue` on the right, NOT a null literal:
444
+
445
+ ```xml
446
+ <conditions>
447
+ <leftValueReference>v_ParentId</leftValueReference>
448
+ <operator>IsNull</operator>
449
+ <rightValue>
450
+ <booleanValue>false</booleanValue> <!-- true = is null, false = is not null -->
451
+ </rightValue>
452
+ </conditions>
453
+ ```
454
+
455
+ ---
456
+
457
+ ## Calculation timing (CRITICAL)
458
+
459
+ Calculated values **cannot display on the same screen that collects the inputs** — calculations run only after the user taps Next. Pattern:
460
+
461
+ ```text
462
+ Screen N (collect inputs) → recordLookups / assignments / decisions → Screen N+1 (display results)
463
+ ```
464
+
465
+ Screen N's connector must point to the calculation element, NOT to Screen N+1. All decision branches must eventually converge on Screen N+1.
466
+
467
+ ---
468
+
469
+ ## DisplayText formula limitations (mobile runtime)
470
+
471
+ `DisplayText` in DataCaptureFlow has **severely limited formula support** compared to standard flows — complex formulas deploy fine and preview in Builder but fail at runtime with `Error while resolving default value reference`.
472
+
473
+ **Fails at runtime:**
474
+ - `IF(Toggle.isActive, "YES", "NO")` — any IF/CASE on component properties
475
+ - `TEXT(CASE(...))`, `ADDMONTHS(...)`, nested date math
476
+ - Mixing multiple component refs + formulas in one `fieldText`
477
+
478
+ **Works:**
479
+ - Simple single variable: `{!var_RiskScore}`
480
+ - Simple component ref: `{!MyPicklist.selectedChoiceValues}`, `{!MyNumeric.value}`
481
+ - Global vars: `{!$Flow.CurrentDate}`, `{!$User.FirstName}`
482
+
483
+ Pattern: pre-calculate in an `<assignments>` element → store in a variable → reference that variable in DisplayText.
484
+
485
+ ### Global variables as input `value` defaults
486
+
487
+ | Default binding | Variable | Works? |
488
+ |-----------------|----------|--------|
489
+ | `dcTextInput` | `$User.Username` | ✅ |
490
+ | `dcTextInput` | `$User.Name` | ❌ type mismatch error |
491
+ | `dcDateTime` | `$Flow.InterviewStartTime` | ✅ |
492
+ | `dcDate` | `$Flow.CurrentDate` | ✅ |
493
+
494
+ ---
495
+
496
+ ## Record Choice Set (`dynamicChoiceSets`) — mobile offline gotcha
497
+
498
+ `<outputAssignments>` inside a `dynamicChoiceSets` deploys fine but **does NOT reliably populate the target variables at runtime** in mobile offline DataCaptureFlow. Downstream screens render blank.
499
+
500
+ Correct pattern: keep the choice set minimal (`displayField`, `valueField`, `filters`, `object`, `dataType`). After the selection screen, route through a `recordLookups` filtered by `Id = {!picklistName.selectedChoiceValues}` and put extra fields into variables via the lookup's `outputAssignments`. Fits calculation-timing rule naturally (lookup sits between selection screen and display screen).
501
+
502
+ ```xml
503
+ <recordLookups>
504
+ <name>gr_SelectedChild</name>
505
+ <filters>
506
+ <field>Id</field>
507
+ <operator>EqualTo</operator>
508
+ <value><elementReference>pl_Child.selectedChoiceValues</elementReference></value>
509
+ </filters>
510
+ <getFirstRecordOnly>true</getFirstRecordOnly>
511
+ <object>Child__c</object>
512
+ <outputAssignments>
513
+ <assignToReference>v_SelectedValue</assignToReference>
514
+ <field>Reading_Value__c</field>
515
+ </outputAssignments>
516
+ </recordLookups>
517
+ ```
518
+
519
+ ---
520
+
521
+ ## Visual polish patterns (verified render in mobile runtime)
522
+
523
+ Colors from the Lightning Design System: `#2E844A` (green), `#0176D3` (blue), `#FE9339` (orange), `#C9C7C5` (neutral).
524
+
525
+ ### Hero banner
526
+ ```html
527
+ <div style="background: linear-gradient(135deg, #2E844A 0%, #0176D3 100%); color: white; padding: 20px; border-radius: 10px; text-align: center;">
528
+ <p style="margin: 0; font-size: 22px;"><strong>🔧 Site Visit Report</strong></p>
529
+ <p style="margin: 4px 0 0 0; font-size: 13px;">Subtitle</p>
530
+ </div>
531
+ ```
532
+
533
+ ### Progress bar (per screen)
534
+ ```html
535
+ <p><b>Step X of N – 📍 Section Title</b></p>
536
+ <div style="width: 100%; height: 8px; background-color: #C9C7C5; border-radius: 4px; margin: 5px 0;">
537
+ <div style="width: PERCENT%; height: 100%; background: linear-gradient(90deg, #2E844A 0%, #0176D3 100%); border-radius: 4px;"></div>
538
+ </div>
539
+ ```
540
+ Separator between counter and title MUST be en dash `–` (U+2013), not hyphen.
541
+
542
+ ### Callout boxes
543
+ ```html
544
+ <!-- Info (blue) -->
545
+ <div style="background-color: #EAF5FE; border-left: 4px solid #0176D3; padding: 10px 14px; border-radius: 4px;">
546
+ <p style="margin: 0; color: #014486; font-size: 13px;"><b>ℹ️ Info:</b> …</p>
547
+ </div>
548
+ <!-- Warning (orange) -->
549
+ <div style="background-color: #FFF4E6; border-left: 4px solid #FE9339; padding: 10px 14px; border-radius: 4px;">
550
+ <p style="margin: 0; color: #704D00; font-size: 13px;"><b>⚠️ Heads up:</b> …</p>
551
+ </div>
552
+ <!-- Success (green) -->
553
+ <div style="background-color: #E8F5E9; border-left: 4px solid #2E844A; padding: 10px 14px; border-radius: 4px;">
554
+ <p style="margin: 0; color: #1B5E20; font-size: 13px;"><b>✅ Ready:</b> …</p>
555
+ </div>
556
+ ```
557
+
558
+ ### Review card (merge fields from prior screens)
559
+ ```html
560
+ <div style="border: 1px solid #DDDBDA; border-radius: 8px; padding: 14px 16px; background-color: #FAFAF9;">
561
+ <p style="margin: 0 0 8px 0; color: #0176D3; font-size: 14px;"><b>📍 Section</b></p>
562
+ <p style="margin: 2px 0;"><b>Name:</b> {!Input_SiteName.value}</p>
563
+ <p style="margin: 2px 0;"><b>Contact:</b> {!Input_Contact.firstName} {!Input_Contact.lastName}</p>
564
+ <p style="margin: 2px 0;"><b>Priority:</b> {!Input_Priority.selectedChoiceValues}</p>
565
+ <p style="margin: 2px 0;"><b>After-hours:</b> {!Input_Toggle.isActive}</p>
566
+ </div>
567
+ ```
568
+
569
+ All HTML must be XML-escaped in `<fieldText>`: `&` → `&amp;`, `"` → `&quot;`, `<` → `&lt;`, `>` → `&gt;`.
570
+
571
+ ---
572
+
573
+ ## Deploying supporting objects alongside the flow
574
+
575
+ Custom object + field deploys **do not auto-grant FLS/CRUD** on the System Administrator profile. Flows running as the admin still can't read/write the new fields. Ship a PermissionSet and assign it:
576
+
577
+ ```xml
578
+ <!-- MyObject_Access.permissionset-meta.xml -->
579
+ <PermissionSet xmlns="http://soap.sforce.com/2006/04/metadata">
580
+ <label>My Object Access</label>
581
+ <license>Salesforce</license>
582
+ <hasActivationRequired>false</hasActivationRequired>
583
+ <objectPermissions>
584
+ <allowCreate>true</allowCreate><allowDelete>true</allowDelete>
585
+ <allowEdit>true</allowEdit><allowRead>true</allowRead>
586
+ <modifyAllRecords>true</modifyAllRecords><viewAllRecords>true</viewAllRecords>
587
+ <object>MyObject__c</object>
588
+ </objectPermissions>
589
+ <fieldPermissions><field>MyObject__c.MyField__c</field><editable>true</editable><readable>true</readable></fieldPermissions>
590
+ <tabSettings><tab>MyObject__c</tab><visibility>Visible</visibility></tabSettings>
591
+ </PermissionSet>
592
+ ```
593
+
594
+ Assign after deploy: `sf org assign permset --name MyObject_Access --target-org <alias>`
595
+
596
+ ### CustomObject gotchas
597
+
598
+ - Master-detail children need `<sharingModel>ControlledByParent</sharingModel>`, else `Must specify a sharing model value`.
599
+ - Sfdx retrieve may pull `actionOverrides` for actions that aren't standard (`Automation`, `Details`). Strip them before re-deploy, else `X is not a standard action and cannot be overridden`.
600
+ - Text fields > 255 chars must be `<type>LongTextArea</type>`. `Text` max length is 255.
601
+ - A PermissionSet that references a `required=true` field deploys cleanly, but if FLS is set in a separate file, `You cannot deploy to a required field` fires. Flip the field to `required=false` or handle required-ness in the flow instead.
602
+
603
+ ### Custom tab
604
+
605
+ Lets users list records from the App Launcher:
606
+
607
+ ```xml
608
+ <!-- MyObject__c.tab-meta.xml -->
609
+ <CustomTab xmlns="http://soap.sforce.com/2006/04/metadata">
610
+ <customObject>true</customObject>
611
+ <motif>Custom53: Form</motif>
612
+ </CustomTab>
613
+ ```
614
+
615
+ Then add `<tabSettings>` to the permset (as shown above).
616
+
617
+ ---
618
+
619
+ ## Mobile prerequisites — required for Forms tab to render on FSL Mobile
620
+
621
+ A flow that deploys cleanly and shows up on desktop will **silently fail on FSL Mobile** with `"No forms available. Try Again"` if the org isn't set up to share DDC + WorkPlan records with the assigned technician. Verified 2026-05-28: a fully-validated form (Sewerage Further Work Request) was invisible on iOS Field Service for the assigned tech until all four fixes below were in place. The same blocker hid the SDO's pre-shipped Job Safety Assessment form.
622
+
623
+ Why it's silent: FSL Mobile uses the UI API endpoint `/services/data/v67.0/ui-api/related-list-records/{woId}/DynamicDataCaptures`, which **enforces sharing rules**. SOQL queries as a sysadmin bypass sharing, so desktop validation never surfaces the issue. The endpoint returns `INSUFFICIENT_ACCESS` to the tech, the iOS app catches the error, and renders an empty state with a "Try Again" button.
624
+
625
+ ### 1. DynamicDataCapture + WorkPlan OWD must be Public Read/Write
626
+
627
+ Default platform OWD is **Private** for both objects. Override in object metadata:
628
+
629
+ ```xml
630
+ <!-- objects/DynamicDataCapture/DynamicDataCapture.object-meta.xml -->
631
+ <CustomObject xmlns="http://soap.sforce.com/2006/04/metadata">
632
+ <sharingModel>ReadWrite</sharingModel>
633
+ <externalSharingModel>ReadWrite</externalSharingModel>
634
+ </CustomObject>
635
+ ```
636
+
637
+ ```xml
638
+ <!-- objects/WorkPlan/WorkPlan.object-meta.xml -->
639
+ <CustomObject xmlns="http://soap.sforce.com/2006/04/metadata">
640
+ <sharingModel>ReadWrite</sharingModel>
641
+ <externalSharingModel>ReadWrite</externalSharingModel>
642
+ </CustomObject>
643
+ ```
644
+
645
+ `WorkStep` inherits via `ControlledByParent` and doesn't need a separate change.
646
+
647
+ ### 2. FieldServiceSettings must share SAs and parent WOs with assigned resources
648
+
649
+ Many SDO orgs ship with these `false`. Without them, the AssignedResource never gets shared access to the WO, even though they show on the SA's resource list.
650
+
651
+ ```xml
652
+ <!-- settings/FieldService.settings-meta.xml -->
653
+ <FieldServiceSettings xmlns="http://soap.sforce.com/2006/04/metadata">
654
+ <doesShareSaWithAr>true</doesShareSaWithAr>
655
+ <doesShareSaParentWoWithAr>true</doesShareSaParentWoWithAr>
656
+ </FieldServiceSettings>
657
+ ```
658
+
659
+ ### 3. Re-save existing AssignedResources after the settings flip
660
+
661
+ The settings change only applies to **new** AssignedResource rows. Existing rows need a touch-update to trigger sharing recalc:
662
+
663
+ ```bash
664
+ sf apex run --target-org <alias> <<'APEX'
665
+ List<AssignedResource> ars = [
666
+ SELECT Id FROM AssignedResource
667
+ WHERE ServiceResource.RelatedRecord.Username = :techUsername
668
+ ];
669
+ update ars;
670
+ APEX
671
+ ```
672
+
673
+ ### 4. Tech must sign out and sign back in
674
+
675
+ FSL Mobile caches the sharing snapshot at login. Pull-to-refresh does not pick up new sharing — only a fresh auth token will. Tell the user to **sign out completely** of the FSL Mobile app, then sign back in. After that, the Forms tab fetch succeeds and DDC records render.
676
+
677
+ ### What is NOT the cause (don't waste time on these)
678
+
679
+ - **Layout related-list naming** — `<relatedList>DynamicDataCapture</relatedList>` (singular) is the correct XML form. The UI API uses plural `DynamicDataCaptures` separately. Don't try to align them.
680
+ - **Field-level security on `PausedFlowInterviewId`** — granted by default to all profiles.
681
+ - **Object permissions on DynamicDataCapture** — granted by default to Standard User and SDO-Service profiles.
682
+ - **Permset stack** — `SDO_SFS_All_Permissions` (or any equivalent FSL permset) is sufficient. No extra permset needed for the Forms tab.
683
+ - **API version override in Advanced Settings** — production iOS hardcodes `v67.0`; only DEBUG builds dynamically discover.
684
+ - **Briefcase / offline priming** — irrelevant when device has internet connectivity. The Forms tab fetches live, not from priming cache.
685
+
686
+ ---
687
+
688
+ ## Prohibited patterns — deploy errors and fixes
689
+
690
+ | Wrong | Correct | Deploy error (exact) |
691
+ |-------|---------|----------------------|
692
+ | `dcRadioButtons` | `dcRbGroup` | `extension not found` |
693
+ | `dcSection` | `RegionContainer` | `extension not found` |
694
+ | `minimumDate` / `maximumDate` | `minDate` / `maxDate` | `input attribute not found` |
695
+ | `multiSelection` on Lookup | `isMultiSelection` | `input attribute not found` |
696
+ | `disabled` / `readOnly` on Lookup | `isDisabled` / `isReadonly` (lowercase o) | `input attribute not found` |
697
+ | `<apiVersion>` tag on flow | Omit entirely | `You can't specify the field API Version` |
698
+ | `extensionName` on Repeater itself | Only on nested fields | `extensionName isn't supported` |
699
+ | `InputField` fieldType | `ComponentInstance` + extensionName | Field type rejected |
700
+ | `<fieldText>` on `ComponentInstance` | Use `label` inputParameter | `A required input parameter is missing: 'label'` |
701
+ | `placeholder` inputParameter on `dc*` | Not supported — bake into label text | `We can't find this input attribute: "placeholder"` |
702
+ | `min`/`max` on `dcNumeric` | Valid only on `dcCounter` | `We can't find this input attribute: "min"` |
703
+ | `<fieldType>Range</fieldType>` (slider) | Not valid in DataCaptureFlow | `'Range' is not a valid value for the enum 'FlowScreenFieldType'` |
704
+ | `storeOutputAutomatically` on Repeater | Omit (collection is always `.AllItems`) | `the storeOutputAutomatically field isn't supported` |
705
+ | `collectionReference=Repeater_Name` in loop | `Repeater_Name.AllItems` | `Element "X" doesn't exist. Specify an existing collection element` |
706
+ | Loop body: `Repeater_Name.field.value` | `Loop_Name.field.value` (loop's name, not repeater's) | Invalid reference |
707
+ | Cross-row validation: `AllItems[$Items - 1]` | Use post-screen loops + decisions | Formula `Syntax error` |
708
+ | Decision between CUD nodes | Sequential CUDs, no branches | `Append multiple Create, Update, or Delete operations only at the end of the flow` |
709
+ | Get Records after CUD | Move gets to before CUD | Flow structure rejected |
710
+ | `Step X of Y - Topic` (hyphen) | `Step X of Y – Topic` (en dash U+2013) | Validator counts 0 progress indicators |
711
+ | `<start>` → recordLookups / decisions | `<start>` → `<screens>` (intro screen first) | Mobile offline fails to render |
712
+ | `<actionCalls>` | Remove; use DisplayText for notifications | Action elements not allowed |
713
+ | `helpText` inputParameter | Bake into label text | `input attribute not found` |
714
+ | `IsLlmTargetable` as `<booleanValue>` (optional property, but if present) | `<stringValue>{&quot;value&quot;:&quot;false&quot;}</stringValue>` or omit the property entirely | Activation error: `The value of the IsLlmTargetable custom property's value field must be a string in JSON format` |
715
+ | `recordIds` inputParameter on Lookup | `recordIdCollection` (singular Id + Collection) | `We can't find this input attribute: "recordIds"` |
716
+ | `recordIdCollection` with single-select Lookup | Set `isMultiSelection=true` (scoping ignored otherwise) | No error — silently unfiltered at runtime |
717
+ | `<outputAssignments>` inside `dynamicChoiceSets` | Post-selection `recordLookups` with `outputAssignments` | No deploy error — variables stay blank on downstream screens |
718
+ | `IF`/`CASE`/date math in `DisplayText` | Pre-calculate in Assignment, reference simple variable | `Error while resolving default value reference` at runtime |
719
+ | `$User.Name` as `value` default on dcTextInput | `$User.Username` | `field integrity exception… type for input parameter "Value" doesn't match` |
720
+ | Missing `nextOrFinishButtonLabel` on screen | Add `<nextOrFinishButtonLabel>Next</nextOrFinishButtonLabel>` | Next/Finish button not visible |
721
+ | Calling AutoLaunched subflow from DataCaptureFlow | Inline the logic, or call only another DataCaptureFlow | `This flow can't reference [FlowName] because the referenced flow type is Autolaunched Flow` |
722
+ | `isRequired=true` on field behind `visibilityRule` | Set `isRequired=false`; use `validationRule` IF(trigger, rule, TRUE) | User blocked from proceeding on hidden field |
723
+
724
+ ---
725
+
726
+ ## Deployment
727
+
728
+ ```bash
729
+ # Single file
730
+ sf project deploy start -d force-app/main/default/flows/MyFlow.flow-meta.xml \
731
+ --target-org <alias> --wait 60 --json
732
+
733
+ # Multi-dir (use repeated -d, NOT comma-separated)
734
+ sf project deploy start \
735
+ -d force-app/main/default/objects \
736
+ -d force-app/main/default/permissionsets \
737
+ -d force-app/main/default/tabs \
738
+ --target-org <alias> --wait 60 --json
739
+ ```
740
+
741
+ Extract errors:
742
+ ```bash
743
+ ... --json 2>&1 | python3 -c "
744
+ import sys, json
745
+ d = json.load(sys.stdin)
746
+ r = d.get('result', {})
747
+ print('Status:', r.get('status'))
748
+ for f in r.get('details', {}).get('componentFailures', []):
749
+ print('ERROR:', f.get('fullName'), '-', f.get('problem'))
750
+ "
751
+ ```
752
+
753
+ ---
754
+
755
+ ## Reference examples
756
+
757
+ Bundled alongside this skill at `examples/` — these are **human / IDE reference files for hand-authoring locally; they are not fetched at agent runtime.** The rules inlined in this skill body above are authoritative at runtime; the example files illustrate those same rules in a complete, deploy-ready flow for a person reading the bundle:
758
+
759
+ - `Data_Capture_All_Components.flow-meta.xml` — every component in deployment-ready XML
760
+ - `DataCapture_Showcase.flow-meta.xml` — full end-to-end flow: multi-screen form, continue-editing recordLookup, Repeater → Loop → child records via `.AllItems`, Create-or-Update CUD chain driven by a Decision, visual polish (banner, progress, callouts, review cards). The most complete worked example of the XML format; if you have the bundle open, use it to cross-check structure against the rules above.
761
+ - `Repeater_with_prepopulation.flow-meta.xml` — validated worked example of the prepopulated-Repeater pattern: `recordLookups` (ServiceResource) → Repeater bound via `collection` inputParameter with nested field `value` defaults using `SourceCollection[$EachItem].FieldApiName` → post-Repeater Loop over `.AllItems` feeding a display screen that reads `{!LoopName.nestedField.value}` and `{!LoopName.UniqueField__Id}`. Mirrors the prepopulation + post-Repeater display rules documented above.
762
+ - `DataCapture_Repeater_with_data_showcase.flow` (in the org, not committed) — `.AllItems` loop spike; also documents non-working cross-row validation formula syntaxes