field-service-data-capture-reference-configure について
Field Service のモバイル・オフラインフォーム向けに、Salesforce Data Capture Flow の作成とデプロイを支援するスキルです。コンポーネントのメタデータ、Repeater の利用法、データ操作の制約、デプロイ時の問題を扱います。
主な機能
- 01DataCaptureFlow メタデータ構造のガイド
- 02モバイル入力・選択コンポーネントのリファレンス
- 03Repeater の事前入力・反復・表示パターン
- 04レコード作成・更新・削除の制約
- 05デプロイとフォーム表示問題の調査
活用シーン
- 01Field Service のモバイルオフラインフォーム作成
- 02Repeater の項目を子レコードとして保存
- 03既存レコードのコレクションから行を事前入力
- 04Flow デプロイやモバイルフォーム表示の問題を調査
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ forcedotcom/ sf-skills --skill field-service-data-capture-reference-configureインストール後、Claude Code で/field-service-data-capture-reference-configureを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
examples/Data_Capture_All_Components.flow-meta.xmlDataCapture_Showcase.flow-meta.xmlRepeater_with_prepopulation.flow-meta.xml詳細
クエリ用 Fs データキャプチャリファレンス
このスキルを使用するタイミング
Salesforce Data Capture Flow(processType DataCaptureFlow)を作成、編集、デプロイする場合に使用します。Field Service モバイル/オフラインフォーム向けです。runtime_service_fieldservice:dc* コンポーネントを使用する flow-meta.xml の作成、Repeater ループ(.AllItems)、主従関係の子レコードの永続化、見た目の調整(グラデーションバナー、進行状況バー、コールアウト)、FLS/権限セットを含むサポートオブジェクト、DataCaptureFlow のデプロイエラーのデバッグ、またはデプロイ済みフォームが FSL Mobile Forms タブに表示されない理由のトラブルシューティング(DDC/WorkPlan OWD と AssignedResource の共有が前提条件)に使用します。
ワークフロー
Salesforce Data Capture Flow スキル
processType: DataCaptureFlow を使用して Salesforce フロー(Field Service モバイル/オフラインフォーム)を作成、編集、デプロイします。
必須メタデータ(すべてのフロー)
<processType>DataCaptureFlow</processType>
<areMetricsLoggedToDataCloud>false</areMetricsLoggedToDataCloud>
<environments>Offline</environments>
省略可能な IsLlmTargetable カスタムプロパティを含める場合は、ブール値ではなく JSON 文字列にする必要があります。
<customProperties>
<name>IsLlmTargetable</name>
<value><stringValue>{"value":"false"}</stringValue></value>
</customProperties>
<booleanValue>false</booleanValue> の形式ではデプロイできますが、有効化がブロックされ、次のエラーが発生します。The value of the IsLlmTargetable custom property's value field must be a string in JSON format。プロパティ自体を省略しても問題ありません。
XML 構造のルール
Salesforce の Flow スキーマではグループ化が必須です。同じ種類のすべての要素は、連続したひとつのブロック内に配置する必要があります。これに違反すると、Element X is duplicated at this location というエラーでデプロイが失敗します。
グループの順序は問いませんが、各グループ内の要素は隣接している必要があります。
- すべての
<choices>をまとめる - すべての
<dynamicChoiceSets>をまとめる - すべての
<screens>をまとめる - すべての
<decisions>をまとめる - すべての
<recordLookups>をまとめる - すべての
<recordCreates>をまとめる - すべての
<recordUpdates>をまとめる - すべての
<loops>をまとめる - すべての
<assignments>をまとめる - すべての
<variables>をまとめる
実行順序は XML の順序ではなく、コネクタの参照によって決まります。
コンポーネントリファレンス
すべての拡張機能のプレフィックス:runtime_service_fieldservice:
| コンポーネント | 拡張機能 | fieldType |
|---|---|---|
| 短いテキスト | dcTextInput | ComponentInstance |
| 長いテキスト | dcLongText | ComponentInstance |
| メール | dcEmail | ComponentInstance |
| 電話 | dcPhone | ComponentInstance |
| 名前 | dcName | ComponentInstance |
| 数値 | dcNumeric | ComponentInstance |
| カウンター | dcCounter | ComponentInstance |
| 日付 | dcDate | ComponentInstance |
| 日付と時刻 | dcDateTime | ComponentInstance |
| チェックボックス | dcCheckbox | ComponentInstance |
| 切り替え | dcToggle | ComponentInstance |
| 住所/GPS | dcAddress | ComponentInstance |
| ルックアップ | dcLookup | ComponentInstance |
| 静的画像 | dcFileView | ComponentInstance |
| 画像のアップロード(モバイル) | dcUpImage | ComponentInstance |
| ファイルのアップロード(モバイル) | dcUpFile | ComponentInstance |
| 署名(モバイル) | dcSignature | ComponentInstance |
| 単一選択リスト | dcPicklist | ComponentChoice |
| 複数選択リスト | dcPicklist | ComponentMultiChoice |
| ラジオボタン | dcRbGroup | ComponentChoice |
| チェックボックスグループ | dcCbGroup | ComponentMultiChoice |
| マトリックス | dcMatrix | ComponentMultiChoice |
| 表示テキスト | (なし) | DisplayText |
| セクション | (なし) | RegionContainer + Region |
| Repeater | (なし) | Repeater |
注:<fieldType>Range</fieldType> は DataCaptureFlow で有効なスライダーの fieldType ではありません(Builder UI のリストに「Range/Slider」と表示されていても同様です)。このプロセスタイプでは、純粋なメタデータでスライダーを利用できません。dcNumeric または dcCounter を使用してください。forceContent:repeater(Lightning 汎用)と <fieldType>Repeater</fieldType>(FSL オフライン)は別物です。概念は共通していますが、XML は異なります。
ラベルの設定
| fieldType | 方法 |
|---|---|
ComponentInstance | <inputParameters><name>label</name><value><stringValue>…</stringValue></value></inputParameters> |
ComponentChoice / ComponentMultiChoice | <fieldText>Label</fieldText> |
DisplayText | <fieldText>HTML</fieldText> |
すべての ComponentInstance 拡張(dcAddress や dcToggle を含む)は label inputParameter を受け付けます — DisplayText でラップする必要はありません。
必須フラグ
すべての入力フィールドには、フィールドレベルで <isRequired>true/false</isRequired> が必要です。この単一のフラグはすべての dc* コンポーネントに対して十分です — 追加の required / isRequired inputParameter は不要です。
dcLookup はさらに isRequired inputParameter(boolean)も受け付けますが、適用を制御するのはフィールドレベルの <isRequired> です。
dcCheckbox と dcToggle は <isRequired>true</isRequired> を構文的には受け付けますが、実行時には適用しません。
すべての入力フィールドには以下も必要です
<inputsOnNextNavToAssocScrn>UseStoredValues</inputsOnNextNavToAssocScrn>
<storeOutputAutomatically>true</storeOutputAutomatically>
<styleProperties>
<verticalAlignment><stringValue>top</stringValue></verticalAlignment>
<width><stringValue>12</stringValue></width>
</styleProperties>
例外: <fieldType>Repeater</fieldType> は storeOutputAutomatically を明示的に拒否します("the storeOutputAutomatically field isn't supported")。Repeater の出力は常に .AllItems として利用可能です — オプトインは不要です。
画面のルール
すべての画面には、以下の 3 つすべてが必要です。そうでなければ Next/Finish ボタンがレンダリングされません:
<allowFinish>true</allowFinish>(最終画面でなくても)<showFooter>true</showFooter><nextOrFinishButtonLabel>Next</nextOrFinishButtonLabel>
さらに:
<start>の後の最初の要素は常に<screens>要素でなければなりません- すべての
<screens>要素は XML 内でまとめてグループ化する必要があります
Repeater — 行の反復と子レコードの作成
Repeater の出力コレクションは .AllItems として公開されます。API v66 で動作を確認済みです。
<fields>
<name>MyRepeater</name>
<fieldType>Repeater</fieldType>
<fields>
<name>Row_PartName</name>
<extensionName>runtime_service_fieldservice:dcTextInput</extensionName>
<fieldType>ComponentInstance</fieldType>
<storeOutputAutomatically>true</storeOutputAutomatically>
</fields>
<fields>
<name>Row_PartQty</name>
<extensionName>runtime_service_fieldservice:dcCounter</extensionName>
<fieldType>ComponentInstance</fieldType>
<storeOutputAutomatically>true</storeOutputAutomatically>
</fields>
<isRequired>false</isRequired>
</fields>
<loops>
<name>Loop_Parts</name>
<collectionReference>MyRepeater.AllItems</collectionReference>
<iterationOrder>Asc</iterationOrder>
<nextValueConnector>
<targetReference>Create_Part</targetReference>
</nextValueConnector>
</loops>
<recordCreates>
<name>Create_Part</name>
<object>CustomFormPart__c</object>
<connector>
<targetReference>Loop_Parts</targetReference>
</connector>
<inputAssignments>
<field>PartName__c</field>
<value>
<elementReference>Loop_Parts.Row_PartName.value</elementReference>
</value>
</inputAssignments>
<inputAssignments>
<field>Quantity__c</field>
<value>
<elementReference>Loop_Parts.Row_PartQty.value</elementReference>
</value>
</inputAssignments>
<storeOutputAutomatically>true</storeOutputAutomatically>
</recordCreates>
やってはいけないこと:
<collectionReference>MyRepeater</collectionReference>→Element "MyRepeater" doesn't exist<collectionReference>MyRepeater.items</collectionReference>→ 汎用サーバーエラー<collectionReference>MyRepeater.data</collectionReference>→ 汎用サーバーエラー- ループ本体の内部では、
MyRepeater.Row_PartName.valueは動作しません — Repeater の名前ではなく、ループの名前を使用する必要があります。
行をまたぐ検証はコンパイルされません。 r_GR4.AllItems[$Items].field.value や r_GR4.AllItems[$Items - 1].field.value のような数式参照は Syntax error で失敗します。行ごとの検証は、ネストされたフィールド自身の validationRule 内で通常の fieldName.value を使って動作します。行をまたぐルールには、画面後の loops + decisions を使用してください。
その他の Repeater アクセサーは現在解決されません。 動作するのは .AllItems のみです。AddedItems、PrepopulatedItems、RemovedItems はすべて doesn't exist でデプロイに失敗します。
既存のコレクションからリピーターに値を事前入力する
既存の SObject コレクションをリピーターにバインドすると、ソースレコードごとに値が事前入力された行が 1 つずつ表示されます。その後、ユーザーは送信前に行を編集、追加、削除できます。
パターン:recordLookups(ソースコレクションを取得し、getFirstRecordOnly=false、storeOutputAutomatically=true)→ collection inputParameter を介してバインドした Repeater のある画面 → ネストされたフィールドでは、SourceCollection[$EachItem].FieldApiName を value のデフォルト値として使用します。
<recordLookups>
<name>Get_Source</name>
<object>ServiceResource</object>
<getFirstRecordOnly>false</getFirstRecordOnly>
<storeOutputAutomatically>true</storeOutputAutomatically>
<connector><targetReference>Screen_Repeater</targetReference></connector>
</recordLookups>
<fields>
<name>accountRepeater</name>
<fieldType>Repeater</fieldType>
<inputParameters>
<name>collection</name>
<value><elementReference>Get_Source</elementReference></value>
</inputParameters>
<fields>
<name>account_info</name>
<fieldType>DisplayText</fieldType>
<fieldText><p>Id: {!Get_Source[$EachItem].Id}</p></fieldText>
</fields>
<fields>
<name>name</name>
<extensionName>runtime_service_fieldservice:dcTextInput</extensionName>
<fieldType>ComponentInstance</fieldType>
<inputParameters>
<name>label</name>
<value><stringValue>Name</stringValue></value>
</inputParameters>
<inputParameters>
<name>value</name>
<value><elementReference>Get_Source[$EachItem].Name</elementReference></value>
</inputParameters>
<isRequired>true</isRequired>
<storeOutputAutomatically>true</storeOutputAutomatically>
<inputsOnNextNavToAssocScrn>UseStoredValues</inputsOnNextNavToAssocScrn>
<styleProperties>…</styleProperties>
</fields>
<isRequired>false</isRequired>
<styleProperties>…</styleProperties>
</fields>
要点:
- バインド用の inputParameter の名前は
collectionです。valueやsourceではありません。 - リピーター内では、
SourceCollectionName[$EachItem].FieldApiNameを使ってソース行を参照します。リピーターの名前ではなく、レコードルックアップの名前を使用してください。DisplayText.fieldText({!Get_Source[$EachItem].Id}として)と、コンポーネントのvalueのデフォルト値(<elementReference>Get_Source[$EachItem].Name</elementReference>として)の両方で機能します。 $EachItemは、リピーターのレンダリング時に Salesforce が挿入する行ごとのイテレーターです。リピーター内にネストされたフィールド内でのみ解決されます。- 後続のループでは、通常どおり
Repeater_Name.AllItemsを反復処理します。事前入力によって変わるのは入力であり、出力アクセサーではありません。 - 事前入力された行は、送信後に通常の
.AllItemsエントリとして表示されます。PrepopulatedItemsとAddedItemsのような分割はありません(これらのアクセサーを使うとデプロイに失敗します)。
リピーターのエントリをユーザーに表示する(リピーター後のループ画面)
ユーザーが入力した内容(レビュー、確認、行ごとの詳細など)を表示するには、リピーター画面の後に、本体を表示画面に接続したループを配置します。表示画面からはループに戻るよう接続します。ループの終了コネクターは次のステップに進みます。
<loops>
<name>Loop_Through_Repeater</name>
<collectionReference>accountRepeater.AllItems</collectionReference>
<iterationOrder>Asc</iterationOrder>
<nextValueConnector>
<targetReference>Repeater_Output_Screen</targetReference>
</nextValueConnector>
</loops>
<screens>
<name>Repeater_Output_Screen</name>
<connector><targetReference>Loop_Through_Repeater</targetReference></connector>
<fields>
<name>display_info</name>
<fieldType>DisplayText</fieldType>
<fieldText><p>Source Id: {!Loop_Through_Repeater.UniqueField__Id}</p>
<p>Name: {!Loop_Through_Repeater.name.value}</p>
<p>Type: {!Loop_Through_Repeater.description.value}</p></fieldText>
<styleProperties>…</styleProperties>
</fields>
<allowFinish>true</allowFinish>
<showFooter>true</showFooter>
<nextOrFinishButtonLabel>Next</nextOrFinishButtonLabel>
</screens>
ループ本体内のアクセサールール:
- ユーザーが入力した値 —
{!LoopName.nestedFieldName.value}(他の場合と同じ.value/.selectedChoiceValues/.isActiveなどのアクセサーです)。 - 事前入力された行のソースレコード Id —
{!LoopName.UniqueField__Id}。これはリピーターが各反復で公開する合成フィールドです。バインドされたcollectionに由来する行にのみ値が入り(ユーザーが追加した新しい行は空欄になります)。 - ループ本体内では、リピーターの名前ではなくループの名前を使用してください。前述の標準的な
.AllItems+ Create パターンと同じルールです。
この .AllItems をループして表示するパターンは、Create/Update パターンと組み合わせられます。レビュー画面の表示に 1 つのループを使い、CUD に後続のループ(または順序上問題がなければ同じループ)を使います。CUD のルールを忘れないでください。連続する CUD ノードの間には、何も(画面、取得、判定など)置けません。そのため、レビュー用ループは CUD チェーンの開始前に完全に完了する必要があります。
CUD のルール(プラットフォーム上の厳格な制約)
- Decision で開始する CUD チェーンを選択できます(たとえば、保存モードを判定する Decision の Create 分岐と Update 分岐)。ただし、CUD チェーンの開始後、連続する CUD ノードの間に Decision を配置することはできません。配置すると、
Append multiple Create, Update, or Delete operations only at the end of the flow, in any orderというエラーでデプロイに失敗します。- 回避策:「入力がある場合のみ作成する」には、常に作成する(空の行を許容する)か、CUD チェーンの開始前に条件ロジックを移動してください。
- すべての CUD はフローの末尾に配置します。 いずれかの CUD の後に Get Records や画面を配置してはいけません。CUD を含むサブフローも配置できません。
- ループ内の CUD 後の Assignment は v260 で不具合がありました。 v262/API 66 で修正されています。現在は安全に使用できます。
Counter パラメーター
<inputParameters><name>min</name><value><numberValue>1.0</numberValue></value></inputParameters>
<inputParameters><name>max</name><value><numberValue>10.0</numberValue></value></inputParameters>
<inputParameters><name>step</name><value><numberValue>1.0</numberValue></value></inputParameters>
<inputParameters><name>minCustomErrorMessage</name><value><stringValue>…</stringValue></value></inputParameters>
<inputParameters><name>maxCustomErrorMessage</name><value><stringValue>…</stringValue></value></inputParameters>
Date パラメーター
<inputParameters><name>minDate</name><value><elementReference>$Flow.CurrentDate</elementReference></value></inputParameters>
<inputParameters><name>maxDate</name><value><dateValue>2027-12-31</dateValue></value></inputParameters>
Picklist のコンパクトモード
すべてのラベルが 8 文字以下で、かつ選択肢が 5 個以下の場合に限り、isCompact=true を使用してください。
Lookup パラメーター
<inputParameters><name>objectApiName</name><value><stringValue>Asset</stringValue></value></inputParameters>
<inputParameters><name>searchedFields</name><value><stringValue>Name, SerialNumber</stringValue></value></inputParameters>
<inputParameters><name>isMultiSelection</name><value><booleanValue>true</booleanValue></value></inputParameters>
<inputParameters><name>recordIdCollection</name><value><elementReference>v_Ids</elementReference></value></inputParameters>
recordIdCollection — 検索対象の絞り込み
- ビルダーのラベル: Record IDs Collection。XML 属性:
recordIdCollection(単数形のrecordIdにCollectionを付加)。recordIdsを指定すると、デプロイ時にWe can't find this input attribute: "recordIds"というエラーが発生します。 - これは絞り込みフィルターであり、デフォルトの事前選択ではありません。 指定した Id の String コレクション内だけを検索するように絞り込みます。
isMultiSelection=trueの場合にのみ有効です。 単一選択モードでは無視され、ユーザーにはフィルターされていないオブジェクト全体が表示されます。- 標準的なパターン:
recordLookups(絞り込んだサブセット)→loops+assignments(Id の String コレクションを構築)→dcLookup recordIdCollection=v_Idsを指定した画面。この方法は Briefcase で事前に読み込まれたデータに対してオフラインで動作し、約 60,000 件のレコードを 1 秒未満で処理できます。 - 複数選択モードでの出力は
{!Lookup.recordIds}(String コレクション)です。以前{!Lookup.recordId}(単数形)を使用していた表示ルールや DML では、コレクションを反復処理するか、最初の要素を取得する必要があります。
dcLookup の表示ラベル
dcLookup には表示フィールドの入力パラメーターがありません(displayField/primaryField はありません)。検索結果と選択済みチップに表示されるラベルは、オブジェクトの Primary Compact Layout によって決まります。そのレイアウトの先頭フィールドが使用されます。変更するには、Setup → Object Manager → Object → Compact Layouts の順に開き、順序を変更して Primary として割り当てます(組織全体に適用される変更です)。searchedFields は検索対象を制御するものであり、表示内容は制御しません。
フロー内で代替する場合は、dcLookup を、<displayField>/<valueField> を指定した dynamicChoiceSets を使用する dcPicklist に置き換えます。
GPS 付き住所
<inputParameters><name>useCoordinates</name><value><booleanValue>true</booleanValue></value></inputParameters>
マトリックス
<inputParameters><name>questions</name><value><stringValue>["Q1","Q2","Q3"]</stringValue></value></inputParameters>
JSON 文字列内の & は & としてエスケープしてください。
2 列セクション
<fields>
<name>MySection</name>
<fieldText>Section Header</fieldText>
<fieldType>RegionContainer</fieldType>
<fields>
<name>MySection_Col1</name>
<fieldType>Region</fieldType>
<fields></fields>
<inputParameters><name>width</name><value><stringValue>6</stringValue></value></inputParameters>
<isRequired>false</isRequired>
</fields>
<fields>
<name>MySection_Col2</name>
<fieldType>Region</fieldType>
<fields></fields>
<inputParameters><name>width</name><value><stringValue>6</stringValue></value></inputParameters>
<isRequired>false</isRequired>
</fields>
<isRequired>false</isRequired>
<regionContainerType>SectionWithHeader</regionContainerType>
…styleProperties…
</fields>
表示ルール
<visibilityRule>
<conditionLogic>and</conditionLogic>
<conditions>
<leftValueReference>componentName.value</leftValueReference>
<operator>GreaterThan</operator>
<rightValue><numberValue>0.0</numberValue></rightValue>
</conditions>
</visibilityRule>
プロパティアクセサー:.value(dcCheckbox を含む入力コンポーネント)、.selectedChoiceValues(選択肢コンポーネント)、.isActive(トグル)、.firstName/.lastName(Name コンポーネント)、.recordId/.recordIds(Lookup の単一選択/複数選択)。
同じアクセサーは、recordCreates/recordUpdates の inputAssignments 内でも使用します。例:<elementReference>new_Reading.value</elementReference>。
条件付きで非表示になる必須項目 — isRequired ではなく validationRule を使用
IF(TriggerField.selectedChoiceValues = "Yes",
AND(NOT(ISBLANK(value)), value >= 0, value <= 100000),
TRUE)
標準的な Decision の IsNull パターン
IsNull の右辺には null リテラルではなく、booleanValue を指定します。
<conditions>
<leftValueReference>v_ParentId</leftValueReference>
<operator>IsNull</operator>
<rightValue>
<booleanValue>false</booleanValue>
</rightValue>
</conditions>
計算のタイミング(重要)
計算値は、入力を収集する画面には表示できません。計算はユーザーが「次へ」をタップした後にのみ実行されます。パターン:
Screen N (collect inputs) → recordLookups / assignments / decisions → Screen N+1 (display results)
画面 N のコネクターは、画面 N+1 ではなく計算要素を指す必要があります。すべての Decision 分岐は、最終的に画面 N+1 に合流する必要があります。
DisplayText の数式の制限(モバイルランタイム)
DataCaptureFlow の DisplayText は、標準フローと比べて数式のサポートが 大幅に制限されています。複雑な数式は正常にデプロイされ、ビルダーのプレビューにも表示されますが、実行時に Error while resolving default value reference というエラーが発生します。
実行時に失敗するもの:
IF(Toggle.isActive, "YES", "NO")— コンポーネントのプロパティに対する IF/CASE はすべて失敗しますTEXT(CASE(...))、ADDMONTHS(...)、ネストされた日付計算- 1 つの
fieldText内で複数のコンポーネント参照と数式を組み合わせること
動作するもの:
- 単純な単一変数:
{!var_RiskScore} - 単純なコンポーネント参照:
{!MyPicklist.selectedChoiceValues}、{!MyNumeric.value} - グローバル変数:
{!$Flow.CurrentDate}、{!$User.FirstName}
パターン:<assignments> 要素で事前に計算し、変数に格納してから、その変数を DisplayText で参照します。
入力 value のデフォルト値としてのグローバル変数
| デフォルトのバインド | 変数 | 動作するか |
|---|---|---|
dcTextInput | $User.Username | ✅ |
dcTextInput | $User.Name | ❌ 型の不一致エラー |
dcDateTime | $Flow.InterviewStartTime | ✅ |
dcDate | $Flow.CurrentDate | ✅ |
選択肢セットの記録(dynamicChoiceSets)— モバイルのオフライン環境での注意点
dynamicChoiceSets 内の <outputAssignments> は問題なくデプロイできますが、モバイルのオフライン DataCaptureFlow では、実行時に対象の変数へ確実に値が設定されるわけではありません。後続の画面が空白で表示されます。
正しいパターン:選択肢セットは最小限(displayField、valueField、filters、object、dataType)に保ちます。選択画面の後に、Id = {!picklistName.selectedChoiceValues} で絞り込んだ recordLookups を経由し、ルックアップの outputAssignments を使って追加の項目を変数に格納します。ルックアップが選択画面と表示画面の間に配置されるため、計算タイミングのルールにも自然に沿います。
<recordLookups>
<name>gr_SelectedChild</name>
<filters>
<field>Id</field>
<operator>EqualTo</operator>
<value><elementReference>pl_Child.selectedChoiceValues</elementReference></value>
</filters>
<getFirstRecordOnly>true</getFirstRecordOnly>
<object>Child__c</object>
<outputAssignments>
<assignToReference>v_SelectedValue</assignToReference>
<field>Reading_Value__c</field>
</outputAssignments>
</recordLookups>
見た目を整えるパターン(モバイル実行環境での表示を確認済み)
Lightning Design System のカラー:#2E844A(緑)、#0176D3(青)、#FE9339(オレンジ)、#C9C7C5(ニュートラル)。
ヒーローバナー
<div style="background: linear-gradient(135deg, #2E844A 0%, #0176D3 100%); color: white; padding: 20px; border-radius: 10px; text-align: center;">
<p style="margin: 0; font-size: 22px;"><strong>🔧 Site Visit Report</strong></p>
<p style="margin: 4px 0 0 0; font-size: 13px;">Subtitle</p>
</div>
プログレスバー(画面ごと)
<p><b>Step X of N – 📍 Section Title</b></p>
<div style="width: 100%; height: 8px; background-color: #C9C7C5; border-radius: 4px; margin: 5px 0;">
<div style="width: PERCENT%; height: 100%; background: linear-gradient(90deg, #2E844A 0%, #0176D3 100%); border-radius: 4px;"></div>
</div>
カウンターとタイトルの区切りには、ハイフンではなくエンダッシュ –(U+2013)を必ず使用してください。
コールアウトボックス
<div style="background-color: #EAF5FE; border-left: 4px solid #0176D3; padding: 10px 14px; border-radius: 4px;">
<p style="margin: 0; color: #014486; font-size: 13px;"><b>ℹ️ Info:</b> …</p>
</div>
<div style="background-color: #FFF4E6; border-left: 4px solid #FE9339; padding: 10px 14px; border-radius: 4px;">
<p style="margin: 0; color: #704D00; font-size: 13px;"><b>⚠️ Heads up:</b> …</p>
</div>
<div style="background-color: #E8F5E9; border-left: 4px solid #2E844A; padding: 10px 14px; border-radius: 4px;">
<p style="margin: 0; color: #1B5E20; font-size: 13px;"><b>✅ Ready:</b> …</p>
</div>
レビューカード(前の画面の差し込み項目を使用)
<div style="border: 1px solid #DDDBDA; border-radius: 8px; padding: 14px 16px; background-color: #FAFAF9;">
<p style="margin: 0 0 8px 0; color: #0176D3; font-size: 14px;"><b>📍 Section</b></p>
<p style="margin: 2px 0;"><b>Name:</b> {!Input_SiteName.value}</p>
<p style="margin: 2px 0;"><b>Contact:</b> {!Input_Contact.firstName} {!Input_Contact.lastName}</p>
<p style="margin: 2px 0;"><b>Priority:</b> {!Input_Priority.selectedChoiceValues}</p>
<p style="margin: 2px 0;"><b>After-hours:</b> {!Input_Toggle.isActive}</p>
</div>
<fieldText> 内の HTML はすべて XML エスケープする必要があります:& → &、" → "、< → <、> → >。
フローと一緒に関連オブジェクトをデプロイする
カスタムオブジェクトと項目をデプロイしても、システム管理者プロファイルに FLS/CRUD が自動的に付与されることはありません。管理者として実行されるフローでも、新しい項目を読み書きできません。PermissionSet を用意して割り当ててください:
<PermissionSet xmlns="http://soap.sforce.com/2006/04/metadata">
<label>My Object Access</label>
<license>Salesforce</license>
<hasActivationRequired>false</hasActivationRequired>
<objectPermissions>
<allowCreate>true</allowCreate><allowDelete>true</allowDelete>
<allowEdit>true</allowEdit><allowRead>true</allowRead>
<modifyAllRecords>true</modifyAllRecords><viewAllRecords>true</viewAllRecords>
<object>MyObject__c</object>
</objectPermissions>
<fieldPermissions><field>MyObject__c.MyField__c</field><editable>true</editable><readable>true</readable></fieldPermissions>
<tabSettings><tab>MyObject__c</tab><visibility>Visible</visibility></tabSettings>
</PermissionSet>
デプロイ後に割り当てます:sf org assign permset --name MyObject_Access --target-org <alias>
CustomObject に関する注意点
- 主従関係の子オブジェクトには
<sharingModel>ControlledByParent</sharingModel>が必要です。設定しないとMust specify a sharing model valueが発生します。 - Sfdx の取得では、標準ではないアクション(
Automation、Details)のactionOverridesが含まれることがあります。再デプロイ前に削除してください。削除しないとX is not a standard action and cannot be overriddenが発生します。 - 255 文字を超えるテキスト項目には
<type>LongTextArea</type>が必要です。Textの最大長は 255 です。 required=trueの項目を参照する PermissionSet は問題なくデプロイできますが、FLS を別ファイルで設定するとYou cannot deploy to a required fieldが発生します。項目をrequired=falseにするか、必須設定をフロー側で処理してください。
カスタムタブ
ユーザーが App Launcher からレコードを一覧表示できるようにします:
<CustomTab xmlns="http://soap.sforce.com/2006/04/metadata">
<customObject>true</customObject>
<motif>Custom53: Form</motif>
</CustomTab>
次に、上記のように <tabSettings> を permset に追加します。
モバイルの前提条件 — FSL Mobile で Forms タブを表示するために必要
問題なくデプロイされ、デスクトップで表示されるフローでも、組織が割り当て済みの技術者と DDC および WorkPlan レコードを共有するように設定されていないと、FSL Mobile では "No forms available. Try Again" と表示され、何も通知されないまま失敗します。2026-05-28 に確認済み:完全に検証済みのフォーム(Sewerage Further Work Request)は、以下の 4 つの修正をすべて適用するまで、割り当てられた技術者の iOS Field Service に表示されませんでした。同じ問題により、SDO に標準搭載されていた Job Safety Assessment フォームも表示されませんでした。
通知されない理由:FSL Mobile は UI API エンドポイント /services/data/v67.0/ui-api/related-list-records/{woId}/DynamicDataCaptures を使用し、共有ルールを適用します。システム管理者としての SOQL クエリは共有を回避するため、デスクトップでの検証では問題が表面化しません。このエンドポイントは技術者に INSUFFICIENT_ACCESS を返しますが、iOS アプリはエラーを捕捉し、「Try Again」ボタンのある空の状態を表示します。
1. DynamicDataCapture と WorkPlan の OWD は「公開/参照・更新可」にする必要があります
両方のオブジェクトで、プラットフォームの既定の OWD は 非公開 です。オブジェクトのメタデータで上書きします:
<CustomObject xmlns="http://soap.sforce.com/2006/04/metadata">
<sharingModel>ReadWrite</sharingModel>
<externalSharingModel>ReadWrite</externalSharingModel>
</CustomObject>
<CustomObject xmlns="http://soap.sforce.com/2006/04/metadata">
<sharingModel>ReadWrite</sharingModel>
<externalSharingModel>ReadWrite</externalSharingModel>
</CustomObject>
WorkStep は ControlledByParent を介して継承するため、個別に変更する必要はありません。
2. FieldServiceSettings で、SA と親 WO を割り当て済みリソースと共有する必要があります
多くの SDO 組織では、これらは false に設定されています。これらを有効にしないと、AssignedResource は SA のリソース一覧に表示されていても、WO への共有アクセスを得られません。
<FieldServiceSettings xmlns="http://soap.sforce.com/2006/04/metadata">
<doesShareSaWithAr>true</doesShareSaWithAr>
<doesShareSaParentWoWithAr>true</doesShareSaParentWoWithAr>
</FieldServiceSettings>
3. 設定変更後、既存の AssignedResources を再保存する
設定変更が適用されるのは、新しい AssignedResource 行のみです。共有の再計算を実行するには、既存の行を更新して変更を反映させる必要があります。
sf apex run --target-org <alias> <<'APEX'
List<AssignedResource> ars = [
SELECT Id FROM AssignedResource
WHERE ServiceResource.RelatedRecord.Username = :techUsername
];
update ars;
APEX
4. 担当者はサインアウトしてから、再度サインインする必要があります
原因ではないもの(これらに時間を費やさないでください)
- レイアウトの関連リスト名 —
<relatedList>DynamicDataCapture</relatedList>(単数形)が正しい XML 形式です。UI API では別途、複数形のDynamicDataCapturesが使われます。両者を揃えようとしないでください。 PausedFlowInterviewIdの項目レベルセキュリティ — デフォルトですべてのプロファイルに付与されています。- DynamicDataCapture のオブジェクト権限 — デフォルトで Standard User および SDO-Service プロファイルに付与されています。
- 権限セットの構成 —
SDO_SFS_All_Permissions(または同等の FSL 権限セット)で十分です。Forms タブに追加の権限セットは必要ありません。 - 詳細設定での API バージョンの上書き — 本番用 iOS では
v67.0がハードコードされています。動的に検出されるのは DEBUG ビルドのみです。 - Briefcase/オフライン用データの事前読み込み — デバイスがインターネットに接続されている場合は関係ありません。Forms タブは事前読み込みキャッシュからではなく、ライブでデータを取得します。
禁止パターン — デプロイエラーと修正方法
| 誤り | 正しい設定 | デプロイエラー(正確なメッセージ) |
|---|---|---|
dcRadioButtons | dcRbGroup | extension not found |
dcSection | RegionContainer | extension not found |
minimumDate / maximumDate | minDate / maxDate | input attribute not found |
Lookup の multiSelection | isMultiSelection | input attribute not found |
Lookup の disabled / readOnly | isDisabled / isReadonly(o は小文字) | input attribute not found |
flow の <apiVersion> タグ | 完全に省略 | You can't specify the field API Version |
Repeater 自体の extensionName | ネストされたフィールドにのみ指定 | extensionName isn't supported |
InputField の fieldType | ComponentInstance + extensionName | フィールドタイプが拒否される |
ComponentInstance の <fieldText> | label inputParameter を使用 | A required input parameter is missing: 'label' |
dc* の placeholder inputParameter | サポート対象外 — ラベルテキストに含める | We can't find this input attribute: "placeholder" |
dcNumeric の min / max | dcCounter でのみ有効 | We can't find this input attribute: "min" |
<fieldType>Range</fieldType>(スライダー) | DataCaptureFlow では無効 | 'Range' is not a valid value for the enum 'FlowScreenFieldType' |
Repeater の storeOutputAutomatically | 省略(コレクションは常に .AllItems) | the storeOutputAutomatically field isn't supported |
ループ内の collectionReference=Repeater_Name | Repeater_Name.AllItems | Element "X" doesn't exist. Specify an existing collection element |
ループ本体の Repeater_Name.field.value | Loop_Name.field.value(Repeater ではなくループの名前) | 無効な参照 |
行をまたぐ検証:AllItems[$Items - 1] | 画面後のループ + 判定を使用 | 数式の Syntax error |
| CUD ノード間の判定 | 分岐を使わず、CUD を順番に実行 | Append multiple Create, Update, or Delete operations only at the end of the flow |
| CUD の後の Get Records | Get を CUD の前に移動 | フロー構造が拒否される |
Step X of Y - Topic(ハイフン) | Step X of Y – Topic(en ダッシュ U+2013) | バリデーターが進行状況インジケーターを 0 件としてカウントする |
<start> → recordLookups / 判定 | <start> → <screens>(最初に導入画面を配置) | モバイルオフラインでレンダリングされない |
<actionCalls> | 削除し、通知には DisplayText を使用 | アクション要素は許可されない |
helpText inputParameter | ラベルテキストに含める | input attribute not found |
<booleanValue> としての IsLlmTargetable(任意プロパティですが、指定する場合) | <stringValue>{"value":"false"}</stringValue> またはプロパティを完全に省略 | 有効化エラー:The value of the IsLlmTargetable custom property's value field must be a string in JSON format |
Lookup の recordIds inputParameter | recordIdCollection(Id は単数形、Collection を付加) | We can't find this input attribute: "recordIds" |
単一選択の Lookup での recordIdCollection | isMultiSelection=true を設定(それ以外の場合、スコープ指定は無視される) | エラーなし — 実行時にフィルターが適用されない |
dynamicChoiceSets 内の <outputAssignments> | 選択後の recordLookups で outputAssignments を使用 | デプロイエラーなし — 後続の画面で変数が空のままになる |
DisplayText 内の IF / CASE / 日付計算 | Assignment で事前計算し、単純な変数を参照 | 実行時の Error while resolving default value reference |
dcTextInput のデフォルト value としての $User.Name | $User.Username | field integrity exception… type for input parameter "Value" doesn't match |
画面に nextOrFinishButtonLabel がない | <nextOrFinishButtonLabel>Next</nextOrFinishButtonLabel> を追加 | Next/Finish ボタンが表示されない |
| DataCaptureFlow から AutoLaunched サブフローを呼び出す | ロジックをインライン化するか、別の DataCaptureFlow のみを呼び出す | This flow can't reference [FlowName] because the referenced flow type is Autolaunched Flow |
visibilityRule の背後にあるフィールドでの isRequired=true | isRequired=false に設定し、validationRule で IF(trigger, rule, TRUE) を使用 | 非表示のフィールドが原因で、ユーザーが先に進めなくなる |
デプロイ
# Single file
sf project deploy start -d force-app/main/default/flows/MyFlow.flow-meta.xml \
--target-org <alias> --wait 60 --json
# Multi-dir (use repeated -d, NOT comma-separated)
sf project deploy start \
-d force-app/main/default/objects \
-d force-app/main/default/permissionsets \
-d force-app/main/default/tabs \
--target-org <alias> --wait 60 --json
エラーを抽出:
... --json 2>&1 | python3 -c "
import sys, json
d = json.load(sys.stdin)
r = d.get('result', {})
print('Status:', r.get('status'))
for f in r.get('details', {}).get('componentFailures', []):
print('ERROR:', f.get('fullName'), '-', f.get('problem'))
"
参考例
このスキルの examples/ に同梱されています。
Data_Capture_All_Components.flow-meta.xml— デプロイ可能な XML で、すべてのコンポーネントを記載DataCapture_Showcase.flow-meta.xml— エンドツーエンドのフロー全体:複数画面のフォーム、編集を続けられる recordLookup、Repeater → Loop →.AllItems経由の子レコード、Decision によって動作する Create-or-Update CUD チェーン、視覚的な仕上げ(バナー、進捗表示、コールアウト、レビューカード)。XML 形式の標準となる「正解」です。スキルのルールとこのファイルの内容が食い違う場合は、このファイルを優先してください。Repeater_with_prepopulation.flow-meta.xml— 事前入力された Repeater の標準パターン:recordLookups(ServiceResource)→collectioninputParameter でバインドされた Repeater。ネストされたフィールドのvalueのデフォルト値にはSourceCollection[$EachItem].FieldApiNameを使用 →.AllItemsを対象とした Repeater 後の Loop で、{!LoopName.nestedField.value}と{!LoopName.UniqueField__Id}を読み取る表示画面にデータを渡します。検証済みの例です。事前入力および Repeater 後の表示 XML の信頼できる正解として扱ってください。DataCapture_Repeater_with_data_showcase.flow(コミットされていない組織内のファイル)—.AllItemsのループに関する標準的な検証例です。動作しない、行をまたいだ検証式の構文も記載しています。
─────
実行時のコンテキスト(Headless 360/エージェント型): このスキルが Headless 360/エージェント型のコンテキストで実行される場合は、可能であれば CLI ツール(sf project deploy、sfdx、シェルコマンド)よりもプラットフォームのディスパッチツール(ホスト型 Headless 360 MCP の dispatch、ローカル開発用 MCP の dispatch)を優先してください。利用可能な操作は以下の steps: に記載されており、実稼働組織でそれぞれ検証済みです。正規のパスを指定してディスパッチツールを呼び出してください。該当する機能に API パスがない場合に限り、CLI を代替として使用できます。
重要な制約
運用ルール:
- 必須の入力変数:
<variables><name>recordId</name><dataType>String</dataType><isInput>true</isInput><isOutput>false</isOutput><isCollection>false</isCollection></variables>
<variables><name>parentRecordId</name><dataType>String</dataType><isInput>true</isInput><isOutput>false</isOutput><isCollection>false</isCollection></variables>
<variables><name>parentObjectType</name><dataType>String</dataType><isInput>true</isInput><isOutput>false</isOutput><isCollection>false</isCollection></variables>
- フィールドが
visibilityRuleの対象になっている場合、そのフィールドをisRequired=trueにしないでください。フィールドが非表示でも必須チェックが実行されるため、ユーザーが先に進めなくなります。代わりにフィールドをisRequired=falseに設定し、ルールを次のように記述します。 - FSL Mobile はログイン時に共有スナップショットをキャッシュします。プルして更新しても新しい共有設定は反映されず、新しい認証トークンが必要です。ユーザーには FSL Mobile アプリから完全にサインアウトしてから、再度サインインするよう案内してください。その後、Forms タブの取得が成功し、DDC レコードが表示されます。