跳到主要内容
知仓学习社ZHICANG

platform-apex-generate

Primary Apex authoring skill for class generation, refactoring, and review. ALWAYS ACTIVATE when the user mentions Apex, .cls, triggers, or asks to …

不碰外部(只输出文字)无严重或高危命中forcedotcom/sf-skills

它会碰到什么

扫了多少1 个文本文件,27 KB
它会碰到什么不碰外部(只输出文字)
命中总数0 处
命中统计严重 0 · 高 0 · 中 0 · 低 0

这一栏是扫描器报的事实,不是结论。命中多不等于有毒(安全工具、规则库、示例脚本本来就会包含危险写法),命中少也不等于干净。它和你手上的凭据、文件、网络有什么关系,需要你自己看。

技能内容

Generating Apex

Use this skill for production-grade Apex: new classes, selectors, services, async jobs,

invocable methods, and triggers; and for evidence-based review of existing .cls OR .trigger.

Required Inputs

Gather or infer before authoring:

  • Class type (service, selector, domain, batch, queueable, schedulable, invocable, trigger, trigger action, DTO, utility, interface, abstract, exception, REST resource)
  • Target object(s) and business goal
  • Class name (derive using the naming table below)
  • Net-new vs refactor/fix; any org/API constraints
  • Deployment targets (default to runSpecifiedTests and use generated tests where applicable)

Defaults unless specified:

  • Sharing: with sharing (see sharing rules per type below)
  • Access: public (use global only when required by managed packages or @RestResource)
  • API version: 66.0 (minimum version)
  • ApexDoc comments: yes

If the user provides a clear, complete request, generate immediately without unnecessary back-and-forth.


Workflow

All steps are sequential. Do not skip, merge, or reorder. If blocked, stop and ask for missing context. If not applicable, mark N/A with a one-line justification in the report.

Phase 1 — Author

  1. Discover project conventions
  • Service-Selector-Domain layering, logging utilities
  • Existing classes/triggers and current trigger framework or handler pattern
  • Whether Trigger Actions Framework (TAF) is already in use
  • When refactoring or reviewing an existing .cls, call mcp__plugin_salesforce-development_salesforce-lsp__apex_documentSymbol with {filePath: "<absolute-path>"} to map the class's methods, properties, and inner types before editing, and call mcp__plugin_salesforce-development_salesforce-lsp__apex_hover with {filePath, line, character} (one-based line/character) to resolve the type or signature of a symbol you are unsure about. On error envelope or unavailable ({error: <code>} / tool not registered), fall back to reading the source directly.
  1. Choose the smallest correct pattern (see Type-Specific Guidance below)
  1. Review templates and assets
  • Read the matching template from assets/ before authoring (see Type-Specific Guidance for the file mapping)
  • When a references/ example exists for the type, read it as a concrete style guide
  • For any test class work, always read and use platform-apex-test-generate skill
  1. Author with guardrails -- apply every rule in the Rules section below
  • Generate {ClassName}.cls with ApexDoc
  • Generate {ClassName}.cls-meta.xml
  1. Generate test classes -- Load the skill platform-apex-test-generate to create {ClassName}Test.cls and {ClassName}Test.cls-meta.xml. Apex tests are always required to be generated to deploy. No test file creation or edits can occur without loading the platform-apex-test-generate skill to generate tests.

Phase 2 — Validate (required before reporting)

