@salesforce/afv-skills 1.30.0 → 1.31.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/data360-code-extension-generate/SKILL.md +15 -2
- package/skills/dx-pkg-post-install-configure/SKILL.md +184 -0
- package/skills/experience-ui-bundle-app-coordinate/SKILL.md +198 -34
- package/skills/experience-ui-bundle-app-coordinate/scripts/check-hosting-target.sh +26 -0
- package/skills/experience-ui-bundle-app-coordinate/scripts/check-sfdx-project.sh +15 -0
- package/skills/experience-ui-bundle-metadata-generate/SKILL.md +19 -8
- package/skills/experience-ui-bundle-metadata-generate/references/csp-metadata-format.md +2 -2
- package/skills/experience-ui-bundle-metadata-generate/scripts/check-api-version.sh +30 -0
- package/skills/platform-custom-field-generate/SKILL.md +12 -11
- package/skills/platform-custom-field-generate/references/advanced-picklists.md +17 -17
- package/skills/platform-custom-report-type-generate/SKILL.md +259 -0
- package/skills/platform-custom-report-type-generate/examples/AccountProjectsWithTasks.reportType-meta.xml +51 -0
- package/skills/platform-custom-report-type-generate/examples/AccountsWithIndustry.reportType-meta.xml +27 -0
- package/skills/platform-custom-report-type-generate/examples/AccountsWithProjects.reportType-meta.xml +44 -0
- package/skills/platform-custom-report-type-generate/references/category-values.md +32 -0
- package/skills/platform-custom-report-type-generate/references/errors-and-troubleshooting.md +24 -0
- package/skills/platform-dataspace-access-configure/SKILL.md +318 -0
- package/skills/platform-docs-get/SKILL.md +4 -0
- package/skills/platform-docs-get/scripts/extract_salesforce_doc.py +78 -13
- package/skills/platform-encryption-configure/SKILL.md +122 -0
- package/skills/platform-encryption-configure/assets/EncryptionKey.settings-meta.xml +17 -0
- package/skills/platform-encryption-configure/assets/PlatformEncryption.settings-meta.xml +15 -0
- package/skills/platform-encryption-configure/assets/encrypted-field.field-meta.xml +22 -0
- package/skills/platform-encryption-configure/examples/cache-only-keys.settings-meta.xml +11 -0
- package/skills/platform-encryption-configure/references/encryption-schemes.md +34 -0
- package/skills/platform-encryption-configure/references/key-models.md +34 -0
- package/skills/platform-encryption-configure/references/tenant-secret-lifecycle.md +23 -0
- package/skills/platform-encryption-configure/scripts/validate-encryption-metadata.sh +54 -0
- package/skills/platform-metadata-api-context-get/SKILL.md +13 -10
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Check which hosting target is configured in .uibundle-meta.xml files
|
|
3
|
+
|
|
4
|
+
# Find all .uibundle-meta.xml files
|
|
5
|
+
META_FILES=$(find . -name "*.uibundle-meta.xml" -type f 2>/dev/null)
|
|
6
|
+
|
|
7
|
+
if [ -z "$META_FILES" ]; then
|
|
8
|
+
echo "ERROR: No .uibundle-meta.xml files found"
|
|
9
|
+
exit 1
|
|
10
|
+
fi
|
|
11
|
+
|
|
12
|
+
# Check for ExperienceSite target
|
|
13
|
+
if echo "$META_FILES" | xargs grep -q '<target>ExperienceSite</target>' 2>/dev/null; then
|
|
14
|
+
echo "ExperienceSite"
|
|
15
|
+
exit 0
|
|
16
|
+
fi
|
|
17
|
+
|
|
18
|
+
# Check for CustomApplication target
|
|
19
|
+
if echo "$META_FILES" | xargs grep -q '<target>CustomApplication</target>' 2>/dev/null; then
|
|
20
|
+
echo "CustomApplication"
|
|
21
|
+
exit 0
|
|
22
|
+
fi
|
|
23
|
+
|
|
24
|
+
# No valid target found
|
|
25
|
+
echo "ERROR: No valid hosting target found in .uibundle-meta.xml"
|
|
26
|
+
exit 1
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Check if sfdx-project.json exists and is valid JSON
|
|
3
|
+
|
|
4
|
+
if [ ! -f sfdx-project.json ]; then
|
|
5
|
+
echo 'ERROR: sfdx-project.json not found'
|
|
6
|
+
exit 1
|
|
7
|
+
fi
|
|
8
|
+
|
|
9
|
+
# Validate JSON format using python (more portable than node)
|
|
10
|
+
if ! python3 -c "import json; json.load(open('sfdx-project.json'))" 2>/dev/null; then
|
|
11
|
+
echo 'ERROR: sfdx-project.json is not valid JSON'
|
|
12
|
+
exit 1
|
|
13
|
+
fi
|
|
14
|
+
|
|
15
|
+
echo 'sfdx-project.json is valid'
|
|
@@ -1,8 +1,18 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: experience-ui-bundle-metadata-generate
|
|
3
|
-
description: "
|
|
3
|
+
description: "Use this skill when adding a front-end React UI bundle to an existing project or configuring UI bundle metadata and config files. TRIGGER when: adding or scaffolding a new UI bundle inside a project that already exists; running sf template generate ui-bundle; editing ui-bundle.json routing, headers, or output directory; working with *.uibundle-meta.xml files; or registering CSP Trusted Sites, resolving blocked images or fonts or external API calls, or editing cspTrustedSites/*.cspTrustedSite-meta.xml files. DO NOT TRIGGER when: creating a brand-new Salesforce project from scratch, where the whole SFDX starter project (UI bundle plus Experience Site metadata and toolchain) is generated together (use experience-ui-bundle-project-generate)."
|
|
4
4
|
metadata:
|
|
5
5
|
version: "1.0"
|
|
6
|
+
minApiVersion: "51.0"
|
|
7
|
+
relatedSkills:
|
|
8
|
+
- "experience-ui-bundle-frontend-generate"
|
|
9
|
+
- "experience-ui-bundle-custom-app-generate"
|
|
10
|
+
- "experience-ui-bundle-site-generate"
|
|
11
|
+
cliTools:
|
|
12
|
+
- tool: ["sf"]
|
|
13
|
+
semver: ">=2.0.0"
|
|
14
|
+
- tool: ["jq"]
|
|
15
|
+
semver: ">=1.6"
|
|
6
16
|
---
|
|
7
17
|
|
|
8
18
|
# UI Bundle Metadata
|
|
@@ -11,9 +21,9 @@ metadata:
|
|
|
11
21
|
|
|
12
22
|
Use `sf template generate ui-bundle` to create new apps — not create-react-app, Vite, or other generic scaffolds.
|
|
13
23
|
|
|
14
|
-
**Always pass `--template reactbasic`** to scaffold a React-based bundle.
|
|
15
|
-
|
|
16
|
-
|
|
24
|
+
- **Always pass `--template reactbasic`** to scaffold a React-based bundle.
|
|
25
|
+
- **UI bundle name (`-n`):** Alphanumerical only — no spaces, hyphens, underscores, or special characters.
|
|
26
|
+
- Pass `--output-dir` to use a different location for template generation.
|
|
17
27
|
|
|
18
28
|
**Example:**
|
|
19
29
|
```bash
|
|
@@ -21,10 +31,11 @@ sf template generate ui-bundle -n CoffeeBoutique --template reactbasic
|
|
|
21
31
|
```
|
|
22
32
|
|
|
23
33
|
After generation:
|
|
24
|
-
1.
|
|
25
|
-
2.
|
|
26
|
-
3.
|
|
27
|
-
4.
|
|
34
|
+
1. **Verify API version** — run `bash <skill_dir>/scripts/check-api-version.sh` from the project root to ensure `sourceApiVersion` in `sfdx-project.json` is 67.0 or higher. The script will automatically update it if needed.
|
|
35
|
+
2. Replace all default boilerplate — "React App", "Vite + React", default `<title>`, placeholder text
|
|
36
|
+
3. Populate the home page with real content (landing section, banners, hero, navigation)
|
|
37
|
+
4. Update navigation and placeholders (see the `experience-ui-bundle-frontend-generate` skill)
|
|
38
|
+
5. **Configure a hosting target** — a UI bundle without a `<target>` in its meta XML will not be visible in the org. Use `experience-ui-bundle-custom-app-generate` for internal (App Launcher) apps or `experience-ui-bundle-site-generate` for external (Experience Site) apps.
|
|
28
39
|
|
|
29
40
|
Always install dependencies before running any scripts in the UI bundle directory.
|
|
30
41
|
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
## File location
|
|
4
4
|
|
|
5
|
-
```
|
|
5
|
+
```text
|
|
6
6
|
force-app/main/default/cspTrustedSites/{Name}.cspTrustedSite-meta.xml
|
|
7
7
|
```
|
|
8
8
|
|
|
@@ -256,7 +256,7 @@ Some services split resources across multiple subdomains. Create one CSP Trusted
|
|
|
256
256
|
|
|
257
257
|
If the browser console shows a CSP error like:
|
|
258
258
|
|
|
259
|
-
```
|
|
259
|
+
```text
|
|
260
260
|
Refused to load the image 'https://example.com/image.png' because it violates
|
|
261
261
|
the following Content Security Policy directive: "img-src 'self' ..."
|
|
262
262
|
```
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Checks that sourceApiVersion in sfdx-project.json is 67.0 or higher.
|
|
3
|
+
# If lower, updates it to "67.0".
|
|
4
|
+
|
|
5
|
+
set -e
|
|
6
|
+
|
|
7
|
+
PROJECT_FILE="sfdx-project.json"
|
|
8
|
+
|
|
9
|
+
if [[ ! -f "$PROJECT_FILE" ]]; then
|
|
10
|
+
echo "ERROR: $PROJECT_FILE not found in current directory"
|
|
11
|
+
exit 1
|
|
12
|
+
fi
|
|
13
|
+
|
|
14
|
+
# Extract sourceApiVersion and check if it's below 67.0
|
|
15
|
+
version=$(jq -r '.sourceApiVersion // "0"' "$PROJECT_FILE")
|
|
16
|
+
is_below=$(jq --arg v "$version" -n '($v | split(".") | .[0] | tonumber) < 67')
|
|
17
|
+
|
|
18
|
+
if [[ "$is_below" == "true" ]]; then
|
|
19
|
+
echo "WARNING: sourceApiVersion is $version (< 67.0)"
|
|
20
|
+
echo "Updating $PROJECT_FILE to set sourceApiVersion to \"67.0\""
|
|
21
|
+
|
|
22
|
+
# Update the file
|
|
23
|
+
jq '.sourceApiVersion = "67.0"' "$PROJECT_FILE" > "$PROJECT_FILE.tmp"
|
|
24
|
+
mv "$PROJECT_FILE.tmp" "$PROJECT_FILE"
|
|
25
|
+
|
|
26
|
+
echo "OK: Updated sourceApiVersion to 67.0"
|
|
27
|
+
exit 0
|
|
28
|
+
fi
|
|
29
|
+
|
|
30
|
+
echo "OK: sourceApiVersion is $version (>= 67.0)"
|
|
@@ -4,6 +4,7 @@ description: "Use this skill when users need to create, generate, or validate Sa
|
|
|
4
4
|
metadata:
|
|
5
5
|
version: "1.0"
|
|
6
6
|
minApiVersion: "51.0"
|
|
7
|
+
relatedSkills: ["platform-value-set-generate", "platform-validation-rule-generate"]
|
|
7
8
|
---
|
|
8
9
|
|
|
9
10
|
# Salesforce Custom Field Generator and Validator
|
|
@@ -20,7 +21,7 @@ Every generated field must include these tags:
|
|
|
20
21
|
|
|
21
22
|
| Attribute | Requirement | Notes |
|
|
22
23
|
|-----------|-------------|-------|
|
|
23
|
-
| `<fullName>` | Required | **Field** name only: derive from `<label>` — capitalize each word, replace spaces with `_`, append `__c`. Must start with a letter. E.g., label `Total Contract Value` → `Total_Contract_Value__c`.
|
|
24
|
+
| `<fullName>` | Required | **Field** name only: derive from `<label>` — capitalize each word, replace spaces with `_`, append `__c`. Must start with a letter. E.g., label `Total Contract Value` → `Total_Contract_Value__c`. This rule is for the FIELD name. **Picklist VALUE `<fullName>` is different — keep it exactly as the user spelled it, spaces and all, no `__c`** (e.g. `Closed Won`, NOT `Closed_Won`). See [`references/advanced-picklists.md`](references/advanced-picklists.md) (ref §3). |
|
|
24
25
|
| `<label>` | Required | The UI name (Title Case) |
|
|
25
26
|
| `<description>` | Always include | Explain the business reason *why* this field exists. |
|
|
26
27
|
| `<inlineHelpText>` | Always include | Actionable end-user guidance that adds value beyond the label (e.g., "Enter the value in USD including tax", not "The amount"). |
|
|
@@ -49,7 +50,7 @@ To ensure deployment success, follow these mathematical constraints:
|
|
|
49
50
|
|
|
50
51
|
### The "Fixed 255" Rule
|
|
51
52
|
|
|
52
|
-
**TextArea:
|
|
53
|
+
**TextArea: do NOT include `<length>`** — the Metadata API fixes the length at 255 implicitly and **rejects an explicit `<length>` value** with "Can not specify 'length' for a CustomField of type TextArea". Omit `<length>` entirely; the field only needs `<fullName>`, `<label>`, and `<type>TextArea</type>`.
|
|
53
54
|
|
|
54
55
|
### Visible Lines
|
|
55
56
|
|
|
@@ -76,7 +77,7 @@ Mandatory for Long/Rich text and Multi-select picklists to control UI height.
|
|
|
76
77
|
| Phone | `Phone` | Standardizes phone number formatting |
|
|
77
78
|
| Picklist | `Picklist` | `valueSet` containing EITHER `valueSetDefinition` (inline) OR `valueSetName` (reference); `restricted` (see "Picklist `restricted` default" below; advanced cases in §3.4) |
|
|
78
79
|
| Text | `Text` | `length` (Max 255) |
|
|
79
|
-
| Text Area | `TextArea` | `<length
|
|
80
|
+
| Text Area | `TextArea` | None — do NOT include `<length>`; the API fixes length at 255 implicitly |
|
|
80
81
|
| Text (Long) | `LongTextArea` | `length`, `visibleLines` (default 3) |
|
|
81
82
|
| Text (Rich) | `Html` | `length`, `visibleLines` (default 25) |
|
|
82
83
|
| Time | `Time` | Stores time only (no date) |
|
|
@@ -112,7 +113,7 @@ Mandatory for Long/Rich text and Multi-select picklists to control UI height.
|
|
|
112
113
|
|
|
113
114
|
### 3.4 Advanced Picklists
|
|
114
115
|
|
|
115
|
-
The inline `<valueSetDefinition>` above is the simple case. Full rules and worked
|
|
116
|
+
The inline `<valueSetDefinition>` above is the simple case. Full rules and worked correct/incorrect
|
|
116
117
|
examples for everything below are in
|
|
117
118
|
[`references/advanced-picklists.md`](references/advanced-picklists.md) — load it for any
|
|
118
119
|
non-trivial picklist. Section numbers in parentheses below (e.g. "ref §1") point to that
|
|
@@ -166,12 +167,12 @@ Master-Detail fields have **strict attribute restrictions** that differ from Loo
|
|
|
166
167
|
|
|
167
168
|
| Attribute | Master-Detail | Lookup |
|
|
168
169
|
|-----------|---------------|--------|
|
|
169
|
-
| `<required>` |
|
|
170
|
-
| `<deleteConstraint>` |
|
|
171
|
-
| `<lookupFilter>` |
|
|
172
|
-
| `<relationshipOrder>` |
|
|
173
|
-
| `<reparentableMasterDetail>` |
|
|
174
|
-
| `<writeRequiresMasterRead>` |
|
|
170
|
+
| `<required>` | FORBIDDEN | Optional |
|
|
171
|
+
| `<deleteConstraint>` | FORBIDDEN (always CASCADE) | Required (`SetNull`, `Restrict`, `Cascade`) |
|
|
172
|
+
| `<lookupFilter>` | FORBIDDEN | Optional |
|
|
173
|
+
| `<relationshipOrder>` | Required (0 or 1) | Not applicable |
|
|
174
|
+
| `<reparentableMasterDetail>` | Optional | Not applicable |
|
|
175
|
+
| `<writeRequiresMasterRead>` | Optional | Not applicable |
|
|
175
176
|
|
|
176
177
|
### INCORRECT — Master-Detail with forbidden attributes:
|
|
177
178
|
|
|
@@ -451,7 +452,7 @@ Before generating CustomField XML, verify:
|
|
|
451
452
|
- [ ] Is `precision ≤ 18`?
|
|
452
453
|
|
|
453
454
|
### Text Area Checks
|
|
454
|
-
- [ ] For TextArea: Is `<length
|
|
455
|
+
- [ ] For TextArea: Is `<length>` **omitted**? (The API rejects an explicit `<length>` value on TextArea fields.)
|
|
455
456
|
- [ ] For LongTextArea/Html: Is `<visibleLines>` set?
|
|
456
457
|
|
|
457
458
|
### Relationship Limit Checks
|
|
@@ -21,7 +21,7 @@ A picklist field can either define its values **inline** or **reference an exist
|
|
|
21
21
|
value set** (a Global Value Set or a Standard Value Set). The shared set is defined
|
|
22
22
|
once and reused across many fields.
|
|
23
23
|
|
|
24
|
-
###
|
|
24
|
+
### HARD RULE: `<valueSet>` is EITHER a reference OR inline — never both
|
|
25
25
|
|
|
26
26
|
A `<valueSet>` element must contain **exactly one** of:
|
|
27
27
|
|
|
@@ -30,7 +30,7 @@ A `<valueSet>` element must contain **exactly one** of:
|
|
|
30
30
|
|
|
31
31
|
Including both in the same `<valueSet>` is a deployment error.
|
|
32
32
|
|
|
33
|
-
####
|
|
33
|
+
#### INCORRECT — both reference and inline definition:
|
|
34
34
|
|
|
35
35
|
```xml
|
|
36
36
|
<CustomField xmlns="http://soap.sforce.com/2006/04/metadata">
|
|
@@ -54,7 +54,7 @@ Including both in the same `<valueSet>` is a deployment error.
|
|
|
54
54
|
|
|
55
55
|
**Error:** `Value set must reference a value set name or define a value set, but not both.`
|
|
56
56
|
|
|
57
|
-
####
|
|
57
|
+
#### CORRECT — reference a Global Value Set:
|
|
58
58
|
|
|
59
59
|
```xml
|
|
60
60
|
<CustomField xmlns="http://soap.sforce.com/2006/04/metadata">
|
|
@@ -88,7 +88,7 @@ the name you put inside it differs.
|
|
|
88
88
|
> local project" warning) is expected org-storage display — keep local metadata on the bare name.
|
|
89
89
|
> Never append `__c` to a value-set name either.
|
|
90
90
|
|
|
91
|
-
####
|
|
91
|
+
#### CORRECT — reference a Standard Value Set (bare name, no suffix):
|
|
92
92
|
|
|
93
93
|
```xml
|
|
94
94
|
<CustomField xmlns="http://soap.sforce.com/2006/04/metadata">
|
|
@@ -126,7 +126,7 @@ A **dependent** picklist filters its available values based on the selected valu
|
|
|
126
126
|
**dependent** field via a `<controllingField>` element plus one `<valueSettings>` block
|
|
127
127
|
per (controlling value → dependent value) pair.
|
|
128
128
|
|
|
129
|
-
###
|
|
129
|
+
### Use the MODERN API 38.0+ form ONLY
|
|
130
130
|
|
|
131
131
|
| Form | Elements | Status |
|
|
132
132
|
|------|----------|--------|
|
|
@@ -136,7 +136,7 @@ per (controlling value → dependent value) pair.
|
|
|
136
136
|
Never emit the legacy `<picklist>`, `<picklistValues>`, or `<controllingFieldValues>`
|
|
137
137
|
tags. They are not valid against the modern Metadata API and will fail deployment.
|
|
138
138
|
|
|
139
|
-
###
|
|
139
|
+
### HARD RULE: both the controlling and dependent field must be `<restricted>true</restricted>`
|
|
140
140
|
|
|
141
141
|
A field dependency requires a fixed, admin-defined value set on **both** ends. **Always emit
|
|
142
142
|
`<restricted>true</restricted>` inside the `<valueSet>` of the controlling field AND the
|
|
@@ -186,7 +186,7 @@ Inside the dependent field's `<valueSet>`, in this order:
|
|
|
186
186
|
> EMEA→UK,Germany) you emit **one block for each (controllingValue, dependentValue) pair** — four
|
|
187
187
|
> pairs = four `<valueSettings>` blocks. And remember: both fields carry `<restricted>true</restricted>`.
|
|
188
188
|
|
|
189
|
-
###
|
|
189
|
+
### CORRECT — State dependent on Country (USA → California, Texas)
|
|
190
190
|
|
|
191
191
|
**Controlling field — `Country__c` (a plain restricted picklist):**
|
|
192
192
|
|
|
@@ -258,7 +258,7 @@ Inside the dependent field's `<valueSet>`, in this order:
|
|
|
258
258
|
> `<valueSettings>` block with that country's `<controllingFieldValue>` and
|
|
259
259
|
> `<valueName>California</valueName>`.
|
|
260
260
|
|
|
261
|
-
###
|
|
261
|
+
### INCORRECT — deprecated legacy form:
|
|
262
262
|
|
|
263
263
|
```xml
|
|
264
264
|
<CustomField xmlns="http://soap.sforce.com/2006/04/metadata">
|
|
@@ -282,7 +282,7 @@ legacy dependency elements are not valid in the modern `<valueSet>` structure.
|
|
|
282
282
|
|
|
283
283
|
## 3. Enhanced Value Attributes
|
|
284
284
|
|
|
285
|
-
###
|
|
285
|
+
### Value-name fidelity — do NOT underscore picklist value names
|
|
286
286
|
|
|
287
287
|
A **picklist value's `<fullName>` is NOT a field API name** and must NOT be transformed.
|
|
288
288
|
Use the value text **exactly as the user spelled it**, spaces and all. A value the user
|
|
@@ -315,7 +315,7 @@ Inline `<value>` entries (CustomValue subfields) support more than `<fullName>`,
|
|
|
315
315
|
|
|
316
316
|
These are independent of `<default>` and `<label>` and may be combined freely.
|
|
317
317
|
|
|
318
|
-
###
|
|
318
|
+
### CORRECT — Status picklist with colors and an inactive value
|
|
319
319
|
|
|
320
320
|
```xml
|
|
321
321
|
<CustomField xmlns="http://soap.sforce.com/2006/04/metadata">
|
|
@@ -367,7 +367,7 @@ The Metadata API rejects malformed picklist values at deploy time. Two common fa
|
|
|
367
367
|
Two `<value>` entries with the same `<fullName>` inside one `<valueSetDefinition>` are
|
|
368
368
|
rejected.
|
|
369
369
|
|
|
370
|
-
####
|
|
370
|
+
#### INCORRECT — duplicate value:
|
|
371
371
|
|
|
372
372
|
```xml
|
|
373
373
|
<valueSetDefinition>
|
|
@@ -398,7 +398,7 @@ The stricter "only alphanumerics and single underscores, no leading digit, no do
|
|
|
398
398
|
or trailing underscore" rule applies to the *field* `<fullName>` (the `__c`-suffixed
|
|
399
399
|
API name), not to picklist value fullNames.
|
|
400
400
|
|
|
401
|
-
####
|
|
401
|
+
#### INCORRECT — invalid value API name:
|
|
402
402
|
|
|
403
403
|
```xml
|
|
404
404
|
<value>
|
|
@@ -410,7 +410,7 @@ API name), not to picklist value fullNames.
|
|
|
410
410
|
|
|
411
411
|
**Error:** `Invalid fullName: must begin with a letter and use only alphanumeric characters and underscores`
|
|
412
412
|
|
|
413
|
-
####
|
|
413
|
+
#### CORRECT:
|
|
414
414
|
|
|
415
415
|
```xml
|
|
416
416
|
<value>
|
|
@@ -454,7 +454,7 @@ include a `<fullName>`** element — the record type's developer name (e.g. `<fu
|
|
|
454
454
|
matching the filename `Internal.recordType-meta.xml`. It's bare (no object prefix); the object
|
|
455
455
|
comes from the `objects/<Object>/` folder path.
|
|
456
456
|
|
|
457
|
-
###
|
|
457
|
+
### STEP 1 — Decide if this object needs a BusinessProcess (do this BEFORE writing files)
|
|
458
458
|
|
|
459
459
|
A record type on a **BusinessProcess-gated object — Opportunity, Lead, Case, or Solution —
|
|
460
460
|
will NOT deploy without a `<businessProcess>` reference**, even when it only filters a *custom*
|
|
@@ -472,7 +472,7 @@ developer name instead of generating a new one (confirm via the grounding MCP's
|
|
|
472
472
|
if available; otherwise generate a minimal one). For everything else, **do not invent a
|
|
473
473
|
BusinessProcess** — adding one to a custom-object record type is wrong.
|
|
474
474
|
|
|
475
|
-
####
|
|
475
|
+
#### CORRECT — Opportunity "Enterprise" record type, two deployable files
|
|
476
476
|
|
|
477
477
|
```xml
|
|
478
478
|
<!-- File 1: objects/Opportunity/businessProcesses/Enterprise_Sales_Process.businessProcess-meta.xml -->
|
|
@@ -519,7 +519,7 @@ BusinessProcess** — adding one to a custom-object record type is wrong.
|
|
|
519
519
|
</RecordType>
|
|
520
520
|
```
|
|
521
521
|
|
|
522
|
-
####
|
|
522
|
+
#### INCORRECT — BusinessProcess file emitted but NOT referenced (most common failure)
|
|
523
523
|
|
|
524
524
|
```xml
|
|
525
525
|
<!-- File 1 (businessProcesses/Enterprise_Sales_Process...) was generated correctly, BUT -->
|
|
@@ -571,7 +571,7 @@ RecordType (filters the field's values; references the BusinessProcess)
|
|
|
571
571
|
- For Opportunity/Lead/Case/Solution, the `<businessProcess>` must exist (same package or
|
|
572
572
|
already in the org) before the RecordType.
|
|
573
573
|
|
|
574
|
-
###
|
|
574
|
+
### UI-sync gotcha — values may not auto-display after API deploy
|
|
575
575
|
|
|
576
576
|
When `<picklistValues>` are loaded via the Metadata API, the values are correctly associated
|
|
577
577
|
under the hood, **but they may not automatically appear as "Selected Values" in the Record
|
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: platform-custom-report-type-generate
|
|
3
|
+
description: "Use this skill when users need to create, generate, or validate Salesforce Custom Report Type metadata. Trigger when users mention custom report types, report types, CRTs, reporting frameworks, cross-object reports, report builder data sources, or ask to expose fields for reporting across related objects. Also use when users mention primary and related objects for reports, inner vs outer joins in reports, report type categories, or encounter deployment errors for .reportType-meta.xml files. Do NOT trigger for: running, editing, or filtering existing reports; creating report folders, dashboards, or list views; or general reporting questions that don't involve authoring a .reportType-meta.xml file."
|
|
4
|
+
metadata:
|
|
5
|
+
version: "1.0"
|
|
6
|
+
minApiVersion: "51.0"
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Specification
|
|
10
|
+
|
|
11
|
+
# Salesforce Custom Report Type Metadata Knowledge
|
|
12
|
+
|
|
13
|
+
## Overview
|
|
14
|
+
Custom Report Types (CRTs) define the **data framework** for Salesforce reports. They specify a primary object, up to 3 related objects, the relationship (join) between them, and which fields are available in the report builder.
|
|
15
|
+
|
|
16
|
+
## Purpose
|
|
17
|
+
- Enable reporting across custom objects and custom relationships not covered by standard report types
|
|
18
|
+
- Curate a focused set of fields for report builders (including fields reached via lookup)
|
|
19
|
+
- Control inner/outer join behavior to include or exclude primary records without related records
|
|
20
|
+
|
|
21
|
+
## Configuration
|
|
22
|
+
|
|
23
|
+
**File extension:** `.reportType-meta.xml`. The file basename is the report type's developer name (e.g. `AccountsWithProjects.reportType-meta.xml`). Each CRT is a single file, not nested under an object folder.
|
|
24
|
+
|
|
25
|
+
### Key Elements
|
|
26
|
+
|
|
27
|
+
Top-level `<ReportType>` children:
|
|
28
|
+
|
|
29
|
+
| Element | Required | Notes |
|
|
30
|
+
|---------|----------|-------|
|
|
31
|
+
| `<fullName>` | Yes | API identifier; must match the file name. Letters, numbers, underscores; must begin with a letter; no spaces; no trailing underscore; no consecutive underscores |
|
|
32
|
+
| `<label>` | Yes | Human-friendly name shown in the report type picker |
|
|
33
|
+
| `<description>` | Recommended | State the business "why" — who uses this and what they learn |
|
|
34
|
+
| `<baseObject>` | Yes | API name of the primary object (e.g. `Account`, `Project__c`). Cannot be changed after initial creation. All objects, including custom and external, are supported (external objects from API 38.0+) |
|
|
35
|
+
| `<category>` | Recommended | Report builder category — see `references/category-values.md` |
|
|
36
|
+
| `<deployed>` | Yes | `true` to expose to users; `false` while building/iterating |
|
|
37
|
+
| `<join>` | Conditional | Adds a related object and its join behavior. Nest further `<join>` blocks for deeper relationships |
|
|
38
|
+
| `<sections>` | Recommended | Groups of columns available to the report type. Though not strictly required, a report without columns isn't useful |
|
|
39
|
+
|
|
40
|
+
`<sections>` (group of columns) sub-elements:
|
|
41
|
+
|
|
42
|
+
| Element | Required | Notes |
|
|
43
|
+
|---------|----------|-------|
|
|
44
|
+
| `<masterLabel>` | Yes | Section heading shown in the report builder |
|
|
45
|
+
| `<columns>` | Conditional | One per field exposed in the section |
|
|
46
|
+
|
|
47
|
+
`<columns>` (single field) sub-elements:
|
|
48
|
+
|
|
49
|
+
| Element | Required | Notes |
|
|
50
|
+
|---------|----------|-------|
|
|
51
|
+
| `<field>` | Yes | Field API name (or dotted lookup-traversal path) |
|
|
52
|
+
| `<table>` | Yes | The object the field belongs to — base object name or dotted relationship path |
|
|
53
|
+
| `<checkedByDefault>` | Yes | `true` if the column is selected by default in the report builder |
|
|
54
|
+
| `<displayNameOverride>` | No | Custom column label shown in the report builder, overriding the field's default label |
|
|
55
|
+
|
|
56
|
+
## Critical Rules (Read First)
|
|
57
|
+
|
|
58
|
+
### Rule 1: If `<fullName>` Is Present, It Must Match the File Name
|
|
59
|
+
In source format, `fullName` is inherited from `Metadata` and derived from the file name, so the `<fullName>` element is technically optional. The repo convention is to include it. **If you include `<fullName>`, its value must equal the file name (everything before `.reportType-meta.xml`) exactly — same characters, same casing, same underscores.**
|
|
60
|
+
|
|
61
|
+
**Wrong** — file name and `<fullName>` differ:
|
|
62
|
+
- File: `account_projects.reportType-meta.xml`
|
|
63
|
+
- `<fullName>AccountProjects</fullName>`
|
|
64
|
+
(Mismatch: file uses `account_projects`, fullName uses `AccountProjects`)
|
|
65
|
+
|
|
66
|
+
**Right** — file name and `<fullName>` are identical:
|
|
67
|
+
- File: `AccountProjects.reportType-meta.xml`
|
|
68
|
+
- `<fullName>AccountProjects</fullName>`
|
|
69
|
+
|
|
70
|
+
### Rule 2: Join Semantics — `outerJoin` Controls Inclusion
|
|
71
|
+
|
|
72
|
+
Each `<join>` block has an `<outerJoin>` element that determines which primary records appear in the report:
|
|
73
|
+
|
|
74
|
+
| `<outerJoin>` value | Behavior | Report Builder Label |
|
|
75
|
+
|---------------------|----------|----------------------|
|
|
76
|
+
| `false` | Inner join — only primary records that HAVE at least one related record | "Each 'A' record must have at least one related 'B' record" |
|
|
77
|
+
| `true` | Outer join — all primary records, with or without related records | "'A' records may or may not have related 'B' records" |
|
|
78
|
+
|
|
79
|
+
**Default when unspecified:** Use `true` (outer join) when the user wants to see all primary records regardless of children. Use `false` when the report only makes sense if children exist.
|
|
80
|
+
|
|
81
|
+
### Rule 3: Each Object Needs Its Own `<sections>` Block
|
|
82
|
+
|
|
83
|
+
Every object in the CRT (primary + each joined object) must have a corresponding `<sections>` block that lists the fields exposed for reporting. Without a section for an object, none of its fields appear in the report builder.
|
|
84
|
+
|
|
85
|
+
- `<masterLabel>` on each section is the section heading in the report builder
|
|
86
|
+
- `<columns>` entries list the fields — each with a `<field>` (API name) and `<table>` (object API name)
|
|
87
|
+
- For fields reached via lookup, use the relationship path in `<field>` (e.g. `Owner.Name` with `<table>` set to the owning object)
|
|
88
|
+
|
|
89
|
+
### Rule 4: Field API Names, Not Labels
|
|
90
|
+
|
|
91
|
+
Use exact API names for fields: standard fields use their defined names (`Name`, `CreatedDate`, `OwnerId`), custom fields use `Field__c`. Custom objects must include `__c`.
|
|
92
|
+
|
|
93
|
+
**Wrong:**
|
|
94
|
+
- `<field>Account Name</field>`
|
|
95
|
+
|
|
96
|
+
**Right:**
|
|
97
|
+
- `<field>Name</field>` with `<table>Account</table>`
|
|
98
|
+
|
|
99
|
+
### Rule 5: Relationship Path for Joined Objects
|
|
100
|
+
|
|
101
|
+
When adding a `<join>`, the `<relationship>` element must use the **child relationship name** as defined on the lookup/master-detail field pointing from the child object to the parent. For custom relationships, this typically ends in `__r`.
|
|
102
|
+
|
|
103
|
+
**Wrong:**
|
|
104
|
+
- `<relationship>Project</relationship>` (for a custom child relationship)
|
|
105
|
+
|
|
106
|
+
**Right:**
|
|
107
|
+
- `<relationship>Projects__r</relationship>` (child relationship name)
|
|
108
|
+
- `<relationship>Contacts</relationship>` (standard, non-custom child relationship)
|
|
109
|
+
|
|
110
|
+
### Rule 6: Maximum 4 Objects Total in a Join Chain
|
|
111
|
+
|
|
112
|
+
A single CRT can join a maximum of **four objects total** (the base object + up to 3 additional objects via nested `<join>` blocks).
|
|
113
|
+
|
|
114
|
+
### Rule 7: No Inner Join After an Outer Join
|
|
115
|
+
|
|
116
|
+
Once the join chain contains an outer join (`<outerJoin>true</outerJoin>`), every subsequent nested join must also be an outer join. An inner join that follows an outer join earlier in the sequence is not allowed.
|
|
117
|
+
|
|
118
|
+
**Wrong:**
|
|
119
|
+
```xml
|
|
120
|
+
<join>
|
|
121
|
+
<outerJoin>true</outerJoin> <!-- outer join first -->
|
|
122
|
+
<relationship>Contacts</relationship>
|
|
123
|
+
<join>
|
|
124
|
+
<outerJoin>false</outerJoin> <!-- WRONG: inner join after outer -->
|
|
125
|
+
<relationship>Assets</relationship>
|
|
126
|
+
</join>
|
|
127
|
+
</join>
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
**Right:**
|
|
131
|
+
```xml
|
|
132
|
+
<join>
|
|
133
|
+
<outerJoin>true</outerJoin>
|
|
134
|
+
<relationship>Contacts</relationship>
|
|
135
|
+
<join>
|
|
136
|
+
<outerJoin>true</outerJoin> <!-- outer stays outer -->
|
|
137
|
+
<relationship>Assets</relationship>
|
|
138
|
+
</join>
|
|
139
|
+
</join>
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
### Rule 8: `<table>` for Joined Objects Uses Dotted Path
|
|
143
|
+
|
|
144
|
+
In `<sections>`, the `<table>` element identifies which object in the join chain each column belongs to. For the base object, use the object name directly (e.g. `Account`). For joined objects, use the **dotted relationship path** from the base object.
|
|
145
|
+
|
|
146
|
+
| Object in chain | `<table>` value |
|
|
147
|
+
|-----------------|-----------------|
|
|
148
|
+
| Base (Account) | `Account` |
|
|
149
|
+
| First join (Account → Contacts) | `Account.Contacts` |
|
|
150
|
+
| Nested join (Account → Contacts → Assets) | `Account.Contacts.Assets` |
|
|
151
|
+
|
|
152
|
+
### Rule 9: Field Paths Can Traverse Lookups
|
|
153
|
+
|
|
154
|
+
`<field>` values may reference fields reached via lookup relationships using dot notation — for example `Owner.Email` (owner User's email) or `ReportsTo.CreatedBy.Contact.Owner.MobilePhone`. The `<table>` must still be the object that owns the starting field.
|
|
155
|
+
|
|
156
|
+
### Rule 10: Historical Trending Fields Use `_hst` Suffix
|
|
157
|
+
|
|
158
|
+
For a field with `trackTrending=true`, the API name in `<field>` and `<table>` uses the `_hst` suffix:
|
|
159
|
+
|
|
160
|
+
```xml
|
|
161
|
+
<columns>
|
|
162
|
+
<checkedByDefault>false</checkedByDefault>
|
|
163
|
+
<field>Field2__c_hst</field>
|
|
164
|
+
<table>CustomTrendedObject__c.CustomTrendedObject__c_hst</table>
|
|
165
|
+
</columns>
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
### Rule 11: Primary Object Cannot Be Changed After Deployment
|
|
169
|
+
|
|
170
|
+
Once deployed, the `<baseObject>` of a CRT is locked. To change the primary object, create a new CRT and retire the old one.
|
|
171
|
+
|
|
172
|
+
### Rule 12: `autogenerated` Is Reserved for Historical Trending
|
|
173
|
+
|
|
174
|
+
The `<autogenerated>` element (API 29.0+) marks CRTs that Salesforce created automatically when historical trending was enabled on an object. Do not set this manually on hand-authored CRTs.
|
|
175
|
+
|
|
176
|
+
## Generation Workflow
|
|
177
|
+
|
|
178
|
+
### Step 1: Gather Requirements
|
|
179
|
+
- Primary object API name (e.g. `Account`, `Project__c`)
|
|
180
|
+
- Related objects and the relationship between each (which has the lookup/master-detail to which)
|
|
181
|
+
- For each relationship: inner join (children required) or outer join (children optional)?
|
|
182
|
+
- Which fields to expose per object — aim for task-relevant, not the full field list
|
|
183
|
+
- Audience and category — where should this appear in the report builder picker?
|
|
184
|
+
- Whether this ships as `deployed=true` now or stays `deployed=false` during iteration
|
|
185
|
+
|
|
186
|
+
### Step 2: Examine Existing Examples
|
|
187
|
+
- Look in the project for in-project CRT patterns
|
|
188
|
+
- If existing report types have been retrieved from an org, compare against those structures
|
|
189
|
+
|
|
190
|
+
### Step 3: Write the Specification
|
|
191
|
+
Document before authoring:
|
|
192
|
+
- `fullName` and `label`
|
|
193
|
+
- `baseObject`
|
|
194
|
+
- Category and `deployed` state
|
|
195
|
+
- Join chain: for each related object — relationship name, outer vs inner join
|
|
196
|
+
- Section layout: one section per object, ordered list of fields
|
|
197
|
+
- Acceptance criteria: which records should appear when the report runs, which fields are available in the builder
|
|
198
|
+
|
|
199
|
+
### Step 4: Author the Metadata File
|
|
200
|
+
|
|
201
|
+
Start from the closest example in `examples/` and adapt it to the user's scenario:
|
|
202
|
+
|
|
203
|
+
- Primary object only (no joins) → `examples/AccountsWithIndustry.reportType-meta.xml`
|
|
204
|
+
- Outer join (primary records included even without children) → `examples/AccountsWithProjects.reportType-meta.xml`
|
|
205
|
+
- Nested inner join (every level requires children) → `examples/AccountProjectsWithTasks.reportType-meta.xml`
|
|
206
|
+
|
|
207
|
+
Name the file `<DeveloperName>.reportType-meta.xml`.
|
|
208
|
+
|
|
209
|
+
### Step 5: Validate
|
|
210
|
+
- Well-formed XML with correct namespace (`xmlns="http://soap.sforce.com/2006/04/metadata"`)
|
|
211
|
+
- File name (without `.reportType-meta.xml`) matches `<fullName>` when `<fullName>` is included
|
|
212
|
+
- `<baseObject>` is a valid API name and the object is deployed
|
|
213
|
+
- Every `<relationship>` uses the correct child relationship name (`__r` suffix for custom)
|
|
214
|
+
- Each object referenced in `<sections>` is part of the CRT (primary or joined)
|
|
215
|
+
- All `<field>` references exist on the parent `<table>` and use API names (not labels)
|
|
216
|
+
- `<category>` is a valid Salesforce category value
|
|
217
|
+
- `<deployed>` is `true` if users need to access the CRT immediately
|
|
218
|
+
|
|
219
|
+
## Reference File Index
|
|
220
|
+
|
|
221
|
+
| File | When to read |
|
|
222
|
+
|------|--------------|
|
|
223
|
+
| `examples/AccountsWithIndustry.reportType-meta.xml` | Step 2 / Step 4 — primary-object-only template |
|
|
224
|
+
| `examples/AccountsWithProjects.reportType-meta.xml` | Step 2 / Step 4 — outer-join template (primary included even without children) |
|
|
225
|
+
| `examples/AccountProjectsWithTasks.reportType-meta.xml` | Step 2 / Step 4 — nested inner-join template (every level requires children) |
|
|
226
|
+
| `references/category-values.md` | Step 3 — to choose a valid `<category>` value from the `ReportTypeCategory` enum |
|
|
227
|
+
| `references/errors-and-troubleshooting.md` | When fields don't appear in the report builder or join requirements conflict |
|
|
228
|
+
|
|
229
|
+
## Verification Checklist
|
|
230
|
+
|
|
231
|
+
### Universal Checks
|
|
232
|
+
- [ ] File extension is `.reportType-meta.xml`
|
|
233
|
+
- [ ] File basename satisfies the developer-name rules (begins with a letter, only letters/numbers/underscores, no spaces, no trailing underscore, no consecutive underscores)
|
|
234
|
+
- [ ] If `<fullName>` is included, it matches the file basename exactly (same characters, casing, and underscores)
|
|
235
|
+
- [ ] `<label>` is human-readable and under 40 characters
|
|
236
|
+
- [ ] `<description>` explains the business purpose
|
|
237
|
+
- [ ] `<baseObject>` uses a valid API name and that object is deployed
|
|
238
|
+
- [ ] `<category>` is a valid `ReportTypeCategory` enum value
|
|
239
|
+
- [ ] `<deployed>` is set appropriately (`true` for user access, `false` for in-progress iteration)
|
|
240
|
+
- [ ] `<autogenerated>` is NOT set manually (reserved for historical-trending CRTs)
|
|
241
|
+
|
|
242
|
+
### Join Checks
|
|
243
|
+
- [ ] Each `<join>` uses the correct child **relationship name** (not the lookup field API name)
|
|
244
|
+
- [ ] Custom relationships use `__r` suffix
|
|
245
|
+
- [ ] `<outerJoin>` is set intentionally: `true` = optional children, `false` = required children
|
|
246
|
+
- [ ] No inner join (`<outerJoin>false</outerJoin>`) appears after an outer join earlier in the sequence
|
|
247
|
+
- [ ] Total object count (base + joins, including nested) is 4 or fewer
|
|
248
|
+
|
|
249
|
+
### Section Checks
|
|
250
|
+
- [ ] Every object in the CRT has a corresponding `<sections>` block
|
|
251
|
+
- [ ] `<masterLabel>` on each section is descriptive
|
|
252
|
+
- [ ] Every `<columns>` has both `<field>` (API name) and `<table>` (object API name or dotted path)
|
|
253
|
+
- [ ] `<checkedByDefault>` is set for each column
|
|
254
|
+
- [ ] `<table>` for base object is the object API name (e.g. `Account`)
|
|
255
|
+
- [ ] `<table>` for joined objects uses the dotted relationship path (e.g. `Account.Projects__r`, `Account.Projects__r.Tasks__r`)
|
|
256
|
+
- [ ] Field references use API names (not labels); custom fields use `__c`
|
|
257
|
+
- [ ] Lookup traversal fields use dot notation (e.g. `Owner.Email`) with `<table>` set to the object owning the starting field
|
|
258
|
+
- [ ] Historical trending fields use `_hst` suffix in both `<field>` and `<table>` when applicable
|
|
259
|
+
- [ ] No duplicate fields within a section
|