mirror of
https://github.com/forcedotcom/afv-library.git
synced 2026-08-02 13:25:16 +08:00
Merge branch 'main' into k-j-kim/consolidate-webapp-skills
This commit is contained in:
commit
faa2b68d15
6
.gitignore
vendored
6
.gitignore
vendored
@ -128,10 +128,8 @@ venv.bak/
|
||||
|
||||
# React sample templates: track internal `src/lib` utility modules
|
||||
# These rules override the global `lib/` ignore in the Python section above.
|
||||
!samples/webapp-template-app-react-sample-b2x-experimental/force-app/main/default/webapplications/appreactsampleb2x/src/lib/
|
||||
!samples/webapp-template-app-react-sample-b2x-experimental/force-app/main/default/webapplications/appreactsampleb2x/src/lib/**
|
||||
!samples/webapp-template-app-react-sample-b2e-experimental/force-app/main/default/webapplications/appreactsampleb2e/src/lib/
|
||||
!samples/webapp-template-app-react-sample-b2e-experimental/force-app/main/default/webapplications/appreactsampleb2e/src/lib/**
|
||||
!samples/**/lib/
|
||||
!samples/**/lib/**
|
||||
|
||||
# IDEs and Editors
|
||||
.vscode/
|
||||
|
||||
@ -1,3 +1,12 @@
|
||||
## [1.5.1](https://github.com/forcedotcom/afv-library/compare/1.5.0...1.5.1) (2026-03-27)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* correct .gitignore to track sample lib/ folders @W-21361802@ ([#119](https://github.com/forcedotcom/afv-library/issues/119)) ([7018d49](https://github.com/forcedotcom/afv-library/commit/7018d49e26aa366962e0073f3e964adab47ccea2))
|
||||
|
||||
|
||||
|
||||
# [1.5.0](https://github.com/forcedotcom/afv-library/compare/1.4.0...1.5.0) (2026-03-24)
|
||||
|
||||
|
||||
|
||||
427
README.md
427
README.md
@ -1,48 +1,34 @@
|
||||
# Agentforce Vibes Library
|
||||
|
||||
AI prompts and rules library for Agentforce Vibes development, content creation, and workflow automation.
|
||||
AI skills and rules library for Agentforce Vibes development of Salesforce metadata.
|
||||
|
||||
## 📚 About
|
||||
|
||||
This repository curates Salesforce-focused prompts, system rules, and executable skills from the wider developer community to accelerate Agentforce Vibes agentic workflows. Collections are organized by development discipline—Apex, LWC, flows, deployments, testing, investigation, spec-driven delivery, and more—so contributors can share reusable prompts, scaffolds, guardrails, and workflows that other teams can adapt and extend.
|
||||
This repository curates Salesforce-focused skills and system rules from the wider developer community to accelerate Agentforce Vibes agentic workflows.
|
||||
|
||||
## 🗂️ Structure
|
||||
|
||||
```
|
||||
afv-library/
|
||||
├── prompts/ # Single-file instructions for straightforward tasks
|
||||
│ ├── apex-development/
|
||||
│ ├── lwc-development/
|
||||
│ ├── flow-development/
|
||||
│ ├── getting-started/
|
||||
│ └── ...
|
||||
├── rules/ # Single-file guardrails and standards
|
||||
│ ├── apex-development/
|
||||
│ ├── lwc-development/
|
||||
│ ├── spec-driven-dev/
|
||||
│ └── ...
|
||||
├── skills/ # Directory-based executable workflows
|
||||
│ ├── apex-development/
|
||||
│ │ └── trigger-refactor-pipeline/
|
||||
│ │ ├── SKILL.md
|
||||
│ │ ├── scripts/
|
||||
│ │ ├── references/
|
||||
│ │ └── assets/
|
||||
│ ├── metadata-deployments/
|
||||
│ ├── testing-automation/
|
||||
│ ├── generating-apex/
|
||||
│ ├── generating-custom-object/
|
||||
│ ├── generating-flow/
|
||||
│ └── ...
|
||||
├── samples/ # Synced sample apps (e.g. from npm)
|
||||
│ └── webapp-template-app-react-sample-b2e-experimental/
|
||||
│ └── ...
|
||||
├── scripts/
|
||||
│ └── ...
|
||||
└── README.md
|
||||
```
|
||||
|
||||
## 🚀 Quick Start
|
||||
## Manual Usage
|
||||
|
||||
### Manual Usage
|
||||
Browse the repository and copy/paste any rule or skill directly into Agentforce Vibes or your preferred AI tool.
|
||||
|
||||
Browse the repository and copy/paste any prompt, rule, or skill directly into Agentforce Vibes or your preferred AI tool.
|
||||
|
||||
### Samples
|
||||
## Samples
|
||||
|
||||
The `samples/` folder contains synced sample apps. For example, `samples/webapp-template-app-react-sample-b2e-experimental/` is kept in sync with the npm package `@salesforce/webapp-template-app-react-sample-b2e-experimental` (nightly and on manual trigger via GitHub Actions). To run the same sync locally from the repo root:
|
||||
|
||||
@ -53,87 +39,10 @@ npm run sync-react-b2e-sample
|
||||
|
||||
The GitHub Action runs these same commands and opens a PR only when the npm package version has changed. See [samples/README.md](samples/README.md) for details.
|
||||
|
||||
### Connecting Team or Personal Libraries
|
||||
|
||||
You can register additional repos with the extension as long as they mirror this structure:
|
||||
## 🛠️ Agent Skills
|
||||
|
||||
- Root folders named `prompts/`, `rules/`, and `skills/`, each containing category subfolders (e.g., `prompts/apex-development/`).
|
||||
- Each prompt or rule stored in its own Markdown file with YAML frontmatter (`name`, `description`, `tags`, optional setup metadata).
|
||||
- Each skill stored in its own directory containing a `SKILL.md` file with required frontmatter, plus optional `scripts/`, `references/`, and `assets/` subdirectories.
|
||||
- Category folders may include a `README.md` describing their focus; empty folders are allowed for future content.
|
||||
|
||||
When you add a new library:
|
||||
|
||||
1. **Structure your repository** with the same folder layout shown in `## 🗂️ Structure`:
|
||||
- `prompts/` folder with category subfolders containing `.md` files
|
||||
- `rules/` folder with category subfolders containing `.md` files
|
||||
- `skills/` folder with category subfolders, each containing skill directories with `SKILL.md`
|
||||
2. **Follow format requirements**:
|
||||
- Prompts and rules: YAML frontmatter (`name`, `description`, `tags`) + markdown body
|
||||
- Skills: Directory with `SKILL.md` + optional `scripts/`, `references/`, `assets/` subdirectories
|
||||
3. **Ensure script executability** for skills: Mark Python/Bash scripts as executable (`chmod +x`)
|
||||
4. **Register the repository** with `Agentforce Vibes: Add Library` in VS Code
|
||||
5. **Refresh the extension** to index and display the new content
|
||||
|
||||
## 📝 Prompt Format
|
||||
|
||||
Every prompt begins with YAML frontmatter that surfaces key metadata to contributors and tooling:
|
||||
|
||||
```markdown
|
||||
---
|
||||
name: Concise Prompt Title
|
||||
description: One-sentence summary of the outcome you want
|
||||
tags: category, use-case, tooling
|
||||
requires_deploy: true # optional – include when pre-work is required
|
||||
setup_summary: Deploy baseline trigger before refactor # optional helper text
|
||||
---
|
||||
```
|
||||
|
||||
- `name`, `description`, and `tags` are required.
|
||||
- Use lowercase, comma-separated tags drawn from the category and focus area (e.g., `apex, refactor, testing`).
|
||||
- Add `requires_deploy` (and an optional `setup_summary`) when the prompt depends on seed metadata or data.
|
||||
|
||||
After the frontmatter, organize the body with clear sections. A common pattern is:
|
||||
|
||||
1. `## Setup` – only when pre-work, sample metadata, or environment configuration is needed.
|
||||
2. `## Context` – summarize the scenario, constraints, personas, or assets involved.
|
||||
3. `## Instructions` – detail the tasks in numbered steps, calling out decision points or checkpoints.
|
||||
4. `## Testing & Reporting` – define verification steps, coverage expectations, or deliverables.
|
||||
5. `## Follow-ups` – optional space for stretch goals, review questions, or iteration loops.
|
||||
|
||||
### Example Prompt
|
||||
|
||||
**File:** `prompts/apex-development/trigger-refactoring.md`
|
||||
|
||||
```markdown
|
||||
---
|
||||
name: Trigger Refactor Helper
|
||||
description: Refactor the Opportunity trigger into a handler pattern with tests
|
||||
tags: apex, refactor, testing
|
||||
requires_deploy: true
|
||||
setup_summary: Deploy baseline trigger to target org before running instructions
|
||||
---
|
||||
|
||||
## Setup
|
||||
1. Deploy the baseline trigger shown below to your default or scratch org.
|
||||
2. Confirm the trigger compiles successfully before continuing.
|
||||
|
||||
```apex
|
||||
// ... baseline trigger omitted for brevity ...
|
||||
```
|
||||
|
||||
## Instructions
|
||||
Refactor `OpportunityTrigger` into a handler class (or classes) that handles the same behavior using bulk-safe patterns. Ensure the trigger itself delegates and remains behaviorally identical.
|
||||
|
||||
## Testing & Reporting
|
||||
- Create unit tests covering positive and negative paths for each handler method.
|
||||
- Include a bulk test that updates 50 `Opportunity` records where only half qualify for the `after update` logic.
|
||||
- Deploy the refactored code and run the tests, then report coverage and key observations.
|
||||
```
|
||||
|
||||
## 🛠️ Agent Skills Format
|
||||
|
||||
Agent Skills extend prompts and rules by bundling executable workflows, scripts, and reference materials into self-contained directories. Skills follow the open [Agent Skills specification](https://agentskills.io/) and are portable across many agent tools (Cursor, Claude Code, VS Code extensions, etc.).
|
||||
Agent Skills extend rules by bundling executable workflows, scripts, and reference materials into self-contained directories. Skills follow the open [Agent Skills specification](https://agentskills.io/) and are portable across many agent tools (Cursor, Claude Code, VS Code extensions, etc.).
|
||||
|
||||
### Directory Structure
|
||||
|
||||
@ -143,324 +52,16 @@ Each skill is a folder containing:
|
||||
- `references/` (optional) - additional documentation
|
||||
- `assets/` (optional) - templates, schemas, lookup data
|
||||
|
||||
### Required Frontmatter
|
||||
|
||||
```yaml
|
||||
---
|
||||
name: skill-name-here # lowercase, hyphens, matches folder name
|
||||
description: What this skill does and when to use it (1-1024 chars)
|
||||
license: Apache-2.0 # optional
|
||||
compatibility: Requires... # optional
|
||||
metadata: # optional
|
||||
author: your-org
|
||||
version: "1.0"
|
||||
allowed-tools: Bash Read Write # optional, space-delimited
|
||||
---
|
||||
```
|
||||
|
||||
The `name` must:
|
||||
- Be 1-64 characters
|
||||
- Use only lowercase letters, numbers, and hyphens
|
||||
- Match the parent directory name
|
||||
- Not start or end with hyphens
|
||||
|
||||
The `description` should explain both what the skill does and when to use it, including keywords that help agents identify relevant tasks.
|
||||
|
||||
### Progressive Disclosure
|
||||
|
||||
Skills are designed for efficient context use:
|
||||
|
||||
1. **Discovery** - agents load only name + description at startup
|
||||
2. **Activation** - full SKILL.md loaded when needed
|
||||
3. **Execution** - scripts/references loaded on-demand
|
||||
|
||||
Keep your main `SKILL.md` under 500 lines and move detailed reference material to separate files.
|
||||
|
||||
### Example Skill Structure
|
||||
|
||||
**File:** `skills/apex-development/trigger-refactor-pipeline/SKILL.md`
|
||||
|
||||
```markdown
|
||||
---
|
||||
name: trigger-refactor-pipeline
|
||||
description: Refactor Salesforce triggers into handler patterns with automated test generation and deployment. Use when modernizing legacy triggers with DML/SOQL in loops.
|
||||
license: Apache-2.0
|
||||
compatibility: Requires Salesforce CLI, Python 3.9+, jq
|
||||
metadata:
|
||||
author: afv-library
|
||||
version: "1.0"
|
||||
---
|
||||
|
||||
## When to Use This Skill
|
||||
|
||||
Use when you need to modernize legacy triggers with DML/SOQL in loops or inconsistent patterns.
|
||||
|
||||
## Step 1: Analyze Trigger
|
||||
|
||||
Run `scripts/analyze_trigger.py <TriggerName>` to identify anti-patterns:
|
||||
- DML operations inside loops
|
||||
- SOQL queries inside loops
|
||||
- Missing bulkification
|
||||
|
||||
The script outputs a report showing:
|
||||
- Line numbers with issues
|
||||
- Recommended refactoring approach
|
||||
- Complexity score
|
||||
|
||||
## Step 2: Generate Handler
|
||||
|
||||
See [handler patterns reference](references/handler_patterns.md) for templates that match your trigger context:
|
||||
- Before insert/update patterns
|
||||
- After insert/update/delete patterns
|
||||
- Bulk collection strategies
|
||||
|
||||
Copy the appropriate template from `assets/` and customize.
|
||||
|
||||
## Step 3: Create Tests
|
||||
|
||||
Use `assets/test_template.apex` as a scaffold. Ensure coverage includes:
|
||||
- Single record operations
|
||||
- Bulk operations (200+ records)
|
||||
- Mixed scenarios
|
||||
- Negative cases
|
||||
|
||||
## Step 4: Deploy and Validate
|
||||
|
||||
Deploy using Salesforce CLI and run all tests. Verify:
|
||||
- All tests pass with 100% coverage
|
||||
- No new governor limit issues
|
||||
- Behavior matches original trigger
|
||||
```
|
||||
|
||||
### Validation
|
||||
|
||||
Skills can be validated using the [skills-ref](https://github.com/agentskills/agentskills/tree/main/skills-ref) tool:
|
||||
|
||||
```bash
|
||||
skills-ref validate ./skills/apex-development/trigger-refactor-pipeline
|
||||
```
|
||||
|
||||
This checks that your `SKILL.md` frontmatter is valid and follows all naming conventions.
|
||||
|
||||
## 📂 Categories Guide
|
||||
|
||||
These starter categories reflect the current repository layout. Contributors are welcome to propose new ones or reorganize as long as the structure stays consistent for the VS Code extension.
|
||||
|
||||
### When to Use Each Format
|
||||
|
||||
| Format | Use When | Example |
|
||||
|--------|----------|---------|
|
||||
| **Prompt** | Single-shot instruction for a straightforward task | "Create a validation rule on Account that prevents blank NumberOfEmployees" |
|
||||
| **Rule** | Ongoing guardrail or standard to enforce | "Apex triggers must delegate to handler classes with bulk-safe patterns" |
|
||||
| **Skill** | Multi-step workflow requiring scripts, templates, or reference docs | "Refactor trigger → analyze anti-patterns → generate handler → create tests → deploy" |
|
||||
|
||||
### Prompts
|
||||
|
||||
| Category | Purpose | Example Topics |
|
||||
|----------|---------|----------------|
|
||||
| **apex-development** | Build and optimize Apex codebases | Trigger frameworks, async patterns, governor limit tuning |
|
||||
| **lwc-development** | Craft Lightning Web Components | Component architecture, reactive data, UI patterns |
|
||||
| **metadata-deployments** | Plan and execute releases | Packaging, Git branching, rollback prep |
|
||||
| **vibe-coding** | Agentforce Vibes coding workflows | Apex/LWC scaffolds, prompt-to-code translation |
|
||||
| **testing-automation** | Validate platform behavior | Apex tests, Flow scenarios, regression suites |
|
||||
| **investigation-triage** | Diagnose and resolve issues | Incident response, log analysis, performance forensics |
|
||||
| **data-operations** | Manage data pipelines | ETL prompts, bulk operations, platform events |
|
||||
| **spec-driven-dev** | Generate and refine specification-first workflows | Requirement capture, traceability matrices, auto-generated tasks |
|
||||
| **security-compliance** | Enforce standards and controls | Permission audits, secure coding, compliance narratives |
|
||||
| **integration-fabric** | Coordinate external services | API design, middleware coordination, error recovery |
|
||||
| **enablement-docs** | Share knowledge and runbooks | Onboarding guides, release notes, changelog automation |
|
||||
|
||||
### Skills
|
||||
|
||||
Skills mirror the same category structure as prompts and rules. Each skill is a directory containing executable workflows.
|
||||
|
||||
| Category | Purpose | Example Skills |
|
||||
|----------|---------|----------------|
|
||||
| **apex-development** | Automated Apex refactoring and analysis | Trigger refactor pipeline, bulk operation optimizer |
|
||||
| **lwc-development** | Lightning Web Component workflows | Component generator, accessibility audit |
|
||||
| **flow-development** | Flow automation and optimization | Flow analyzer, subflow extractor |
|
||||
| **metadata-deployments** | Release management automation | Deployment readiness check, rollback automation |
|
||||
| **testing-automation** | Test generation and execution | Test data factory, coverage analyzer |
|
||||
| **investigation-triage** | Debugging and diagnostics | Log parser, governor limit analyzer |
|
||||
| **data-operations** | Data pipeline automation | ETL validator, data quality checker |
|
||||
| **spec-driven-dev** | Specification-to-code workflows | Requirements parser, test case generator |
|
||||
|
||||
### Rules
|
||||
|
||||
| Category | Focus | Example Assets |
|
||||
|----------|-------|----------------|
|
||||
| **apex-development** | Standards for Apex architecture and quality | Trigger guardrails, async execution policies |
|
||||
| **lwc-development** | Front-end guardrails for Lightning Web Components | Accessibility checklists, component review templates |
|
||||
| **metadata-deployments** | Release management discipline | Branching policies, deployment readiness reviews |
|
||||
| **vibe-coding** | Coding quality for Agentforce Vibes assets | Code review criteria, secure pattern guides |
|
||||
| **testing-automation** | Verification and validation expectations | Test coverage thresholds, regression playbooks |
|
||||
| **investigation-triage** | Incident and root-cause response | Escalation runbooks, logging requirements |
|
||||
| **data-operations** | Data stewardship and job governance | Data quality SLAs, bulk job safeguards |
|
||||
| **spec-driven-dev** | Specification-first delivery standards | Definition-of-done templates, traceability requirements |
|
||||
| **security-compliance** | Platform security and regulatory posture | Access reviews, compliance attestation steps |
|
||||
| **integration-fabric** | External connection reliability | Retry policies, credential rotation standards |
|
||||
| **enablement-docs** | Knowledge management and enablement | Release note templates, onboarding workflows |
|
||||
| **org-governance** | Enterprise policy alignment | Org strategy playbooks, architecture review guidelines |
|
||||
| **support-operations** | Production support excellence | Incident response SLAs, shift handover procedures |
|
||||
| **ai-safety** | Responsible agent behavior | Ethical guidelines, bias detection checklists |
|
||||
|
||||
## ✨ Creating New Prompts & Rules
|
||||
|
||||
1. **Choose the right category** based on use case (if nothing fits, propose a new category)
|
||||
2. **Create a descriptive filename** (use kebab-case: `my-prompt.md`)
|
||||
3. **Add frontmatter** with name, description, and tags
|
||||
4. **Write clear instructions** with placeholders for user input
|
||||
5. **Test** before committing
|
||||
6. **Commit with message**: `Add [name] for [use case]`
|
||||
|
||||
### Naming Conventions
|
||||
|
||||
- Use lowercase with hyphens: `code-review-helper.md`
|
||||
- Be descriptive: `salesforce-apex-debug.md` not `debug.md`
|
||||
- Include context: `blog-post-outline.md` not `outline.md`
|
||||
|
||||
## 🔧 Best Practices
|
||||
|
||||
### Writing Effective Prompts
|
||||
|
||||
- ✅ **Be specific** - Clear instructions yield better results
|
||||
- ✅ **Use structure** - Numbered lists and sections help
|
||||
- ✅ **Add context** - Explain what you want and why
|
||||
- ✅ **Include examples** - Show expected output format
|
||||
- ✅ **Test thoroughly** - Verify prompts work as intended
|
||||
|
||||
### Prompt Engineering
|
||||
|
||||
- ✅ **Clarify the objective** – Capture the outcome, stakeholders, and success metrics directly in the frontmatter
|
||||
- ✅ **Share context** – Provide links, metadata, or sample records so the agent can ground its reasoning
|
||||
- ✅ **Set guardrails** – Define tone, compliance boundaries, what to avoid, and when to ask for confirmation
|
||||
- ✅ **Guide the workflow** – Break the request into staged checkpoints (ideate → propose → confirm → deliver)
|
||||
- ✅ **Capture feedback loops** – Invite the agent to flag assumptions, pose questions, and suggest validation steps
|
||||
- ✅ **Encourage adaptability** – Note how the prompt or rule can flex across org types, industries, and data volumes
|
||||
|
||||
#### Structuring Prompts
|
||||
|
||||
- **Prime with examples**: Include concise samples that illustrate the desired format or code pattern
|
||||
- **Model the format**: Provide headings and numbered steps so the agent mirrors the final artifact
|
||||
- **Address ambiguity**: Explicitly call out unknowns and ask the agent to gather missing inputs
|
||||
- **Control verbosity**: Specify length limits, number of alternatives, or time horizons
|
||||
- **Request diagnostics**: Ask the agent to share reasoning, risks, and verification plans when appropriate
|
||||
|
||||
#### Template: Multi-Step Prompt
|
||||
|
||||
```markdown
|
||||
---
|
||||
name: Apex Service Hardening Plan
|
||||
description: Audit and fortify an Apex service to stay within governor limits while preserving behavior
|
||||
tags: apex-development, optimization, audit
|
||||
requires_deploy: false
|
||||
---
|
||||
|
||||
## Context
|
||||
- Usage profile: [Invocation volume, entry points, data scale]
|
||||
- Known issues: [Timeouts, limit exceptions, performance complaints]
|
||||
- Stakeholders: [Product owners, support teams, compliance partners]
|
||||
|
||||
## Instructions
|
||||
1. Summarize existing architecture, dependencies, and limit usage; list assumptions needing confirmation.
|
||||
2. Propose at least two optimization strategies, including refactor scope, data implications, and rollback considerations.
|
||||
3. Recommend a preferred strategy once assumptions are resolved, detailing implementation phases and change management steps.
|
||||
|
||||
## Testing & Reporting
|
||||
- Define unit, integration, and bulk test coverage with pass criteria.
|
||||
- Specify telemetry/observability updates (logging, metrics, alerts) to validate success.
|
||||
- Produce an execution checklist with owners, timelines, and escalation contacts.
|
||||
```
|
||||
|
||||
### Organizing Rules
|
||||
|
||||
- ✅ **One rule per file** - Keep rules focused and modular
|
||||
- ✅ **Use clear names** - Describe what the rule enforces
|
||||
- ✅ **Document purpose** - Explain why the rule exists
|
||||
- ✅ **Keep updated** - Review and refine regularly
|
||||
- ✅ **Version control** - Track changes over time
|
||||
|
||||
## 🤝 Contributing
|
||||
|
||||
### How to Contribute
|
||||
|
||||
See [Contributing](./CONTRIBUTING.md) for complete details.
|
||||
|
||||
**Contribution checklist**
|
||||
- Confirm the file lives in the correct category folder
|
||||
- Complete the YAML frontmatter (`name`, `description`, `tags`)
|
||||
- Include clear instructions and placeholders for user-specific details
|
||||
- Add a short note on how others can adapt the prompt, especially for varying Salesforce environments
|
||||
- Verify the content respects licensing and attribution requirements
|
||||
- Provide any supporting references or context in the pull request description
|
||||
|
||||
### Creating New Skills
|
||||
|
||||
Skills are more complex than prompts and require additional setup:
|
||||
|
||||
1. **Create a folder** under the appropriate `skills/<category>/` directory using lowercase + hyphens (e.g., `trigger-refactor-pipeline`).
|
||||
2. **Add a `SKILL.md` file** with required frontmatter:
|
||||
- `name` - must match the folder name (lowercase, hyphens only)
|
||||
- `description` - explain what the skill does and when to use it (1-1024 characters)
|
||||
- Optional: `license`, `compatibility`, `metadata`, `allowed-tools`
|
||||
3. **Optionally add subdirectories**:
|
||||
- `scripts/` - executable Python, Bash, or JavaScript files
|
||||
- `references/` - additional documentation files
|
||||
- `assets/` - templates, schemas, or lookup data
|
||||
4. **Validate your skill** using the [skills-ref](https://github.com/agentskills/agentskills/tree/main/skills-ref) tool:
|
||||
```bash
|
||||
skills-ref validate ./skills/<category>/<skill-name>
|
||||
```
|
||||
5. **Test the skill end-to-end** before submitting. Ensure:
|
||||
- The skill activates correctly when the description keywords match
|
||||
- All scripts execute without errors
|
||||
- Reference files are accessible and well-organized
|
||||
- The workflow produces the expected outcomes
|
||||
6. **Document dependencies** clearly in the `compatibility` field if your skill requires specific tools or system packages.
|
||||
|
||||
### Feedback
|
||||
## Feedback
|
||||
|
||||
Found an issue or have a suggestion?
|
||||
- Open an issue in GitHub
|
||||
- Suggest improvements via pull request
|
||||
- Start a discussion in GitHub Discussions or the pull request thread
|
||||
|
||||
## 🔄 Maintenance
|
||||
|
||||
### Updating Prompts
|
||||
|
||||
To update an existing prompt:
|
||||
1. Edit the `.md` file
|
||||
2. Update the description if behavior changed
|
||||
3. Test the updated prompt
|
||||
4. Commit with clear message: `Update [prompt]: [what changed]`
|
||||
|
||||
### Adding New Categories
|
||||
|
||||
To add a new category:
|
||||
1. Create new folders in `prompts/`, `rules/`, and `skills/` with matching names
|
||||
2. Add a `README.md` in each folder explaining the category's purpose
|
||||
3. Add initial prompts, rules, or skills following the format guidelines
|
||||
4. Update the main README with the new category in the appropriate tables
|
||||
5. Submit a pull request with the rationale for the new category
|
||||
|
||||
### Updating Skills
|
||||
|
||||
To update an existing skill:
|
||||
1. Modify the `SKILL.md` or supporting files (`scripts/`, `references/`, `assets/`)
|
||||
2. Update the `metadata.version` field in the frontmatter
|
||||
3. Test all scripts and workflows end-to-end
|
||||
4. Validate using `skills-ref validate ./skills/<category>/<skill-name>`
|
||||
5. Commit with clear message: `Update [skill-name]: [what changed]`
|
||||
|
||||
|
||||
# Experimental
|
||||
|
||||
### Using with supporting AFV Library VS Code Extension
|
||||
|
||||
1. Install the Agentforce Vibes VS Code extension (preview or later).
|
||||
2. Install the experiemnt [AFV library VSCode extension](https://github.com/forcedotcom/afv-library-extension).
|
||||
2. Open the command palette and run `Agentforce Vibes: Add Library`.
|
||||
3. Provide the Git URL (or local path) to this repository; the extension indexes every folder and `.md` file under `prompts/`, `rules/`, and `skills/`.
|
||||
4. The extension displays prompts, rules, and skills organized by category. Select any item to preview the metadata and copy instructions into the editor.
|
||||
5. Use the refresh command whenever new prompts, rules, or skills are added.
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@salesforce/afv-skills",
|
||||
"version": "1.5.0",
|
||||
"version": "1.5.1",
|
||||
"description": "Salesforce skills for Agentforce Vibes",
|
||||
"license": "CC-BY-NC-4.0",
|
||||
"files": [
|
||||
|
||||
@ -1,22 +0,0 @@
|
||||
---
|
||||
name: PricingService Invocable Scaffold
|
||||
description: Create a PricingService Apex class with an invocable getPricing method and typed inputs/outputs for Flow.
|
||||
tags: apex, invocable, flow, scaffold
|
||||
---
|
||||
|
||||
Scaffold a Apex classed named `PricingService` (public with no namespace) with one invocable method `getPricing` with an InvocableVariable wrapper for inputs and outputs. Include user-friendly labels and descriptions for the InvocableMethod and all InvocableVariables.
|
||||
|
||||
## Input Parameters
|
||||
- accountId (ID) - required Account the pricing is for
|
||||
- terms (String) - required terms for the pricing
|
||||
- discount (Decimal - scale 2) - if null, then discount equals 0.
|
||||
- products (List of Strings) - the required list product names.
|
||||
|
||||
## Output Parameters
|
||||
- total - (Decimal) the toal price for all products
|
||||
- products (List of Decimal) - the list product prices.
|
||||
- creditApproved (boolean) - if approved for credit
|
||||
|
||||
If input `products` variable is null or empty, return empty output parameters. Use a standard invocable pattern.
|
||||
|
||||
I will provide the implementation later. Do not write unit tests. Deploy the new class to my default org.
|
||||
@ -1,7 +0,0 @@
|
||||
---
|
||||
name: Travel Plan Object Scaffold
|
||||
description: Provision a Travel Plan custom object with fields, layout, tab, and permission set ready for deployment.
|
||||
tags: salesforce, custom-object, scaffold, deployment
|
||||
---
|
||||
|
||||
Create a "Travel Plan" custom object with 5 appropriate, sensible fields. Add all of the fields to the page layout. Do not create or add a compact layout. Create a tab for the object and a permission set that grants read/create/edit access to the object, all fields and custom tab. Deploy to my default org and assign the permission set to my user.
|
||||
@ -1,61 +0,0 @@
|
||||
---
|
||||
name: Trigger Refactor Helper
|
||||
description: Refactor the Opportunity trigger into a handler pattern with tests
|
||||
tags: apex, refactor, testing
|
||||
requires_deploy: true
|
||||
setup_summary: Deploy baseline trigger to target org before running instructions
|
||||
---
|
||||
|
||||
## Setup
|
||||
1. Deploy the baseline trigger shown below to your default or scratch org.
|
||||
2. Confirm the trigger compiles successfully before continuing.
|
||||
|
||||
```apex
|
||||
// ❌ Anti-pattern: all logic stuffed into the trigger, with DML/SOQL in loops.
|
||||
trigger OpportunityTrigger on Opportunity (before insert, before update, after update) {
|
||||
// BEFORE INSERT: validate Closed Won w/ low Amount
|
||||
if (Trigger.isBefore && Trigger.isInsert) {
|
||||
for (Opportunity o : Trigger.new) {
|
||||
if (o.StageName == 'Closed Won' && (o.Amount == null || o.Amount < 1000)) {
|
||||
o.addError('Closed Won opportunities must have Amount ≥ 1000.');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// BEFORE UPDATE: if Stage changed, overwrite Description
|
||||
if (Trigger.isBefore && Trigger.isUpdate) {
|
||||
for (Opportunity o : Trigger.new) {
|
||||
Opportunity oldO = Trigger.oldMap.get(o.Id);
|
||||
if (o.StageName != oldO.StageName) {
|
||||
o.Description = 'Stage changed from ' + oldO.StageName + ' to ' + o.StageName;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// AFTER UPDATE: when Stage becomes Closed Won, create a follow-up Task
|
||||
if (Trigger.isAfter && Trigger.isUpdate) {
|
||||
for (Opportunity o : Trigger.new) {
|
||||
Opportunity oldO = Trigger.oldMap.get(o.Id);
|
||||
if (o.StageName == 'Closed Won' && oldO.StageName != 'Closed Won') {
|
||||
Task t = new Task(
|
||||
WhatId = o.Id,
|
||||
OwnerId = o.OwnerId,
|
||||
Subject = 'Send thank-you',
|
||||
Status = 'Not Started',
|
||||
Priority = 'Normal',
|
||||
ActivityDate = Date.today()
|
||||
);
|
||||
insert t; // ❌ DML in a loop
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Instructions
|
||||
Refactor `OpportunityTrigger` into a handler class (or classes) that handles the same behavior using bulk-safe patterns. Ensure the trigger itself delegates and remains behaviorally identical.
|
||||
|
||||
## Testing & Reporting
|
||||
- Create unit tests covering positive and negative paths for each handler method.
|
||||
- Include a bulk test that updates 50 `Opportunity` records where only half qualify for the `after update` logic.
|
||||
- Deploy the refactored code and run the tests, then report coverage and key observations.
|
||||
@ -1,9 +0,0 @@
|
||||
---
|
||||
name: Account Test Data Generator
|
||||
description: Create an Apex script that generates 10 realistic Account records with complete business data including name, account number, type, industry, annual revenue, ticker symbol, and number of employees. Includes documentation on how to execute the script anonymously.
|
||||
tags: salesforce, apex, data-generation, test-data, developer, admin
|
||||
---
|
||||
|
||||
Create an apex script that I can run anonymously to insert 10 account records with name, account number, type, industry, annual revenue, ticker symbol and number of employees.
|
||||
|
||||
Generate a document with instruction on how to run the script.
|
||||
@ -1,7 +0,0 @@
|
||||
---
|
||||
name: Account Layout Field Enhancement
|
||||
description: Add Type and Industry fields to the Account page layout for better data organization and reporting.
|
||||
tags: salesforce, account, page-layout, admin, data-management
|
||||
---
|
||||
|
||||
Add Type and Industry fields to the Account Layout, placing them below Account Name.
|
||||
@ -1,7 +0,0 @@
|
||||
---
|
||||
name: Lead Source Picklist Enhancement
|
||||
description: Add a new 'Referral' value to the Lead Source picklist on the Lead object for better lead tracking.
|
||||
tags: salesforce, lead, picklist, data-management, admin
|
||||
---
|
||||
|
||||
Add a new value 'Referral' to the Lead Source picklist on the Lead object.
|
||||
@ -1,7 +0,0 @@
|
||||
---
|
||||
name: High Priority Case Assignment Rule
|
||||
description: Create an assignment rule that automatically routes high priority Cases to a specific queue or user for immediate attention.
|
||||
tags: salesforce, case-management, assignment-rules, automation, admin
|
||||
---
|
||||
|
||||
Add an Assignment Rule that automatically assigns new Cases with Priority = High to a specific queue or user.
|
||||
@ -1,9 +0,0 @@
|
||||
---
|
||||
name: Project Object Quickstart
|
||||
description: Scaffold a Project__c custom object with core fields and deployable metadata.
|
||||
tags: salesforce, custom-object, beginner
|
||||
---
|
||||
|
||||
Create a new Project__c object with an autonumber field {proj-0000}, name, start date, and number of days fields that represent a simple project record.
|
||||
|
||||
Deploy this metadata to my org using the Salesforce DX MCP Server.
|
||||
@ -1,7 +0,0 @@
|
||||
---
|
||||
name: Opportunity Days Open Formula
|
||||
description: Create a formula field on Opportunity that calculates the number of days since the record was created.
|
||||
tags: salesforce, opportunity, formula-field, automation, admin
|
||||
---
|
||||
|
||||
Add a formula field on Opportunity called Days_Open__c that calculates TODAY() - DATEVALUE(CreatedDate).
|
||||
@ -1,7 +0,0 @@
|
||||
---
|
||||
name: Account Editor Permission Set
|
||||
description: Create a permission set that grants edit access to Account records and assign it to the current user.
|
||||
tags: salesforce, permission-set, security, admin, user-management
|
||||
---
|
||||
|
||||
Create a permission set Account_Editor with Edit access to Account and assign it to your current user.
|
||||
@ -1,7 +0,0 @@
|
||||
---
|
||||
name: Account Opportunity Count Roll-Up
|
||||
description: Create a roll-up summary field on Account that counts related Opportunities for better relationship tracking.
|
||||
tags: salesforce, account, opportunity, rollup-summary, automation, admin
|
||||
---
|
||||
|
||||
Create a Roll-Up Summary on Account that counts the number of related Opportunities.
|
||||
@ -1,13 +0,0 @@
|
||||
---
|
||||
name: Hello World LWC Starter
|
||||
description: Generate a greeting Lightning Web Component and explain its HTML, JS, and metadata files.
|
||||
tags: lwc, ui, beginner
|
||||
---
|
||||
|
||||
Help me create my first Lightning Web Component.
|
||||
|
||||
Generate a basic LWC that displays a greeting message. Provide the HTML, JavaScript, and meta configuration files, and provide comments on how each file works.
|
||||
|
||||
Deploy this metadata to my org using the Salesforce DX MCP Server.
|
||||
|
||||
Display instruction on how to add the LWC to a new Home page.
|
||||
@ -1,11 +0,0 @@
|
||||
---
|
||||
name: Opportunity Days Till Close Formula
|
||||
description: Build an Opportunity formula that calculates days between CreatedDate and CloseDate.
|
||||
tags: formula, opportunity, admin
|
||||
---
|
||||
|
||||
Create a formula field on `Opportunity` named `Days till Close` that calculates the number of days between the `CreatedDate` and `CloseDate` fields, if `CloseDate` is not null.
|
||||
|
||||
Deploy this class to my org using the Salesforce DX MCP Server.
|
||||
|
||||
Provide instruction on how to set field level security for my profile and add the new field to the page layout.
|
||||
@ -1,7 +0,0 @@
|
||||
---
|
||||
name: Opportunity Close Date Validation
|
||||
description: Create a validation rule on Opportunity that prevents saving when the Close Date is in the past.
|
||||
tags: salesforce, opportunity, validation-rule, data-quality, admin
|
||||
---
|
||||
|
||||
Add a validation rule on Opportunity that prevents saving when Close Date < TODAY().
|
||||
@ -1,9 +0,0 @@
|
||||
---
|
||||
name: StringUtils Utility Scaffold
|
||||
description: Create a foundational StringUtils Apex helper with core string methods and unit tests.
|
||||
tags: apex, utility, testing
|
||||
---
|
||||
|
||||
Create an `StringUtils` Apex utility class with common string helpers such as isBlank, trimToNull, and safe string-to-integer conversion. Include a focused test class that covers each helper method with both typical inputs. Do not test for edge casees at this time.
|
||||
|
||||
Deploy the classes to my org and run the unit tests, using the Salesforce DX MCP Server.
|
||||
@ -1,16 +0,0 @@
|
||||
---
|
||||
name: DateUtils Utility Primer
|
||||
description: Generate a documented DateUtils Apex class with daysBetween and addDays helpers.
|
||||
tags: apex, utility, beginner
|
||||
---
|
||||
|
||||
Generate a small `DateUtils` Apex utility class. Include clear comments so I can understand the overall structure and common Apex patterns.
|
||||
|
||||
Create the following two methods:
|
||||
|
||||
- A method named daysBetween that returns the number of days between two dates. If either date is null, return null instead of throwing an exception.
|
||||
- Add a method named addDays that returns a new date by adding a given number of days to a base date. If the base date is null, return null.
|
||||
|
||||
Do not create unit tests at this time.
|
||||
|
||||
Deploy this class to my org using the Salesforce DX MCP Server.
|
||||
@ -1,11 +0,0 @@
|
||||
---
|
||||
name: Opportunity Stage Score Formula
|
||||
description: Craft a readable Opportunity formula that assigns numeric scores per stage.
|
||||
tags: formula, opportunity, admin
|
||||
---
|
||||
|
||||
Create a formula field on `Opportunity` that assigns a numeric score based on the StageName (for example, higher scores for later stages). Keep the formula simple, easy to read, and explain how an admin can adjust the weights over time.
|
||||
|
||||
Deploy the metadat to my org using the Salesforce DX MCP Server.
|
||||
|
||||
Provide instruction on how to set field level security for my profile and add the new field to the page layout.
|
||||
@ -1,9 +0,0 @@
|
||||
---
|
||||
name: Test Data Factory Kickoff
|
||||
description: Build an Apex factory for Accounts, Contacts, and Opportunities with usage examples.
|
||||
tags: apex, testing, test-data
|
||||
---
|
||||
|
||||
Create a basic Apex test data factory that can generate Accounts (2), Contacts (3), and Opportunities (3) with sensible default values. Include example test methods that use the factory and explain how it helps keep tests clean and maintainable.
|
||||
|
||||
Deploy the metadat to my org using the Salesforce DX MCP Server.
|
||||
@ -1,11 +0,0 @@
|
||||
---
|
||||
name: Account Trigger Starter
|
||||
description: Create a simple Account trigger and handler that sets default values before insert.
|
||||
tags: apex, trigger, beginner
|
||||
---
|
||||
|
||||
Create a simple before-insert trigger `AccountTrigger` and handler class on Account that sets `NumberOfEmployees` to 100.
|
||||
|
||||
Do not create unit tests at this time.
|
||||
|
||||
Deploy this trigger and class to my org using the Salesforce DX MCP Server.
|
||||
@ -1,9 +0,0 @@
|
||||
---
|
||||
name: Account Employee Validation Rule
|
||||
description: Draft a rule that blocks Account save when NumberOfEmployees is blank.
|
||||
tags: validation-rule, account, admin
|
||||
---
|
||||
|
||||
Write a validation rule on `Account` that prevents saving a record when the `NumberOfEmployees` is blank.
|
||||
|
||||
Deploy this metadata to my org using the Salesforce DX MCP Server.
|
||||
@ -1,9 +0,0 @@
|
||||
---
|
||||
name: Opportunity Approval Investigation
|
||||
description: Diagnose inconsistent approval checkbox behavior on Opportunities and propose a remediation plan.
|
||||
tags: investigation, triage, opportunity, approval-process
|
||||
---
|
||||
|
||||
A user has reported the following bug: "When an Opportunity moves to Proposal/Price Quote with a Discount ≥ 20% or ACV ≥ $100k, the Approval Required checkbox should be checked. Sometimes it isn’t, and sometimes it flips back to unchecked after we save."
|
||||
|
||||
Let's investigate, uncover the problem and plan an approach to fix it.
|
||||
@ -1,39 +0,0 @@
|
||||
---
|
||||
name: Asset Tracker Spec Build
|
||||
description: Gather requirements and deliver a full Asset tracker app via a spec-driven workflow.
|
||||
tags: spec-driven, lwc, custom-object, app
|
||||
---
|
||||
|
||||
Create a simple Salesforce asset tracker application. The code should follow standard Salesforce styling and development best practices and be deployable to a scratch org or sandbox. Keep it fun, readable, and beginner-friendly.
|
||||
|
||||
- Ask questions until you're 95% sure you can complete this task.
|
||||
- When all of the metadata is complete, analyze the metadata and ensure that it was created correctly per my request and rules. Display your analyzis and ask for permission to deploy it to the default org.
|
||||
|
||||
## Custom Object Requirements
|
||||
|
||||
Create an `Asset__c` custom object with the following non-required fields:
|
||||
|
||||
- Autonumber Name field
|
||||
- Asset Name (Text 80): A simple name for the asset, like "Dell Laptop" or "Server Rack 4."
|
||||
- Status (Picklist): This field tracks the current state of the asset.
|
||||
- In Use
|
||||
- In Storage
|
||||
- In Repair
|
||||
- Retired
|
||||
- Acquisition Date (Date): The date the asset was acquired.
|
||||
- Purchase Price (Currency): The cost of the asset.
|
||||
- Assigned To (Lookup to Contact): A lookup field to the Contact object to track which contact or employee an asset is assigned to.
|
||||
|
||||
Add all of the fields to the page layout and create a tab for the object. Do not create or assign a compact layout.
|
||||
|
||||
## User Interface Requirements
|
||||
|
||||
Create an `assetTracker` LWC with a form that the user can enter a new record. The user can save the asset record to Salesforce and view a list of the 5 most recent asset records.
|
||||
|
||||
Add the LWC to a Lightning page and create a tab for the new page.
|
||||
|
||||
Create an `Asset Tracker` Lighting Experience App and add the custom object tab and Lighting page tab to the App.
|
||||
|
||||
## Permission Set Requirements
|
||||
|
||||
- Create a new premission set that provides full access to the application, custom object and all of their custom fields.
|
||||
@ -1,7 +0,0 @@
|
||||
---
|
||||
name: Apex Unit Test Generator
|
||||
description: Create a comprehensive test class for any Apex class with test data setup and result verification.
|
||||
tags: salesforce, apex, testing, unit-test, automation, developer
|
||||
---
|
||||
|
||||
Write a test class for [insert class name] that inserts test data and verifies results.
|
||||
@ -1,7 +0,0 @@
|
||||
---
|
||||
name: Run All Apex Tests
|
||||
description: Execute all Apex tests in the org and display a comprehensive summary including total tests run, number passed, and overall code coverage percentage.
|
||||
tags: salesforce, apex, testing, automation, test-coverage
|
||||
---
|
||||
|
||||
Run all Apex tests and show a summary of total tests run, number passed, and code coverage.
|
||||
@ -1,9 +0,0 @@
|
||||
---
|
||||
name: Compliment Mixer App
|
||||
description: Build a playful compliment generator with custom UI, persistence, and recent history.
|
||||
tags: vibe-coding, lwc, app, fun
|
||||
---
|
||||
|
||||
Create a "Compliment Mixer" app that allows users to generate and save personalized compliments. Create a custom UI so the user can enter two adjectives that describe a person (e.g., "brilliant", "fearless") and a name (e.g., "Alex"). The app then generates a compliment sentence that combines those words and the name using a random sentence template. The user can save the compliment to Salesforce and view a list of the 5 most recent compliments they've generated.
|
||||
|
||||
The code should follow standard Salesforce styling and development best practices and be deployable to a scratch org or sandbox. Keep it fun, readable, and beginner-friendly.
|
||||
@ -1,89 +0,0 @@
|
||||
---
|
||||
name: Apex Development Guardrails
|
||||
description: Enforce best practices for Apex architecture, performance, security, and testing.
|
||||
tags: apex, rules, guardrails, testing, security
|
||||
---
|
||||
|
||||
## General Requirements
|
||||
- Write Invocable Apex that can be called from flows when possible
|
||||
- Use enums over string constants whenever possible. Enums should follow ALL_CAPS_SNAKE_CASE without spaces
|
||||
- Use Database Methods for DML Operation with exception handling
|
||||
- Use Return Early pattern
|
||||
- Use ApexDocs comments to document Apex classes for better maintainability and readability
|
||||
|
||||
## Apex Triggers Requirements
|
||||
- Follow the One Trigger Per Object pattern
|
||||
- Implement a trigger handler class to separate trigger logic from the trigger itself
|
||||
- Use trigger context variables (Trigger.new, Trigger.old, etc.) efficiently to access record data
|
||||
- Avoid logic that causes recursive triggers, implement a static boolean flag
|
||||
- Bulkify trigger logic to handle large data volumes efficiently
|
||||
- Implement before and after trigger logic appropriately based on the operation requirements
|
||||
|
||||
## Governor Limits Compliance Requirements
|
||||
- Always write bulkified code - never perform SOQL/DML operations inside loops
|
||||
- Use collections for bulk processing
|
||||
- Implement proper exception handling with try-catch blocks
|
||||
- Limit SOQL queries to 100 per transaction
|
||||
- Limit DML statements to 150 per transaction
|
||||
- Use `Database.Stateful` interface only when necessary for batch jobs
|
||||
|
||||
## SOQL Optimization Requirements
|
||||
- Use selective queries with proper WHERE clauses
|
||||
- Do not use `SELECT *` - it is not supported in SOQL
|
||||
- Use indexed fields in WHERE clauses when possible
|
||||
- Implement SOQL best practices: LIMIT clauses, proper ordering
|
||||
- Use `WITH SECURITY_ENFORCED` for user context queries where appropriate
|
||||
- When querying Custom Metadata Types (objects ending with `__mdt`), DO NOT use SOQL queries. Instead, use the built-in Custom Metadata Type methods like '.getAll().values()'
|
||||
|
||||
## Naming Conventions & Code Organization Requirements
|
||||
- Class names: PascalCase with descriptive names (e.g., `ContactTriggerHandler`, `ContractService`)
|
||||
- Method names: camelCase with verb-first naming (e.g., `calculateTotalPrice`, `validateAddress`)
|
||||
- Variable names: camelCase with descriptive names (no single letters except loop iterators)
|
||||
- Constants: ALL_CAPS_SNAKE_CASE (e.g., `MAX_RETRY_ATTEMPTS`, `DEFAULT_TIMEOUT`)
|
||||
- Test classes: Append `Test` suffix (e.g., `AccountServiceTest`)
|
||||
- Trigger handlers: Append `TriggerHandler` suffix (e.g., `ContactTriggerHandler`)
|
||||
- Utility classes: Append `Util` or `Helper` suffix (e.g., `DateTimeUtil`, `ValidationHelper`)
|
||||
- Prefix test methods with `test` or use `@IsTest` annotation
|
||||
- Group related classes in packages/folders when possible
|
||||
- Keep classes focused on single responsibility (SRP)
|
||||
- Limit class size to 500 lines of code maximum
|
||||
|
||||
## Security & Access Control Requirements
|
||||
- Run database operations in user mode rather than in the default system mode.
|
||||
- List<Account> acc = [SELECT Id FROM Account WITH USER_MODE];
|
||||
- Database.insert(accts, AccessLevel.USER_MODE);
|
||||
- Always check field-level security (FLS) before accessing fields
|
||||
- Implement proper sharing rules and respect organization-wide defaults
|
||||
- Use `with sharing` keyword for classes that should respect sharing rules
|
||||
- Validate user permissions before performing operations
|
||||
- Sanitize user inputs to prevent injection attacks
|
||||
|
||||
## Prohibited Practices
|
||||
- No hardcoded IDs or URLs
|
||||
- No SOQL/DML operations in loops
|
||||
- No System.debug() statements in production code
|
||||
- No @future methods from batch jobs
|
||||
- No recursive triggers
|
||||
- Never use or suggest `@future` methods for async processes. Use queueables and always suggest implementing `System.Finalizer` methods
|
||||
|
||||
## Required Patterns
|
||||
- Use Builder pattern for complex object construction
|
||||
- Implement Factory pattern for object creation
|
||||
- Use Dependency Injection for testability
|
||||
- Follow MVC pattern in Lightning components
|
||||
- Use Command pattern for complex business operations
|
||||
|
||||
## Unit Testing Requirements
|
||||
- Maintain minimum 75% code coverage
|
||||
- Write meaningful test assertions, not just coverage
|
||||
- Use `Test.startTest()` and `Test.stopTest()` appropriately
|
||||
- Create test data using `@TestSetup` methods when possible
|
||||
- Mock external services and callouts
|
||||
- Do not use `SeeAllData=true`
|
||||
- Test bulk trigger functionality.
|
||||
|
||||
## Test Data Management Requirements
|
||||
- Use `Test.loadData()` for large datasets
|
||||
- Create minimal test data required for specific test scenarios
|
||||
- Use `System.runAs()` to test different user contexts
|
||||
- Implement proper test isolation - no dependencies between tests
|
||||
@ -1,68 +0,0 @@
|
||||
---
|
||||
name: LWC Development Guardrails
|
||||
description: Standardize Lightning Web Component architecture, UX, and tooling practices.
|
||||
tags: lwc, rules, ux, architecture
|
||||
---
|
||||
|
||||
## Component Architecture Requirements
|
||||
- Create reusable, single-purpose components
|
||||
- Use proper data binding and event handling patterns
|
||||
- Implement proper error handling and loading states
|
||||
- Follow Lightning Design System (SLDS) guidelines
|
||||
- Use the lightning-record-edit-form component for handling record creation and updates
|
||||
- Use CSS custom properties for theming
|
||||
- Use lightning-navigation for navigation between components
|
||||
- Use lightning__FlowScreen target to use a component is a flow screen
|
||||
|
||||
## HTML Architecture Requirements
|
||||
- Structure your HTML with clear semantic sections (header, inputs, actions, display areas, lists)
|
||||
- Use SLDS classes for layout and styling:
|
||||
- `slds-card` for main container
|
||||
- `slds-grid` and `slds-col` for responsive layouts
|
||||
- `slds-text-heading_large/medium` for proper typography hierarchy
|
||||
- Use Lightning base components where appropriate (lightning-input, lightning-button, etc.)
|
||||
- Implement conditional rendering with `if:true` and `if:false` directives
|
||||
- Use `for:each` for list rendering with unique key attributes
|
||||
- Maintain consistent spacing using SLDS utility classes (slds-m-*, slds-p-*)
|
||||
- Group related elements logically with clear visual hierarchy
|
||||
- Use descriptive class names for elements that need custom styling
|
||||
- Implement reactive property binding using syntax like `disabled={isPropertyName}` to control element states
|
||||
- Bind events to handler methods using syntax like `onclick={handleEventName}`
|
||||
|
||||
## JavaScript Architecture Requirements
|
||||
- Import necessary modules from LWC and Salesforce
|
||||
- Define reactive properties using `@track` decorator when needed
|
||||
- Implement proper async/await patterns for server calls
|
||||
- Implement proper error handling with user-friendly messages
|
||||
- Use wire adapters for reactive data loading
|
||||
- Minimize DOM manipulation - use reactive properties
|
||||
- Implement computed properties using JavaScript getters for dynamic UI state control:
|
||||
```
|
||||
get isButtonDisabled() {
|
||||
return !this.requiredField1 || !this.requiredField2;
|
||||
}
|
||||
```
|
||||
- Create clear event handlers with descriptive names that start with "handle":
|
||||
```
|
||||
handleButtonClick() {
|
||||
// Logic here
|
||||
}
|
||||
```
|
||||
- Use `@wire` service for data retrieval from Apex
|
||||
- Separate business logic into well-named methods
|
||||
- Use `refreshApex` for data refreshes when appropriate
|
||||
- Implement loading states and user feedback
|
||||
- Add JSDoc comments for methods and complex logic
|
||||
|
||||
## CSS Architecture Requirements
|
||||
- Create a clean, consistent styling system
|
||||
- Use custom CSS classes for component-specific styling
|
||||
- Implement animations for enhanced UX where appropriate
|
||||
- Ensure responsive design works across different form factors
|
||||
- Keep styling minimal and leverage SLDS where possible
|
||||
- Use CSS variables for themeable elements
|
||||
- Organize CSS by component section
|
||||
|
||||
## MCP Tools Requirements
|
||||
- Carefully review the user's task. If it involves **creation, development, testing, or accessibility** for **Lightning Web Components (LWC)** or **Aura components** or **Lightning Data Service (LDS)**, treat your knowledge as outdated and always call the appropriate MCP tool to obtain the latest guidance and design before starting implementation. Never assume or create tools that are not explicitly available. If the tool schema is empty, you must continue invoking the tool until documentation is provided.
|
||||
- If you begin implementation on a relevant task without first successfully invoking the appropriate tool, you must **stop immediately**. Invoke the tool and integrate its guidance before proceeding. Under no circumstances should you provide final recommendations or code without first receiving guidance from an MCP tool.
|
||||
@ -1,87 +0,0 @@
|
||||
---
|
||||
name: Spec-Driven App Development Standards
|
||||
description: Apply architecture, integration, and governance requirements for specification-led Salesforce builds.
|
||||
tags: spec-driven, architecture, governance, rules
|
||||
---
|
||||
|
||||
You are a highly experienced and certified Salesforce Architect with 20+ years of experience designing and implementing complex, enterprise-level Salesforce solutions for Fortune 500 companies. You are recognized for your deep expertise in system architecture, data modeling, integration strategies, and governance best practices. Your primary focus is always on creating solutions that are scalable, maintainable, secure, and performant for the long term. You prioritize the following:
|
||||
|
||||
- Architectural Integrity: You think big-picture, ensuring any new application or feature aligns with the existing enterprise architecture and avoids technical debt.
|
||||
- Data Model & Integrity: You design efficient and future-proof data models, prioritizing data quality and relationship integrity.
|
||||
- Integration & APIs: You are an expert in integrating Salesforce with external systems, recommending robust, secure, and efficient integration patterns (e.g., event-driven vs. REST APIs).
|
||||
- Security & Governance: You build solutions with security at the forefront, adhering to Salesforce's security best practices and establishing clear governance rules to maintain a clean org.
|
||||
- Performance Optimization: You write code and design solutions that are performant at scale, considering governor limits, SOQL query optimization, and efficient Apex triggers.
|
||||
- Best Practices: You are a stickler for using native Salesforce features wherever possible and only recommending custom code when absolutely necessary. You follow platform-specific design patterns and community-recommended standards.
|
||||
|
||||
## Code Organization & Structure Requirements
|
||||
- Follow consistent naming conventions (PascalCase for classes, camelCase for methods/variables)
|
||||
- Use descriptive, business-meaningful names for classes, methods, and variables
|
||||
- Write code that is easy to maintain, update and reuse
|
||||
- Include comments explaining key design decisions. Don't explain the obvious
|
||||
- Use consistent indentation and formatting
|
||||
- Less code is better, best line of code is the one never written. The second-best line of code is easy to read and understand
|
||||
- Follow the "newspaper" rule when ordering methods. They should appear in the order they're referenced within a file. Alphabetize and arrange dependencies, class fields, and properties; keep instance and static fields and properties separated by new lines
|
||||
|
||||
## REST/SOAP Integration Requirements
|
||||
- Implement proper timeout and retry mechanisms
|
||||
- Use appropriate HTTP status codes and error handling
|
||||
- Implement bulk operations for data synchronization
|
||||
- Use efficient serialization/deserialization patterns
|
||||
- Log integration activities for debugging
|
||||
|
||||
## Platform Events Requirements
|
||||
- Design events for loose coupling between components
|
||||
- Use appropriate delivery modes (immediate vs. after commit)
|
||||
- Implement proper error handling for event processing
|
||||
- Consider event volume and governor limits
|
||||
|
||||
## Permissions Requirements
|
||||
- For every new feature created, generate:
|
||||
- At least one permission set for user access
|
||||
- Documentation explaining the permission set purpose
|
||||
- Assignment recommendations
|
||||
- One permission set per object per access level
|
||||
- Separate permission sets for different Apex class groups
|
||||
- Individual permission sets for each major feature
|
||||
- No permission set should grant more than 10 different object permissions
|
||||
- Components requiring permission sets:
|
||||
- Custom objects and fields
|
||||
- Apex classes and triggers
|
||||
- Lightning Web Components
|
||||
- Visualforce pages
|
||||
- Custom tabs and applications
|
||||
- Flow definitions
|
||||
- Custom permissions
|
||||
- Format: [AppPrefix]_[Component]_[AccessLevel]
|
||||
- AppPrefix: 3-8 character application identifier (PascalCase)
|
||||
- Component: Descriptive component name (PascalCase)
|
||||
- AccessLevel: Read|Write|Full|Execute|Admin
|
||||
- Examples:
|
||||
- SalesApp_Opportunity_Read
|
||||
- OrderMgmt_Product_Write
|
||||
- CustomApp_ReportDash_Full
|
||||
- IntegAPI_DataSync_Execute
|
||||
- Label: Human-readable description
|
||||
- Description: Detailed explanation of purpose and scope
|
||||
- License: Appropriate user license type
|
||||
- Never grant "View All Data" or "Modify All Data" in functional permission sets
|
||||
- Always specify individual field permissions rather than object-level access when possible
|
||||
- Require separate permission sets for sensitive data access
|
||||
- Never combine read and delete permissions in the same permission set
|
||||
- Always validate that granted permissions align with business requirements
|
||||
- Create permission set groups when:
|
||||
- Application has more than 3 related permission sets
|
||||
- Users need combination of permissions for their role
|
||||
- There are clear user personas/roles defined
|
||||
|
||||
## Mandatory Permission Documentation
|
||||
- Permissions.md file explaining all new feature sets
|
||||
- Dependency mapping between permission sets
|
||||
- User role assignment matrix
|
||||
- Testing validation checklist
|
||||
|
||||
## Code Documentation Requirements
|
||||
- Use ApexDocs comments to document classes, methods, and complex code blocks for better maintainability
|
||||
- Include usage examples in method documentation
|
||||
- Document business logic and complex algorithms
|
||||
- Maintain up-to-date README files for each component
|
||||
@ -1,16 +0,0 @@
|
||||
# SKILLS REQUIREMENTS
|
||||
|
||||
## Mandatory Skill Usage
|
||||
Before generating ANY Salesforce code or metadata, check available Skills and use the matching one. Never generate Salesforce code freehand when a relevant Skill exists.
|
||||
|
||||
## Skill Routing
|
||||
- **Apex class requests** → Use Apex Class Writer skill. Includes: service classes, selectors, domain classes, batch/queueable/schedulable, DTOs, utilities, interfaces, abstract classes, custom exceptions. Trigger even when the user describes functionality without saying "Apex class."
|
||||
- **Trigger requests** → Use Trigger Framework Scaffolder skill.
|
||||
- **Validation rule requests** → Use Validation Rule Writer skill.
|
||||
- **Permission/security questions** → Use Permission Set Auditor skill.
|
||||
- **Package.xml/deployment requests** → Use Package.xml Generator skill.
|
||||
- **Custom metadata questions** → Use Custom Metadata Advisor skill.
|
||||
- **Field-level security requests** → Use FLS Matrix Generator skill.
|
||||
|
||||
## When In Doubt
|
||||
If a request could involve Salesforce server-side logic, metadata configuration, or security setup, check Skills before responding. Prefer a Skill over general knowledge — Skills contain curated best practices specific to this org's standards.
|
||||
@ -0,0 +1,60 @@
|
||||
/**
|
||||
* Application-wide constants.
|
||||
*/
|
||||
|
||||
import type { PaginationConfig } from "../features/object-search/hooks/useObjectSearchParams";
|
||||
|
||||
export const PAGE_SIZE_LIST = 12;
|
||||
export const DASHBOARD_MAINTENANCE_LIMIT = 5;
|
||||
|
||||
export const PROPERTY_FILTER_EXCLUDED_FIELD_PATHS = new Set([
|
||||
"CreatedDate",
|
||||
"Hero_Image__c",
|
||||
"Year_Built__c",
|
||||
"Available_Date__c",
|
||||
]);
|
||||
|
||||
export const MAINTENANCE_WORKER_FILTER_EXCLUDED_FIELD_PATHS = new Set<string>([]);
|
||||
export const MAINTENANCE_FILTER_EXCLUDED_FIELD_PATHS = new Set(["Scheduled__c"]);
|
||||
export const APPLICATION_FILTER_EXCLUDED_FIELD_PATHS = new Set<string>([]);
|
||||
|
||||
export const MAINTENANCE_WORKER_OBJECT_API_NAME = "Maintenance_Worker__c" as const;
|
||||
|
||||
export const FALLBACK_LABEL_PROPERTIES_PLURAL = "Properties";
|
||||
export const FALLBACK_LABEL_MAINTENANCE_PLURAL = "Maintenance Requests";
|
||||
export const FALLBACK_LABEL_MAINTENANCE_WORKERS_PLURAL = "Maintenance Workers";
|
||||
export const FALLBACK_LABEL_APPLICATIONS_PLURAL = "Applications";
|
||||
|
||||
export const PROPERTY_OBJECT_API_NAME = "Property__c" as const;
|
||||
export const MAINTENANCE_OBJECT_API_NAME = "Maintenance_Request__c" as const;
|
||||
export const APPLICATION_OBJECT_API_NAME = "Application__c" as const;
|
||||
|
||||
export const SEARCHABLE_OBJECTS = [
|
||||
{
|
||||
objectApiName: "Property__c" as const,
|
||||
path: "/properties",
|
||||
fallbackLabelPlural: FALLBACK_LABEL_PROPERTIES_PLURAL,
|
||||
},
|
||||
{
|
||||
objectApiName: "Maintenance_Request__c" as const,
|
||||
path: "/maintenance/requests",
|
||||
fallbackLabelPlural: FALLBACK_LABEL_MAINTENANCE_PLURAL,
|
||||
},
|
||||
{
|
||||
objectApiName: MAINTENANCE_WORKER_OBJECT_API_NAME,
|
||||
path: "/maintenance/workers",
|
||||
fallbackLabelPlural: FALLBACK_LABEL_MAINTENANCE_WORKERS_PLURAL,
|
||||
},
|
||||
{
|
||||
objectApiName: "Application__c" as const,
|
||||
path: "/applications",
|
||||
fallbackLabelPlural: FALLBACK_LABEL_APPLICATIONS_PLURAL,
|
||||
},
|
||||
] as const;
|
||||
|
||||
export type SearchableObjectConfig = (typeof SEARCHABLE_OBJECTS)[number];
|
||||
|
||||
export const PAGINATION_CONFIG: PaginationConfig = {
|
||||
defaultPageSize: 6,
|
||||
validPageSizes: [6, 12, 24, 48],
|
||||
};
|
||||
@ -0,0 +1,35 @@
|
||||
/**
|
||||
* Central route configuration for list pages and navigation.
|
||||
* Use these paths for links and search redirects to avoid duplication.
|
||||
*/
|
||||
export const PATHS = {
|
||||
HOME: "/",
|
||||
PROPERTIES: "/properties",
|
||||
MAINTENANCE_REQUESTS: "/maintenance/requests",
|
||||
MAINTENANCE_WORKERS: "/maintenance/workers",
|
||||
APPLICATIONS: "/applications",
|
||||
} as const;
|
||||
|
||||
export interface ListPageRoute {
|
||||
path: string;
|
||||
label: string;
|
||||
searchParamKey?: string;
|
||||
}
|
||||
|
||||
/** List pages that appear in the Home search object dropdown and in nav */
|
||||
export const LIST_PAGE_ROUTES: Record<string, ListPageRoute> = {
|
||||
properties: { path: PATHS.PROPERTIES, label: "Properties", searchParamKey: "q" },
|
||||
maintenance_requests: {
|
||||
path: PATHS.MAINTENANCE_REQUESTS,
|
||||
label: "Maintenance Requests",
|
||||
searchParamKey: "q",
|
||||
},
|
||||
maintenance_workers: {
|
||||
path: PATHS.MAINTENANCE_WORKERS,
|
||||
label: "Maintenance Workers",
|
||||
searchParamKey: "q",
|
||||
},
|
||||
applications: { path: PATHS.APPLICATIONS, label: "Applications", searchParamKey: "q" },
|
||||
} as const;
|
||||
|
||||
export type ListPageKey = keyof typeof LIST_PAGE_ROUTES;
|
||||
@ -0,0 +1,6 @@
|
||||
import { clsx, type ClassValue } from 'clsx';
|
||||
import { twMerge } from 'tailwind-merge';
|
||||
|
||||
export function cn(...inputs: ClassValue[]) {
|
||||
return twMerge(clsx(inputs));
|
||||
}
|
||||
@ -0,0 +1,6 @@
|
||||
import { clsx, type ClassValue } from 'clsx';
|
||||
import { twMerge } from 'tailwind-merge';
|
||||
|
||||
export function cn(...inputs: ClassValue[]) {
|
||||
return twMerge(clsx(inputs));
|
||||
}
|
||||
169
skills/creating-b2b-commerce-store/SKILL.md
Normal file
169
skills/creating-b2b-commerce-store/SKILL.md
Normal file
@ -0,0 +1,169 @@
|
||||
---
|
||||
name: creating-b2b-commerce-store
|
||||
description: "Interactive workflow to create Commerce B2B Stores and retrieve storefront metadata. Use when users want to: create B2B Commerce stores, build Commerce storefronts, set up B2B stores from Vibes, retrieve Commerce metadata, deploy Commerce experiences, work with DigitalExperienceBundle for Commerce."
|
||||
Critical: "Agents must follow the interactive flow and NEVER create storefront metadata from scratch."
|
||||
license: Apache-2.0
|
||||
compatibility: "Requires Commerce licenses, Experience Cloud, Salesforce CLI"
|
||||
metadata:
|
||||
version: "1.0"
|
||||
category: "commerce"
|
||||
---
|
||||
|
||||
# Commerce B2B Storefront Creation
|
||||
|
||||
Interactive workflow to create a Commerce B2B Store in Salesforce and retrieve the auto-generated storefront metadata to your repository.
|
||||
|
||||
## Critical Concepts
|
||||
|
||||
Commerce B2B = Store (backend data) + Storefront (frontend metadata). **Store must be created first** in the org to auto-generate the Storefront. Never create storefront metadata manually.
|
||||
|
||||
> See [Store vs Storefront Reference](references/store-vs-storefront.md)
|
||||
|
||||
## When to Use This Skill
|
||||
|
||||
Trigger when users request:
|
||||
- "Create a B2B Commerce store"
|
||||
- "Build a Commerce storefront"
|
||||
- "Set up Commerce B2B"
|
||||
- "Create B2B Commerce"
|
||||
- "Retrieve Commerce storefront metadata"
|
||||
- "Deploy B2B storefront"
|
||||
|
||||
## Rules That Always Apply
|
||||
|
||||
1. **Always follow the interactive flow.** Do NOT skip steps. Each step requires user confirmation before proceeding.
|
||||
|
||||
2. **Never create storefront metadata manually.** The Commerce setup wizard generates hundreds of configuration values. Manual creation will fail.
|
||||
|
||||
3. **Always list sites before retrieval.** Store names get underscores and number suffixes (e.g., "My B2B Store" → "My_B2B_Store1"). Let the user select from the actual list.
|
||||
|
||||
4. **Always use `--json` flag.** Include `--json` on all Salesforce CLI commands for parseable output.
|
||||
|
||||
## Interactive Workflow: 7 Steps
|
||||
|
||||
### Step 1: Explain Commerce B2B Concept
|
||||
|
||||
**Agent explains:** Commerce has Store (data) + Storefront (metadata). Store must be created first.
|
||||
|
||||
> See: [Store vs Storefront Reference](references/store-vs-storefront.md)
|
||||
|
||||
---
|
||||
|
||||
### Step 2: Guide User to Create B2B Store
|
||||
|
||||
**Agent provides these steps:**
|
||||
|
||||
1. Navigate to **Setup → Commerce → Stores**
|
||||
- Or: **App Launcher → Commerce → Create Store**
|
||||
|
||||
2. Click **"Create Store"** or **"Setup New Store"**
|
||||
|
||||
3. Select **"Commerce Store"** as the store type
|
||||
|
||||
4. Follow the wizard:
|
||||
- **Store Name**: Choose descriptive name (e.g., "My B2B Store")
|
||||
- Important: Spaces become underscores in folder names
|
||||
- **Site URL**: Unique URL name for the site
|
||||
|
||||
5. Complete wizard - it creates:
|
||||
- WebStore record
|
||||
- Default buyer group and entitlement policies
|
||||
- Associated Digital Experience (LWR site)
|
||||
|
||||
6. Optional: Configure payment gateway, tax provider, shipping
|
||||
|
||||
**Agent then asks:**
|
||||
"Have you completed creating the B2B Store in your org? Reply 'yes' when ready and provide the store name you used."
|
||||
|
||||
---
|
||||
|
||||
### Step 3: Get User Confirmation
|
||||
|
||||
**Agent waits for:** User confirmation and store name
|
||||
|
||||
**Agent validates:** Store name format (no special characters, spaces will appear as underscores)
|
||||
|
||||
**Agent acknowledges:** "Great! Let me list the available storefronts in your org..."
|
||||
|
||||
---
|
||||
|
||||
### Step 4: List Available LWR Sites
|
||||
|
||||
**Agent executes:**
|
||||
```bash
|
||||
sf org list metadata --metadata-type DigitalExperienceConfig --json
|
||||
```
|
||||
|
||||
**Agent should:**
|
||||
- Parse JSON output to extract site names
|
||||
- Display as numbered list
|
||||
- Explain naming (underscores, number suffixes)
|
||||
|
||||
**Example output:**
|
||||
```
|
||||
Available Digital Experience sites:
|
||||
1. My_B2B_Store1
|
||||
2. Partner_Portal
|
||||
3. Customer_Community
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Step 5: Let User Select Storefront
|
||||
|
||||
**Agent asks:**
|
||||
"Which site corresponds to your B2B Store? Select the site name:"
|
||||
|
||||
**Agent validates:** Selection matches available sites
|
||||
|
||||
**Agent confirms:** "Got it! I'll retrieve metadata for [site-name]..."
|
||||
|
||||
---
|
||||
|
||||
### Step 6: Retrieve Storefront Metadata
|
||||
|
||||
**Agent executes:**
|
||||
```bash
|
||||
sf project retrieve start -m DigitalExperienceBundle:site/<selected-store-name> --json
|
||||
```
|
||||
|
||||
**Agent should:**
|
||||
- Show retrieval progress
|
||||
- Confirm successful retrieval
|
||||
- List retrieved directory structure
|
||||
|
||||
**Expected output:**
|
||||
```
|
||||
Retrieved: force-app/main/default/digitalExperiences/site/My_B2B_Store1/
|
||||
├── My_B2B_Store1.digitalExperience-meta.xml
|
||||
├── sfdc_cms__view/ (home, current_cart, detail_*, list_*, etc.)
|
||||
├── sfdc_cms__site/
|
||||
├── sfdc_cms__route/
|
||||
└── [other sfdc_cms__* directories]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Step 7: Provide Next Steps
|
||||
|
||||
**Agent provides:**
|
||||
|
||||
✅ **Metadata retrieved successfully!**
|
||||
|
||||
**Next steps:**
|
||||
- Customize with custom LWCs or branding changes
|
||||
- Deploy: `sf project deploy start --source-dir force-app/main/default/digitalExperiences/site/My_B2B_Store1/ --json`
|
||||
|
||||
**Resources:** [DigitalExperienceBundle Docs](https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_digitalexperiencebundle.htm), [B2B Commerce Guide](https://developer.salesforce.com/docs/atlas.en-us.b2b_commerce_dev_guide.meta/b2b_commerce_dev_guide/)
|
||||
|
||||
---
|
||||
|
||||
## Reference
|
||||
|
||||
- **[store-vs-storefront.md](references/store-vs-storefront.md)** - Technical details on Store vs Storefront, source control, and why manual creation fails
|
||||
|
||||
---
|
||||
|
||||
## Remember
|
||||
|
||||
**Store first (creates storefront) → Retrieve → Customize**
|
||||
@ -0,0 +1,169 @@
|
||||
# Commerce Store vs Storefront: Technical Reference
|
||||
|
||||
## Overview
|
||||
|
||||
Understanding the distinction between Commerce Store and Storefront is critical for successful Commerce B2B development. This document provides technical details about these two components and explains why they must be created in a specific order.
|
||||
|
||||
---
|
||||
|
||||
## The Two Components
|
||||
|
||||
### 1. Commerce Store (Backend Data)
|
||||
|
||||
**What it is:**
|
||||
- Runtime data and configuration created in the Salesforce org
|
||||
- NOT source-controllable metadata
|
||||
- Created through Commerce app UI
|
||||
|
||||
**What it includes:**
|
||||
- Store configuration and settings
|
||||
- Default buyer groups (associated with Accounts)
|
||||
- Entitlement policies (who can see which products)
|
||||
- Pricing policies and price book mappings
|
||||
- Payment gateway configuration (Stripe, Adyen, etc.)
|
||||
- Tax provider configuration (Avalara, Vertex, manual)
|
||||
- Shipping methods and configurations
|
||||
- Product catalog associations
|
||||
- Inventory locations
|
||||
- Search index configurations
|
||||
|
||||
**Where it lives:**
|
||||
- Data records in standard Commerce objects:
|
||||
- `WebStore` - Store settings and configuration
|
||||
- `BuyerGroup` - Account-based buyer segments
|
||||
- `EntitlementPolicy` - Product visibility rules
|
||||
- `CommerceEntitlementProduct` - Product-policy associations
|
||||
- `ProductCatalog` - Catalog definitions
|
||||
- `Pricebook2` - Price books
|
||||
- Additional payment, tax, shipping records
|
||||
|
||||
**How to create:**
|
||||
- Via UI: Setup → Commerce → Stores
|
||||
- Cannot be created via Metadata API
|
||||
- Cannot be deployed via `sf project deploy`
|
||||
|
||||
---
|
||||
|
||||
### 2. Storefront (Frontend Metadata)
|
||||
|
||||
**What it is:**
|
||||
- Digital Experience (LWR site) for buyer-facing shopping experience
|
||||
- Source-controllable as ExperienceBundle metadata
|
||||
- Created automatically when you create a Commerce Store
|
||||
|
||||
**What it includes:**
|
||||
- ExperienceBundle metadata (`StorefrontName.digitalExperience-meta.xml`)
|
||||
- URL routing configuration (`sfdc_cms__route`)
|
||||
- Page definitions (`sfdc_cms__view`)
|
||||
- Homepage
|
||||
- Product List Pages (PLP)
|
||||
- Product Detail Pages (PDP)
|
||||
- Shopping cart
|
||||
- Checkout flow
|
||||
- Order confirmation
|
||||
- Search results
|
||||
- Lightning Web Components (product cards, cart components, checkout)
|
||||
- Branding and theme configuration (`sfdc_cms__brandingSet`, `sfdc_cms__theme`)
|
||||
- Page layouts (`sfdc_cms__themeLayout`)
|
||||
- Navigation structure
|
||||
- Custom LWCs for extensions
|
||||
|
||||
**Where it lives:**
|
||||
- `force-app/main/default/digitalExperiences/site/StorefrontName/`
|
||||
- Example: `force-app/main/default/digitalExperiences/site/My_B2B_Store1/`
|
||||
|
||||
**How to create:**
|
||||
- Automatically generated by Commerce Store setup wizard
|
||||
- Retrieved from org using Salesforce CLI
|
||||
- Cannot be manually created from scratch
|
||||
|
||||
**How to deploy:**
|
||||
- Retrievable: `sf project retrieve start -m DigitalExperienceBundle:site/<name>`
|
||||
- Deployable: `sf project deploy start -m DigitalExperienceBundle`
|
||||
- Source-controllable in Git
|
||||
|
||||
---
|
||||
|
||||
## Why You Cannot Create Storefront Metadata from Scratch
|
||||
|
||||
### Technical Reasons
|
||||
|
||||
1. **Complex Dependency Chain**
|
||||
- Create merchandisers store
|
||||
- Create DigitalExperienceBundle
|
||||
- Integrate both together
|
||||
|
||||
2. **Hundreds of Auto-Generated Configurations**
|
||||
- Component IDs and region IDs (UUIDs)
|
||||
- WebStore associations
|
||||
- Commerce-managed component configurations
|
||||
- Default routing rules
|
||||
- Search configurations
|
||||
- Cart and checkout flow definitions
|
||||
- Payment integration settings
|
||||
|
||||
3. **Commerce-Managed Components**
|
||||
- Product List Page (PLP) components
|
||||
- Product Detail Page (PDP) components
|
||||
- Cart components
|
||||
- Checkout components
|
||||
- Search components
|
||||
- These require specific configurations from Store data
|
||||
|
||||
4. **Metadata API Limitation**
|
||||
- Metadata API deploys metadata types (Apex, LWCs, objects)
|
||||
- Metadata API CANNOT create SObject data (WebStore records)
|
||||
- Store creation requires data operations, not metadata operations
|
||||
|
||||
---
|
||||
|
||||
## The Required Creation Order
|
||||
|
||||
### Step 1: Create Commerce Store (Must Be First)
|
||||
|
||||
```
|
||||
User Interface (Commerce App)
|
||||
↓
|
||||
WebStore Record Created
|
||||
↓
|
||||
BuyerGroup Records Created
|
||||
↓
|
||||
EntitlementPolicy Records Created
|
||||
↓
|
||||
Digital Experience Auto-Generated
|
||||
↓
|
||||
Commerce Components Configured
|
||||
```
|
||||
|
||||
**Why this must be first:**
|
||||
- Generates WebStore record with unique ID
|
||||
- Creates default configurations
|
||||
- Auto-generates associated Digital Experience
|
||||
- Configures Commerce component relationships
|
||||
- Sets up default buyer access rules
|
||||
|
||||
### Step 2: Retrieve Storefront Metadata
|
||||
|
||||
```
|
||||
sf org list metadata --metadata-type DigitalExperienceConfig
|
||||
↓
|
||||
Select Store from List
|
||||
↓
|
||||
sf project retrieve start -m DigitalExperienceBundle:site/<name>
|
||||
↓
|
||||
Metadata Saved to Local Repository
|
||||
↓
|
||||
Now Editable and Source-Controllable
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Key Takeaway
|
||||
|
||||
**Commerce B2B = Store (data) + Storefront (metadata)**
|
||||
|
||||
1. Create Store → generates Storefront
|
||||
2. Retrieve Storefront → customize and version control if needed
|
||||
3. Deploy Storefront → only after creating Store in target org
|
||||
|
||||
**Never skip the Store creation. Never create Storefront metadata from scratch.**
|
||||
@ -48,15 +48,25 @@ sf template generate flexipage \
|
||||
npm install -g @salesforce/cli@latest
|
||||
```
|
||||
|
||||
#### **Field Selection Guidelines**
|
||||
#### **Template-specific requirements**
|
||||
|
||||
**RecordPage:**
|
||||
- Requires `--sobject` (e.g., Account, Custom_Object__c)
|
||||
- Requires field parameters:
|
||||
- `--primary-field`: Most important identifying field (e.g., Name)
|
||||
- `--secondary-fields`: Record summary (recommended 4-6, max 12)
|
||||
- `--detail-fields`: Full record details, including required fields (e.g., Name)
|
||||
|
||||
**AppPage:**
|
||||
- No additional requirements
|
||||
|
||||
**HomePage:**
|
||||
- No additional requirements
|
||||
|
||||
#### **Field Selection Rules**
|
||||
- **Validate fields exist**: Use MCP tools or describe commands to discover available fields for the object before specifying them in the command
|
||||
- **Prefer compound fields**: Use `Name` (not `FirstName`/`LastName`), `BillingAddress` (not `BillingStreet`/`BillingCity`/`BillingState`), `MailingAddress`, etc. when available
|
||||
|
||||
#### **Template-specific requirements**
|
||||
- **RecordPage**: Requires `--sobject` (e.g., Account, Custom_Object__c)
|
||||
- **RecordPage**: Requires `--primary-field` and `--secondary-fields` for dynamic highlights, `--detail-fields` for full record details. Use the most important identifying field as primary, e.g. Name. Use the secondary fields (max 12, recommended 4-6) to show a summary of the record. Use detail fields to show the full details of the record.
|
||||
- **AppPage**: No additional requirements
|
||||
- **HomePage**: No additional requirements
|
||||
- **Include required fields in detail-fields**: Always include object required fields (like `Name`) in the `--detail-fields` parameter, even if they're also used in `--primary-field` or `--secondary-fields`
|
||||
|
||||
#### **What you get**
|
||||
- Valid FlexiPage XML with correct structure
|
||||
@ -238,7 +248,7 @@ Every fieldInstance requires:
|
||||
|
||||
### "We couldn't retrieve or load the information on the field"
|
||||
**Cause:** Invalid field API name - field doesn't exist on the object or has incorrect spelling
|
||||
**Fix:** Use MCP tools or describe commands to discover valid fields, then update the field reference (see Field Selection Guidelines)
|
||||
**Fix:** Use MCP tools or describe commands to discover valid fields, then update the field reference (see Field Selection Rules)
|
||||
|
||||
### "Invalid field reference"
|
||||
**Cause:** Used `ObjectName.Field` instead of `Record.Field`
|
||||
|
||||
342
skills/searching-media/SKILL.md
Normal file
342
skills/searching-media/SKILL.md
Normal file
@ -0,0 +1,342 @@
|
||||
---
|
||||
name: searching-media
|
||||
description: "Searches for and retrieves existing visual media (images, logos, icons, photos, graphics, banners, thumbnails, hero images, backgrounds) from any source. Use this skill ANY TIME a user request involves finding, searching, getting, fetching, retrieving, grabbing, looking up, or locating media. Takes PRIORITY and activates FIRST when ANY media search/retrieval is mentioned, regardless of what else happens with the media afterward. Triggers for requests like \"search for logo\", \"find hero image\", \"get company logo\", \"locate icons\", \"fetch background image\", \"retrieve product photos\". Handles the search and source selection workflow. Does not apply when the request is to generate NEW images with AI, design custom graphics from scratch, or edit existing images."
|
||||
compatibility: "Requires search_media_cms_channels and/or search_electronic_media MCP tools"
|
||||
metadata:
|
||||
version: "1.0"
|
||||
---
|
||||
|
||||
# Media Search
|
||||
|
||||
Universal routing skill for searching and retrieving existing images and media.
|
||||
|
||||
## Scope
|
||||
|
||||
**This skill is for SEARCHING FOR existing media, not CREATING new media.**
|
||||
|
||||
**Use this skill when the user wants to:**
|
||||
- Search for images in Salesforce CMS, Data Cloud
|
||||
- Find existing visual assets to use in their app
|
||||
- Retrieve media from connected sources
|
||||
- Browse available images for their project
|
||||
- Locate specific photos or graphics
|
||||
|
||||
**DO NOT use this skill when the user wants to:**
|
||||
- Generate new images with AI (use image generation tools)
|
||||
- Create graphics or designs from scratch
|
||||
- Edit or modify existing images
|
||||
- Build custom visuals or diagrams
|
||||
|
||||
## Before You Search
|
||||
|
||||
**CRITICAL: This is a routing skill, not a direct search skill.**
|
||||
|
||||
When a user requests to find an image:
|
||||
|
||||
**Your first response MUST be plain text only — zero tool calls.** You MUST follow this sequence:
|
||||
|
||||
1. **First response MUST be text only:** A numbered list of search sources for the user. No tool calls of any kind.
|
||||
2. **Wait for user to reply** with their selected option number
|
||||
3. **Only then** call the appropriate search tool (this is the FIRST tool call in the entire interaction)
|
||||
|
||||
**Example of what NOT to do:**
|
||||
- ❌ Calling ANY tool before the user picks a source (MCP tools, file reads, descriptor checks, etc.)
|
||||
- ❌ "Checking which MCP tools are available" — do not probe or discover tools via tool calls
|
||||
- ❌ Immediately calling `search_electronic_media` or `search_media_cms_channels`
|
||||
- ❌ Reading MCP tool descriptors or schemas to see what's available
|
||||
- ❌ Deciding which search source to use without asking
|
||||
|
||||
**Example of what TO do:**
|
||||
- ✅ Respond with ONLY text — a numbered list of search sources
|
||||
- ✅ Ask: "Which option would you like to use?"
|
||||
- ✅ Wait for user to reply with their choice
|
||||
- ✅ Then (and only then) call the tool they selected
|
||||
|
||||
**Your first response when this skill triggers MUST be a text-only message presenting search sources. No tool calls. No exceptions.**
|
||||
|
||||
|
||||
## Workflow Overview
|
||||
|
||||
**The user MUST choose the search source. You CANNOT skip this step.**
|
||||
|
||||
Copy this checklist and track your progress:
|
||||
|
||||
```
|
||||
Media Search Progress:
|
||||
- [ ] Step 1: Check your own tool list for available search tools (no tool calls — just inspect what's in your context)
|
||||
- [ ] Step 2: Present only the available options to the user as a numbered list (plain text, no tool calls)
|
||||
- [ ] Step 3: Wait for the user to reply with their selection
|
||||
- [ ] Step 4: Execute the selected search method (this is the first tool call)
|
||||
- [ ] Step 5: Present all results to user for selection
|
||||
- [ ] Step 6: Apply selected image to code
|
||||
```
|
||||
|
||||
If you call any tool before step 4, you are not following this skill correctly.
|
||||
|
||||
## Presenting Search Sources (First Response)
|
||||
|
||||
**DO NOT call any tool, read any MCP descriptor, or make any external request to determine available tools.**
|
||||
|
||||
Your tools are already loaded into your context. Look at the tool names you already have access to — this is introspection, not a tool call.
|
||||
|
||||
**Step 1: Check your own tool list (no tool calls)**
|
||||
|
||||
Look at the tools already in your context and check for these names:
|
||||
- `search_media_cms_channels` → If present, include **"Search using keywords"**
|
||||
- `search_electronic_media` → If present, include **"Search using Data 360 hybrid search"**
|
||||
- Always include **"Other"** as the last option
|
||||
|
||||
**Step 2: Build your response**
|
||||
|
||||
Include ONLY the sources whose tools you actually have. Number them sequentially.
|
||||
|
||||
```
|
||||
I can help you find that image. Where would you like to search?
|
||||
|
||||
[NUMBER]. [SEARCH SOURCE NAME] — [Brief description]
|
||||
...
|
||||
[NUMBER]. Other — Provide your own URL or path
|
||||
|
||||
Which option would you like to use?
|
||||
```
|
||||
|
||||
**Step 3: Stop and wait**
|
||||
|
||||
After presenting the list, STOP. Do not call any tool. Do not proceed. Wait for the user to reply with their choice.
|
||||
|
||||
### Examples
|
||||
|
||||
**Both tools available:**
|
||||
```
|
||||
I can help you find that image. Where would you like to search?
|
||||
|
||||
1. Search using Data 360 hybrid search — Semantic search across Salesforce CMS and connected DAMs
|
||||
2. Search using keywords — Search Salesforce CMS by keywords and taxonomies
|
||||
3. Other — Provide your own URL or path
|
||||
|
||||
Which option would you like to use?
|
||||
```
|
||||
|
||||
**Only `search_media_cms_channels` available:**
|
||||
```
|
||||
I can help you find that image. Where would you like to search?
|
||||
|
||||
1. Search using keywords — Search Salesforce CMS by keywords and taxonomies
|
||||
2. Other — Provide your own URL or path
|
||||
|
||||
Which option would you like to use?
|
||||
```
|
||||
|
||||
**Only `search_electronic_media` available:**
|
||||
```
|
||||
I can help you find that image. Where would you like to search?
|
||||
|
||||
1. Search using Data 360 hybrid search — Semantic search across Salesforce CMS and connected DAMs
|
||||
2. Other — Provide your own URL or path
|
||||
|
||||
Which option would you like to use?
|
||||
```
|
||||
|
||||
**Neither tool available:**
|
||||
```
|
||||
No automated media search sources are currently configured. Please provide a direct URL or asset library path.
|
||||
```
|
||||
|
||||
**Wait for the user to select** before proceeding.
|
||||
|
||||
## Executing the Selected Search Method
|
||||
|
||||
**⚠️ ONLY reach this step if the user has explicitly selected an option from your numbered list.**
|
||||
|
||||
If you haven't shown options yet, go back to the "Presenting Search Sources" section first.
|
||||
|
||||
After the user selects an option, execute the corresponding search method below.
|
||||
|
||||
### Search using keywords
|
||||
|
||||
**Tool:** `search_media_cms_channels`
|
||||
|
||||
**Process:**
|
||||
|
||||
1. **Analyze the query** — Understand what the user is searching for (subject, attributes, domain)
|
||||
|
||||
2. **Extract keywords** — Concrete nouns that would appear in image metadata
|
||||
- Use domain-specific synonyms
|
||||
- Maximum 10 terms
|
||||
- Examples:
|
||||
- "luxury apartments" → apartment, villa, penthouse, residence, condo
|
||||
- "company logo" → logo, emblem, corporate logo
|
||||
- "bright room" → _(empty if no concrete nouns)_
|
||||
|
||||
3. **Extract taxonomies** — Descriptive qualities, styles, moods, categories
|
||||
- Only adjectives and attributes
|
||||
- Examples:
|
||||
- "luxury apartment with river view" → Luxury, Premium, Waterfront, Riverside, Panoramic
|
||||
- "bright spacious room" → Bright, Spacious, Open, Airy, Light
|
||||
- "car" → _(empty if no descriptive terms)_
|
||||
|
||||
4. **Determine locale** — Use format `en_US`, `es_MX`, `fr_FR` (default: `en_US`)
|
||||
|
||||
5. **Build the JSON payload** — Construct this exact structure:
|
||||
|
||||
```json
|
||||
{
|
||||
"inputs": [{
|
||||
"searchKeyword": "keyword1 OR keyword2 OR keyword3",
|
||||
"taxonomyExpression": "{\"OR\": [\"Taxonomy1\", \"Taxonomy2\"]}",
|
||||
"searchLanguage": "en_US",
|
||||
"channelIds": "",
|
||||
"channelType": "PublicUnauthenticated",
|
||||
"contentTypeFqn": "sfdc_cms__image",
|
||||
"pageOffset": 0,
|
||||
"searchLimit": 5
|
||||
}]
|
||||
}
|
||||
```
|
||||
|
||||
**Field rules:**
|
||||
- `searchKeyword`: Join keywords with ` OR ` (space-OR-space). Use empty string if no keywords.
|
||||
- `taxonomyExpression`: Stringify JSON object `{"OR": ["term1", "term2"]}`. Use `"{}"` if no taxonomies.
|
||||
- `searchLanguage`: Locale with underscore (e.g., `en_US`)
|
||||
- `channelIds`: Always empty string
|
||||
- `channelType`: Always `"PublicUnauthenticated"`
|
||||
- `contentTypeFqn`: Always `"sfdc_cms__image"`
|
||||
- `pageOffset`: Start at `0`, increment by `searchLimit` for pagination
|
||||
- `searchLimit`: Default `5`, adjust if user requests more
|
||||
|
||||
**Examples:**
|
||||
|
||||
Query: "luxury apartment with river view"
|
||||
```json
|
||||
{
|
||||
"inputs": [{
|
||||
"searchKeyword": "apartment OR villa OR penthouse OR residence",
|
||||
"taxonomyExpression": "{\"OR\": [\"Luxury\", \"Premium\", \"Waterfront\", \"Riverside\"]}",
|
||||
"searchLanguage": "en_US",
|
||||
"channelIds": "",
|
||||
"channelType": "PublicUnauthenticated",
|
||||
"contentTypeFqn": "sfdc_cms__image",
|
||||
"pageOffset": 0,
|
||||
"searchLimit": 5
|
||||
}]
|
||||
}
|
||||
```
|
||||
|
||||
Query: "bright spacious room" (no concrete nouns)
|
||||
```json
|
||||
{
|
||||
"inputs": [{
|
||||
"searchKeyword": "",
|
||||
"taxonomyExpression": "{\"OR\": [\"Bright\", \"Spacious\", \"Open\", \"Airy\"]}",
|
||||
"searchLanguage": "en_US",
|
||||
"channelIds": "",
|
||||
"channelType": "PublicUnauthenticated",
|
||||
"contentTypeFqn": "sfdc_cms__image",
|
||||
"pageOffset": 0,
|
||||
"searchLimit": 5
|
||||
}]
|
||||
}
|
||||
```
|
||||
|
||||
Query: "car images" (no descriptive terms)
|
||||
```json
|
||||
{
|
||||
"inputs": [{
|
||||
"searchKeyword": "car OR automobile OR vehicle OR auto",
|
||||
"taxonomyExpression": "{}",
|
||||
"searchLanguage": "en_US",
|
||||
"channelIds": "",
|
||||
"channelType": "PublicUnauthenticated",
|
||||
"contentTypeFqn": "sfdc_cms__image",
|
||||
"pageOffset": 0,
|
||||
"searchLimit": 5
|
||||
}]
|
||||
}
|
||||
```
|
||||
|
||||
6. **Call the tool** with the exact JSON payload
|
||||
|
||||
### Search using Data 360 hybrid search
|
||||
|
||||
**Tool:** `search_electronic_media`
|
||||
|
||||
**Process:**
|
||||
|
||||
1. Use the user's query **as-is** — no keyword extraction or transformation needed
|
||||
2. Call `search_electronic_media`
|
||||
3. Pass the query to the tool's `searchQuery` parameter
|
||||
|
||||
**Example:**
|
||||
- User query: "modern luxury apartment with natural lighting"
|
||||
- Tool call: `search_electronic_media(searchQuery="modern luxury apartment with natural lighting")`
|
||||
|
||||
### Other (User-Provided URL)
|
||||
|
||||
Ask the user to provide:
|
||||
- Direct URL to the image
|
||||
- Asset library path
|
||||
- Specific system/location to check
|
||||
|
||||
## Presenting Search Results
|
||||
|
||||
Parse the tool response and present **ALL** results as numbered options. Show the image title only — do not display the URL. When the user selects an option, use the URL internally to apply the image.
|
||||
|
||||
```
|
||||
I found 4 images. Which one would you like to use?
|
||||
|
||||
1. Luxury Apartment Exterior
|
||||
Source: Salesforce CMS
|
||||
|
||||
2. Modern High-Rise Building
|
||||
Source: Salesforce CMS
|
||||
|
||||
3. Waterfront Residence
|
||||
Source: Salesforce CMS
|
||||
|
||||
4. Premium Condominium
|
||||
Source: Salesforce CMS
|
||||
```
|
||||
|
||||
**Never auto-select an image.** Always wait for user choice.
|
||||
|
||||
## Applying the Selected Image
|
||||
|
||||
After the user chooses:
|
||||
|
||||
1. Confirm the selection with image name and URL
|
||||
2. Use the complete URL returned by the tool, including all query parameters. CMS and DAM URLs rely on query parameters for authentication, resizing, and CDN routing — dropping them breaks the image. For example, a URL like `https://cms.example.com/media/img.jpg?oid=00D&refid=0EM&v=2` must be used in full.
|
||||
3. Apply the URL to the user's code/component
|
||||
4. Show what was changed (file path and line number)
|
||||
|
||||
## Error Handling
|
||||
|
||||
| Error | Response |
|
||||
|---|---|
|
||||
| Tool unavailable | "The [source name] tool is unavailable. Would you like to try a different source?" |
|
||||
| Tool returns error | Show error message, offer retry with different terms or alternative source |
|
||||
| No results found | "No results found. Try broader keywords, removing descriptive terms, or a different source." |
|
||||
| Invalid user selection | Re-display options and ask again |
|
||||
|
||||
**Never silently fail.** Always inform the user and offer alternatives.
|
||||
|
||||
## Search Behavior Notes
|
||||
|
||||
**Search using keywords:**
|
||||
- Both keyword and taxonomy → results match keyword OR (keyword + taxonomy)
|
||||
- Empty keyword → search by taxonomy only
|
||||
- Empty taxonomy → search by keyword only
|
||||
- Use `pageOffset` for pagination (increment by `searchLimit`)
|
||||
|
||||
**Search using Data 360 hybrid search:**
|
||||
- Handles natural language queries
|
||||
- Semantic similarity matching
|
||||
- Searches across multiple connected systems
|
||||
|
||||
## Key Principles
|
||||
|
||||
1. **First response is always text-only** — Present search sources without calling any tool
|
||||
2. **Only show configured sources** — Check your own tool list (introspection, not tool calls) and only present sources whose tools you have
|
||||
3. **Wait for user selection** — Never auto-select a source or image
|
||||
4. **Show all results** — Let the user choose the best match
|
||||
5. **Confirm before applying** — Verify the selection before modifying code
|
||||
6. **Handle errors gracefully** — Provide clear feedback and alternatives
|
||||
Loading…
Reference in New Issue
Block a user