diff --git a/.github/workflows/release-skills.yml b/.github/workflows/release-skills.yml index 2ec98b0..aaf9319 100644 --- a/.github/workflows/release-skills.yml +++ b/.github/workflows/release-skills.yml @@ -58,29 +58,24 @@ jobs: output-file: "CHANGELOG.md" git-push: "false" - - name: Report validate-skills status on release commit + - name: Push release commit to main if: ${{ steps.changelog.outputs.skipped == 'false' }} env: GH_TOKEN: ${{ secrets.IDEE_GH_TOKEN }} run: | SHA=$(git rev-parse HEAD) + TEMP_BRANCH="release-$(date +%s)" + # Push commit to a temp branch so the SHA exists on the remote + git push origin "$SHA:refs/heads/$TEMP_BRANCH" + # Report the required status check on the now-visible commit gh api "repos/${{ github.repository }}/statuses/$SHA" \ -f state=success \ -f context=validate-skills \ -f description="Validated in release workflow" - - - name: Verify tag does not already exist - if: ${{ steps.changelog.outputs.skipped == 'false' }} - run: | - TAG="${{ steps.changelog.outputs.tag }}" - if git ls-remote --tags origin | grep -q "refs/tags/$TAG$"; then - echo "::error::Tag $TAG already exists on remote. Delete it first if re-releasing: git push --delete origin $TAG" - exit 1 - fi - - - name: Push release commit and tag - if: ${{ steps.changelog.outputs.skipped == 'false' }} - run: git push origin main --follow-tags + # Push to main (status check is now satisfied) + git push origin main --follow-tags + # Clean up temp branch + git push origin --delete "$TEMP_BRANCH" || true - name: Create Github Release id: release diff --git a/CHANGELOG.md b/CHANGELOG.md index e312649..5e70203 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,18 @@ +# [1.3.0](https://github.com/forcedotcom/afv-library/compare/1.2.0...1.3.0) (2026-03-23) + + +### Bug Fixes + +* resolve release workflow branch protection failure @W-21658353@ ([#80](https://github.com/forcedotcom/afv-library/issues/80)) ([5d3f085](https://github.com/forcedotcom/afv-library/commit/5d3f085ad67f10be3a3a20d7dc0142a000dbd957)) + + +### Features + +* Add switching-org skill @W-21436488@ ([#74](https://github.com/forcedotcom/afv-library/issues/74)) ([5c40e3b](https://github.com/forcedotcom/afv-library/commit/5c40e3b63ed81e9559a4d64c82f112a94c5c2566)) +* syncing webapp skills sync to afv @W-21338965@ ([#57](https://github.com/forcedotcom/afv-library/issues/57)) ([9ba0641](https://github.com/forcedotcom/afv-library/commit/9ba064174a714e487c683b986c3c6e08d478b784)) + + + # [1.2.0](https://github.com/forcedotcom/afv-library/compare/1.1.0...1.2.0) (2026-03-19) diff --git a/package.json b/package.json index 1ae5e1a..9b4e419 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@salesforce/afv-skills", - "version": "1.2.0", + "version": "1.3.0", "description": "Salesforce skills for Agentforce Vibes", "license": "CC-BY-NC-4.0", "files": [ diff --git a/rules/a4v-expert-global-rule.md b/rules/a4v-expert-global-rule.md index 7112f61..a636538 100644 --- a/rules/a4v-expert-global-rule.md +++ b/rules/a4v-expert-global-rule.md @@ -1,42 +1,88 @@ # Rule: Salesforce Metadata Generation +## Objective +Enforce: **skill load -> API context -> file generation** for all Salesforce metadata. + ## Constraints -1. **Never write** without both: metadata type skill loaded AND context tools from `salesforce-api-context` MCP server called for that type. -2. **One type at a time** - finish one type before starting the next -3. **One type per API call** - do not batch types when calling MCP tools -4. **Child types need their own context** - if adding any child metadata inside a parent metadata's file, treat the child metadata seperately; don't rely on the parent's schema for creating child metadata -5. **Max one clarifying question** before starting +1. **Never write** without a loaded metadata type skill for that type. +2. **One type at a time** - complete the full cycle for the current type before moving to the next type. +3. **Always attempt `salesforce-api-context` MCP** for each type before writing; if it is unavailable after a real attempt, proceed with the loaded skill only. +4. **Child types need their own API context response** - if adding child metadata inside a parent metadata file, load the child metadata skill and use `salesforce-api-context` MCP for each child type separately; do not rely on the parent's schema or API context response for child metadata creation. The same fallback in constraint 3 applies. +5. **Max one clarifying question** before starting. +6. **Do not call `execute_metadata_action` unless a skill instructs you to do so.** -## Workflow +## Skill Selection -### Step 1: Metadata Loop - Execute for Each Type -For each type, execute loop below +- Search available skills and load the best-matching app-level skill first when the request asks for a Lightning app, end-to-end solution, or a business app spanning multiple metadata types. +- Search available skills and load the best-matching per-type metadata skill first when the request targets individual metadata components. + +## Initial Gate + +Never create files or generate metadata before completing skill selection. + +1. Determine whether the request is app-level or metadata-type-level. +2. Search available skills for the request and identify the best-matching candidate skill. +3. If the request is app-level, load the best-matching app-level skill by reading its contents and use it to identify metadata types and dependency order. +4. If the request is metadata-type-level, identify the target metadata type and the best-matching per-type metadata skill for that type. Do not treat skill selection as the per-type skill-load step. +5. Confirm skill selection with: + `intent= selected_skill= skill_selection=complete|pending` +6. Set `skill_selection=complete` only after the exact selected skill name has been identified and recorded. +7. Print this exact skill-selection status line in the chat before proceeding. + +Do not continue until `skill_selection=complete` and `selected_skill=` are recorded. + +## Per-Type Loop (a-e) + +For each metadata type in scope, whether identified by an app-level skill or requested directly, execute steps a through e below one metadata type at a time. Do not create or modify files for the current metadata type, and do not move to the next metadata type, until steps a through e are complete. **a. Load Skill** -- Load the metadata type skill once (not per record) +- Search available skills for the best-matching skill for the current metadata type and load it by reading its SKILL.md. +- Record `selected_skill=` for the current metadata type before proceeding. +- Load once per type, not per record. +- If no skill exists after a real search, stop and ask for guidance instead of writing without a skill. -**b. Get entity context** -- Use these tools from `salesforce-api-context` MCP server for entity context. - - `get_metadata_type_sections` - - `get_metadata_type_context` - - `get_metadata_type_fields` - - `get_metadata_type_fields_properties` - - `search_metadata_types` +**b. Use `salesforce-api-context` MCP** +- Use one or more of these tools as required: + - `get_metadata_type_sections` + - `get_metadata_type_context` + - `get_metadata_type_fields` + - `get_metadata_type_fields_properties` + - `search_metadata_types` +- Attempt API context for every type before writing. +- Record which tools were called for the current metadata type before proceeding. +- If API context is unavailable after a real attempt, record that state and continue with the loaded skill only. +- Treat templates, generators, pipelines, and CLI bootstraps as implementation aids, not as replacements for this gate. +**c. Pre-Write Gate** +- Before EVERY write: confirm `selected_skill=` is recorded and that skill is loaded for this type. +- Before EVERY write: confirm `mcp_tools=` is recorded for this type, or confirm `mcp=unavailable` after a real attempt. +- If `selected_skill=none` or the skill is missing -> stop. +- If `mcp_tools=none` and `mcp` is not `unavailable` -> stop and call MCP now. -### Step 2. Verify deployment -```bash -sf project deploy start --dry-run -d "force-app/main/default" --target-org --test-level NoTestRun --wait 10 --json -``` -On failure: attempt to fix the errors and re-run, retrying up to a maximum of 3 times until it succeeds. +**d. Generate Files** +- Use skill constraints + API context when available. +- Use skill constraints only when API context was unavailable after a real attempt. +- Generate all records for this type now. +**e. Checkpoint** +- Record: + `type= selected_skill= skill=complete|pending mcp=complete|pending|unavailable mcp_tools=` +- Skill loaded? API context called or unavailable after a real attempt? All files written? +- Only proceed to the next type when all are true. ## Anti-Patterns | Don't | Why | Do | |-------|-----|-----| -| Reload skill per record | Wastes tokens | Load once per type | -| Skip metadata skills | Missing platform constraints | Load skill for every type | -| Ask 3+ questions | Token waste | Max 1 question | -| Batch types in calls to MCP tools | Violates constraint | One type per call | \ No newline at end of file +| Never write without loading the metadata skill | Missing platform constraints | Search for and load the skill before any write | +| Never mark `skill_selection=complete` without `selected_skill=` | Fake gate completion | Record the exact selected skill before continuing | +| Never treat skill selection as skill loading | Fake gate completion | Perform the actual per-type skill load in step a | +| Never skip the Initial Gate | Sequence breach | Complete skill selection before any generation | +| Never reload a skill per record | Wastes tokens | Load once per type | +| Never skip the API context attempt for any type | No schema for those types | Attempt API context for EVERY type | +| Never write using API context alone without a loaded skill | Missing platform constraints | Stop and ask for guidance when no skill exists | +| Never write without recorded `mcp_tools` or `mcp=unavailable` | No evidence of MCP gate completion | Record MCP tool usage before any write | +| Never ask more than 1 clarifying question | Token waste | Max 1 question | +| Never skip any gate in the loop (skill load, API context, pre-write, checkpoint) | Wrong artifacts | Follow all mandatory gates in the loop (a-e) | +| Never write with a missing checkpoint | Aware violation | Stop and complete missing step | diff --git a/samples/native-mobile-rental-tenant-app/force-app/main/default/digitalExperiences/experiencecontainer/rentalApp/experience__camaAppMetadata/appMetadata/content.json b/samples/native-mobile-rental-tenant-app/force-app/main/default/digitalExperiences/experiencecontainer/rentalApp/experience__camaAppMetadata/appMetadata/content.json index e60f664..3875791 100644 --- a/samples/native-mobile-rental-tenant-app/force-app/main/default/digitalExperiences/experiencecontainer/rentalApp/experience__camaAppMetadata/appMetadata/content.json +++ b/samples/native-mobile-rental-tenant-app/force-app/main/default/digitalExperiences/experiencecontainer/rentalApp/experience__camaAppMetadata/appMetadata/content.json @@ -2,9 +2,9 @@ "type": "experience__camaAppMetadata", "title": "App Metadata", "contentBody": { + "version": "1.0.0", "name": "Homestead", "description": "Mobile application for managing property rentals, tenant information, lease agreements, and maintenance requests.", - "version": "1.0.0", "url": "http://login.test1.pc-rnd.salesforce.com/", "templateID": "1", "tabs": [ @@ -12,30 +12,33 @@ "id": "home", "label": "Home", "icon": "house.fill", - "screen": "homeScreen" + "screenAPIName": "uem_homesteadHome" }, { - "id": "tenants", - "label": "Tenants", - "icon": "person.2.fill", - "screen": "tenantsScreen" - }, - { - "id": "properties", - "label": "Properties", - "icon": "building.2.fill", - "screen": "propertiesScreen" + "id": "calendar", + "label": "Calendar", + "icon": "calendar", + "screenAPIName": "calendar" } ], "toolbarActions": { "notifications": false, - "search": false, - "agentforce": false + "search": false }, "theme": { - "accentColor": "#9400D3", - "primaryColor": "#000000", - "secondaryColor": "#B3B3B3" + "colors": { + "accent1": "#7526E3", + "accent2": "#7526E3", + "accentContainer1": "#7526E3", + "accentContainer2": "#1F1A30", + "onSurface1": "#181818", + "onSurface2": "#444444", + "onSurface3": "#747474" + }, + "cornerRadius": { + "radiusBorderCircle": "12" + } } - } + }, + "urlName": "app-metadata" } diff --git a/samples/native-mobile-rental-tenant-app/force-app/main/default/digitalExperiences/experiencecontainer/rentalApp/experience__camaBuildMetadata/buildMetadata/content.json b/samples/native-mobile-rental-tenant-app/force-app/main/default/digitalExperiences/experiencecontainer/rentalApp/experience__camaBuildMetadata/buildMetadata/content.json index 86f0450..835446d 100644 --- a/samples/native-mobile-rental-tenant-app/force-app/main/default/digitalExperiences/experiencecontainer/rentalApp/experience__camaBuildMetadata/buildMetadata/content.json +++ b/samples/native-mobile-rental-tenant-app/force-app/main/default/digitalExperiences/experiencecontainer/rentalApp/experience__camaBuildMetadata/buildMetadata/content.json @@ -3,6 +3,7 @@ "title": "Build Metadata", "contentBody": { "BiometricOptIn": false, - "NotificationOptIn": false - } + "NotificationOptIn": true + }, + "urlName": "build-metadata" } diff --git a/samples/native-mobile-rental-tenant-app/force-app/main/default/digitalExperiences/experiencecontainer/rentalApp/experience__camaECDefinition/rentalApp/_meta.json b/samples/native-mobile-rental-tenant-app/force-app/main/default/digitalExperiences/experiencecontainer/rentalApp/experience__camaECDefinition/rentalApp/_meta.json deleted file mode 100644 index b04fbca..0000000 --- a/samples/native-mobile-rental-tenant-app/force-app/main/default/digitalExperiences/experiencecontainer/rentalApp/experience__camaECDefinition/rentalApp/_meta.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "apiName": "rentalApp", - "type": "experience__camaECDefinition", - "path": "rentalApp" -} diff --git a/samples/native-mobile-rental-tenant-app/force-app/main/default/digitalExperiences/experiencecontainer/rentalApp/experience__camaECDefinition/rentalApp/content.json b/samples/native-mobile-rental-tenant-app/force-app/main/default/digitalExperiences/experiencecontainer/rentalApp/experience__camaECDefinition/rentalApp/content.json deleted file mode 100644 index 3cb236c..0000000 --- a/samples/native-mobile-rental-tenant-app/force-app/main/default/digitalExperiences/experiencecontainer/rentalApp/experience__camaECDefinition/rentalApp/content.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "type": "experience__camaECDefinition", - "title": "CAMA EC Definition", - "contentBody": {} -} diff --git a/samples/native-mobile-rental-tenant-app/force-app/main/default/digitalExperiences/experiencecontainer/rentalApp/experience__camaScreen/calendar/_meta.json b/samples/native-mobile-rental-tenant-app/force-app/main/default/digitalExperiences/experiencecontainer/rentalApp/experience__camaScreen/calendar/_meta.json new file mode 100644 index 0000000..a1fdbb0 --- /dev/null +++ b/samples/native-mobile-rental-tenant-app/force-app/main/default/digitalExperiences/experiencecontainer/rentalApp/experience__camaScreen/calendar/_meta.json @@ -0,0 +1,5 @@ +{ + "apiName": "calendar", + "type": "experience__camaScreen", + "path": "calendar" +} diff --git a/samples/native-mobile-rental-tenant-app/force-app/main/default/digitalExperiences/experiencecontainer/rentalApp/experience__camaScreen/calendar/content.json b/samples/native-mobile-rental-tenant-app/force-app/main/default/digitalExperiences/experiencecontainer/rentalApp/experience__camaScreen/calendar/content.json new file mode 100644 index 0000000..9c570ea --- /dev/null +++ b/samples/native-mobile-rental-tenant-app/force-app/main/default/digitalExperiences/experiencecontainer/rentalApp/experience__camaScreen/calendar/content.json @@ -0,0 +1,26 @@ +{ + "type": "experience__camaScreen", + "title": "Calendar", + "contentBody": { + "view": { + "definition": "calendar/root", + "properties": {}, + "regions": { + "components": { + "name": "components", + "components": [ + { + "definition": "calendar/home", + "properties": {}, + "regions": {} + } + ] + } + } + }, + "target": "native__calendar", + "apiName": "calendar", + "id": "calendar-home-001" + }, + "urlName": "calendar" +} diff --git a/samples/native-mobile-rental-tenant-app/force-app/main/default/digitalExperiences/experiencecontainer/rentalApp/experience__camaScreen/home/_meta.json b/samples/native-mobile-rental-tenant-app/force-app/main/default/digitalExperiences/experiencecontainer/rentalApp/experience__camaScreen/home/_meta.json new file mode 100644 index 0000000..de3486a --- /dev/null +++ b/samples/native-mobile-rental-tenant-app/force-app/main/default/digitalExperiences/experiencecontainer/rentalApp/experience__camaScreen/home/_meta.json @@ -0,0 +1,5 @@ +{ + "apiName": "home", + "type": "experience__camaScreen", + "path": "home" +} diff --git a/samples/native-mobile-rental-tenant-app/force-app/main/default/digitalExperiences/experiencecontainer/rentalApp/experience__camaScreen/home/content.json b/samples/native-mobile-rental-tenant-app/force-app/main/default/digitalExperiences/experiencecontainer/rentalApp/experience__camaScreen/home/content.json new file mode 100644 index 0000000..ff2da6b --- /dev/null +++ b/samples/native-mobile-rental-tenant-app/force-app/main/default/digitalExperiences/experiencecontainer/rentalApp/experience__camaScreen/home/content.json @@ -0,0 +1,742 @@ +{ + "type": "experience__camaScreen", + "title": "Home", + "contentBody": { + "view": { + "definition": "builder/screen", + "name": "Tenant App", + "properties": {}, + "regions": { + "components": { + "name": "components", + "components": [ + { + "definition": "ui/container", + "properties": { + "padding": "0", + "backgroundColor": "$colors.accentContainer2", + "gap": "$spacing.spacing4" + }, + "regions": { + "components": { + "name": "components", + "components": [ + { + "definition": "ui/column", + "properties": { + "padding": "$spacing.spacing4", + "gap": "$spacing.spacing4" + }, + "regions": { + "components": { + "name": "components", + "components": [ + { + "definition": "ui/box", + "properties": { + "padding": { + "top": "$spacing.spacing4" + } + }, + "regions": { + "components": { + "name": "components", + "components": [ + { + "definition": "ui/text", + "properties": { + "text": "Good evening, Maria", + "style": "titlesFontScale4Regular", + "color": "$colors.onSurfaceInverse1" + }, + "regions": {} + } + ] + } + } + } + ] + } + } + }, + { + "definition": "ui/card", + "properties": { + "backgroundColor": "$colors.surfaceContainer1", + "padding": "$spacing.spacing4", + "borderColor": null + }, + "regions": { + "components": { + "name": "components", + "components": [ + { + "definition": "ui/column", + "properties": { + "gap": "$spacing.spacing2" + }, + "regions": { + "components": { + "name": "components", + "components": [ + { + "definition": "ui/row", + "properties": { + "gap": "spaceBetween" + }, + "regions": { + "components": { + "name": "components", + "components": [ + { + "definition": "ui/text", + "properties": { + "text": "Latest news", + "style": "titlesFontScale3Regular", + "color": "$colors.onSurface2" + }, + "regions": {} + }, + { + "definition": "ui/text", + "properties": { + "text": "See all", + "style": "bodyFontScale1Regular", + "color": "$colors.accent1" + }, + "regions": {} + } + ] + } + } + }, + { + "definition": "ui/horizontalScroll", + "properties": { + "gap": "$spacing.spacing4" + }, + "regions": { + "components": { + "name": "components", + "components": [ + { + "definition": "ui/column", + "properties": { + "gap": "$spacing.spacing2", + "alignment": "start" + }, + "regions": { + "components": { + "name": "components", + "components": [ + { + "definition": "ui/box", + "properties": { + "radius": "$radius.radiusBorder2", + "width": "fill" + }, + "regions": { + "components": { + "name": "components", + "components": [ + { + "definition": "ui/image", + "properties": { + "source": { + "url": "https://picsum.photos/seed/community/220/140" + }, + "alternativeText": "Community Park", + "width": "220", + "height": "140" + }, + "regions": {} + } + ] + } + } + }, + { + "definition": "ui/text", + "properties": { + "text": "Community Park opens", + "style": "bodyFontScale1Semibold", + "color": "$colors.onSurface1", + "textAlign": "start" + }, + "regions": {} + }, + { + "definition": "ui/text", + "properties": { + "text": "Mar 1, 2026", + "style": "bodyFontScaleNeg1Regular", + "color": "$colors.onSurface2", + "textAlign": "start" + }, + "regions": {} + } + ] + } + } + }, + { + "definition": "ui/column", + "properties": { + "gap": "$spacing.spacing2", + "alignment": "start" + }, + "regions": { + "components": { + "name": "components", + "components": [ + { + "definition": "ui/box", + "properties": { + "radius": "$radius.radiusBorder2", + "width": "fill" + }, + "regions": { + "components": { + "name": "components", + "components": [ + { + "definition": "ui/image", + "properties": { + "source": { + "url": "https://picsum.photos/seed/treadmills/220/140" + }, + "alternativeText": "New treadmills", + "width": "220", + "height": "140" + }, + "regions": {} + } + ] + } + } + }, + { + "definition": "ui/text", + "properties": { + "text": "New treadmills!", + "style": "bodyFontScale1Semibold", + "color": "$colors.onSurface1", + "textAlign": "start" + }, + "regions": {} + }, + { + "definition": "ui/text", + "properties": { + "text": "Feb 12, 2026", + "style": "bodyFontScaleNeg1Regular", + "color": "$colors.onSurface2", + "textAlign": "start" + }, + "regions": {} + } + ] + } + } + }, + { + "definition": "ui/column", + "properties": { + "gap": "$spacing.spacing2", + "alignment": "start" + }, + "regions": { + "components": { + "name": "components", + "components": [ + { + "definition": "ui/box", + "properties": { + "radius": "$radius.radiusBorder2", + "width": "fill" + }, + "regions": { + "components": { + "name": "components", + "components": [ + { + "definition": "ui/image", + "properties": { + "source": { + "url": "https://picsum.photos/seed/pool/220/140" + }, + "alternativeText": "Pool hours extended", + "width": "220", + "height": "140" + }, + "regions": {} + } + ] + } + } + }, + { + "definition": "ui/text", + "properties": { + "text": "Pool hours extended", + "style": "bodyFontScale1Semibold", + "color": "$colors.onSurface1", + "textAlign": "start" + }, + "regions": {} + }, + { + "definition": "ui/text", + "properties": { + "text": "Feb 28, 2026", + "style": "bodyFontScaleNeg1Regular", + "color": "$colors.onSurface2", + "textAlign": "start" + }, + "regions": {} + } + ] + } + } + } + ] + } + } + }, + { + "definition": "ui/card", + "properties": { + "borderColor": "$colors.border1", + "padding": "$spacing.spacing4" + }, + "regions": { + "components": { + "name": "components", + "components": [ + { + "definition": "ui/row", + "properties": { + "gap": "$spacing.spacing10", + "alignment": "center" + }, + "regions": { + "components": { + "name": "components", + "components": [ + { + "definition": "ui/progressRing", + "properties": { + "value": 85, + "size": "large", + "showProgressText": true + }, + "regions": {} + }, + { + "definition": "ui/column", + "properties": { + "gap": "$spacing.spacing2", + "alignment": "start" + }, + "regions": { + "components": { + "name": "components", + "components": [ + { + "definition": "ui/text", + "properties": { + "text": "Lease progress", + "style": "titlesFontScale3Semibold", + "color": "$colors.onSurface1", + "textAlign": "start" + }, + "regions": {} + }, + { + "definition": "ui/text", + "properties": { + "text": "Renewal period", + "style": "bodyFontScaleBaseRegular", + "color": "$colors.onSurface2" + }, + "regions": {} + }, + { + "definition": "ui/text", + "properties": { + "text": "ends Mar 1, 2026", + "style": "bodyFontScaleNeg1Regular", + "color": "$colors.onSurface2" + }, + "regions": {} + }, + { + "definition": "ui/button", + "properties": { + "label": "Continue", + "variant": "brandOutline" + }, + "regions": {} + } + ] + } + } + } + ] + } + } + } + ] + } + } + }, + { + "definition": "ui/text", + "properties": { + "text": "Recommended for you", + "style": "titlesFontScale3Regular", + "color": "$colors.onSurface2", + "textAlign": "start" + }, + "regions": {} + }, + { + "definition": "ui/column", + "properties": { + "gap": "$spacing.spacing3" + }, + "regions": { + "components": { + "name": "components", + "components": [ + { + "definition": "ui/card", + "properties": { + "borderColor": "$colors.border1", + "padding": "$spacing.spacing4" + }, + "regions": { + "components": { + "name": "components", + "components": [ + { + "definition": "ui/row", + "properties": { + "gap": "$spacing.spacing3", + "alignment": "center" + }, + "regions": { + "components": { + "name": "components", + "components": [ + { + "definition": "ui/icon", + "properties": { + "iconName": "utility:email", + "size": "large", + "color": "$colors.success1" + }, + "regions": {} + }, + { + "definition": "ui/column", + "properties": { + "gap": "$spacing.spacing1" + }, + "regions": { + "components": { + "name": "components", + "components": [ + { + "definition": "ui/text", + "properties": { + "text": "3 packages ready for pickup", + "style": "bodyFontScale1Semibold", + "color": "$colors.onSurface1", + "textAlign": "start" + }, + "regions": {} + }, + { + "definition": "ui/text", + "properties": { + "text": "Locker #104 | Code:8829", + "style": "bodyFontScaleNeg1Regular", + "color": "$colors.onSurface2", + "textAlign": "start" + }, + "regions": {} + } + ] + } + } + } + ] + } + } + } + ] + } + } + }, + { + "definition": "ui/card", + "properties": { + "borderColor": "$colors.border1", + "padding": "$spacing.spacing4" + }, + "regions": { + "components": { + "name": "components", + "components": [ + { + "definition": "ui/row", + "properties": { + "gap": "$spacing.spacing3", + "alignment": "center" + }, + "regions": { + "components": { + "name": "components", + "components": [ + { + "definition": "ui/icon", + "properties": { + "iconName": "utility:favorite", + "size": "large", + "color": "$colors.warning1" + }, + "regions": {} + }, + { + "definition": "ui/column", + "properties": { + "gap": "$spacing.spacing1" + }, + "regions": { + "components": { + "name": "components", + "components": [ + { + "definition": "ui/text", + "properties": { + "text": "Rate your technician", + "style": "bodyFontScale1Semibold", + "color": "$colors.onSurface1", + "textAlign": "start" + }, + "regions": {} + }, + { + "definition": "ui/text", + "properties": { + "text": "How was your recent dishwasher fix?", + "style": "bodyFontScaleNeg1Regular", + "color": "$colors.onSurface2", + "textAlign": "start" + }, + "regions": {} + } + ] + } + } + } + ] + } + } + } + ] + } + } + }, + { + "definition": "ui/card", + "properties": { + "borderColor": "$colors.border1", + "padding": "$spacing.spacing4" + }, + "regions": { + "components": { + "name": "components", + "components": [ + { + "definition": "ui/row", + "properties": { + "gap": "$spacing.spacing3", + "alignment": "center" + }, + "regions": { + "components": { + "name": "components", + "components": [ + { + "definition": "ui/icon", + "properties": { + "iconName": "utility:list", + "size": "large", + "color": "$colors.information1" + }, + "regions": {} + }, + { + "definition": "ui/column", + "properties": { + "gap": "$spacing.spacing2", + "alignment": "start" + }, + "regions": { + "components": { + "name": "components", + "components": [ + { + "definition": "ui/text", + "properties": { + "text": "Complete Move-In Inspection", + "style": "bodyFontScale1Semibold", + "color": "$colors.onSurface1", + "textAlign": "start" + }, + "regions": {} + }, + { + "definition": "ui/text", + "properties": { + "text": "You've been here 30 days. How is everything?", + "style": "bodyFontScaleNeg1Regular", + "color": "$colors.onSurface2", + "textAlign": "start" + }, + "regions": {} + }, + { + "definition": "ui/button", + "properties": { + "label": "Take a survey", + "variant": "brandOutline" + }, + "regions": {} + } + ] + } + } + } + ] + } + } + } + ] + } + } + }, + { + "definition": "ui/card", + "properties": { + "borderColor": "$colors.border1", + "padding": "$spacing.spacing4" + }, + "regions": { + "components": { + "name": "components", + "components": [ + { + "definition": "ui/row", + "properties": { + "gap": "$spacing.spacing3", + "alignment": "center" + }, + "regions": { + "components": { + "name": "components", + "components": [ + { + "definition": "ui/icon", + "properties": { + "iconName": "utility:event", + "size": "large", + "color": "$colors.accent1" + }, + "regions": {} + }, + { + "definition": "ui/column", + "properties": { + "gap": "$spacing.spacing2", + "alignment": "start" + }, + "regions": { + "components": { + "name": "components", + "components": [ + { + "definition": "ui/text", + "properties": { + "text": "Check out your perks", + "style": "bodyFontScale1Semibold", + "color": "$colors.onSurface1", + "textAlign": "start" + }, + "regions": {} + }, + { + "definition": "ui/text", + "properties": { + "text": "Schedule a personal tour of amenities", + "style": "bodyFontScaleNeg1Regular", + "color": "$colors.onSurface2", + "textAlign": "start" + }, + "regions": {} + }, + { + "definition": "ui/button", + "properties": { + "label": "Book a tour", + "variant": "brandOutline" + }, + "regions": {} + } + ] + } + } + } + ] + } + } + } + ] + } + } + }, + { + "definition": "ui/footer", + "properties": { + "label": "More" + }, + "regions": {} + } + ] + } + } + } + ] + } + } + } + ] + } + } + } + ] + } + } + } + ] + } + } + }, + "target": "native__homesteadHome", + "apiName": "uem_homesteadHome", + "id": "homestead-app-home" + }, + "urlName": "home" +} diff --git a/samples/native-mobile-rental-tenant-app/force-app/main/default/digitalExperiences/experiencecontainer/rentalApp/experience__camaScreen/homeScreen/_meta.json b/samples/native-mobile-rental-tenant-app/force-app/main/default/digitalExperiences/experiencecontainer/rentalApp/experience__camaScreen/homeScreen/_meta.json deleted file mode 100644 index c2d0d5d..0000000 --- a/samples/native-mobile-rental-tenant-app/force-app/main/default/digitalExperiences/experiencecontainer/rentalApp/experience__camaScreen/homeScreen/_meta.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "apiName": "homeScreen", - "type": "experience__camaScreen", - "path": "homeScreen" -} diff --git a/samples/native-mobile-rental-tenant-app/force-app/main/default/digitalExperiences/experiencecontainer/rentalApp/experience__camaScreen/homeScreen/content.json b/samples/native-mobile-rental-tenant-app/force-app/main/default/digitalExperiences/experiencecontainer/rentalApp/experience__camaScreen/homeScreen/content.json deleted file mode 100644 index 2f89f6c..0000000 --- a/samples/native-mobile-rental-tenant-app/force-app/main/default/digitalExperiences/experiencecontainer/rentalApp/experience__camaScreen/homeScreen/content.json +++ /dev/null @@ -1,489 +0,0 @@ -{ - "type": "experience__camaScreen", - "title": "Home Screen", - "contentBody": { - "view": { - "definition": "homestead/HomeScreen", - "properties": { - "pullToRefresh": true - }, - "regions": { - "components": { - "components": [ - { - "definition": "ui/container", - "properties": { - "padding": "$spacing.spacing4", - "backgroundColor": "$colors.surface2" - }, - "regions": { - "components": { - "components": [ - { - "definition": "ui/card", - "properties": {}, - "regions": { - "components": { - "components": [ - { - "definition": "ui/column", - "properties": { - "width": "fill", - "height": "fill", - "alignment": "start", - "gap": "$spacing.spacing4", - "padding": "$spacing.spacing4" - }, - "regions": { - "components": { - "components": [ - { - "definition": "ui/text", - "properties": { - "text": "Today", - "style": "titlesFontScale4Semibold", - "color": "$colors.onSurface1" - }, - "regions": {} - }, - { - "definition": "ui/text", - "properties": { - "text": "You have no event.", - "color": "$colors.onSuccess1", - "style": "bodyFontScale2Regular" - }, - "regions": {} - } - ] - } - } - } - ] - } - } - }, - { - "definition": "ui/card", - "properties": {}, - "regions": { - "components": { - "components": [ - { - "definition": "ui/column", - "properties": { - "width": "fill", - "height": "fill", - "alignment": "start", - "gap": "$spacing.spacing4", - "padding": "$spacing.spacing4" - }, - "regions": { - "components": { - "components": [ - { - "definition": "ui/text", - "properties": { - "text": "Upcoming", - "style": "titlesFontScale4Semibold", - "color": "$colors.onSurface1" - }, - "regions": {} - } - ] - } - } - }, - { - "definition": "ui/baseRow", - "properties": { - "title": "123 Oak Street", - "subtitle": "Inspection on 01/08/2026" - }, - "regions": { - "components": { - "components": [ - { - "definition": "ui/utilityIcon", - "properties": { - "iconName": "utility/nothing" - }, - "regions": {} - }, - { - "definition": "ui/badge", - "properties": { - "label": "Scheduled", - "variant": "success" - }, - "regions": {} - } - ] - } - } - }, - { - "definition": "ui/baseRow", - "properties": { - "title": "456 Maple Avenue", - "subtitle": "Lease Signing on 01/10/2026" - }, - "regions": { - "components": { - "components": [ - { - "definition": "ui/utilityIcon", - "properties": { - "iconName": "utility/nothing" - }, - "regions": {} - }, - { - "definition": "ui/badge", - "properties": { - "label": "Scheduled", - "variant": "success" - }, - "regions": {} - } - ] - } - } - }, - { - "definition": "ui/baseRow", - "properties": { - "title": "789 Pine Road", - "subtitle": "Maintenance on 01/15/2026" - }, - "regions": { - "components": { - "components": [ - { - "definition": "ui/utilityIcon", - "properties": { - "iconName": "utility/nothing" - }, - "regions": {} - }, - { - "definition": "ui/badge", - "properties": { - "label": "Requested", - "variant": "error" - }, - "regions": {} - } - ] - } - } - }, - { - "definition": "ui/baseRow", - "properties": { - "title": "321 Elm Street", - "subtitle": "Rent Collection on 01/20/2026" - }, - "regions": { - "components": { - "components": [ - { - "definition": "ui/utilityIcon", - "properties": { - "iconName": "utility/nothing" - }, - "regions": {} - }, - { - "definition": "ui/badge", - "properties": { - "label": "Scheduled", - "variant": "success" - }, - "regions": {} - } - ] - } - } - }, - { - "definition": "ui/baseRow", - "properties": { - "title": "Community Center", - "subtitle": "HOA Meeting on 01/22/2026" - }, - "regions": { - "components": { - "components": [ - { - "definition": "ui/utilityIcon", - "properties": { - "iconName": "utility/nothing" - }, - "regions": {} - }, - { - "definition": "ui/badge", - "properties": { - "label": "Proposed", - "variant": "warning" - }, - "regions": {} - } - ] - } - } - }, - { - "definition": "ui/baseRow", - "properties": { - "title": "555 Cedar Lane", - "subtitle": "Background Check" - }, - "regions": { - "components": { - "components": [ - { - "definition": "ui/utilityIcon", - "properties": { - "iconName": "utility/nothing" - }, - "regions": {} - }, - { - "definition": "ui/badge", - "properties": { - "label": "In Progress", - "variant": "warning" - }, - "regions": {} - } - ] - } - } - } - ] - } - } - }, - { - "definition": "ui/card", - "properties": {}, - "regions": { - "components": { - "components": [ - { - "definition": "ui/column", - "properties": { - "width": "fill", - "height": "fill", - "alignment": "start", - "gap": "$spacing.spacing4", - "padding": "$spacing.spacing4" - }, - "regions": { - "components": { - "components": [ - { - "definition": "ui/text", - "properties": { - "text": "Tenants", - "style": "titlesFontScale4Semibold", - "color": "$colors.onSurface1" - }, - "regions": {} - } - ] - } - } - }, - { - "definition": "ui/baseRow", - "properties": { - "title": "Sarah Johnson", - "subtitle": "456 Maple Avenue, Apt 5" - }, - "regions": { - "components": { - "components": [ - { - "definition": "ui/utilityIcon", - "properties": { - "iconName": "utility/user", - "size": "small" - }, - "regions": {} - }, - { - "definition": "ui/badge", - "properties": { - "label": "Paid", - "variant": "success" - }, - "regions": {} - } - ] - } - } - }, - { - "definition": "ui/baseRow", - "properties": { - "title": "Michael Chen", - "subtitle": "789 Pine Road" - }, - "regions": { - "components": { - "components": [ - { - "definition": "ui/utilityIcon", - "properties": { - "iconName": "utility/user", - "size": "small" - }, - "regions": {} - }, - { - "definition": "ui/badge", - "properties": { - "label": "Overdue", - "variant": "error" - }, - "regions": {} - } - ] - } - } - }, - { - "definition": "ui/baseRow", - "properties": { - "title": "Emily Davis", - "subtitle": "321 Elm Street, Unit 5B" - }, - "regions": { - "components": { - "components": [ - { - "definition": "ui/utilityIcon", - "properties": { - "iconName": "utility/user", - "size": "small" - }, - "regions": {} - }, - { - "definition": "ui/badge", - "properties": { - "label": "Paid", - "variant": "success" - }, - "regions": {} - } - ] - } - } - }, - { - "definition": "ui/baseRow", - "properties": { - "title": "Robert Williams", - "subtitle": "555 Cedar Lane" - }, - "regions": { - "components": { - "components": [ - { - "definition": "ui/utilityIcon", - "properties": { - "iconName": "utility/user", - "size": "small" - }, - "regions": {} - }, - { - "definition": "ui/badge", - "properties": { - "label": "Paid", - "variant": "success" - }, - "regions": {} - } - ] - } - } - }, - { - "definition": "ui/baseRow", - "properties": { - "title": "Jessica Martinez", - "subtitle": "123 Oak Street, Unit 3C" - }, - "regions": { - "components": { - "components": [ - { - "definition": "ui/utilityIcon", - "properties": { - "iconName": "utility/user", - "size": "small" - }, - "regions": {} - }, - { - "definition": "ui/badge", - "properties": { - "label": "Moved Out", - "variant": "warning" - }, - "regions": {} - } - ] - } - } - }, - { - "definition": "ui/baseRow", - "properties": { - "title": "David Lee", - "subtitle": "456 Maple Avenue, Apt 2" - }, - "regions": { - "components": { - "components": [ - { - "definition": "ui/utilityIcon", - "properties": { - "iconName": "utility/user", - "size": "small" - }, - "regions": {} - }, - { - "definition": "ui/badge", - "properties": { - "label": "Signed", - "variant": "lightest" - }, - "regions": {} - } - ] - } - } - } - ] - } - } - } - ] - } - } - } - ] - } - } - }, - "target": "native__homesteadHome", - "apiName": "uem_homesteadHome" - } -} diff --git a/samples/native-mobile-rental-tenant-app/force-app/main/default/digitalExperiences/experiencecontainer/rentalApp/experience__camaScreen/propertiesScreen/_meta.json b/samples/native-mobile-rental-tenant-app/force-app/main/default/digitalExperiences/experiencecontainer/rentalApp/experience__camaScreen/propertiesScreen/_meta.json deleted file mode 100644 index 2446d28..0000000 --- a/samples/native-mobile-rental-tenant-app/force-app/main/default/digitalExperiences/experiencecontainer/rentalApp/experience__camaScreen/propertiesScreen/_meta.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "apiName": "propertiesScreen", - "type": "experience__camaScreen", - "path": "propertiesScreen" -} diff --git a/samples/native-mobile-rental-tenant-app/force-app/main/default/digitalExperiences/experiencecontainer/rentalApp/experience__camaScreen/propertiesScreen/content.json b/samples/native-mobile-rental-tenant-app/force-app/main/default/digitalExperiences/experiencecontainer/rentalApp/experience__camaScreen/propertiesScreen/content.json deleted file mode 100644 index 4412998..0000000 --- a/samples/native-mobile-rental-tenant-app/force-app/main/default/digitalExperiences/experiencecontainer/rentalApp/experience__camaScreen/propertiesScreen/content.json +++ /dev/null @@ -1,565 +0,0 @@ -{ - "type": "experience__camaScreen", - "title": "Properties Screen", - "contentBody": { - "view": { - "definition": "homestead/PropertiesScreen", - "properties": { - "pullToRefresh": true - }, - "regions": { - "components": { - "components": [ - { - "definition": "ui/container", - "properties": { - "padding": "$spacing.spacing4", - "backgroundColor": "$colors.surface2" - }, - "regions": { - "components": { - "components": [ - { - "definition": "ui/card", - "properties": {}, - "regions": { - "components": { - "components": [ - { - "definition": "ui/baseRow", - "properties": { - "title": "Oak Street Apartments", - "subtitle": "123 Oak Street" - }, - "regions": { - "components": { - "components": [ - { - "definition": "ui/utilityIcon", - "properties": { - "iconName": "utility/home", - "size": "small" - }, - "regions": {} - }, - { - "definition": "ui/badge", - "properties": { - "label": "Full", - "variant": "success" - }, - "regions": {} - } - ] - } - } - }, - { - "definition": "ui/baseRow", - "properties": { - "title": "Maple Avenue Complex", - "subtitle": "456 Maple Avenue" - }, - "regions": { - "components": { - "components": [ - { - "definition": "ui/utilityIcon", - "properties": { - "iconName": "utility/home", - "size": "small" - }, - "regions": {} - }, - { - "definition": "ui/badge", - "properties": { - "label": "Partial", - "variant": "warning" - }, - "regions": {} - } - ] - } - } - }, - { - "definition": "ui/baseRow", - "properties": { - "title": "Pine Road House", - "subtitle": "789 Pine Road" - }, - "regions": { - "components": { - "components": [ - { - "definition": "ui/utilityIcon", - "properties": { - "iconName": "utility/home", - "size": "small" - }, - "regions": {} - }, - { - "definition": "ui/badge", - "properties": { - "label": "Vacant", - "variant": "lightest" - }, - "regions": {} - } - ] - } - } - }, - { - "definition": "ui/baseRow", - "properties": { - "title": "Cedar Lane Condos", - "subtitle": "555 Cedar Lane" - }, - "regions": { - "components": { - "components": [ - { - "definition": "ui/utilityIcon", - "properties": { - "iconName": "utility/home", - "size": "small" - }, - "regions": {} - }, - { - "definition": "ui/badge", - "properties": { - "label": "Full", - "variant": "success" - }, - "regions": {} - } - ] - } - } - }, - { - "definition": "ui/baseRow", - "properties": { - "title": "Elm Street Tower", - "subtitle": "321 Elm Street" - }, - "regions": { - "components": { - "components": [ - { - "definition": "ui/utilityIcon", - "properties": { - "iconName": "utility/home", - "size": "small" - }, - "regions": {} - }, - { - "definition": "ui/badge", - "properties": { - "label": "Partial", - "variant": "warning" - }, - "regions": {} - } - ] - } - } - }, - { - "definition": "ui/baseRow", - "properties": { - "title": "Birch Boulevard Villa", - "subtitle": "234 Birch Boulevard" - }, - "regions": { - "components": { - "components": [ - { - "definition": "ui/utilityIcon", - "properties": { - "iconName": "utility/home", - "size": "small" - }, - "regions": {} - }, - { - "definition": "ui/badge", - "properties": { - "label": "Full", - "variant": "success" - }, - "regions": {} - } - ] - } - } - }, - { - "definition": "ui/baseRow", - "properties": { - "title": "Willow Way Estates", - "subtitle": "890 Willow Way" - }, - "regions": { - "components": { - "components": [ - { - "definition": "ui/utilityIcon", - "properties": { - "iconName": "utility/home", - "size": "small" - }, - "regions": {} - }, - { - "definition": "ui/badge", - "properties": { - "label": "Vacant", - "variant": "lightest" - }, - "regions": {} - } - ] - } - } - }, - { - "definition": "ui/baseRow", - "properties": { - "title": "Sunset Plaza", - "subtitle": "567 Sunset Drive" - }, - "regions": { - "components": { - "components": [ - { - "definition": "ui/utilityIcon", - "properties": { - "iconName": "utility/home", - "size": "small" - }, - "regions": {} - }, - { - "definition": "ui/badge", - "properties": { - "label": "Full", - "variant": "success" - }, - "regions": {} - } - ] - } - } - }, - { - "definition": "ui/baseRow", - "properties": { - "title": "Riverside Apartments", - "subtitle": "678 River Road" - }, - "regions": { - "components": { - "components": [ - { - "definition": "ui/utilityIcon", - "properties": { - "iconName": "utility/home", - "size": "small" - }, - "regions": {} - }, - { - "definition": "ui/badge", - "properties": { - "label": "Partial", - "variant": "warning" - }, - "regions": {} - } - ] - } - } - }, - { - "definition": "ui/baseRow", - "properties": { - "title": "Lakeside Manor", - "subtitle": "901 Lake Avenue" - }, - "regions": { - "components": { - "components": [ - { - "definition": "ui/utilityIcon", - "properties": { - "iconName": "utility/home", - "size": "small" - }, - "regions": {} - }, - { - "definition": "ui/badge", - "properties": { - "label": "Full", - "variant": "success" - }, - "regions": {} - } - ] - } - } - }, - { - "definition": "ui/baseRow", - "properties": { - "title": "Mountain View Heights", - "subtitle": "112 Mountain Road" - }, - "regions": { - "components": { - "components": [ - { - "definition": "ui/utilityIcon", - "properties": { - "iconName": "utility/home", - "size": "small" - }, - "regions": {} - }, - { - "definition": "ui/badge", - "properties": { - "label": "Maintenance", - "variant": "error" - }, - "regions": {} - } - ] - } - } - }, - { - "definition": "ui/baseRow", - "properties": { - "title": "Harbor Point Lofts", - "subtitle": "445 Harbor Street" - }, - "regions": { - "components": { - "components": [ - { - "definition": "ui/utilityIcon", - "properties": { - "iconName": "utility/home", - "size": "small" - }, - "regions": {} - }, - { - "definition": "ui/badge", - "properties": { - "label": "Partial", - "variant": "warning" - }, - "regions": {} - } - ] - } - } - }, - { - "definition": "ui/baseRow", - "properties": { - "title": "Garden Terrace", - "subtitle": "223 Garden Lane" - }, - "regions": { - "components": { - "components": [ - { - "definition": "ui/utilityIcon", - "properties": { - "iconName": "utility/home", - "size": "small" - }, - "regions": {} - }, - { - "definition": "ui/badge", - "properties": { - "label": "Full", - "variant": "success" - }, - "regions": {} - } - ] - } - } - }, - { - "definition": "ui/baseRow", - "properties": { - "title": "Park Place Residences", - "subtitle": "334 Park Avenue" - }, - "regions": { - "components": { - "components": [ - { - "definition": "ui/utilityIcon", - "properties": { - "iconName": "utility/home", - "size": "small" - }, - "regions": {} - }, - { - "definition": "ui/badge", - "properties": { - "label": "Vacant", - "variant": "lightest" - }, - "regions": {} - } - ] - } - } - }, - { - "definition": "ui/baseRow", - "properties": { - "title": "Hillside Court", - "subtitle": "778 Hill Street" - }, - "regions": { - "components": { - "components": [ - { - "definition": "ui/utilityIcon", - "properties": { - "iconName": "utility/home", - "size": "small" - }, - "regions": {} - }, - { - "definition": "ui/badge", - "properties": { - "label": "Full", - "variant": "success" - }, - "regions": {} - } - ] - } - } - }, - { - "definition": "ui/baseRow", - "properties": { - "title": "Downtown Tower", - "subtitle": "990 Main Street" - }, - "regions": { - "components": { - "components": [ - { - "definition": "ui/utilityIcon", - "properties": { - "iconName": "utility/home", - "size": "small" - }, - "regions": {} - }, - { - "definition": "ui/badge", - "properties": { - "label": "Partial", - "variant": "warning" - }, - "regions": {} - } - ] - } - } - }, - { - "definition": "ui/baseRow", - "properties": { - "title": "Bayside Commons", - "subtitle": "101 Bay Road" - }, - "regions": { - "components": { - "components": [ - { - "definition": "ui/utilityIcon", - "properties": { - "iconName": "utility/home", - "size": "small" - }, - "regions": {} - }, - { - "definition": "ui/badge", - "properties": { - "label": "Full", - "variant": "success" - }, - "regions": {} - } - ] - } - } - }, - { - "definition": "ui/baseRow", - "properties": { - "title": "Meadow Brook Village", - "subtitle": "212 Meadow Lane" - }, - "regions": { - "components": { - "components": [ - { - "definition": "ui/utilityIcon", - "properties": { - "iconName": "utility/home", - "size": "small" - }, - "regions": {} - }, - { - "definition": "ui/badge", - "properties": { - "label": "Maintenance", - "variant": "error" - }, - "regions": {} - } - ] - } - } - } - ] - } - } - } - ] - } - } - } - ] - } - } - }, - "target": "native__homesteadProperties", - "apiName": "uem_homesteadProperties" - } -} diff --git a/samples/native-mobile-rental-tenant-app/force-app/main/default/digitalExperiences/experiencecontainer/rentalApp/experience__camaScreen/tenantsScreen/_meta.json b/samples/native-mobile-rental-tenant-app/force-app/main/default/digitalExperiences/experiencecontainer/rentalApp/experience__camaScreen/tenantsScreen/_meta.json deleted file mode 100644 index fc4592a..0000000 --- a/samples/native-mobile-rental-tenant-app/force-app/main/default/digitalExperiences/experiencecontainer/rentalApp/experience__camaScreen/tenantsScreen/_meta.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "apiName": "tenantsScreen", - "type": "experience__camaScreen", - "path": "tenantsScreen" -} diff --git a/samples/native-mobile-rental-tenant-app/force-app/main/default/digitalExperiences/experiencecontainer/rentalApp/experience__camaScreen/tenantsScreen/content.json b/samples/native-mobile-rental-tenant-app/force-app/main/default/digitalExperiences/experiencecontainer/rentalApp/experience__camaScreen/tenantsScreen/content.json deleted file mode 100644 index 9100149..0000000 --- a/samples/native-mobile-rental-tenant-app/force-app/main/default/digitalExperiences/experiencecontainer/rentalApp/experience__camaScreen/tenantsScreen/content.json +++ /dev/null @@ -1,478 +0,0 @@ -{ - "type": "experience__camaScreen", - "title": "Tenants Screen", - "contentBody": { - "view": { - "definition": "homestead/TenantsScreen", - "properties": { - "pullToRefresh": true - }, - "regions": { - "components": { - "components": [ - { - "definition": "ui/container", - "properties": { - "padding": "$spacing.spacing4", - "backgroundColor": "$colors.surface2" - }, - "regions": { - "components": { - "components": [ - { - "definition": "ui/card", - "properties": {}, - "regions": { - "components": { - "components": [ - { - "definition": "ui/baseRow", - "properties": { - "title": "Sarah Johnson", - "subtitle": "456 Maple Avenue, Apt 5" - }, - "regions": { - "components": { - "components": [ - { - "definition": "ui/utilityIcon", - "properties": { - "iconName": "utility/user", - "size": "small" - }, - "regions": {} - }, - { - "definition": "ui/badge", - "properties": { - "label": "Paid", - "variant": "success" - }, - "regions": {} - } - ] - } - } - }, - { - "definition": "ui/baseRow", - "properties": { - "title": "Michael Chen", - "subtitle": "789 Pine Road" - }, - "regions": { - "components": { - "components": [ - { - "definition": "ui/utilityIcon", - "properties": { - "iconName": "utility/user", - "size": "small" - }, - "regions": {} - }, - { - "definition": "ui/badge", - "properties": { - "label": "Overdue", - "variant": "error" - }, - "regions": {} - } - ] - } - } - }, - { - "definition": "ui/baseRow", - "properties": { - "title": "Emily Davis", - "subtitle": "321 Elm Street, Unit 5B" - }, - "regions": { - "components": { - "components": [ - { - "definition": "ui/utilityIcon", - "properties": { - "iconName": "utility/user", - "size": "small" - }, - "regions": {} - }, - { - "definition": "ui/badge", - "properties": { - "label": "Paid", - "variant": "success" - }, - "regions": {} - } - ] - } - } - }, - { - "definition": "ui/baseRow", - "properties": { - "title": "Robert Williams", - "subtitle": "555 Cedar Lane" - }, - "regions": { - "components": { - "components": [ - { - "definition": "ui/utilityIcon", - "properties": { - "iconName": "utility/user", - "size": "small" - }, - "regions": {} - }, - { - "definition": "ui/badge", - "properties": { - "label": "Paid", - "variant": "success" - }, - "regions": {} - } - ] - } - } - }, - { - "definition": "ui/baseRow", - "properties": { - "title": "Jessica Martinez", - "subtitle": "123 Oak Street, Unit 3C" - }, - "regions": { - "components": { - "components": [ - { - "definition": "ui/utilityIcon", - "properties": { - "iconName": "utility/user", - "size": "small" - }, - "regions": {} - }, - { - "definition": "ui/badge", - "properties": { - "label": "Moved Out", - "variant": "warning" - }, - "regions": {} - } - ] - } - } - }, - { - "definition": "ui/baseRow", - "properties": { - "title": "David Lee", - "subtitle": "456 Maple Avenue, Apt 2" - }, - "regions": { - "components": { - "components": [ - { - "definition": "ui/utilityIcon", - "properties": { - "iconName": "utility/user", - "size": "small" - }, - "regions": {} - }, - { - "definition": "ui/badge", - "properties": { - "label": "Signed", - "variant": "lightest" - }, - "regions": {} - } - ] - } - } - }, - { - "definition": "ui/baseRow", - "properties": { - "title": "Amanda Thompson", - "subtitle": "789 Pine Road, Unit 7A" - }, - "regions": { - "components": { - "components": [ - { - "definition": "ui/utilityIcon", - "properties": { - "iconName": "utility/user", - "size": "small" - }, - "regions": {} - }, - { - "definition": "ui/badge", - "properties": { - "label": "Paid", - "variant": "success" - }, - "regions": {} - } - ] - } - } - }, - { - "definition": "ui/baseRow", - "properties": { - "title": "Christopher Garcia", - "subtitle": "321 Elm Street, Apt 8" - }, - "regions": { - "components": { - "components": [ - { - "definition": "ui/utilityIcon", - "properties": { - "iconName": "utility/user", - "size": "small" - }, - "regions": {} - }, - { - "definition": "ui/badge", - "properties": { - "label": "Overdue", - "variant": "error" - }, - "regions": {} - } - ] - } - } - }, - { - "definition": "ui/baseRow", - "properties": { - "title": "Nicole Anderson", - "subtitle": "555 Cedar Lane, Unit 12B" - }, - "regions": { - "components": { - "components": [ - { - "definition": "ui/utilityIcon", - "properties": { - "iconName": "utility/user", - "size": "small" - }, - "regions": {} - }, - { - "definition": "ui/badge", - "properties": { - "label": "Paid", - "variant": "success" - }, - "regions": {} - } - ] - } - } - }, - { - "definition": "ui/baseRow", - "properties": { - "title": "James Wilson", - "subtitle": "123 Oak Street, Apt 1A" - }, - "regions": { - "components": { - "components": [ - { - "definition": "ui/utilityIcon", - "properties": { - "iconName": "utility/user", - "size": "small" - }, - "regions": {} - }, - { - "definition": "ui/badge", - "properties": { - "label": "Pending", - "variant": "warning" - }, - "regions": {} - } - ] - } - } - }, - { - "definition": "ui/baseRow", - "properties": { - "title": "Rachel Brown", - "subtitle": "456 Maple Avenue, Unit 9C" - }, - "regions": { - "components": { - "components": [ - { - "definition": "ui/utilityIcon", - "properties": { - "iconName": "utility/user", - "size": "small" - }, - "regions": {} - }, - { - "definition": "ui/badge", - "properties": { - "label": "Paid", - "variant": "success" - }, - "regions": {} - } - ] - } - } - }, - { - "definition": "ui/baseRow", - "properties": { - "title": "Kevin Taylor", - "subtitle": "789 Pine Road, Apt 4B" - }, - "regions": { - "components": { - "components": [ - { - "definition": "ui/utilityIcon", - "properties": { - "iconName": "utility/user", - "size": "small" - }, - "regions": {} - }, - { - "definition": "ui/badge", - "properties": { - "label": "Signed", - "variant": "lightest" - }, - "regions": {} - } - ] - } - } - }, - { - "definition": "ui/baseRow", - "properties": { - "title": "Stephanie Miller", - "subtitle": "321 Elm Street, Unit 6D" - }, - "regions": { - "components": { - "components": [ - { - "definition": "ui/utilityIcon", - "properties": { - "iconName": "utility/user", - "size": "small" - }, - "regions": {} - }, - { - "definition": "ui/badge", - "properties": { - "label": "Paid", - "variant": "success" - }, - "regions": {} - } - ] - } - } - }, - { - "definition": "ui/baseRow", - "properties": { - "title": "Brian Martinez", - "subtitle": "555 Cedar Lane, Apt 10A" - }, - "regions": { - "components": { - "components": [ - { - "definition": "ui/utilityIcon", - "properties": { - "iconName": "utility/user", - "size": "small" - }, - "regions": {} - }, - { - "definition": "ui/badge", - "properties": { - "label": "Overdue", - "variant": "error" - }, - "regions": {} - } - ] - } - } - }, - { - "definition": "ui/baseRow", - "properties": { - "title": "Laura Rodriguez", - "subtitle": "123 Oak Street, Unit 11B" - }, - "regions": { - "components": { - "components": [ - { - "definition": "ui/utilityIcon", - "properties": { - "iconName": "utility/user", - "size": "small" - }, - "regions": {} - }, - { - "definition": "ui/badge", - "properties": { - "label": "Paid", - "variant": "success" - }, - "regions": {} - } - ] - } - } - } - ] - } - } - } - ] - } - } - } - ] - } - } - }, - "target": "native__homesteadTenants", - "apiName": "uem_homesteadTenants" - } -} diff --git a/samples/native-mobile-rental-tenant-app/force-app/main/default/digitalExperiences/experiencecontainer/rentalApp/rentalApp.digitalExperience-meta.xml b/samples/native-mobile-rental-tenant-app/force-app/main/default/digitalExperiences/experiencecontainer/rentalApp/rentalApp.digitalExperience-meta.xml index b93075a..0456ba8 100644 --- a/samples/native-mobile-rental-tenant-app/force-app/main/default/digitalExperiences/experiencecontainer/rentalApp/rentalApp.digitalExperience-meta.xml +++ b/samples/native-mobile-rental-tenant-app/force-app/main/default/digitalExperiences/experiencecontainer/rentalApp/rentalApp.digitalExperience-meta.xml @@ -1,4 +1,15 @@ + + + + sfdc_cms__collection + ENABLED + + + sfdc_cms__media + ENABLED + + diff --git a/samples/native-mobile-rental-tenant-app/force-app/main/default/digitalExperiences/experiencecontainer/rentalApp/sfdc_cms__languageSettings/languages/_meta.json b/samples/native-mobile-rental-tenant-app/force-app/main/default/digitalExperiences/experiencecontainer/rentalApp/sfdc_cms__languageSettings/languages/_meta.json new file mode 100644 index 0000000..d0381dc --- /dev/null +++ b/samples/native-mobile-rental-tenant-app/force-app/main/default/digitalExperiences/experiencecontainer/rentalApp/sfdc_cms__languageSettings/languages/_meta.json @@ -0,0 +1,5 @@ +{ + "apiName" : "languages", + "type" : "sfdc_cms__languageSettings", + "path" : "_settings" +} \ No newline at end of file diff --git a/samples/native-mobile-rental-tenant-app/force-app/main/default/digitalExperiences/experiencecontainer/rentalApp/sfdc_cms__languageSettings/languages/content.json b/samples/native-mobile-rental-tenant-app/force-app/main/default/digitalExperiences/experiencecontainer/rentalApp/sfdc_cms__languageSettings/languages/content.json new file mode 100644 index 0000000..7016c4e --- /dev/null +++ b/samples/native-mobile-rental-tenant-app/force-app/main/default/digitalExperiences/experiencecontainer/rentalApp/sfdc_cms__languageSettings/languages/content.json @@ -0,0 +1,14 @@ +{ + "type" : "sfdc_cms__languageSettings", + "title" : "LanguageContent", + "contentBody" : { + "languages" : [ { + "locale" : "en_US", + "label" : "English (US)", + "isActive" : true, + "isAuthoringOnly" : false + } ], + "defaultLocale" : "en_US" + }, + "urlName" : "languagecontent" +} \ No newline at end of file diff --git a/samples/webapp-template-app-react-sample-b2e-experimental/.a4drules/skills/configuring-webapp-metadata/SKILL.md b/samples/webapp-template-app-react-sample-b2e-experimental/.a4drules/skills/configuring-webapp-metadata/SKILL.md index 17918c8..737de37 100644 --- a/samples/webapp-template-app-react-sample-b2e-experimental/.a4drules/skills/configuring-webapp-metadata/SKILL.md +++ b/samples/webapp-template-app-react-sample-b2e-experimental/.a4drules/skills/configuring-webapp-metadata/SKILL.md @@ -53,7 +53,7 @@ Applies to: Reject: - backslashes -- leading `/` or `\` +- leading `\` - `..` segments - null or control characters - globs: `*`, `?`, `**` diff --git a/samples/webapp-template-app-react-sample-b2x-experimental/.a4drules/skills/configuring-webapp-metadata/SKILL.md b/samples/webapp-template-app-react-sample-b2x-experimental/.a4drules/skills/configuring-webapp-metadata/SKILL.md index 17918c8..737de37 100644 --- a/samples/webapp-template-app-react-sample-b2x-experimental/.a4drules/skills/configuring-webapp-metadata/SKILL.md +++ b/samples/webapp-template-app-react-sample-b2x-experimental/.a4drules/skills/configuring-webapp-metadata/SKILL.md @@ -53,7 +53,7 @@ Applies to: Reject: - backslashes -- leading `/` or `\` +- leading `\` - `..` segments - null or control characters - globs: `*`, `?`, `**` diff --git a/skills/configuring-webapp-metadata/SKILL.md b/skills/configuring-webapp-metadata/SKILL.md index d3863ab..0fb714e 100644 --- a/skills/configuring-webapp-metadata/SKILL.md +++ b/skills/configuring-webapp-metadata/SKILL.md @@ -53,7 +53,7 @@ Applies to: Reject: - backslashes -- leading `/` or `\` +- leading `\` - `..` segments - null or control characters - globs: `*`, `?`, `**` diff --git a/skills/generating-custom-lightning-type/SKILL.md b/skills/generating-custom-lightning-type/SKILL.md index a09e1b0..2b89d15 100644 --- a/skills/generating-custom-lightning-type/SKILL.md +++ b/skills/generating-custom-lightning-type/SKILL.md @@ -103,9 +103,11 @@ When strict validation is enabled (`unevaluatedProperties: false`), keep each pr - Top-level `editor` object. - Use `editor.componentOverrides` for component overrides. - Use `editor.layout` for layout. + - **DEPRECATED**: Do NOT use `propertyRenderers` or `view` — these are legacy keys. Always use `componentOverrides` and `layout` instead. - **Root override pattern** (most common for fully custom editing UI): - `editor.componentOverrides["$"] = { "definition": "c/", "attributes": { ... } }` - When passing schema data into a custom LWC, use attribute mapping with the `{!$attrs.}` syntax: e.g. `"attributes": { "myField": "{!$attrs.value}" }` so the runtime binds schema values to your component's attributes. + - **CRITICAL**: The `` in `{!$attrs.}` must be a property defined in your type schema. For example, if your schema has a property called `temperature`, use `{!$attrs.temperature}`, not `{!$attrs.value}` unless `value` is an actual property. - **Property-level override pattern** (for individual fields): - `editor.componentOverrides[""] = { "definition": "es_property_editors/<...>" }` - **Valid editor components** (examples): `es_property_editors/inputText`, `es_property_editors/inputNumber`, `es_property_editors/inputRichText`, `es_property_editors/inputImage`, `es_property_editors/inputTextarea`. **Do not use** `es_property_editors/inputList`. @@ -113,6 +115,7 @@ When strict validation is enabled (`unevaluatedProperties: false`), keep each pr - **Layout pattern**: - `editor.layout.definition = "lightning/verticalLayout"` - `editor.layout.children[*].definition = "lightning/propertyLayout"` with `attributes.property = ""` + - **CRITICAL**: `lightning/propertyLayout` only accepts the `property` attribute. Do NOT add `label`, `title`, or any other attributes — these will fail validation with `additionalProperties: false` errors. - **Avoid known-invalid patterns**: - Do not use `es_property_editors/inputList`. - Do not use `itemSchema` attributes. @@ -121,18 +124,41 @@ When strict validation is enabled (`unevaluatedProperties: false`), keep each pr - Top-level `renderer` object. - Use `renderer.componentOverrides` for component overrides. - Use `renderer.layout` for layout. + - **DEPRECATED**: Do NOT use `propertyRenderers` or `view` — these are legacy keys. Always use `componentOverrides` and `layout` instead. - **Root override pattern** (most common for fully custom rendering UI): - `renderer.componentOverrides["$"] = { "definition": "c/", "attributes": { ... } }` - Use `{!$attrs.}` in attribute mappings when binding schema data to custom renderer component attributes. + - **CRITICAL**: Attribute mappings like `{!$attrs.propertyName}` must reference properties that **actually exist** in your type schema. Referencing non-existent properties will fail validation. + - **Type matching**: Attribute values must match the expected type for the component. For example, if a component expects a string attribute, passing an integer will fail validation. - **Property-level override pattern**: - `renderer.componentOverrides[""] = { "definition": "es_property_editors/outputText" | "es_property_editors/outputNumber" | "es_property_editors/outputImage" | ... }`. **Valid renderer components** (examples): `es_property_editors/outputText`, `es_property_editors/outputNumber`, `es_property_editors/outputImage`. Avoid input-style components in the renderer. + - **Layout pattern for renderer**: + - `renderer.layout.definition = "lightning/verticalLayout"` + - `renderer.layout.children[*].definition = "lightning/propertyLayout"` with `attributes.property = ""` + - **CRITICAL**: Same as editor layouts, `lightning/propertyLayout` only accepts the `property` attribute. Do NOT add `label`, `title`, or any other attributes. - **Collection renderer** (for root-level `lightning__listType` properties): Use `collection.renderer.componentOverrides["$"] = { "definition": "c/" }` or `es_property_editors/genericListTypeRenderer` to render the list. 5. **Place files in the correct bundle structure** - `lightningTypes//schema.json` - (Optional) `lightningTypes//lightningDesktopGenAi/editor.json` - (Optional) `lightningTypes//lightningDesktopGenAi/renderer.json` - For Gen AI / Copilot the standard path is `lightningDesktopGenAi/`. Other targets (e.g. Experience Builder, Mobile Copilot, Enhanced Web Chat) use different subfolders when supported: `experienceBuilder/`, `lightningMobileGenAi/`, `enhancedWebChat/`. -6. **Deploy and validate** +6. **Configure custom LWC components (if using custom components)** + - **CRITICAL**: Custom LWC components referenced in editor/renderer configs MUST have the correct target configuration in their `-meta.xml` files: + - **For editor components** (`c/` used in `editor.json`): The LWC's `-meta.xml` file must include `lightning__AgentforceInput` + - **For renderer components** (`c/` used in `renderer.json`): The LWC's `-meta.xml` file must include `lightning__AgentforceOutput` + - Without the correct target, deployment will fail with: `Invalid target configuration. To use 'c/componentName' as a renderer/editor, your js-meta.xml file must include valid target 'lightning__AgentforceOutput/Input'.` + - Example `-meta.xml` for a renderer component: + ```xml + + + 60.0 + true + + lightning__AgentforceOutput + + + ``` +7. **Deploy and validate** - Deploy the bundle using your org's standard metadata deployment flow (e.g. Salesforce CLI or IDE). The MCP client or tooling in use should provide or integrate with the appropriate deploy/retrieve commands for Lightning Type bundles. - Validate incrementally: if deployment fails, remove disallowed keywords first (especially `examples`, `items`, nested `lightning:type`). @@ -144,6 +170,11 @@ When strict validation is enabled (`unevaluatedProperties: false`), keep each pr | Array property rejected | Use of `items` (or `lightning:type` in nested arrays) rejected by validator | For nested arrays: keep only `type: "array"`. For root arrays: use minimal structure; remove `items` if rejected | | Apex-based CLT rejected | Extra fields added (e.g., `type`, `properties`) | Use only `title`, optional `description`, and `lightning:type` | | Editor config rejected | Use of invalid patterns (`es_property_editors/inputList`, `itemSchema`) or unrecognized top-level keys | Use `editor.componentOverrides` and `editor.layout`; keep config minimal | +| `additionalProperties` error on layout attributes | Adding `label` or other attributes to `lightning/propertyLayout` | Only use `property` attribute in `lightning/propertyLayout`. Remove `label`, `title`, or any other attributes | +| Invalid target configuration for custom LWC | Custom LWC component's `-meta.xml` missing required target (`lightning__AgentforceInput` or `lightning__AgentforceOutput`) | Add correct target to LWC's `-meta.xml`: use `lightning__AgentforceInput` for editors, `lightning__AgentforceOutput` for renderers | +| Attribute mapping doesn't exist in type schema | Using `{!$attrs.propertyName}` where `propertyName` is not defined in schema | Ensure all attribute mappings reference actual properties in your type schema's `properties` section | +| `additionalProperties` error with deprecated keys | Using `propertyRenderers` or `view` in editor/renderer config | Replace deprecated `propertyRenderers` with `componentOverrides` and `view` with `layout` | +| Type mismatch in component attributes | Passing wrong type for component attribute (e.g., integer instead of string) | Ensure attribute values match the expected type defined by the component | ## Verification Checklist - [ ] Root schema has `type: "object"`, `title`, `lightning:type: "lightning__objectType"`, and `unevaluatedProperties: false` @@ -155,3 +186,6 @@ When strict validation is enabled (`unevaluatedProperties: false`), keep each pr - [ ] Bundle structure and filenames match Lightning Types requirements - [ ] Editor config uses only allowed patterns (no `es_property_editors/inputList`, no `itemSchema`); use valid components (e.g. `es_property_editors/inputText`, `es_property_editors/inputNumber`) or custom `c/` components - [ ] Renderer config uses output-style components (e.g. `es_property_editors/outputText`, `es_property_editors/outputNumber`) where applicable, not input editors +- [ ] Layout configurations use `lightning/propertyLayout` with ONLY the `property` attribute (no `label`, `title`, or other attributes) +- [ ] All attribute mappings (`{!$attrs.propertyName}`) reference properties that exist in the type schema +- [ ] Custom LWC components have correct targets in `-meta.xml`: `lightning__AgentforceInput` for editors, `lightning__AgentforceOutput` for renderers diff --git a/skills/generating-flexipage/SKILL.md b/skills/generating-flexipage/SKILL.md index b4fb281..a8c0acc 100644 --- a/skills/generating-flexipage/SKILL.md +++ b/skills/generating-flexipage/SKILL.md @@ -149,6 +149,68 @@ Every fieldInstance requires: - Must have `fieldInstanceProperties` with `uiBehavior` - Use `Record.{Field}` format +### 5. Unique Identifiers and Region Names (CRITICAL - PREVENTS DUPLICATE ERRORS) + +**EVERY identifier and region/facet name MUST be unique across the entire FlexiPage file.** + +**Critical Rules:** +- ❌ **NEVER create two `` blocks with the same ``** +- ✅ **If multiple components belong to same facet, combine them in ONE region with multiple ``** +- ❌ **NEVER reuse the same `` value** +- ✅ **Always read entire file first and extract ALL existing identifiers and names** + +**Wrong - This WILL FAIL with duplicate name error:** +```xml + + + + + flexipage_property_details_fieldSection + ... + + + detailTabContent + Facet + + + + + + + flexipage_pricing_fieldSection + ... + + + detailTabContent + Facet + +``` + +**Correct - Combine itemInstances in ONE region:** +```xml + + + + + flexipage_property_details_fieldSection + ... + + + + + flexipage_pricing_fieldSection + ... + + + detailTabContent + Facet + +``` + +**When to combine vs separate:** +- **Combine**: Components that logically belong to same tab/section (e.g., multiple field sections in detail tab) +- **Separate**: Components that belong to different tabs/sections (e.g., `detailTabContent` vs `relatedTabContent`) + --- ## Common Deployment Errors @@ -178,7 +240,7 @@ Every fieldInstance requires: **Fix:** Use "Volunteer_Record_Page" not "Volunteer__c_Record_Page" ### "Region specifies mode that parent doesn't support" -**Cause:** Added `` tag to region +**Cause:** Added `` tag to region **Fix:** Remove `` tags - they're not needed for standard regions --- @@ -211,21 +273,28 @@ When user provides an existing FlexiPage file path: 1. **Read the file** using native file I/O 2. **Parse XML** to extract: - - Existing component identifiers + - **ALL existing component identifiers** (search for all `` tags) + - **ALL existing region/facet names** (search for all `` tags in ``) - Available regions (parse from file, don't assume names) - Existing facets -3. **Generate component XML** (apply all rules from "Critical XML Rules" section) -4. **Insert** into appropriate region -5. **Write** modified XML back to file -6. **Deploy**: `sf project deploy start --source-dir force-app/...` +3. **Verify uniqueness** - ensure your new identifiers and names don't conflict with ANY existing ones +4. **Check if target facet exists** - if adding to a named facet like `detailTabContent` that already exists: + - **Add new `` to existing region** (don't create duplicate region) + - **Insert before the closing `` tag of that region** +5. **Generate component XML** (apply all rules from "Critical XML Rules" section) +6. **Insert** into appropriate region or add itemInstances to existing facet +7. **Write** modified XML back to file +8. **Deploy**: `sf project deploy start --source-dir force-app/...` --- ### Generating Unique Identifiers -**Algorithm**: +**CRITICAL: Before generating ANY new identifier or facet name, follow the rules in section 5 of "Critical XML Rules" above.** + +**Identifier Generation Algorithm**: ``` -1. Extract all existing values from XML +1. Extract ALL existing AND values from XML 2. Generate base name: {componentType}_{context} Examples: "relatedList_contacts", "richText_header", "tabs_main" 3. Find first available number: @@ -253,6 +322,11 @@ When user provides an existing FlexiPage file path: - Example: `Facet-66d5a4b3-bf14-4665-ba75-1ceaa71b2cde` - Use for field section columns, nested containers, anonymous slots +**When adding components to existing files:** +- Check if target facet name already exists +- If exists: Add new `` to that existing region (see section 5 above for details) +- If doesn't exist: Create new region with unique name + --- ### Region Selection @@ -401,6 +475,9 @@ Identifier Pattern: flexipage_richText or flexipage_richText_{sequence} Before deploying: - [ ] Used CLI to bootstrap (don't start from scratch) +- [ ] **ALL identifiers are unique** - no duplicate `` values anywhere in file +- [ ] **ALL region/facet names are unique** - no duplicate `` values in `` +- [ ] **Multiple components in same facet are combined** - ONE region with multiple ``, NOT separate regions with same name - [ ] All field references use `Record.{Field}` format - [ ] Each fieldInstance has `fieldInstanceProperties` with `uiBehavior` - [ ] Each fieldInstance in own `` wrapper diff --git a/skills/generating-lightning-app-solution/SKILL.md b/skills/generating-lightning-app-solution/SKILL.md deleted file mode 100644 index f08d598..0000000 --- a/skills/generating-lightning-app-solution/SKILL.md +++ /dev/null @@ -1,347 +0,0 @@ ---- -name: generating-lightning-app-solution -description: Build complete Salesforce Lightning Experience applications from natural language descriptions. Use this skill when a user requests a "complete app", "Lightning app", "business solution", "management system", or describes a scenario requiring multiple interconnected Salesforce components (objects, fields, pages, tabs, security). Orchestrates all required metadata types in proper dependency order to produce a deployable application. -metadata: - category: orchestration - version: "1.0" - related-skills: skills/generating-custom-object/SKILL.md, skills/generating-custom-field/SKILL.md, skills/generating-custom-tab/SKILL.md, skills/generating-flexipage/SKILL.md, skills/generating-custom-application/SKILL.md, skills/generating-flow/SKILL.md, skills/generating-validation-rule/SKILL.md, skills/generating-list-view/SKILL.md, skills/generating-permission-set/SKILL.md ---- - -# Generating Lightning App Solution - -## Overview - -Build a complete, deployable Salesforce Lightning Experience application from a natural language description by orchestrating multiple metadata types in correct dependency order. Invoke specialized metadata skills when available; generate metadata directly when no skill exists. - -## When to Use This Skill -**Use when:** -- User requests a "complete app", "Lightning app", or "end-to-end solution" -- User says "build an app", "create an application", "build a [type] app" (project management, tracking, etc.) -- Request involves 3+ metadata types working together (objects + fields + pages + security) -- User describes multiple custom objects with relationships between them -- User mentions custom objects AND Lightning Record Pages in the same request -- User mentions custom objects AND permission sets/security in the same request -- Request includes phrases like "allows users to manage/track", "management system", "tracking app" -- Need to ensure proper sequencing (Objects → Fields → UI → Security) - -**Examples that should trigger this skill:** -- "Build a project management app with Tasks, Resources, and Supplies objects" -- "Create an app to track vehicles with Lightning pages and permission sets" -- "I need a Space Station management system with multiple objects and relationships" -- "Build an employee onboarding app with custom Lightning Record Pages" - -**Do NOT use when:** -- Creating a single metadata component (use specific metadata skill instead) -- Troubleshooting or debugging existing metadata -- Building Salesforce Classic apps (not Lightning Experience) -- User asks for just one object, or just one page, or just one permission set (without others) -- User only needs to create or configure an app container (grouping existing tabs) without other metadata — use skills/generating-custom-application/SKILL.md instead - -## Metadata Type Registry - -This table shows which metadata types are commonly needed for LEX apps and their skill availability. - -| Metadata Type | Skill Available? | Skill Name | Usage Rule | -|---------------|------------------|------------|------------| -| **Custom Object** | ✅ YES | `skills/generating-custom-object/SKILL.md` | MUST use skill | -| **Custom Field** | ✅ YES | `skills/generating-custom-field/SKILL.md` | MUST use skill | -| **Custom Tab** | ✅ YES | `skills/generating-custom-tab/SKILL.md` | MUST use skill | -| **FlexiPage** | ✅ YES | `skills/generating-flexipage/SKILL.md` | MUST use skill | -| **Custom Application** | ✅ YES | `skills/generating-custom-application/SKILL.md` | MUST use skill | -| **List View** | ✅ YES | `skills/generating-list-view/SKILL.md` | MUST use skill | -| **Validation Rule** | ✅ YES | `skills/generating-validation-rule/SKILL.md` | MUST use skill (if requested) | -| **Flow** | ✅ YES | `skills/generating-flow/SKILL.md` | MUST use skill (if requested) | -| **Permission Set** | ✅ YES | `skills/generating-permission-set/SKILL.md` | MUST use skill | - -### Skill Usage Rules - -**CRITICAL RULE**: When a skill exists for a metadata type (✅ YES in table above), you **MUST** invoke that skill. Do NOT generate the metadata directly. - -**FALLBACK RULE**: When NO skill exists for a metadata type (❌ NO in table above), you **MAY** generate the metadata directly using your knowledge of Salesforce Metadata API and best practices. - -**RATIONALE**: Specialized skills contain validated patterns, error handling, and field-specific knowledge that prevent deployment failures. - ---- - -## Dependency Graph & Build Order - -### Phase 1: Data Model (Foundation) -``` -Custom Objects (no dependencies) - ↓ -Custom Fields (depends on: Objects exist) - ↓ -Relationships (depends on: Both parent and child objects + fields exist) -``` - -**Skills to invoke in order:** -1. `skills/generating-custom-object/SKILL.md` — once, with all objects -2. `skills/generating-custom-field/SKILL.md` — once, with all fields (including Master-Detail, Lookup, Roll-up Summary) - -### Phase 2: Business Logic (Optional - only if requested) -``` -Validation Rules (depends on: Fields exist) - ↓ -Flows (depends on: Objects, Fields exist) -``` - -**Skills to invoke (only if user requested):** -1. `skills/generating-validation-rule/SKILL.md` — once, if validation requirements mentioned -2. `skills/generating-flow/SKILL.md` — once, if automation/workflow requirements mentioned - -### Phase 3: User Interface -``` -List Views (depends on: Objects, Fields exist) - ↓ -Custom Tabs (depends on: Objects exist) - ↓ -FlexiPages (depends on: Objects, Tabs exist) -``` - -**Skills to invoke in order:** -1. `skills/generating-list-view/SKILL.md` — once, for filtered record views (if requested) -2. `skills/generating-custom-tab/SKILL.md` — once, with all object tabs -3. `skills/generating-flexipage/SKILL.md` — once, with all record/home/app pages - -### Phase 4: Application Assembly -``` -Custom Application (depends on: Tabs exist) -``` - -**Skills to invoke:** -1. `skills/generating-custom-application/SKILL.md` — once, to create the Lightning App container - -### Phase 5: Security & Access -``` -Permission Sets (depends on: Objects, Fields, Tabs, App exist) -``` - -**Skills to invoke:** -1. `skills/generating-permission-set/SKILL.md` — once, with all permission sets and access to: - - Objects (Read, Create, Edit, Delete) - - Fields (Read, Edit) - - Tabs (Visible) - - Custom Application (Visible) - ---- - -## Execution Workflow - -### STEP 1: Requirements Analysis & Planning - -**Actions:** -1. Parse user's natural language request -2. Extract business entities (become Custom Objects) -3. Extract attributes/properties (become Custom Fields) -4. Identify relationships (Master-Detail, Lookup) -5. Detect validation requirements (become Validation Rules) -6. Detect automation requirements (become Flows) -7. Identify user personas (inform Permission Sets) - -**Output: Build Plan** - -Generate a structured plan listing: - -``` -📋 Lightning App Build Plan: [App Name] - -DATA MODEL: -- Custom Objects: [list with object names] -- Custom Fields: [list grouped by object] -- Relationships: [list M-D and Lookup relationships] - -BUSINESS LOGIC (if applicable): -- Validation Rules: [list with object and rule name] -- Flows: [list with flow name and type] - -USER INTERFACE: -- List Views: [list with object and view name] -- Custom Tabs: [list with object] -- FlexiPages: [list with page name and type] -- Custom Application: [app name] - -SECURITY: -- Permission Sets: [list with purpose] - -METADATA SKILLS TO INVOKE: -- skills/generating-custom-object/SKILL.md (x 1) -- skills/generating-custom-field/SKILL.md (x 1) -- skills/generating-validation-rule/SKILL.md (x 1) - if validation requirements identified -- skills/generating-flow/SKILL.md (x 1) - if automation requirements identified -- skills/generating-custom-tab/SKILL.md (x 1) -- skills/generating-flexipage/SKILL.md (x 1) -- skills/generating-custom-application/SKILL.md (x 1) -- skills/generating-permission-set/SKILL.md (x 1) - -DEPENDENCY ORDER: -1. Phase 1: Data Model (Objects → Fields) -2. Phase 2: Business Logic (Validation Rules → Flows) -3. Phase 3: User Interface (List Views → Tabs → Pages) -4. Phase 4: App Assembly (Application) -5. Phase 5: Security (Permission Sets) -``` - -### STEP 2: Skill Invocation Sequence - -Execute in strict dependency order. Invoke each skill once with all components for that metadata type. - -1. **Check Metadata Type Registry**: Does a skill exist? -2. **If YES (✅)**: Invoke the specialized skill once with all components for that type -3. **If NO (❌)**: Generate metadata directly using Metadata API knowledge -4. **Handle Errors**: If skill invocation fails, log error and continue (don't block entire app) - -**Invocation Pattern (one invocation per metadata type):** - -- Custom Objects → Invoke `skills/generating-custom-object/SKILL.md` once with all objects -- Custom Fields → Invoke `skills/generating-custom-field/SKILL.md` once with all fields -- Validation Rules → Invoke `skills/generating-validation-rule/SKILL.md` once (if requested) -- Flows → Invoke `skills/generating-flow/SKILL.md` once (if requested) -- Custom Tabs → Invoke `skills/generating-custom-tab/SKILL.md` once with all tabs -- FlexiPages → Invoke `skills/generating-flexipage/SKILL.md` once with all pages -- Custom Application → Invoke `skills/generating-custom-application/SKILL.md` once -- Permission Sets → Invoke `skills/generating-permission-set/SKILL.md` once with all permission sets - -### STEP 3: Final Artifact Assembly - -After all phases complete, consolidate outputs into deployment-ready structure. - ---- - -## Output - -The completed build produces: - -1. **Salesforce DX Project Directory** containing all generated metadata - - Organized by standard SFDX structure: `force-app/main/default/` - -2. **Metadata Files** - One file per component, organized by type: - ``` - force-app/main/default/ - ├── objects/ # Custom Objects (.object-meta.xml) - ├── fields/ # Custom Fields (.field-meta.xml) - ├── tabs/ # Custom Tabs (.tab-meta.xml) - ├── flexipages/ # Lightning Pages (.flexipage-meta.xml) - ├── applications/ # Custom Applications (.app-meta.xml) - ├── permissionsets/ # Permission Sets (.permissionset-meta.xml) - ├── flows/ # Flows (.flow-meta.xml) - if applicable - └── objects/.../validationRules/ # Validation Rules (.validationRule-meta.xml) - if applicable - ``` - -3. **Deployment Manifest** (`package.xml`) - - Lists all components with proper API version - - Organized by metadata type in dependency order - - Ready for Salesforce CLI deployment or Metadata API deployment - -4. **Build Summary Report** - A markdown file listing: - - Every component created - - Component type and API name - - File path location - - Dependency relationships - - Any warnings or recommendations - -**Example Summary Structure:** -``` -📦 Lightning App Build Complete: Project Management App - -METADATA GENERATED: -✅ 3 Custom Objects - - Project__c → force-app/main/default/objects/Project__c/Project__c.object-meta.xml - - Task__c → force-app/main/default/objects/Task__c/Task__c.object-meta.xml - - Resource__c → force-app/main/default/objects/Resource__c/Resource__c.object-meta.xml - -✅ 12 Custom Fields - - Project__c.Name → force-app/main/default/objects/Project__c/fields/Name.field-meta.xml - - Project__c.Status__c → force-app/main/default/objects/Project__c/fields/Status__c.field-meta.xml - [... etc ...] - -✅ 3 Custom Tabs - - Project__c → force-app/main/default/tabs/Project__c.tab-meta.xml - [... etc ...] - -✅ 3 Lightning Record Pages - - Project_Record_Page → force-app/main/default/flexipages/Project_Record_Page.flexipage-meta.xml - [... etc ...] - -✅ 1 Custom Application - - Project_Management → force-app/main/default/applications/Project_Management.app-meta.xml - -✅ 2 Permission Sets - - Project_Manager → force-app/main/default/permissionsets/Project_Manager.permissionset-meta.xml - - Project_User → force-app/main/default/permissionsets/Project_User.permissionset-meta.xml - -⚠️ WARNINGS: None -``` - ---- - -## Validation - -Before presenting the completed build to the user, verify cross-component integrity: - -- [ ] **Object-Tab Coverage**: Every Custom Object has at least one Custom Tab -- [ ] **Relationship Integrity**: Every Custom Object referenced in a relationship (parent or child) exists in the build -- [ ] **Field References in Pages**: Every field referenced in a FlexiPage exists on the corresponding object -- [ ] **Tab References in App**: Every tab referenced in the Custom Application was successfully created -- [ ] **Permission Set Completeness**: Permission Sets grant access to all generated objects, fields, tabs, and the application -- [ ] **No Orphaned Components**: No tabs without objects, no pages without corresponding tabs, no app without tabs -- [ ] **Deployment Manifest Completeness**: `package.xml` includes all generated components in proper dependency order - -**Validation Failure Handling:** -- If validation fails, include failed checks in the Build Summary Report under a `⚠️ VALIDATION WARNINGS` section -- Do NOT block delivery of the build, but clearly communicate what needs manual review or correction -- Provide specific remediation steps for each failed validation check - -**Note**: Individual component validations (reserved words, name lengths, field types, etc.) are handled by specialized metadata skills and do not need to be re-validated here. - ---- - -## Error Handling - -### Critical Errors (Stop Execution) - -Stop and ask user for clarification if: -- User request is too vague to extract any objects or fields -- Conflicting requirements detected (e.g., "make it private" + "everyone should see it") -- Invalid Salesforce naming detected (reserved words like `Order`, `Group`) - -### Non-Critical Errors (Continue with Warning) - -Log warning and continue if: -- Optional component fails (e.g., List View generation fails) -- Skill invocation fails for non-critical metadata -- Validation Rule or Flow has minor issues - -**Warning Pattern:** -``` -⚠️ Warning: [Component Type] generation encountered issue - Component: [Name] - Issue: [Description] - Impact: [What won't work] - Recommendation: [How to fix manually] - - Continuing with remaining components... -``` - ---- - -## Best Practices - -### 1. Always Follow Dependency Order -Never invoke skills out of sequence. Fields need objects, pages need tabs, apps need tabs. - -### 2. Use Skills When Available -Don't reinvent the wheel. Specialized skills have field-specific validation that prevents deployment errors. - -### 3. Generate Thoughtful Defaults -When user doesn't specify details: -- Use Text name fields for human entities -- Use AutoNumber for transactions -- Enable Search and Reports for user-facing objects -- Set sharingModel based on relationships - -### 4. Validate Before Building -Check for: -- Reserved words in API names -- Relationship limits (max 2 M-D per object) -- Name length limits -- Duplicate names \ No newline at end of file diff --git a/skills/generating-lightning-app/SKILL.md b/skills/generating-lightning-app/SKILL.md new file mode 100644 index 0000000..d634dc9 --- /dev/null +++ b/skills/generating-lightning-app/SKILL.md @@ -0,0 +1,423 @@ +--- +name: generating-lightning-app +description: Build complete Salesforce Lightning Experience applications from natural language descriptions. Use this skill when a user requests a "complete app", "Lightning app", "business solution", "management system", or describes a scenario requiring multiple interconnected Salesforce components (objects, fields, pages, tabs, security). Orchestrates all required metadata types in proper dependency order to produce a deployable application. +metadata: + version: "1.0" + related-skills: generating-custom-object, generating-custom-field, generating-custom-tab, generating-flexipage, generating-custom-application, generating-flow, generating-validation-rule, generating-list-view, generating-permission-set +--- + +# Generating Lightning App + +## Overview + +Build a complete, deployable Salesforce Lightning Experience application from a natural language description by defining a Lightning Custom Application and orchestrating its dependent metadata types in correct dependency order. Invoke specialized metadata skills when available; generate metadata directly when no skill exists. + +## When to Use This Skill + +**Use when:** + +- User requests a "Lightning app", or "end-to-end solution" +- User says "build an app", "create an application", "build a [type] app" (project management, tracking, etc.) +- The work produces a custom app (CustomApplication) plus supporting metadata, not a lone object, page, or tab in isolation + +**Examples that should trigger this skill:** + +- "Build a project management lightning app with Tasks, Resources, and Supplies objects" +- "Create a LEX app to track vehicles with Lightning pages and permission sets" +- "I need a Space Station management system with multiple objects and relationships" +- "Build an employee onboarding lightning app with custom Lightning Record Pages" + +**Do NOT use when:** + +- Creating a single metadata component (use specific metadata skill instead) +- Troubleshooting or debugging existing metadata +- Building Salesforce Classic apps (not Lightning Experience) +- User asks for just one object, or just one page, or just one permission set (without others) +- User only needs to create or configure an app container (grouping existing tabs) without other metadata; use `generating-custom-application` instead + +## Metadata Type Registry + +This table shows which metadata types are commonly needed for Lightning Experience apps, their skill availability, and API context requirement. + +| Metadata Type | Skill Name | API Context | Usage Rule | +|---------------|------------|-------------|------------| +| **Custom Object** | `generating-custom-object` | `salesforce-api-context` | MUST load skill AND call API context | +| **Custom Field** | `generating-custom-field` | `salesforce-api-context` | MUST load skill AND call API context | +| **Custom Tab** | `generating-custom-tab` | `salesforce-api-context` | MUST load skill AND call API context | +| **FlexiPage** | `generating-flexipage` | `salesforce-api-context` | MUST load skill AND call API context | +| **Custom Application** | `generating-custom-application` | `salesforce-api-context` | MUST load skill AND call API context | +| **List View** | `generating-list-view` | `salesforce-api-context` | MUST load skill AND call API context (if requested) | +| **Validation Rule** | `generating-validation-rule` | `salesforce-api-context` | MUST load skill AND call API context (if requested) | +| **Flow** | `generating-flow` | `metadata-experts` pipeline | MUST load skill AND run pipeline. **Exempt from `salesforce-api-context`**. | +| **Permission Set** | `generating-permission-set` | `salesforce-api-context` | MUST load skill AND call API context | + +### Usage Rules + +**SKILL RULE**: When a skill exists for a metadata type, you **MUST** load that skill. Do NOT generate metadata directly without loading the skill first. + +**API CONTEXT RULE**: For every metadata type (except Flow), you **MUST** call `salesforce-api-context` tools before generating. Do NOT generate metadata without calling API context first. The skill provides structure and rules; API context confirms what is valid for the current API version. Both are essential. + +**FALLBACK RULE**: When no skill exists for a metadata type you need, generate the metadata directly using your knowledge of Salesforce Metadata API and best practices. API context is still required. + +**RATIONALE**: Skills contain validated patterns and constraints. API context provides version-specific accuracy. Together they prevent deployment failures. + +--- + +## Dependency Graph & Build Order + +### Phase 1: Data Model (Foundation) + +``` +Custom Objects (no dependencies) + ↓ +Custom Fields (depends on: Objects exist) + ↓ +Relationships (depends on: Both parent and child objects + fields exist) +``` + +**Metadata types in this phase:** + +1. `generating-custom-object` - once, with all objects +2. `generating-custom-field` - once, with all fields (including Master-Detail, Lookup, Roll-up Summary) + +### Phase 2: Business Logic (Optional - only if requested) + +``` +Validation Rules (depends on: Fields exist) + ↓ +Flows (depends on: Objects, Fields exist) +``` + +**Metadata types in this phase (only if user requested):** + +1. `generating-validation-rule` - once, if validation requirements mentioned +2. `generating-flow` - once, if automation/workflow requirements mentioned + +### Phase 3: User Interface + +``` +List Views (depends on: Objects, Fields exist) + ↓ +Custom Tabs (depends on: Objects exist) + ↓ +FlexiPages (depends on: Objects, Tabs exist) +``` + +**Metadata types in this phase:** + +1. `generating-list-view` - once, for filtered record views (if requested) +2. `generating-custom-tab` - once, with all object tabs +3. `generating-flexipage` - once, with all record/home/app pages + +### Phase 4: Application Assembly + +``` +Custom Application (depends on: Tabs exist) +``` + +**Metadata types in this phase:** + +1. `generating-custom-application` - once, to create the Lightning App container + +### Phase 5: Security & Access + +``` +Permission Sets (depends on: Objects, Fields, Tabs, App exist) +``` + +**Metadata types in this phase:** + +1. `generating-permission-set` - once, with all permission sets and access to: + - Objects (Read, Create, Edit, Delete) + - Fields (Read, Edit) + - Tabs (Visible) + - Custom Application (Visible) + +--- + +## Execution Workflow + +### STEP 1: Requirements Analysis & Planning + +**Actions:** + +1. Parse user's natural language request +2. Extract business entities (become Custom Objects) +3. Extract attributes/properties (become Custom Fields) +4. Identify relationships (Master-Detail, Lookup) +5. Detect validation requirements (become Validation Rules) +6. Detect automation requirements (become Flows) +7. Identify user personas (inform Permission Sets) + +**Output: Build Plan** + +Generate a structured plan listing: + +``` +Lightning App Build Plan: [App Name] + +DATA MODEL: +- Custom Objects: [list with object names] +- Custom Fields: [list grouped by object] +- Relationships: [list M-D and Lookup relationships] + +BUSINESS LOGIC (if applicable): +- Validation Rules: [list with object and rule name] +- Flows: [list with flow name and type] + +USER INTERFACE: +- List Views (if requested): [list with object and view name] +- Custom Tabs: [list with object] +- FlexiPages: [list with page name and type] +- Custom Application: [app name] + +SECURITY: +- Permission Sets: [list with purpose] + +PER-TYPE EXECUTION (skill + API context for each): +- CustomObject: load generating-custom-object + call salesforce-api-context +- CustomField: load generating-custom-field + call salesforce-api-context +- ValidationRule: load generating-validation-rule + call salesforce-api-context (if requested) +- Flow: load generating-flow + run metadata-experts pipeline (if requested) +- ListView: load generating-list-view + call salesforce-api-context (if requested) +- CustomTab: load generating-custom-tab + call salesforce-api-context +- FlexiPage: load generating-flexipage + call salesforce-api-context +- CustomApplication: load generating-custom-application + call salesforce-api-context +- PermissionSet: load generating-permission-set + call salesforce-api-context + +STATUS LINES TO EMIT BEFORE FILE WRITES: +- `type= skill=complete mcp=complete|unavailable mcp_tools=` +- Flow exception: `type=Flow skill=complete pipeline=complete` + +DEPENDENCY ORDER: +1. Phase 1: Data Model (Objects -> Fields) +2. Phase 2: Business Logic (Validation Rules -> Flows) +3. Phase 3: User Interface (List Views -> Tabs -> Pages) +4. Phase 4: App Assembly (Application) +5. Phase 5: Security (Permission Sets) +``` + +### STEP 2: Per-Type Execution + +Execute these four steps for each metadata type, one type at a time. Complete all four steps for the current type before moving to the next type. Do NOT skip any step. + +| Step | What to do | Why | +|------|-----------|-----| +| **① Load skill** | Search for and read the per-type SKILL.md | Gives you the XML structure, required elements, naming rules, and validation constraints | +| **② Call API context** | Call `salesforce-api-context` tools for this metadata type using one or more of: `get_metadata_type_sections`, `get_metadata_type_context`, `get_metadata_type_fields`, `get_metadata_type_fields_properties`, `search_metadata_types` | Gives you the current valid values — allowed enum values, required vs. optional fields, child types for this API version. The skill provides structure; API context provides version-specific accuracy. | +| **③ Record status** | Emit: `type= skill=complete mcp=complete\|unavailable mcp_tools=` | Confirms both steps were attempted before any files are written and records which API context tools were used | +| **④ Generate files** | Generate all files for this type, then checkpoint | Only after ①②③ are done. Verify, then move to the next type. | + +**Do NOT combine ① and ② into a single action or skip ② after completing ①.** They are separate steps that serve different purposes. After loading the skill you may feel ready to generate — stop and do ② first. + +If `salesforce-api-context` is unavailable after a real attempt, record `mcp=unavailable` and generate using skill knowledge alone. Not attempting ② at all is a bug. + +--- + +**1. Custom Objects** +- ① Load skill: Read `generating-custom-object` SKILL.md +- ② API context: Call `salesforce-api-context` for CustomObject +- ③ Status: `type=CustomObject skill=complete mcp=complete|unavailable mcp_tools=` +- ④ Generate + Checkpoint: Generate all Custom Object files, then proceed to #2 + +**2. Custom Fields** +- ① Load skill: Read `generating-custom-field` SKILL.md +- ② API context: Call `salesforce-api-context` for CustomField +- ③ Status: `type=CustomField skill=complete mcp=complete|unavailable mcp_tools=` +- ④ Generate + Checkpoint: Generate all Custom Field files, then proceed to #3 + +**3. Validation Rules** (only if requested) +- ① Load skill: Read `generating-validation-rule` SKILL.md +- ② API context: Call `salesforce-api-context` for ValidationRule +- ③ Status: `type=ValidationRule skill=complete mcp=complete|unavailable mcp_tools=` +- ④ Generate + Checkpoint: Generate all Validation Rule files, then proceed to #4 + +**4. Flows** (only if requested) +- ① Load skill: Read `generating-flow` SKILL.md +- ② Pipeline: Run `metadata-experts/execute_metadata_action` 3-step pipeline (exempt from `salesforce-api-context`) +- ③ Status: `type=Flow skill=complete pipeline=complete` +- ④ Generate + Checkpoint: Generate all Flow files via the pipeline, then proceed to #5 + +**5. List Views** (only if requested) +- ① Load skill: Read `generating-list-view` SKILL.md +- ② API context: Call `salesforce-api-context` for ListView +- ③ Status: `type=ListView skill=complete mcp=complete|unavailable mcp_tools=` +- ④ Generate + Checkpoint: Generate all List View files, then proceed to #6 + +**6. Custom Tabs** +- ① Load skill: Read `generating-custom-tab` SKILL.md +- ② API context: Call `salesforce-api-context` for CustomTab +- ③ Status: `type=CustomTab skill=complete mcp=complete|unavailable mcp_tools=` +- ④ Generate + Checkpoint: Generate all Custom Tab files, then proceed to #7 + +**7. FlexiPages** +- ① Load skill: Read `generating-flexipage` SKILL.md +- ② API context: Call `salesforce-api-context` for FlexiPage +- ③ Status: `type=FlexiPage skill=complete mcp=complete|unavailable mcp_tools=` +- ④ Generate + Checkpoint: Generate all FlexiPage files, then proceed to #8 + +**8. Custom Application** +- ① Load skill: Read `generating-custom-application` SKILL.md +- ② API context: Call `salesforce-api-context` for CustomApplication +- ③ Status: `type=CustomApplication skill=complete mcp=complete|unavailable mcp_tools=` +- ④ Generate + Checkpoint: Generate the Custom Application file, then proceed to #9 + +**9. Permission Sets** +- ① Load skill: Read `generating-permission-set` SKILL.md +- ② API context: Call `salesforce-api-context` for PermissionSet +- ③ Status: `type=PermissionSet skill=complete mcp=complete|unavailable mcp_tools=` +- ④ Generate + Checkpoint: Generate all Permission Set files — all types complete + +### STEP 3: Final Artifact Assembly + +After all phases complete, consolidate outputs into deployment-ready structure. + +--- + +## Output + +The completed build produces: + +1. **Salesforce DX Project Directory** containing all generated metadata + - Organized by standard SFDX structure: `force-app/main/default/` +2. **Metadata Files** - One file per component, organized by type: + + ``` + force-app/main/default/ + ├── objects/ # Custom Objects (.object-meta.xml) + ├── fields/ # Custom Fields (.field-meta.xml) + ├── tabs/ # Custom Tabs (.tab-meta.xml) + ├── flexipages/ # Lightning Pages (.flexipage-meta.xml) + ├── applications/ # Custom Applications (.app-meta.xml) + ├── permissionsets/ # Permission Sets (.permissionset-meta.xml) + ├── flows/ # Flows (.flow-meta.xml) - if applicable + └── objects/.../validationRules/ # Validation Rules (.validationRule-meta.xml) - if applicable + ``` + +3. **Deployment Manifest** (`package.xml`) + - Lists all components with proper API version + - Organized by metadata type in dependency order + - Ready for Salesforce CLI deployment or Metadata API deployment +4. **Build Summary Report** - A markdown file listing: + - Every component created + - Component type and API name + - File path location + - Dependency relationships + - Any warnings or recommendations + +**Example Summary Structure:** + +``` +Lightning App Build Complete: Project Management App + +METADATA GENERATED: +1 Custom Objects + - Project__c -> force-app/main/default/objects/Project__c/Project__c.object-meta.xml + - Task__c -> force-app/main/default/objects/Task__c/Task__c.object-meta.xml + - Resource__c -> force-app/main/default/objects/Resource__c/Resource__c.object-meta.xml + +2 Custom Fields + - Project__c.Name -> force-app/main/default/objects/Project__c/fields/Name.field-meta.xml + - Project__c.Status__c -> force-app/main/default/objects/Project__c/fields/Status__c.field-meta.xml + [... etc ...] + +3 Custom Tabs + - Project__c -> force-app/main/default/tabs/Project__c.tab-meta.xml + [... etc ...] + +4 Lightning Record Pages + - Project_Record_Page -> force-app/main/default/flexipages/Project_Record_Page.flexipage-meta.xml + [... etc ...] + +5 Custom Application + - Project_Management -> force-app/main/default/applications/Project_Management.app-meta.xml + +6 Permission Sets + - Project_Manager -> force-app/main/default/permissionsets/Project_Manager.permissionset-meta.xml + - Project_User -> force-app/main/default/permissionsets/Project_User.permissionset-meta.xml + +WARNINGS: None +``` + +--- + +## Validation + +Before presenting the completed build to the user, verify cross-component integrity: + +- [ ] **Object-Tab Coverage**: Every Custom Object has at least one Custom Tab +- [ ] **Relationship Integrity**: Every Custom Object referenced in a relationship (parent or child) exists in the build +- [ ] **Field References in Pages**: Every field referenced in a FlexiPage exists on the corresponding object +- [ ] **Tab References in App**: Every tab referenced in the Custom Application was successfully created +- [ ] **Permission Set Completeness**: Permission Sets grant access to all generated objects, fields, tabs, and the application +- [ ] **No Orphaned Components**: No tabs without objects, no pages without corresponding tabs, no app without tabs +- [ ] **Deployment Manifest Completeness**: `package.xml` includes all generated components in proper dependency order + +**Validation Failure Handling (Category 2):** + +- If validation fails, include failed checks in the Build Summary Report under a `VALIDATION WARNINGS` section +- These are post-generation issues — do NOT block delivery of the build, but clearly communicate what needs manual review or correction +- Provide specific remediation steps for each failed validation check + +**Note**: Individual component validations (reserved words, name lengths, field types, etc.) are handled by specialized metadata skills and do not need to be re-validated here. + +--- + +## Error Handling + +### Category 1: Stop and Ask User + +Stop execution and ask for clarification if: + +- User request is too vague to extract any objects or fields +- Conflicting requirements detected (e.g., "make it private" + "everyone should see it") +- Invalid Salesforce naming detected (reserved words like `Order`, `Group`) + +### Category 2: Post-Generation Warnings (Log Warning, Continue) + +Log warning and continue if: + +- Cross-component validation check fails (e.g., field referenced in FlexiPage doesn't exist on object) +- Optional component generation fails (e.g., List View generation has minor issues) +- Validation Rule or Flow has minor output issues + +**Warning Pattern:** + +``` +Warning: [Component Type] generation encountered issue + Component: [Name] + Issue: [Description] + Impact: [What won't work] + Recommendation: [How to fix manually] + Continuing with remaining components... +``` + +--- + +## Best Practices + +### 1. Always Follow Dependency Order + +Never invoke skills out of sequence. Fields need objects, pages need tabs, apps need tabs. + +### 2. Use Skills When Available + +Don't reinvent the wheel. Specialized skills have field-specific validation that prevents deployment errors. + +### 3. Generate Thoughtful Defaults + +When user doesn't specify details: + +- Use Text name fields for human entities +- Use AutoNumber for transactions +- Enable Search and Reports for user-facing objects +- Set sharingModel based on relationships + +### 4. Validate Before Building + +Check for: + +- Reserved words in API names +- Relationship limits (max 2 M-D per object) +- Name length limits +- Duplicate names \ No newline at end of file diff --git a/skills/switching-org/SKILL.md b/skills/switching-org/SKILL.md new file mode 100644 index 0000000..148cb09 --- /dev/null +++ b/skills/switching-org/SKILL.md @@ -0,0 +1,28 @@ +--- +name: switching-org +description: Switches the active Salesforce org (default target-org) using the Salesforce CLI. Use whenever someone wants to change which org CLI commands run against — whether they say "switch org", "change default org", "set my org to", "use alias", "point to", or describe wanting to work against a specific org, scratch org, sandbox, or production. +compatibility: Salesforce CLI (sf) v2+ +metadata: + version: "1.0" +--- + +## Steps + +1. Identify the org: the user provides a username or alias (`orgIdentifier`). If not provided, run `sf org list` to show authenticated orgs and ask the user which one to use. +2. Set the default org: + - Local (default): `sf config set target-org ` + - Applies only within the current project directory. Use this for normal project work. + - Global (only if user explicitly requests): `sf config set target-org --global` + - Applies system-wide across all directories. Use when working outside a project or when the user asks for global scope. + - If this fails, report the error and suggest running `sf org login web` if the org may not be authorized. +3. Verify: + - `sf config get target-org --json` + - Note: the JSON output does not include a scope/location field — it cannot confirm whether the value is local or global. Confirm the value only, e.g.: `target-org is now set to: ` + - If it fails, report the error and advise running `sf config get target-org`. + +## Notes + +- Unified CLI uses keys like `target-org` and `target-dev-hub`. Legacy sfdx keys (`defaultusername`, `defaultdevhubusername`) are deprecated in this context. +- The sf CLI does not have `--local` or `--scope` flags for config set. Local scope is the default behavior. +- If the org does not change after setting the config, check whether `SF_TARGET_ORG` is set — environment variables override config values. +- Salesforce CLI config (unified) reference: https://developer.salesforce.com/docs/atlas.en-us.sfdx_cli_reference.meta/sfdx_cli_reference/cli_reference_config_commands_unified.htm#cli_reference_config_set_unified