Writing files is the midpoint, not the finish line. Steps 6, 7, and 8 each require a tool invocation and produce output that must appear in the Step 9 report. Do not summarize or present the report until all three steps have run and their output is captured.

  1. Compile-check every file (REQUIRED) — via the diagnostics tool when available, otherwise via the fallback. Running one of these is mandatory; which one depends on what your environment exposes.
  • Preferred: Invoke mcp__plugin_salesforce-development_salesforce-lsp__apex_diagnostics with {filePath: "<absolute-path>"} on every generated/updated .cls and .trigger file to compile-check and surface errors/warnings before deploy.
  • On success with diagnostics ({ok: true}, non-empty list), remediate all diagnostics with severity error or warning; re-run until clean.
  • Fail closed on an empty diagnostics result — always. The tool returns {ok: true, diagnostics: []} for BOTH a genuinely clean compile AND a swallowed timeout/internal error, so an empty list is not by itself proof the code compiled. Whenever diagnostics come back empty, you MUST corroborate with the Fallback (sf project deploy start --dry-run) before reporting the file as clean or deploy-ready. Do not treat any empty apex_diagnostics response as a passing compile on its own.
  • On error envelope ({error: <code>}), record apex_diagnostics=unavailable: <code> and use the Fallback.
  • On unavailable (tool not registered), record apex_diagnostics=unavailable: lsp_not_present and use the Fallback.
  • If the tool is not resolvable in this environment — e.g. it is a deferred tool and a ToolSearch for it returns no match, or the call otherwise cannot be made — do NOT stall or retry discovery. Record apex_diagnostics=unavailable: lsp_not_present and use the Fallback immediately.
  • If diagnostics report an unknown field or object that you just deployed, call mcp__plugin_salesforce-development_salesforce-lsp__refresh_org_schema to invalidate the cached org describe, then re-run apex_diagnostics before treating it as a real code error.
  • Fallback (fully satisfies this step): Compile-check via sf project deploy start --dry-run and read CLI errors. Remediate any errors and re-run until clean. A clean fallback result is a valid, complete outcome for this step — the diagnostics MCP tool is preferred, not required, when it is not available.
  • Compilation is this step's only concern. It does NOT cover PMD, CRUD/FLS, or complexity rules — those are static analysis, run as a separate required step below (Step 7).
  • NEVER report a class or trigger as valid or deploy-ready without running EITHER the diagnostics tool OR the fallback. "The tool wasn't available" is not a reason to skip validation — fall back and validate. Recording apex_diagnostics=unavailable: <reason> is only acceptable alongside a completed fallback.
  • Capture the final tool (or fallback) output verbatim for the report.
  1. Run static analysis (REQUIRED) — compilation does not check PMD, CRUD/FLS, complexity, and related rules; this step does.
  • Invoke sf code-analyzer run --target <target> on all generated/updated .cls and .trigger files. Remediate all sev0, sev1, and sev2 violations; re-run until clean.
  • This is a distinct gate from Step 6 — a clean compile does not satisfy it, and running it does not substitute for the compile-check.
  • If Code Analyzer cannot run in this environment, record run_code_analyzer=unavailable: <reason> in the report. That explicit outcome is the only acceptable way to skip it.
  • Capture the final tool output verbatim for the report.
  1. Execute Apex tests
  • Run org tests including {ClassName}Test via sf apex run test or MCP.
  • Delegate all test generation/fixes/coverage work to platform-apex-test-generate; iterate until the tests pass.
  • Capture pass/fail counts and coverage percentage for the report.
  • If unavailable, record test_execution=unavailable: <error> in the report.

Phase 3 — Report

  1. Report -- use the output format at the bottom of this file.
  • The Compile line must contain the actual Step 6 output — either the diagnostics tool result, or the fallback (sf project deploy start --dry-run) result prefixed with apex_diagnostics=unavailable: <reason>. Code Analyzer does NOT belong on this line — it cannot establish that Apex compiles.
  • The Analyzer line must contain the actual Step 7 sf code-analyzer run output (or run_code_analyzer=unavailable: <reason> after attempting invocation).
  • The Testing line must contain the actual Step 8 results (or test_execution=unavailable: <reason> after attempting invocation).
  • A report missing any of these lines is incomplete. Always run each step or record its explicit unavailable outcome before reporting.

Rules

Hard-Stop Constraints (Must Enforce)

If any constraint would be violated in generated code, stop and explain the problem before proceeding:

| Constraint | Rationale |

|---|---|

| Place all SOQL outside loops | Avoid query governor limits (100 queries) |

| Place all DML outside loops | Avoid DML governor limits (150 statements) |

| Declare a sharing keyword on every class | Prevent unintended without sharing defaults and data exposure |

| Use Custom Metadata/Labels/describe calls instead of hardcoded IDs | Ensure portability across orgs |

| Always handle exceptions (log, rethrow, or recover) | Prevent silent failures |

