platform-custom-metadata-type-generate について
Salesforce の Custom Metadata Type、フィールド、レコードを生成・検証するスキルです。組織間でデプロイする設定を扱う開発者向けで、メタデータリレーションや `.md-meta.xml` レコードにも対応します。
主な機能
- 01CMDT の型定義とフィールド生成
- 02対応フィールド型とリレーションの検証
- 03デプロイ可能な CMDT レコードファイル作成
- 04フィールド型に応じたレコード値の形式化
- 05デプロイ制約とエラーの診断
活用シーン
- 01パッケージに含める設定の作成
- 02CSV や一覧からの CMDT レコード生成
- 03メタデータリレーションやデプロイ問題の調査
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ forcedotcom/ sf-skills --skill platform-custom-metadata-type-generateインストール後、Claude Code で/platform-custom-metadata-type-generateを入力して読み込まれたか確認します。
同梱ファイルreferences/cmdt-records.mdscripts/sanitize-developer-name.sh
詳細
Salesforce カスタムメタデータ型の生成と検証
このスキルを使う場面
次の作業が必要な場合に、このスキルを使います。
- カスタムメタデータ型(
__mdt)を作成する MetadataRelationshipフィールドを含む CMDT フィールドを生成または検証する- デプロイ可能な
.md-meta.xmlファイルとして CMDT レコードを生成する - CMDT のデプロイエラーをトラブルシューティングする
このスキルの範囲を超える Metadata API の型、フィールド、列挙値については、正確な情報を得るために platform-metadata-api-context-get スキルを使ってください。
1. 概要と目的
カスタムメタデータ型は2種類のアーティファクト群を生成するため、ほとんどのリクエストでは両方が必要です。
| アーティファクト | パス | メタデータ型 |
|---|---|---|
| 型定義 | objects/<Name>__mdt/<Name>__mdt.object-meta.xml | CustomObject |
| フィールド | objects/<Name>__mdt/fields/<Field>__c.field-meta.xml | CustomField |
| レコード | customMetadata/<Name>.<Record>.md-meta.xml | CustomMetadata |
API 名の接尾辞: 型には __mdt、フィールドには引き続き __c を付けます。
カスタム設定に対する決定的な利点:CMDT レコードはメタデータであるため、組織間でデプロイできます。 ユーザーが、設定を「パッケージに含める」または「すべての組織で同じにする」必要があると言った場合、適切な選択肢は CMDT です。
ルート要素は
<CustomObject>ですが、カスタムオブジェクトのルールはほとんど適用されません。 通常のカスタムオブジェクトでは必須または一般的なsharingModel、nameField、deploymentStatusは、ここでは重大なエラーになります。platform-custom-object-generateの前提をそのまま持ち込まないでください。
2. 構文の基本 — 型定義(ティア 1)
必須および使用可能な要素
| 要素 | 要件 | 備考 |
|---|---|---|
<label> | 必須 | UI に表示する単数形の名前 |
<pluralLabel> | 必須 | 省略すると Must specify a non-empty plural label for the CustomObject が返されます |
<visibility> | 常に含める | Public、または開発/サンドボックス/スクラッチ環境のみで Protected/PackageProtected(セクション 6) |
<description> | 常に含める | この型が設定する内容と、その所有者 |
<pluralLabel> はここでは必須ですが、カスタム設定では使用できません。この違いは、2つの系列で最もよく混同されるルールです。どちらのエラーも、もう一方の系列のルールには触れません。
使用禁止の要素
以下の各要素を指定すると Cannot specify: <element> for Custom Metadata Type が発生します。通常のカスタムオブジェクトのひな形を再利用し、sharingModel、deploymentStatus、nameField ブロック、または enableSearch を含めることが、よくある原因です。
sharingModel、nameField、deploymentStatus、enableActivities、enableReports、enableHistory、enableSearch
正しい例 — 最小限の有効な __mdt 型:
<?xml version="1.0" encoding="UTF-8"?>
<CustomObject xmlns="http://soap.sforce.com/2006/04/metadata">
<label>Partner Tier</label>
<pluralLabel>Partner Tiers</pluralLabel>
<description>Discount and threshold configuration per partner tier. Ships with the package; edited by the revenue ops team.</description>
<visibility>Public</visibility>
</CustomObject>
3. フィールドのルール
このスキルが扱うのは CMDT 固有の差分のみです。以下の型の許可リスト、fieldManageability、MetadataRelationship が対象です。一般的なフィールドの仕組み(<fullName> の導出、<label>、<description>、<inlineHelpText>、精度/小数点以下の桁数、<length>、visibleLines)については、platform-custom-field-generate に従ってください。
サポートされているフィールド型
Checkbox、Date、DateTime、Email、Number、Percent、Phone、Picklist、Text、TextArea、LongTextArea、Url、および MetadataRelationship
サポートされていないフィールド型
Currency、AutoNumber、MasterDetail、Summary、Location、Time、EncryptedText、Html、MultiselectPicklist。いずれも、正確で形式の整ったエラーを返します。
Type {TypeName} of CustomMetadataField {Object}__mdt.{Field}__c is not supported for the Entity {Object}__mdt
(末尾にピリオドはありません。)例:Type Currency of CustomMetadataField Partner_Tier__mdt.Discount__c is not supported for the Entity Partner_Tier__mdt
よくある落とし穴は Currency です。 カスタム設定では使用できますが、ここでは使えません。<precision>/<scale> を指定した Number を使用し、通貨はラベルまたはヘルプテキストに記載してください。
数式フィールドはサポートされていませんが、上記のパターンとは異なるエラーになります。それ以外は有効な型に <formula> 要素を指定すると、次のエラーのみが返されます。
Invalid data type.
Lookup はサイレントに強制変換されます — 重大
__mdt の <type>Lookup</type> は、referenceTo が実在する sObject に解決されてもエラーになりません。デプロイは成功し、プラットフォームがフィールドをサイレントに MetadataRelationship に書き換えます。その後に取得すると、ユーザーが一度も記述していないフィールドが表示されます。
<type>MetadataRelationship</type>
必ず MetadataRelationship を明示的に記述してください。 Lookup を出力すると、デプロイは成功する一方、ソースと組織の不一致が生じ、誰かが初めて取得したときに Git の差分が増え続けます。(稼働中のデプロイで再現済み:解決可能な Lookup は MetadataRelationship として返され、解決できない referenceTo は問題なく拒否されます。)
MetadataRelationship
有効なターゲットは 3 種類です。どれを使うかは referenceTo で指定します。
<referenceTo> | 用途 | 追加要件 |
|---|---|---|
別の __mdt 型 | 2 つのカスタムメタデータ型をリンクします | 異なる型である必要があります |
EntityDefinition | sObject を参照します | なし |
FieldDefinition | フィールドを参照します | <metadataRelationshipControllingField> が必要です |
<?xml version="1.0" encoding="UTF-8"?>
<CustomField xmlns="http://soap.sforce.com/2006/04/metadata">
<fullName>Target_Field__c</fullName>
<label>Target Field</label>
<type>MetadataRelationship</type>
<referenceTo>FieldDefinition</referenceTo>
<metadataRelationshipControllingField>Partner_Tier__mdt.Target_Object__c</metadataRelationshipControllingField>
<relationshipLabel>Target Field</relationshipLabel>
<relationshipName>Target_Field</relationshipName>
</CustomField>
制御フィールドは、同じ型に属する EntityDefinition リレーションシップである必要があり、Type__mdt.Field__c の形式で参照します。これを省略すると、Metadata relationships to Field Definition require a controlling field. が表示されます。
自己参照はできません。 MetadataRelationship の参照先を自分自身の親型にすると、Cannot add a self-lookup relationship child with cascade or restrict options to the object itself というエラーが発生します(稼働中の __mdt デプロイからの原文)。2 つ目の型を使用してください。
<fieldManageability>
省略可能です。デフォルトは DeveloperControlled です。ユーザーが別の値を希望しない限り、追加しないでください。有効な値は DeveloperControlled、SubscriberControlled、Locked です。
これは __mdt フィールドでのみ有効です。通常のカスタムオブジェクトフィールドまたはカスタム設定フィールドでは、次のようになります。
Field manageability cannot be set on this entity.
4. CMDT レコード(.md-meta.xml)
ファイル名の規則
customMetadata/<TypeNameWithout__mdt>.<RecordDeveloperName>.md-meta.xml として記述してください。
customMetadata/Partner_Tier.Bronze_AMER.md-meta.xml
ファイル名に __mdt のサフィックスを付けてもデプロイされ、実際のレコードが作成されるため許容されます。ただし、Salesforce の取得処理ではサフィックスなしの形式に正規化されるため、Git の差分が増えるのを避けるには、必ず __mdt を付けずに記述してください(詳細は references/cmdt-records.md を参照)。
必須の名前空間
ルート要素では 3 つすべてが必須です。値に xsi:type を指定しても、これらがなければ解決されません。
<CustomMetadata xmlns="http://soap.sforce.com/2006/04/metadata"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
xsi:type の対応表 — すべての値に指定が必要です
| フィールド型 | 正しい xsi:type | 値の例 |
|---|---|---|
| チェックボックス | xsd:boolean | true |
| 日付 | xsd:date | 2024-01-15 |
| 日時 | xsd:dateTime | 2024-01-15T10:30:00.000Z |
| 数値、パーセント | xsd:double | 42.0 |
| テキスト、テキストエリア、長文テキストエリア | xsd:string | some text |
| メール、電話、URL | xsd:string | [email protected] |
| 選択リスト | xsd:string | Beta |
MetadataRelationship → EntityDefinition | xsd:string | Account |
MetadataRelationship → FieldDefinition | xsd:string | Account.Name |
| 任意の型、null | xsi:type なし — <value xsi:nil="true"/> と記述 |
MetadataRelationship を介して別の __mdt 型を参照する値は検証されていません。ターゲットの DeveloperName を xsd:string で指定すると想定されますが、確認してください。
xsd:picklist を出力してはいけません — 重大
Salesforce の公式ドキュメントでは、選択リストフィールドに xsd:picklist を使うよう指示されていますが、これは誤りです。有効な XML Schema 型ではありません。プラットフォームは明確な検証エラーを返す代わりに、サーバー側でデプロイ全体を失敗させ、コンポーネント単位の診断情報も表示しません。その結果、ほかのすべてのコンポーネントも巻き添えになります。選択リストフィールドの値には必ず xsd:string を出力し、xsd:picklist は決して使用しないでください。 references/cmdt-records.md §2 を参照してください。
レコード本体のルール
<label>は必須です。省略するとRequired fields are missing: [MasterLabel]が返されます。報告されるのはlabelではなく、sObject のフィールド名MasterLabelです。<protected>は省略可能で、デフォルトはfalseです。<values>ブロック内に<fullName>を入れないでください。パースエラーになります。<value xsi:nil="true"/>は省略可能なフィールドでは機能します。必須フィールドでは、フィールドが存在しない場合と同様に拒否されます。nil でない値でxsi:typeを省略すると、テキストフィールドを含め、必ず致命的なエラーになります。
正しい例 — 完全なレコード:
<?xml version="1.0" encoding="UTF-8"?>
<CustomMetadata xmlns="http://soap.sforce.com/2006/04/metadata"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<label>Bronze AMER</label>
<protected>false</protected>
<values>
<field>Discount_Percent__c</field>
<value xsi:type="xsd:double">5.0</value>
</values>
<values>
<field>Region__c</field>
<value xsi:type="xsd:string">AMER</value>
</values>
<values>
<field>Effective_Date__c</field>
<value xsi:type="xsd:date">2024-01-15</value>
</values>
<values>
<field>Notes__c</field>
<value xsi:nil="true"/>
</values>
</CustomMetadata>
レコードの DeveloperName ルール
名前はファイル名の2番目のセグメントです。英字で始まり、英数字とアンダースコアのみを含み、アンダースコアで終わらず、連続するアンダースコアを含まず、最大40文字である必要があります。違反すると、次のエラーが返されます。
Custom Metadata Record Name: The <Type>__mdt API Name can only contain underscores and alphanumeric characters. It must be unique, begin with a letter, not include spaces, not end with an underscore, and not contain two consecutive underscores.
40文字を超えると Value too long for field: fullName maximum length is:40 が返されます(コロンの後にスペースはありません)。
デプロイ順序
順序の制約はありません — 型と参照されるすべてのフィールドは、解決できればよいだけです(組織にすでに存在するか、同じデプロイに含まれていること)。不足しているものは、次の2種類のエラーで確認できます。
Custom metadata type <Type>__mdt is not available in this organization.(型が存在しない場合)および
<Type>__mdt: could not find fields: <Field>__c(型は存在するが、フィールドが存在しない場合)。
→ レコード値のエラー一覧と xsi:type の型強制における非対称性:references/cmdt-records.md。
ユーザー入力からのレコード生成
レコードデータは3つの方法で渡されます。いずれの場合も、各行につき <Type>.<Record>.md-meta.xml を1つ出力し、列を適切な xsi:type を持つ <field>/<value> の組に対応付けます。
- インラインのリスト/テーブル — 列をそのままフィールドに対応付けます。
- CSV — ヘッダーにはフィールドの API 名を指定します(またはラベルを API 名に対応付けます)。各行が1つのレコードで、キー列から DeveloperName を取得します。
- 文章 — 行を推測し(「Bronze は5%、Gold は15%」など)、生成前にフィールドの対応付けを確認します。
キー列またはラベルから、各 DeveloperName を決定論的に導出してください。手作業で作成してはいけません。各行について、レコードファイルを書き込む前に scripts/sanitize-developer-name.sh "<LABEL>" <ROW> を実行します(同じ入力からは同じ有効な名前が得られます。空のラベル、記号のみのラベル、非ラテン文字のラベルには Record_<ROW> が割り当てられます)。
変換は多対一です。United States と United-States はどちらも United_States になり、各レコードは <Type>.<DeveloperName>.md-meta.xml であるため、衝突すると行が警告なく上書きされます。バッチ全体の名前を導出した後、書き込む前に重複を確認してください。衝突があれば処理を停止し、衝突した元のラベルを報告します(ユーザーが自動解決を求めた場合に限り、決定論的な _2/_3 のサフィックスを追加します)。
順序付きのアルゴリズム、ASCII のみという制限、一意性チェック、具体例:references/cmdt-records.md §7。
Apex でのレコードの使用
レコードは生成された型付きクラスを介して読み取られます。SOQL は不要で、クエリ行も消費しないため、ループやトリガー内でも安全です。
Map<String, Partner_Tier__mdt> all = Partner_Tier__mdt.getAll();
Partner_Tier__mdt bronze = Partner_Tier__mdt.getInstance('Bronze_AMER'); // by DeveloperName
アクセサーによる切り詰め — LongTextArea では重要です。 getAll()/getInstance() は、あらゆるフィールドの先頭255文字のみを返します。これらの呼び出しでは、255文字を超える LongTextArea の値が警告なく切り詰められるため、SOQL(SELECT ... FROM Partner_Tier__mdt)で読み取る必要があります。CMDT に LongTextArea を指定する場合は、必ずこの点を伝えてください。
5. 適切なコンポーネントの選択
生成する前に、ユーザーが必要としているものが CMDT であることを確認してください。
| 設定が… | 使用するもの | 理由 |
|---|---|---|
| レコードとともに組織間でデプロイする必要がある参照データ | CMDT(このスキル) | レコードはメタデータです |
| 管理者が保守するマッピング/参照/対応表(項目↔項目、コード↔コード、「A を B に対応付ける」) | CMDT(このスキル) | 編集可能な参照データで、ペアごとに 1 レコードです |
| プロファイル/ユーザーごとに編集可能、または組織ローカルである値 | platform-custom-setting-generate | 値はデータであり、1 つの組織内にとどまります |
| ユーザーが実行時に作成・編集する業務レコード | platform-custom-object-generate | CMDT レコードはトランザクションデータではありません |
| 翻訳可能な UI テキスト | カスタム表示ラベル — ここでは生成しません | 表示ラベルが翻訳対象です |
| 認証情報、API キー、トークン | 名前付き認証情報/外部認証情報 — ここでは生成しません | セクション 6 を参照してください |
| Apex またはフローでの権限チェック | カスタム権限 — ここでは生成しません | ブール値のアクセス権は権限モデルで管理します |
最も重要な違いは、CMDT レコードはデプロイされますが、カスタム設定の値はデプロイされないことです。ユーザーが実行時に管理者によるプロファイルごとの値の編集を必要としている場合、それは CMDT ではなくカスタム設定です。
項目マッピングテーブルや参照テーブルは、代表的な CMDT の用途です。 ユーザーが「A から B に項目をマッピングする」、コード間の参照を管理する、または管理者が編集できる対応表を保持すると依頼した場合は、CMDT としてモデル化してください。ペアごとに 1 レコードにします(例:
Lead_Field__c/Target_Field__c、またはMetadataRelationship項目とFieldDefinitionの組み合わせ)。ハードコードした Apex のMap、定数、またはフローの判断ロジックにしてはいけません。「変換用」や「連携用」という表現でも、コードになるわけではありません。管理者がデプロイなしでペアを保守するのであれば、それは CMDT の参照データです。
6. 可視性、シークレット、そしてサイレントなダウングレードの禁止
Protected と PackageProtected は組織の種類に依存します
どちらも開発者組織、Sandbox、またはスクラッチ組織にのみデプロイできます。それ以外では次のようになります。
You can't set the visibility for a Custom Metadata Type to Protected unless you are in a developer, sandbox, or scratch org.
PackageProtected でも、Protected が PackageProtected に置き換わった同じメッセージが表示されます。このエラーは本番環境に近い組織で確認されています。これらの値が開発者組織、Sandbox、またはスクラッチ組織で成功するという情報は、別途テストした結果ではなく、メッセージ本文に基づいています。
サイレントなダウングレードの禁止 — 重大
組織の種類が原因で Protected に失敗した場合、Public に切り替えて「修正」してはいけません。 処理を停止し、ユーザーに伝えてください。サイレントなダウングレードでは、意図的な機密性の選択が、警告もなく正常にデプロイされた全世界から閲覧可能なコンポーネントに変わってしまいます。何も変わったことを知らせるものがないため、これは最悪の結果です。
代わりに状況を報告してください。組織では Protected が許可されないため、開発者組織/Sandbox/スクラッチ組織にデプロイするか、Public を受け入れるかが選択肢です。選ぶのはユーザーです。
このルールは、このエラーに限らず、可視性を狭めるあらゆるケースに適用されます。
シークレットを CMDT に保存してはいけません
CMDT はシークレットストアではありません。Protected は名前空間の外部からのアクセスを制限しますが、暗号化ではなく、名前空間内のコードや管理者から値を保護するものでもありません。
ユーザーが CMDT に API キー、パスワード、トークン、クライアントシークレット、または証明書を保存しようとした場合:
- 最初に、はっきりと警告してください。何かを生成する前に、CMDT は認証情報を保存する場所として適切ではなく、
Protectedも暗号化ではないことを伝えてください。 - 適切なコンポーネントを推奨してください。名前付き認証情報と外部認証情報を使用してください。このスキルではそれらを生成しないことも明確に伝えてください。
- ユーザーがそれでも希望する場合は、依頼に従ってください。組織で許可される場合は
Protectedの可視性で CMDT を生成し、回答にも警告を残してください。黙って拒否したり、黙って従ったりしてはいけません。
2 つのルールは組み合わせて適用され、順序が重要です。 ユーザーがシークレットを CMDT に保存することを強く希望し、かつ組織が Protected を拒否した場合、サイレントなダウングレードの禁止ルールによって、キーが Public コンポーネントに保存されるのを防ぎます。処理を停止して報告してください。シークレットを含む型を Public にダウングレードしてはいけません。
7. デプロイエラーのリファレンス
型レベルおよびフィールドレベルのエラー文字列は、該当するエラーの原因となる誤りの横に、セクション 2~4 でインラインに記載されています(Cannot specify: <element> for Custom Metadata Type、未対応の型を示す文字列、数式に対する Invalid data type.、Field manageability cannot be set on this entity.、MetadataRelationship の制御フィールドおよび自己参照エラー、ならびに Must specify a non-empty plural label のケース)。
レコード値の完全な逐語カタログ(xsi:type の誤りによるすべての拒否、Required fields are missing: [MasterLabel]、必須項目の nil、DeveloperName のルール、正確な文字列に関する注意点(API 名ではなく Label で指定されたフィールド名、xsi:type なしのエラーに含まれる二重スペースと i.g. の誤記、スペースなしの maximum length is:40))は、references/cmdt-records.md にあります。
一致させる際の注意点が 1 つあります。ここでの接尾辞は for Custom Metadata Type(スペースあり、タイトルケース)です。カスタム設定では for CustomSettings を使います。これらの文字列が共通のテンプレートに従うと想定しないでください。
8. 検証チェックリスト
型定義のチェック
-
<label>、<pluralLabel>、<visibility>がすべて含まれていますか? -
<description>が含まれており、具体的な内容になっていますか? -
<sharingModel>、<nameField>、<deploymentStatus>は含まれていませんか? -
<enableActivities>、<enableReports>、<enableHistory>、<enableSearch>は含まれていませんか? - ディレクトリ名とファイル名の末尾が
__mdtになっていますか?
フィールドのチェック
- すべてのフィールド型がサポート対象の一覧(セクション 3)に含まれていますか?
-
Currencyは含まれていませんか?(ここでは未対応です。代わりにNumberを使用してください) - すべての
<formula>要素が含まれていませんか? -
<type>Lookup</type>は含まれておらず、代わりにMetadataRelationshipと記述されていますか? 重大 —Lookupはエラーなしでデプロイされ、書き換えられます -
FieldDefinitionのリレーションシップに<metadataRelationshipControllingField>が含まれていますか? -
MetadataRelationshipが自身の親型を参照していませんか? - デフォルト以外の値が要求されていない限り、
<fieldManageability>は省略されていますか?
レコードのチェック 重大
- ファイル名は
__mdtを付けずに<Type>.<Record>.md-meta.xmlとなっていますか? - ルート要素に 3 つすべての名前空間(
xmlns、xmlns:xsd、xmlns:xsi)がありますか? - nil 以外の
<value>にはすべてxsi:typeが指定されていますか? -
xsi:type="xsd:picklist"はどこにも含まれていませんか?(デプロイ全体がクラッシュします。代わりにxsd:stringを使用してください) - 各
xsi:typeは、セクション 4 の表に従ってフィールド型と一致していますか? - すべてのレコードに
<label>が含まれていますか? - すべての
<values>ブロックから<fullName>が除かれていますか? - 必須フィールドにはすべて、
xsi:nil="true"ではなく実際の値が指定されていますか? - すべてのレコードの DeveloperName は 40 文字以下で、英字で始まり、スペースやハイフンを含んでいませんか?
- レコードがバッチ、リスト、CSV から作成された場合、派生した DeveloperName がすべて重複していないことを(
sort | uniq -dで)確認し、行を黙って上書きせず、重複があれば報告していますか? 重大 — 重複があると、デプロイエラーなしでレコードが失われます - 各
<field>には、その型に存在するフィールド、または今回のデプロイに含まれるフィールドが指定されていますか? - レコードがリスト、CSV、または文章による説明から作成された場合、各行につきファイルが 1 つだけあり、列が正しいフィールドに対応付けられていますか?
利用時のチェック
- ユーザーがレコードの読み取り方法を尋ねた場合、
getAll()/getInstance(developerName)を使用する Apex スニペットを提示しましたか? - いずれかのレコードが
LongTextAreaに値を設定している場合、アクセサーは 255 文字で切り詰めるため、値全体を取得するには SOQL が必要であることをユーザーに伝えましたか?
セキュリティのチェック 重大
- リクエストにシークレット、キー、トークン、またはパスワードが含まれる場合、生成前に警告し、Named Credential を推奨しましたか?
- 組織タイプの不一致があっても、
Protectedをそのまま維持し、黙ってPublicに変更していませんか?
コンポーネント選択の確認項目
- 実行時に管理者がプロファイルやユーザーごとに値を編集する必要がある場合、代わりに
platform-custom-setting-generateが推奨されていますか? - データが実際にはトランザクション型のビジネスレコードである場合、代わりに
platform-custom-object-generateが推奨されていますか?
リファレンスファイル一覧
| ファイル | 読むタイミング |
|---|---|
references/cmdt-records.md | CMDT レコードのデプロイに関するデバッグ — レコード値のエラーを網羅した完全なカタログ、型強制の非対称性(プラットフォームが暗黙的に受け入れる xsi:type の不一致)、レコードの具体例 |