sf-apex
Generates and reviews Salesforce Apex code with 2025 best practices and 150-point scoring. Use when writing Apex classes, triggers, test classes, batch jobs, or reviewing existing Apex code for bulkification, security, and SOLID principles.
$ 설치
git clone https://github.com/Jaganpro/sf-skills /tmp/sf-skills && cp -r /tmp/sf-skills/sf-apex ~/.claude/skills/sf-skills// tip: Run this command in your terminal to install the skill
name: sf-apex description: > Generates and reviews Salesforce Apex code with 2025 best practices and 150-point scoring. Use when writing Apex classes, triggers, test classes, batch jobs, or reviewing existing Apex code for bulkification, security, and SOLID principles. license: MIT metadata: version: "1.0.0" author: "Jag Valaiyapathy" scoring: "150 points across 8 categories"
sf-apex: Salesforce Apex Code Generation and Review
Expert Apex developer specializing in clean code, SOLID principles, and 2025 best practices. Generate production-ready, secure, performant, and maintainable Apex code.
Core Responsibilities
- Code Generation: Create Apex classes, triggers (TAF), tests, async jobs from requirements
- Code Review: Analyze existing Apex for best practices violations with actionable fixes
- Validation & Scoring: Score code against 8 categories (0-150 points)
- Deployment Integration: Validate and deploy via sf-deploy skill
Workflow (5-Phase Pattern)
Phase 1: Requirements Gathering
Use AskUserQuestion to gather:
- Class type (Trigger, Service, Selector, Batch, Queueable, Test, Controller)
- Primary purpose (one sentence)
- Target object(s)
- Test requirements
Then:
- Check existing code:
Glob: **/*.cls,Glob: **/*.trigger - Check for existing Trigger Actions Framework setup:
Glob: **/*TriggerAction*.cls - Create TodoWrite tasks
Phase 2: Design & Template Selection
Select template:
| Class Type | Template |
|---|---|
| Trigger | templates/trigger.trigger |
| Trigger Action | templates/trigger-action.cls |
| Service | templates/service.cls |
| Selector | templates/selector.cls |
| Batch | templates/batch.cls |
| Queueable | templates/queueable.cls |
| Test | templates/test-class.cls |
| Test Data Factory | templates/test-data-factory.cls |
| Standard Class | templates/apex-class.cls |
Template Path Resolution (try in order):
- Marketplace folder:
~/.claude/plugins/marketplaces/sf-skills/sf-apex/templates/[template] - Project folder:
[project-root]/sf-apex/templates/[template]
Example: Read: ~/.claude/plugins/marketplaces/sf-skills/sf-apex/templates/apex-class.cls
Phase 3: Code Generation/Review
For Generation:
- Create class file in
force-app/main/default/classes/ - Apply naming conventions (see docs/naming-conventions.md)
- Include ApexDoc comments
- Create corresponding test class
For Review:
- Read existing code
- Run validation against best practices
- Generate improvement report with specific fixes
Run Validation:
Score: XX/150 ⭐⭐⭐⭐ Rating
├─ Bulkification: XX/25
├─ Security: XX/25
├─ Testing: XX/25
├─ Architecture: XX/20
├─ Clean Code: XX/20
├─ Error Handling: XX/15
├─ Performance: XX/10
└─ Documentation: XX/10
⛔ GENERATION GUARDRAILS (MANDATORY)
BEFORE generating ANY Apex code, Claude MUST verify no anti-patterns are introduced.
If ANY of these patterns would be generated, STOP and ask the user:
"I noticed [pattern]. This will cause [problem]. Should I: A) Refactor to use [correct pattern] B) Proceed anyway (not recommended)"
| Anti-Pattern | Detection | Impact |
|---|---|---|
| SOQL inside loop | for(...) { [SELECT...] } | Governor limit failure (100 SOQL) |
| DML inside loop | for(...) { insert/update } | Governor limit failure (150 DML) |
| Missing sharing | class X { without keyword | Security violation |
| Hardcoded ID | 15/18-char ID literal | Deployment failure |
| Empty catch | catch(e) { } | Silent failures |
| String concatenation in SOQL | 'SELECT...WHERE Name = \'' + var | SOQL injection |
| Test without assertions | @IsTest method with no Assert.* | False positive tests |
DO NOT generate anti-patterns even if explicitly requested. Ask user to confirm the exception with documented justification.
See: resources/security-guide.md for detailed security patterns See: resources/anti-patterns.md for complete anti-pattern catalog
Phase 4: Deployment
Step 1: Validation
Skill(skill="sf-deploy", args="Deploy classes at force-app/main/default/classes/ to [target-org] with --dry-run")
Step 2: Deploy (only if validation succeeds)
Skill(skill="sf-deploy", args="Proceed with actual deployment to [target-org]")
See: resources/troubleshooting.md for deployment prerequisites
Phase 5: Documentation & Testing Guidance
Completion Summary:
✓ Apex Code Complete: [ClassName]
Type: [type] | API: 62.0
Location: force-app/main/default/classes/[ClassName].cls
Test Class: [TestClassName].cls
Validation: PASSED (Score: XX/150)
Next Steps: Run tests, verify behavior, monitor logs
Best Practices (150-Point Scoring)
| Category | Points | Key Rules |
|---|---|---|
| Bulkification | 25 | NO SOQL/DML in loops; collect first, operate after; test 251+ records |
| Security | 25 | WITH USER_MODE; bind variables; with sharing; Security.stripInaccessible() |
| Testing | 25 | 90%+ coverage; Assert class; positive/negative/bulk tests; Test Data Factory |
| Architecture | 20 | TAF triggers; Service/Domain/Selector layers; SOLID; dependency injection |
| Clean Code | 20 | Meaningful names; self-documenting; no != false; single responsibility |
| Error Handling | 15 | Specific before generic catch; no empty catch; custom business exceptions |
| Performance | 10 | Monitor with Limits; cache expensive ops; scope variables; async for heavy |
| Documentation | 10 | ApexDoc on classes/methods; meaningful params |
Thresholds: ✅ 90+ (Deploy) | ⚠️ 67-89 (Review) | ❌ <67 (Block - fix required)
Deep Dives:
- resources/bulkification-guide.md - Governor limits, collection handling
- resources/security-guide.md - CRUD/FLS, sharing, injection prevention
- resources/testing-patterns.md - Exception types, mocking, coverage
- resources/patterns-deep-dive.md - TAF, @InvocableMethod, async patterns
Trigger Actions Framework (TAF)
Quick Reference
When to Use: If TAF package is installed in target org (check: sf package installed list)
Trigger Pattern (one per object):
trigger AccountTrigger on Account (before insert, after insert, before update, after update, before delete, after delete, after undelete) {
new MetadataTriggerHandler().run();
}
Action Class (one per behavior):
public class TA_Account_SetDefaults implements TriggerAction.BeforeInsert {
public void beforeInsert(List<Account> newList) {
for (Account acc : newList) {
if (acc.Industry == null) {
acc.Industry = 'Other';
}
}
}
}
⚠️ CRITICAL: TAF triggers do NOTHING without Trigger_Action__mdt records! Each action class needs a corresponding Custom Metadata record.
Installation:
sf package install --package 04tKZ000000gUEFYA2 --target-org [alias] --wait 10
Fallback: If TAF is NOT installed, use standard trigger pattern (see resources/patterns-deep-dive.md)
See: resources/patterns-deep-dive.md for complete TAF patterns and Custom Metadata setup
Async Decision Matrix
| Scenario | Use |
|---|---|
| Simple callout, fire-and-forget | @future(callout=true) |
| Complex logic, needs chaining | Queueable |
| Process millions of records | Batch Apex |
| Scheduled/recurring job | Schedulable |
| Post-queueable cleanup | Queueable Finalizer |
See: resources/patterns-deep-dive.md for detailed async patterns
Modern Apex Features (API 62.0)
- Null coalescing:
value ?? defaultValue - Safe navigation:
record?.Field__c - User mode:
WITH USER_MODEin SOQL - Assert class:
Assert.areEqual(),Assert.isTrue()
Breaking Change (API 62.0): Cannot modify Set while iterating - throws System.FinalException
See: resources/bulkification-guide.md for collection usage
Flow Integration (@InvocableMethod)
Apex classes can be called from Flow using @InvocableMethod. This pattern enables complex business logic, DML, callouts, and integrations from declarative automation.
Quick Pattern
public with sharing class RecordProcessor {
@InvocableMethod(label='Process Record' category='Custom')
public static List<Response> execute(List<Request> requests) {
List<Response> responses = new List<Response>();
for (Request req : requests) {
Response res = new Response();
res.isSuccess = true;
res.processedId = req.recordId;
responses.add(res);
}
return responses;
}
public class Request {
@InvocableVariable(label='Record ID' required=true)
public Id recordId;
}
public class Response {
@InvocableVariable(label='Is Success')
public Boolean isSuccess;
@InvocableVariable(label='Processed ID')
public Id processedId;
}
}
Template: Use templates/invocable-method.cls for complete pattern
See:
- resources/patterns-deep-dive.md - Complete @InvocableMethod guide
- docs/flow-integration.md - Advanced Flow-Apex patterns
- docs/triangle-pattern.md - Flow-LWC-Apex triangle
Testing Best Practices
The 3 Test Types (PNB Pattern)
Every feature needs:
- Positive: Happy path test
- Negative: Error handling test
- Bulk: 251+ records test
Example:
@IsTest
static void testPositive() {
Account acc = new Account(Name = 'Test', Industry = 'Tech');
insert acc;
Assert.areEqual('Tech', [SELECT Industry FROM Account WHERE Id = :acc.Id].Industry);
}
@IsTest
static void testNegative() {
try {
insert new Account(); // Missing Name
Assert.fail('Expected DmlException');
} catch (DmlException e) {
Assert.isTrue(e.getMessage().contains('REQUIRED_FIELD_MISSING'));
}
}
@IsTest
static void testBulk() {
List<Account> accounts = new List<Account>();
for (Integer i = 0; i < 251; i++) {
accounts.add(new Account(Name = 'Bulk ' + i));
}
insert accounts;
Assert.areEqual(251, [SELECT COUNT() FROM Account]);
}
See:
- resources/testing-patterns.md - Exception types, mocking, Test Data Factory
- docs/testing-guide.md - Complete testing reference
Common Exception Types
When writing test classes, use these specific exception types:
| Exception Type | When to Use |
|---|---|
DmlException | Insert/update/delete failures |
QueryException | SOQL query failures |
NullPointerException | Null reference access |
ListException | List operation failures |
LimitException | Governor limit exceeded |
CalloutException | HTTP callout failures |
Example:
@IsTest
static void testExceptionHandling() {
try {
insert new Account(); // Missing required Name
Assert.fail('Expected DmlException was not thrown');
} catch (DmlException e) {
Assert.isTrue(e.getMessage().contains('REQUIRED_FIELD_MISSING'),
'Expected REQUIRED_FIELD_MISSING but got: ' + e.getMessage());
}
}
See: resources/testing-patterns.md for complete reference
LSP-Based Validation (Auto-Fix Loop)
The sf-apex skill includes Language Server Protocol (LSP) integration for real-time syntax validation. This enables Claude to automatically detect and fix Apex syntax errors during code authoring.
How It Works
- PostToolUse Hook: After every Write/Edit operation on
.clsor.triggerfiles, the LSP hook validates syntax - Apex Language Server: Uses Salesforce's official
apex-jorje-lsp.jar(from VS Code extension) - Auto-Fix Loop: If errors are found, Claude receives diagnostics and auto-fixes them (max 3 attempts)
- Two-Layer Validation:
- LSP Validation: Fast syntax checking (~500ms)
- 150-Point Validation: Semantic analysis for best practices
Prerequisites
For LSP validation to work, users must have:
- VS Code Salesforce Extension Pack: VS Code → Extensions → "Salesforce Extension Pack"
- Java 11+: https://adoptium.net/temurin/releases/
Graceful Degradation: If LSP is unavailable, validation silently skips - the skill continues to work with only 150-point semantic validation.
See: resources/troubleshooting.md for complete LSP guide
Cross-Skill Integration
| Skill | When to Use | Example |
|---|---|---|
| sf-metadata | Discover object/fields before coding | Skill(skill="sf-metadata") → "Describe Invoice__c" |
| sf-data | Generate 251+ test records after deploy | Skill(skill="sf-data") → "Create 251 Accounts for bulk testing" |
| sf-deploy | Deploy to org - see Phase 4 | Skill(skill="sf-deploy", args="Deploy to [org]") |
| sf-flow | Create Flow that calls your Apex | See @InvocableMethod section above |
| sf-lwc | Create LWC that calls your Apex | @AuraEnabled controller patterns |
Reference Documentation
Quick Guides (resources/)
| Guide | Description |
|---|---|
| patterns-deep-dive.md | TAF, @InvocableMethod, async patterns, service layer |
| security-guide.md | CRUD/FLS, sharing, SOQL injection, guardrails |
| bulkification-guide.md | Governor limits, collections, monitoring |
| testing-patterns.md | Exception types, mocking, Test Data Factory, coverage |
| anti-patterns.md | Code smells, red flags, refactoring patterns |
| troubleshooting.md | LSP validation, deployment errors, debug logs |
Full Documentation (docs/)
| Document | Description |
|---|---|
best-practices.md | Bulkification, collections, null safety, guard clauses, DML performance |
code-smells-guide.md | Code smells detection and refactoring patterns |
design-patterns.md | 12 patterns including Domain Class, Abstraction Levels |
trigger-actions-framework.md | TAF setup and advanced patterns |
security-guide.md | Complete CRUD/FLS and sharing reference |
testing-guide.md | Complete test patterns and mocking |
naming-conventions.md | Variable, method, class naming rules |
solid-principles.md | SOLID principles for Apex |
code-review-checklist.md | 150-point scoring criteria |
flow-integration.md | Complete @InvocableMethod guide |
triangle-pattern.md | Flow-LWC-Apex integration |
Path: ~/.claude/plugins/marketplaces/sf-skills/sf-apex/docs/
Dependencies
All optional: sf-deploy, sf-metadata, sf-data. Install: /plugin install github:Jaganpro/sf-skills/[skill-name]
Notes
- API Version: 62.0 required
- TAF Optional: Prefer TAF when package is installed, use standard trigger pattern as fallback
- Scoring: Block deployment if score < 67
- LSP: Optional but recommended for real-time syntax validation
License
MIT License. See LICENSE file. Copyright (c) 2024-2025 Jag Valaiyapathy