| Use bind variables for all dynamic SOQL with user input | Prevent SOQL injection |

| Use Apex-native collections (List, Map, Set) rather than Java types | Prevent compile errors |

| Verify methods exist in Apex before use | Prevent reliance on non-existent APIs |

| Avoid System.debug() in main code paths | Debug statements evaluate even when loggign is not active and consume CPU. Use a logging framework if required on main code paths |

| Never use @future methods | Use Queueable with System.Finalizer; @future cannot chain, cannot be called from Batch, and cannot accept non-primitive types |

Bulkification & Governor Limits

  • All public APIs accept and process collections; single-record overloads delegate to the bulk method
  • In batch/bulk flows, prefer partial-success DML (Database.update(records, false)) and process SaveResult for errors
  • Use Map<Id, SObject> constructor for efficient ID-based lookups from query results
  • Use Map<Id, List<SObject>> to group child records by parent; build the map in a single loop before processing
  • Use Set<Id> for deduplication and membership checks; prefer Set.contains() over List.contains()
  • Use relationship subqueries to fetch parent + child records in a single SOQL when both are needed
  • Use AggregateResult with GROUP BY for rollup calculations instead of querying and counting in Apex
  • Only DML records that actually changed — compare against Trigger.oldMap or prior state before adding to the update list
  • Use Limits.getQueries(), Limits.getDmlStatements(), Limits.getCpuTime() to monitor consumption in complex transactions

SOQL Optimization

  • Use selective queries with proper WHERE clauses; use indexed fields (Id, Name, OwnerId, lookup/master-detail fields, ExternalId fields, custom indexes) in filters when possible
  • SELECT * does not exist in SOQL -- always specify the exact fields needed
  • Apply LIMIT clauses to bound result sets; use ORDER BY for deterministic results
  • When querying Custom Metadata Types (objects ending with __mdt), do NOT use SOQL — use the built-in methods ({CustomMdt__mdt}.getAll().values(), getInstance(), etc.)
  • Queries executed in without sharing keyword classes with API versions 67.0 and up will throw when the running user does not have the proper field or object-level security. If API versions are being updated, ensure queries are safeguarded properly, and that tests are updated accordingly. Only explicitly justified usages of SYSTEM_MODE variants within queries should be allowed by default.

Caching

  • Use Platform Cache (Cache.Org / Cache.Session) for frequently accessed, rarely changed data; set a TTL and always handle cache misses — cache can be evicted at any time
  • Use private static Map fields as transaction-scoped caches to prevent duplicate queries within the same execution context; lazy-initialize on first access

Security

  • Default to with sharing; document justification for without sharing or inherited sharing
  • WITH USER_MODE in SOQL and AccessLevel.USER_MODE for Database DML for CRUD/FLS enforcement — these are the defaults for _all_ Apex classes with API versions of 67.0 or higher
  • Validate dynamic field/operator names via allowlist or Schema.describe
  • Named Credentials for all external credentials/API keys
  • AuraHandledException for @AuraEnabled user-facing errors (no internal details)
  • without sharing requires a Custom Permission check
  • Isolate without sharing logic in dedicated helper classes; call from with sharing entry points to limit elevated-access scope
  • Encrypt PII/sensitive data at rest via Platform Encryption; never expose PII in debug statements, error messages, or API responses

Security Verification

Before finalizing, verify: CRUD/FLS enforced (SOQL + DML) · explicit sharing keyword on every class · no hardcoded secrets or Record IDs · PII excluded from logs and error messages · error messages sanitized for end users.

Error Handling

  • Catch specific exceptions before generic Exception; include context in messages
  • Use try/catch only around code that can throw (DML, callouts, JSON parsing, casts); avoid defensive wrapping of simple assignments/collection ops/arithmetic
  • Preserve exception cause chains: new CustomException('message', cause) (do not replace stack trace with concatenated messages)
  • Provide a custom exception class per service domain when meaningful
  • In @AuraEnabled methods, catch exceptions and rethrow as AuraHandledException
  • Fallback option: when no meaningful domain exception exists, catch generic Exception and either rethrow it or wrap it in a minimal custom exception that preserves the original cause.

Null Safety

  • Add guard clauses for null/empty inputs at the top of every public method; match style to context: return early in private/trigger-handler methods, throw exceptions in public APIs, record.addError() in validation services
  • Return empty collections instead of null
  • Use safe navigation (?.) for chained property access
  • Never dereference map.get(key) inline unless presence is guaranteed; use containsKey, assignment + null check, or safe navigation first
  • Use null coalescing (??) for default values
  • Prefer String.isBlank(value) over manual checks like value == null || value.trim().isEmpty()

Constants & Literals

  • Use enums over string constants whenever possible; enum values follow UPPER_SNAKE_CASE
  • Extract repeated literal strings/numbers into private static final constants or a constants class
  • Use Label. custom labels for user-facing strings
  • Use Custom Metadata for configurable values (thresholds, mappings, feature flags)
  • Never output HTML-escaped entities in code (e.g., &#39;); use literal single quotes ' in Apex string literals

Naming Conventions

| Type | Pattern | Example |

|---|---|---|

| Service | {SObject}Service | AccountService |

| Selector | {SObject}Selector | AccountSelector |

| Domain | {SObject}Domain | OpportunityDomain |

| Batch | {Descriptive}Batch | AccountDeduplicationBatch |

| Queueable | {Descriptive}Queueable | ExternalSyncQueueable |

| Schedulable | {Descriptive}Schedulable | DailyCleanupSchedulable |

| DTO | {Descriptive}DTO | AccountMergeRequestDTO |

| Wrapper | {Descriptive}Wrapper | OpportunityLineWrapper |

| Utility | {Descriptive}Util | StringUtil |

| Interface | I{Descriptive} | INotificationService |

| Abstract | Abstract{Descriptive} | AbstractIntegrationService |

| Exception | {Descriptive}Exception | AccountServiceException |

| REST Resource | {SObject}RestResource | AccountRestResource |

| Trigger | {SObject}Trigger | AccountTrigger |

| Trigger Action | TA_{SObject}_{Action} | TA_Account_SetDefaults |

Additional naming rules:

  • Classes: PascalCase
  • Methods: camelCase, start with a verb (get, create, process, validate, is, has, can)
  • Variables: camelCase, descriptive nouns; Lists as plural nouns (e.g., accounts, relatedContacts); Maps as {value}By{key} (e.g., accountsById); Sets as {noun}Ids
  • Constants: UPPER_SNAKE_CASE
  • Use full descriptive names instead of abbreviations (acc, tks, rec)

ApexDoc

  • Required on the class header and every public/global method
  • Include: brief description, @param, @return, @throws, @example where helpful

Class-level format:

/**
 * Provides services for geolocation and address conversion.
 */
public with sharing class GeolocationService { }

Method-level format:

/**
 * @param paramName Description of the parameter
 * @return Description of the return value
 * @example
 * List<Account> results = AccountService.deduplicateAccounts(accountIds);
 */

Code Structure & Architecture

  • Single responsibility per class; max 500 lines -- split when exceeded
  • Return early: validate preconditions at method top, return/throw immediately
  • Extract private helpers for methods over ~40 lines
  • Use Dependency Injection (constructor/method params) for testability
  • Prefer composition and narrow interfaces over deep inheritance; extend via new implementations, not modifications
  • Enforce single-level abstraction per method across layer boundaries:

| Layer | Owns | Must NOT contain |

|---|---|---|

| Trigger | Event routing only | Business logic, orchestration |

| Handler/Service | Flow control, coordination | Inline SOQL/DML/HTTP/parsing |

| Domain | Business rules, validation | Queries, callouts, persistence details |

| Data/Integration | SOQL, DML, HTTP | Business decisions |

  • Disallowed: methods mixing orchestration with inline SOQL/DML/HTTP; business rules mixed with parsing internals; validation + persistence + cross-system plumbing in one method

Async Decision Matrix

| Scenario | Default | Key Traits |

|---|---|---|

| Standard async work | Queueable | Job ID, chaining, non-primitive types, configurable delay (up to 10 min via AsyncOptions), dedup signatures |

| Very large datasets | Batch Apex | Chunked processing, max 5 concurrent; use QueryLocator for large scopes |

| Modern batch alternative | CursorStep (Database.Cursor) | 2000-record chunks, higher throughput, no 5-job limit |

| Recurring schedule | Scheduled Flow (preferred) or Schedulable | Schedulable has 100-job limit; use only when chaining to Batch or needing complex Apex logic |

| Post-job cleanup | Finalizer (System.Finalizer) | Runs regardless of Queueable success/failure |

| Long-running callouts | Continuation | Up to 3 per transaction, 3 parallel |

| Delays > 10 minutes | System.scheduleBatch() | Schedule a Batch job at a specific future time |

| Legacy fire-and-forget | @future | Do not use in new code — see Hard-Stop Constraints; replace with Queueable + Finalizer |


Type-Specific Guidance

Service

  • Template: assets/service.cls · Reference: references/AccountService.cls
  • with sharing; stateless — no public fields or mutable instance state; keep public APIs focused and static where reasonable
  • Delegate all SOQL to Selectors and SObject behavior to Domains
  • Wrap business errors in a custom exception (e.g., AccountServiceException)

Selector

  • Template: assets/selector.cls · Reference: references/AccountSelector.cls
  • inherited sharing; one per SObject or query domain
  • Return List<SObject> or Map<Id, SObject>; use a shared base field list constant (no inline duplication)
  • Accept filter parameters; always include WITH USER_MODE

Domain

  • Template: assets/domain.cls
  • with sharing; encapsulate field defaults, derivations, and validations
  • Operate on in-memory lists only; no SOQL/DML (belongs in Services/Selectors)

Batch

  • Template: assets/batch.cls · Reference: references/AccountDeduplicationBatch.cls
  • with sharing; implement Database.Batchable<SObject> (add Database.Stateful when tracking across chunks)
  • start() = query definition; execute() = business logic; finish() = logging/notification
  • Use QueryLocator for large datasets; handle partial failures via Database.SaveResult
  • Accept filter parameters via constructor for reusability

Queueable

  • Template: assets/queueable.cls
  • with sharing; implement Queueable and optionally Database.AllowsCallouts when HTTP callouts are needed
  • Accept data via constructor
  • Add chain-depth guards to prevent infinite chains
  • Optionally implement Finalizer for recovery/cleanup
  • Use AsyncOptions for configurable delay (up to 10 min) and dedup signatures

Schedulable

  • Template: assets/schedulable.cls
  • with sharing; execute() delegates to Queueable or Batch
  • Provide CRON constants and a convenience scheduleDaily() helper

DTO / Wrapper

  • Template: assets/dto.cls
  • No sharing keyword needed (pure data containers)
  • Simple public properties; no-arg + parameterized constructors; Comparable when ordering matters
  • Use @JsonAccess on private/protected inner DTOs that are serialized/deserialized

Utility

  • Template: assets/utility.cls
  • No sharing keyword needed; all methods public static; private constructor
  • Pure, side-effect-free; no SOQL/DML

Interface

  • Template: assets/interface.cls
  • Define clear contracts with ApexDoc on each method signature

Abstract

  • Template: assets/abstract.cls
  • with sharing; offer default behavior via virtual methods
  • Mark extension points protected virtual or protected abstract
  • Include a concrete example in the ApexDoc showing how to extend the class

Custom Exception

  • Template: assets/exception.cls
  • No sharing keyword; extend Exception with descriptive names
  • Supported constructors: (), ('msg'), (cause), ('msg', cause)

Trigger

  • Template: assets/trigger.cls
  • One trigger per object; delegate all logic to handler/TAF action classes
  • Include all relevant DML contexts; if TAF: new MetadataTriggerHandler().run();

Trigger Action (TAF)

  • One class per concern per context; implement TriggerAction.{Context}
  • Register via Trigger_Action__mdt (actions are inactive without registration)
  • Name: TA_{SObject}_{ActionName}; prefer field-value comparison over static booleans for recursion

Invocable Method (@InvocableMethod)

  • Template: assets/invocable.cls
  • with sharing; inner Request/Response with @InvocableVariable
  • Method must be public static; non-static or single-object signatures will not compile
  • Accept List<Request>, return List<Response>; bulkify (SOQL/DML outside loops)
  • Decorator parameters: label (required — Flow Builder display name), description, category (groups actions in Builder), callout=true (required when method makes HTTP callouts)
  • @InvocableVariable parameters: label (required), description, required=true/false
  • @InvocableVariable supports: primitives, Id, SObject, List<T> only (no Map/Set/Blob); use List<Id> or List<SObject> fields for Flow collection I/O
  • Always include isSuccess, errorMessage, and errorType (e.getTypeName()) in Response
  • Return errors in Response (recommended); throwing an exception triggers the Flow Fault path — reserve for unrecoverable failures only

REST Resource (@RestResource)

  • Template: assets/rest-resource.cls
  • global with sharing; both class and methods must be global
  • Versioned URL: @RestResource(urlMapping='/{resource}/v1/*')
  • Use proper HTTP status codes per branch (200/201/400/404/422/500); never default all errors to 500
  • Validate inputs (Id format: Pattern.matches('[a-zA-Z0-9]{15,18}', value)); bind all user input in SOQL
  • Include LIMIT/ORDER BY in queries; implement pagination (pageSize/offset)
  • Standardized ApiResponse wrapper (success, message, data/records); inner request/response DTOs
  • Thin controller: delegate business logic to Service classes

@AuraEnabled Controller

  • with sharing; use WITH USER_MODE in all SOQL
  • Use @AuraEnabled(cacheable=true) only for read-only queries; leave cacheable unset for DML operations
  • Catch exceptions and rethrow as AuraHandledException with user-friendly messages

Output Expectations

Deliverables per class:

  • {ClassName}.cls
  • {ClassName}.cls-meta.xml (default API version 66.0 or higher unless specified)
  • {ClassName}Test.cls (generated via platform-apex-test-generate skill)
  • {ClassName}Test.cls-meta.xml (generated via platform-apex-test-generate skill)

Deliverables per trigger:

  • {TriggerName}.trigger
  • {TriggerName}.trigger-meta.xml (default API version 66.0 or higher unless specified)

Meta XML template:

<?xml version="1.0" encoding="UTF-8"?>
<ApexClass xmlns="http://soap.sforce.com/2006/04/metadata">
    <apiVersion>{API_VERSION}</apiVersion>
    <status>Active</status>
</ApexClass>

Report in this order:

Apex work: <summary>
Files: <paths>
Design: <pattern / framework choices>
Workflow: all steps completed (1-9); any N/A justified
Risks: <security, bulkification, async, dependency notes>
Compile: <REQUIRED -- paste actual apex_diagnostics output, or the "sf project deploy start --dry-run" fallback result prefixed with "apex_diagnostics=unavailable: <reason>">
Analyzer: <REQUIRED -- paste actual "sf code-analyzer run" output or state "run_code_analyzer=unavailable: <reason>">
Testing: <REQUIRED -- paste actual test execution results (pass/fail, coverage) or state "test_execution=unavailable: <reason>">
Deploy: <dry-run or next step>

Cross-Skill Integration

| Need | Delegate to |

|---|---|

| Apex tests / fix failures | platform-apex-test-generate skill |

| Describe objects/fields | metadata skill (if available) |

| Deploy to org | deploy skill (if available) |

| Flow calling Apex | Flow skill (if available) |

| LWC calling Apex | LWC skill (if available) |


Troubleshooting Boundary

This skill handles production .cls/.trigger/.apex issues only: compile/parse failures, deployment dependency errors, runtime governor-limit failures. For test execution, assertions, coverage, or sf apex run test failures, delegate to platform-apex-test-generate.

想直接用这个技能?

本站把开放许可(MIT / Apache 等)的技能按仓库打包整理到网盘,点一下转存到你自己的网盘,不用一个个从 GitHub 拉。许可未声明的技能只给原始仓库链接,不打包。

同名技能的其他版本

有 2 个不同仓库或目录里都有叫 platform-apex-generate 的技能。它们内容并不相同,别混用:

  • forcedotcom/sf-skills — Primary Apex authoring skill for class generation, refactoring, and review. ALWAYS ACTIVAT