@salesforce/afv-skills 1.5.0 → 1.5.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (68) hide show
  1. package/README.md +16 -415
  2. package/package.json +5 -3
  3. package/skills/building-ui-bundle-app/SKILL.md +325 -0
  4. package/skills/building-ui-bundle-frontend/SKILL.md +122 -0
  5. package/skills/{building-webapp-react-components → building-ui-bundle-frontend}/implementation/component.md +1 -1
  6. package/skills/creating-b2b-commerce-store/SKILL.md +169 -0
  7. package/skills/creating-b2b-commerce-store/references/store-vs-storefront.md +169 -0
  8. package/skills/deploying-ui-bundle/SKILL.md +77 -0
  9. package/skills/generating-apex/CREDITS.md +30 -0
  10. package/skills/generating-apex/SKILL.md +399 -0
  11. package/skills/generating-apex/assets/abstract.cls +132 -0
  12. package/skills/generating-apex/assets/batch.cls +125 -0
  13. package/skills/generating-apex/assets/domain.cls +102 -0
  14. package/skills/generating-apex/assets/dto.cls +108 -0
  15. package/skills/generating-apex/assets/exception.cls +51 -0
  16. package/skills/generating-apex/assets/interface.cls +25 -0
  17. package/skills/generating-apex/assets/invocable.cls +115 -0
  18. package/skills/generating-apex/assets/queueable.cls +92 -0
  19. package/skills/generating-apex/assets/rest-resource.cls +300 -0
  20. package/skills/generating-apex/assets/schedulable.cls +75 -0
  21. package/skills/generating-apex/assets/selector.cls +92 -0
  22. package/skills/generating-apex/assets/service.cls +69 -0
  23. package/skills/generating-apex/assets/trigger.cls +45 -0
  24. package/skills/generating-apex/assets/utility.cls +97 -0
  25. package/skills/generating-apex/references/AccountDeduplicationBatch.cls +148 -0
  26. package/skills/generating-apex/references/AccountSelector.cls +193 -0
  27. package/skills/generating-apex/references/AccountService.cls +201 -0
  28. package/skills/generating-apex-test/CREDITS.md +30 -0
  29. package/skills/generating-apex-test/SKILL.md +199 -0
  30. package/skills/generating-apex-test/assets/test-class-template.cls +93 -0
  31. package/skills/generating-apex-test/assets/test-data-factory-template.cls +111 -0
  32. package/skills/generating-apex-test/references/assertion-patterns.md +108 -0
  33. package/skills/generating-apex-test/references/async-testing.md +193 -0
  34. package/skills/generating-apex-test/references/mocking-patterns.md +220 -0
  35. package/skills/generating-apex-test/references/test-data-factory.md +75 -0
  36. package/skills/generating-experience-react-site/SKILL.md +20 -9
  37. package/skills/generating-experience-react-site/docs/configure-metadata-digital-experience.md +1 -1
  38. package/skills/generating-flexipage/SKILL.md +58 -60
  39. package/skills/generating-ui-bundle-features/SKILL.md +45 -0
  40. package/skills/generating-ui-bundle-metadata/SKILL.md +106 -0
  41. package/skills/{managing-webapp-agentforce-conversation-client → implementing-ui-bundle-agentforce-conversation-client}/SKILL.md +5 -5
  42. package/skills/{managing-webapp-agentforce-conversation-client → implementing-ui-bundle-agentforce-conversation-client}/references/constraints.md +2 -2
  43. package/skills/{managing-webapp-agentforce-conversation-client → implementing-ui-bundle-agentforce-conversation-client}/references/examples.md +1 -1
  44. package/skills/{implementing-webapp-file-upload → implementing-ui-bundle-file-upload}/SKILL.md +11 -11
  45. package/skills/searching-media/SKILL.md +342 -0
  46. package/skills/{using-webapp-salesforce-data → using-ui-bundle-salesforce-data}/SKILL.md +52 -25
  47. package/skills/using-ui-bundle-salesforce-data/references/mutation-query-generation.md +140 -0
  48. package/skills/using-ui-bundle-salesforce-data/references/query-testing.md +78 -0
  49. package/skills/using-ui-bundle-salesforce-data/references/read-query-generation.md +307 -0
  50. package/skills/using-ui-bundle-salesforce-data/references/schema-introspection.md +53 -0
  51. package/skills/using-ui-bundle-salesforce-data/references/ui-bundle-integration.md +221 -0
  52. package/skills/{using-webapp-salesforce-data → using-ui-bundle-salesforce-data/scripts}/graphql-search.sh +75 -23
  53. package/skills/building-webapp-data-visualization/SKILL.md +0 -72
  54. package/skills/building-webapp-data-visualization/implementation/bar-line-chart.md +0 -316
  55. package/skills/building-webapp-data-visualization/implementation/dashboard-layout.md +0 -189
  56. package/skills/building-webapp-data-visualization/implementation/donut-chart.md +0 -181
  57. package/skills/building-webapp-data-visualization/implementation/stat-card.md +0 -150
  58. package/skills/building-webapp-react-components/SKILL.md +0 -96
  59. package/skills/configuring-webapp-csp-trusted-sites/SKILL.md +0 -90
  60. package/skills/configuring-webapp-metadata/SKILL.md +0 -158
  61. package/skills/creating-webapp/SKILL.md +0 -140
  62. package/skills/deploying-webapp-to-salesforce/SKILL.md +0 -226
  63. package/skills/installing-webapp-features/SKILL.md +0 -210
  64. /package/skills/{building-webapp-react-components → building-ui-bundle-frontend}/implementation/header-footer.md +0 -0
  65. /package/skills/{building-webapp-react-components → building-ui-bundle-frontend}/implementation/page.md +0 -0
  66. /package/skills/{configuring-webapp-csp-trusted-sites/implementation/metadata-format.md → generating-ui-bundle-metadata/implementation/csp-metadata-format.md} +0 -0
  67. /package/skills/{managing-webapp-agentforce-conversation-client → implementing-ui-bundle-agentforce-conversation-client}/references/style-tokens.md +0 -0
  68. /package/skills/{managing-webapp-agentforce-conversation-client → implementing-ui-bundle-agentforce-conversation-client}/references/troubleshooting.md +0 -0
@@ -0,0 +1,132 @@
1
+ /**
2
+ <<<<<<< Updated upstream
3
+ * @description Abstract base class for {describe the family of classes this serves}.
4
+ =======
5
+ * Abstract base class for {describe the family of classes this serves}.
6
+ >>>>>>> Stashed changes
7
+ * Provides common behavior and defines extension points for subclasses.
8
+ * Subclasses must implement the abstract methods to provide specific behavior.
9
+ * @author Generated by Apex Class Writer Skill
10
+ *
11
+ * @example
12
+ * // Extending this abstract class:
13
+ * public class SalesforceIntegrationService extends {ClassName} {
14
+ * protected override String getEndpoint() {
15
+ * return 'callout:Salesforce_API/services/data/v62.0';
16
+ * }
17
+ *
18
+ * protected override Map<String, String> getHeaders() {
19
+ * return new Map<String, String>{
20
+ * 'Content-Type' => 'application/json'
21
+ * };
22
+ * }
23
+ * }
24
+ */
25
+ public abstract with sharing class {ClassName} {
26
+
27
+ // ─── Constants ───────────────────────────────────────────────────────
28
+ private static final Integer DEFAULT_TIMEOUT_MS = 30000;
29
+
30
+ // ─── Protected State ─────────────────────────────────────────────────
31
+ protected Integer timeoutMs;
32
+
33
+ // ─── Constructor ─────────────────────────────────────────────────────
34
+
35
+ /**
36
+ * Initializes the base class with default configuration
37
+ */
38
+ protected {ClassName}() {
39
+ this.timeoutMs = DEFAULT_TIMEOUT_MS;
40
+ }
41
+
42
+ // ─── Abstract Methods (must be implemented by subclasses) ────────────
43
+
44
+ /**
45
+ * Returns the endpoint URL for this integration.
46
+ * Subclasses must provide their specific endpoint.
47
+ * @return The endpoint URL as a String
48
+ */
49
+ protected abstract String getEndpoint();
50
+
51
+ /**
52
+ * Returns the HTTP headers for this integration.
53
+ * Subclasses define their own required headers.
54
+ * @return Map of header name to header value
55
+ */
56
+ protected abstract Map<String, String> getHeaders();
57
+
58
+ // ─── Virtual Methods (can be overridden by subclasses) ───────────────
59
+
60
+ /**
61
+ * Hook called before the main operation executes.
62
+ * Override to add pre-processing logic.
63
+ * Default implementation does nothing.
64
+ * @param context Map of contextual data
65
+ */
66
+ protected virtual void beforeExecute(Map<String, Object> context) {
67
+ // Default: no-op — override in subclass if needed
68
+ }
69
+
70
+ /**
71
+ * Hook called after the main operation completes.
72
+ * Override to add post-processing logic.
73
+ * Default implementation does nothing.
74
+ * @param context Map of contextual data
75
+ * @param result The result from the operation
76
+ */
77
+ protected virtual void afterExecute(Map<String, Object> context, Object result) {
78
+ // Default: no-op — override in subclass if needed
79
+ }
80
+
81
+ // ─── Template Method (common workflow) ───────────────────────────────
82
+
83
+ /**
84
+ * Executes the operation using the template method pattern.
85
+ * Calls beforeExecute → doExecute → afterExecute in sequence.
86
+ * @param context Map of data needed for the operation
87
+ * @return The result of the operation
88
+ */
89
+ public Object execute(Map<String, Object> context) {
90
+ beforeExecute(context);
91
+
92
+ Object result;
93
+ try {
94
+ result = doExecute(context);
95
+ } catch (Exception e) {
96
+ handleError(e);
97
+ throw e;
98
+ }
99
+
100
+ afterExecute(context, result);
101
+ return result;
102
+ }
103
+
104
+ // ─── Protected Helpers ───────────────────────────────────────────────
105
+
106
+ /**
107
+ * Core execution logic — override this for the main operation.
108
+ * Default implementation throws — subclass must provide implementation.
109
+ * @param context Map of data needed for the operation
110
+ * @return The result of the operation
111
+ */
112
+ protected virtual Object doExecute(Map<String, Object> context) {
113
+ throw new UnsupportedOperationException(
114
+ 'Subclass must override doExecute()'
115
+ );
116
+ }
117
+
118
+ /**
119
+ * Error handler called when doExecute throws.
120
+ * Override to customize error handling (e.g., logging, retry).
121
+ * @param e The exception that was thrown
122
+ */
123
+ protected virtual void handleError(Exception e) {
124
+ System.debug(LoggingLevel.ERROR,
125
+ this.toString() + ' error: ' + e.getMessage() + '\n' + e.getStackTraceString()
126
+ );
127
+ }
128
+
129
+ // ─── Exception ───────────────────────────────────────────────────────
130
+
131
+ public class UnsupportedOperationException extends Exception {}
132
+ }
@@ -0,0 +1,125 @@
1
+ /**
2
+ * Batch Apex class for {describe the batch operation}.
3
+ * Processes {SObject} records in configurable batch sizes.
4
+ * Implements Database.Stateful to track cumulative results across chunks.
5
+ * @author Generated by Apex Class Writer Skill
6
+ *
7
+ * @example
8
+ * // Execute with default batch size
9
+ * Database.executeBatch(new {ClassName}());
10
+ *
11
+ * // Execute with custom batch size
12
+ * Database.executeBatch(new {ClassName}(), 100);
13
+ */
14
+ public with sharing class {ClassName} implements Database.Batchable<SObject>, Database.Stateful {
15
+
16
+ // ─── Constants ───────────────────────────────────────────────────────
17
+ private static final Integer DEFAULT_BATCH_SIZE = 200;
18
+
19
+ // ─── Stateful Tracking ───────────────────────────────────────────────
20
+ private Integer totalProcessed = 0;
21
+ private Integer totalErrors = 0;
22
+ private List<String> errorMessages = new List<String>();
23
+
24
+ // ─── Constructor ─────────────────────────────────────────────────────
25
+
26
+ /**
27
+ * Default constructor
28
+ */
29
+ public {ClassName}() {
30
+ // Default configuration
31
+ }
32
+
33
+ // ─── Batchable Interface ─────────────────────────────────────────────
34
+
35
+ /**
36
+ * Defines the scope of records to process.
37
+ * Uses Database.QueryLocator for efficient large-dataset processing.
38
+ * @param bc The batch context
39
+ * @return QueryLocator for the records to process
40
+ */
41
+ public Database.QueryLocator start(Database.BatchableContext bc) {
42
+ return Database.getQueryLocator([
43
+ SELECT Id, Name
44
+ // TODO: Add fields needed for processing
45
+ FROM {SObject}
46
+ // TODO: Add WHERE clause to scope the records
47
+ ]);
48
+ }
49
+
50
+ /**
51
+ * Processes each batch of records.
52
+ * Uses Database.update with allOrNone=false for partial success handling.
53
+ * @param bc The batch context
54
+ * @param scope List of {SObject} records in the current batch
55
+ */
56
+ public void execute(Database.BatchableContext bc, List<{SObject}> scope) {
57
+ List<{SObject}> recordsToUpdate = new List<{SObject}>();
58
+
59
+ for ({SObject} record : scope) {
60
+ // TODO: Apply business logic to each record
61
+ recordsToUpdate.add(record);
62
+ }
63
+
64
+ if (!recordsToUpdate.isEmpty()) {
65
+ List<Database.SaveResult> results = Database.update(recordsToUpdate, false);
66
+ processResults(results);
67
+ }
68
+ }
69
+
70
+ /**
71
+ * Performs post-processing after all batches complete.
72
+ * Logs a summary of the batch execution.
73
+ * @param bc The batch context
74
+ */
75
+ public void finish(Database.BatchableContext bc) {
76
+ String summary = String.format(
77
+ '{0} completed. Processed: {1}, Errors: {2}',
78
+ new List<Object>{
79
+ {ClassName}.class.getName(),
80
+ totalProcessed,
81
+ totalErrors
82
+ }
83
+ );
84
+
85
+ System.debug(LoggingLevel.INFO, summary);
86
+
87
+ if (!errorMessages.isEmpty()) {
88
+ System.debug(LoggingLevel.ERROR, 'Error details: ' + String.join(errorMessages, '\n'));
89
+ }
90
+
91
+ // TODO: Send completion notification email or post to chatter if needed
92
+ }
93
+
94
+ // ─── Private Helpers ─────────────────────────────────────────────────
95
+
96
+ /**
97
+ * Processes Database.SaveResult list, tracking successes and failures
98
+ * @param results List of SaveResult from a DML operation
99
+ */
100
+ private void processResults(List<Database.SaveResult> results) {
101
+ for (Database.SaveResult result : results) {
102
+ if (result.isSuccess()) {
103
+ totalProcessed++;
104
+ } else {
105
+ totalErrors++;
106
+ for (Database.Error err : result.getErrors()) {
107
+ errorMessages.add(
108
+ 'Record ' + result.getId() + ': ' +
109
+ err.getStatusCode() + ' - ' + err.getMessage()
110
+ );
111
+ }
112
+ }
113
+ }
114
+ }
115
+
116
+ // ─── Static Helpers ──────────────────────────────────────────────────
117
+
118
+ /**
119
+ * Convenience method to execute with default batch size
120
+ * @return The batch job Id
121
+ */
122
+ public static Id run() {
123
+ return Database.executeBatch(new {ClassName}(), DEFAULT_BATCH_SIZE);
124
+ }
125
+ }
@@ -0,0 +1,102 @@
1
+ /**
2
+ * Domain class for {SObject}.
3
+ * Encapsulates field-level defaults, derivations, and validations.
4
+ * Operates only on in-memory SObject data — no SOQL or DML.
5
+ * @author Generated by Apex Class Writer Skill
6
+ */
7
+ public with sharing class {SObject}Domain {
8
+
9
+ // ─── Constants ───────────────────────────────────────────────────────
10
+ // TODO: Add constants for default values, statuses, etc.
11
+
12
+ // ─── Field Defaults ──────────────────────────────────────────────────
13
+
14
+ /**
15
+ * Applies default field values to new {SObject} records.
16
+ * Call this before insert to ensure consistent defaults.
17
+ * @param records List of {SObject} records to apply defaults to
18
+ */
19
+ public static void applyDefaults(List<{SObject}> records) {
20
+ if (records == null || records.isEmpty()) {
21
+ return;
22
+ }
23
+
24
+ for ({SObject} record : records) {
25
+ // TODO: Set default field values
26
+ // Example:
27
+ // if (record.Status__c == null) {
28
+ // record.Status__c = DEFAULT_STATUS;
29
+ // }
30
+ }
31
+ }
32
+
33
+ // ─── Derivations ────────────────────────────────────────────────────
34
+
35
+ /**
36
+ * Derives calculated field values based on other fields.
37
+ * Call this before insert and before update.
38
+ * @param records List of {SObject} records to derive values for
39
+ */
40
+ public static void deriveFields(List<{SObject}> records) {
41
+ if (records == null || records.isEmpty()) {
42
+ return;
43
+ }
44
+
45
+ for ({SObject} record : records) {
46
+ // TODO: Derive calculated field values
47
+ // Example:
48
+ // record.FullAddress__c = buildFullAddress(record);
49
+ }
50
+ }
51
+
52
+ // ─── Validations ────────────────────────────────────────────────────
53
+
54
+ /**
55
+ * Validates {SObject} records and adds errors for any violations.
56
+ * Call this before insert and before update.
57
+ * @param records List of {SObject} records to validate
58
+ */
59
+ public static void validate(List<{SObject}> records) {
60
+ if (records == null || records.isEmpty()) {
61
+ return;
62
+ }
63
+
64
+ for ({SObject} record : records) {
65
+ // TODO: Add validation rules
66
+ // Example:
67
+ // if (String.isBlank(record.Name)) {
68
+ // record.addError('Name is required.');
69
+ // }
70
+ }
71
+ }
72
+
73
+ // ─── Comparisons ────────────────────────────────────────────────────
74
+
75
+ /**
76
+ * Determines which fields have changed between old and new record versions.
77
+ * Useful in before update context.
78
+ * @param oldRecord The previous version of the record
79
+ * @param newRecord The current version of the record
80
+ * @return Set of field API names that have changed
81
+ */
82
+ public static Set<String> getChangedFields({SObject} oldRecord, {SObject} newRecord) {
83
+ Set<String> changedFields = new Set<String>();
84
+
85
+ if (oldRecord == null || newRecord == null) {
86
+ return changedFields;
87
+ }
88
+
89
+ Map<String, Schema.SObjectField> fieldMap = Schema.SObjectType.{SObject}.fields.getMap();
90
+ for (String fieldName : fieldMap.keySet()) {
91
+ if (oldRecord.get(fieldName) != newRecord.get(fieldName)) {
92
+ changedFields.add(fieldName);
93
+ }
94
+ }
95
+
96
+ return changedFields;
97
+ }
98
+
99
+ // ─── Private Helpers ─────────────────────────────────────────────────
100
+
101
+ // TODO: Add private helper methods as needed
102
+ }
@@ -0,0 +1,108 @@
1
+ /**
2
+ * Data Transfer Object for {describe the data this DTO represents}.
3
+ * Used to pass structured data between layers without exposing SObjects.
4
+ * Serialization-friendly for use with JSON.serialize/deserialize and API responses.
5
+ * @author Generated by Apex Class Writer Skill
6
+ *
7
+ * @example
8
+ * // Create from constructor
9
+ * {ClassName} dto = new {ClassName}('value1', 42);
10
+ *
11
+ * // Deserialize from JSON
12
+ * {ClassName} dto = ({ClassName}) JSON.deserialize(jsonString, {ClassName}.class);
13
+ */
14
+ public with sharing class {ClassName} {
15
+
16
+ // ─── Properties ──────────────────────────────────────────────────────
17
+
18
+ /** {Describe this property} */
19
+ public String name { get; set; }
20
+
21
+ /** {Describe this property} */
22
+ public Id recordId { get; set; }
23
+
24
+ /** {Describe this property} */
25
+ public Boolean isActive { get; set; }
26
+
27
+ /** {Describe this property} */
28
+ public List<String> tags { get; set; }
29
+
30
+ // TODO: Add additional properties as needed
31
+
32
+ // ─── Constructors ────────────────────────────────────────────────────
33
+
34
+ /**
35
+ * No-arg constructor for deserialization compatibility
36
+ */
37
+ public {ClassName}() {
38
+ this.tags = new List<String>();
39
+ this.isActive = false;
40
+ }
41
+
42
+ /**
43
+ * Parameterized constructor for convenience
44
+ * @param name The name value
45
+ * @param recordId The associated record Id
46
+ */
47
+ public {ClassName}(String name, Id recordId) {
48
+ this();
49
+ this.name = name;
50
+ this.recordId = recordId;
51
+ }
52
+
53
+ // ─── Factory Methods ─────────────────────────────────────────────────
54
+
55
+ /**
56
+ * Creates a DTO instance from an SObject record
57
+ * @param record The source {SObject} record
58
+ * @return A populated {ClassName} instance
59
+ */
60
+ public static {ClassName} fromSObject(SObject record) {
61
+ if (record == null) {
62
+ return new {ClassName}();
63
+ }
64
+
65
+ {ClassName} dto = new {ClassName}();
66
+ dto.recordId = record.Id;
67
+ dto.name = (String) record.get('Name');
68
+ // TODO: Map additional fields
69
+
70
+ return dto;
71
+ }
72
+
73
+ /**
74
+ * Creates a list of DTOs from a list of SObject records
75
+ * @param records The source records
76
+ * @return List of populated {ClassName} instances
77
+ */
78
+ public static List<{ClassName}> fromSObjects(List<SObject> records) {
79
+ List<{ClassName}> dtos = new List<{ClassName}>();
80
+ if (records == null) {
81
+ return dtos;
82
+ }
83
+
84
+ for (SObject record : records) {
85
+ dtos.add(fromSObject(record));
86
+ }
87
+ return dtos;
88
+ }
89
+
90
+ // ─── Utility Methods ─────────────────────────────────────────────────
91
+
92
+ /**
93
+ * Serializes this DTO to a JSON string
94
+ * @return JSON representation of this DTO
95
+ */
96
+ public String toJson() {
97
+ return JSON.serialize(this);
98
+ }
99
+
100
+ /**
101
+ * Deserializes a JSON string into a {ClassName} instance
102
+ * @param jsonString The JSON string to deserialize
103
+ * @return A {ClassName} instance
104
+ */
105
+ public static {ClassName} fromJson(String jsonString) {
106
+ return ({ClassName}) JSON.deserialize(jsonString, {ClassName}.class);
107
+ }
108
+ }
@@ -0,0 +1,51 @@
1
+ /**
2
+ * Custom exception for {describe when this exception is thrown}.
3
+ * Use this exception to signal domain-specific errors that callers
4
+ * can catch and handle distinctly from system exceptions.
5
+ * @author Generated by Apex Class Writer Skill
6
+ *
7
+ * @example
8
+ * throw new {ClassName}('Account merge failed: duplicate detected.');
9
+ *
10
+ * // Wrap a caught exception
11
+ * try {
12
+ * // ... risky operation
13
+ * } catch (DmlException e) {
14
+ * throw new {ClassName}('DML failed during account merge: ' + e.getMessage());
15
+ * }
16
+ */
17
+ public with sharing class {ClassName} extends Exception {
18
+ // Apex custom exceptions automatically inherit:
19
+ // - getMessage()
20
+ // - getCause()
21
+ // - getStackTraceString()
22
+ // - setMessage(String)
23
+ // - initCause(Exception)
24
+ //
25
+ // And support these constructor patterns:
26
+ // - new {ClassName}()
27
+ // - new {ClassName}('message')
28
+ // - new {ClassName}(causeException)
29
+ // - new {ClassName}('message', causeException)
30
+ //
31
+ // Note: Apex does NOT support custom constructors on Exception subclasses.
32
+ // To add context, use the message string or create a wrapper pattern:
33
+ //
34
+ // Example wrapper pattern (if you need structured error data):
35
+ //
36
+ // public class {ClassName}Detail {
37
+ // public String errorCode;
38
+ // public List<Id> failedRecordIds;
39
+ // public String detail;
40
+ //
41
+ // public {ClassName}Detail(String errorCode, List<Id> failedRecordIds, String detail) {
42
+ // this.errorCode = errorCode;
43
+ // this.failedRecordIds = failedRecordIds;
44
+ // this.detail = detail;
45
+ // }
46
+ //
47
+ // public override String toString() {
48
+ // return '[' + errorCode + '] ' + detail + ' (Records: ' + failedRecordIds + ')';
49
+ // }
50
+ // }
51
+ }
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Interface for {describe the capability or contract this interface defines}.
3
+ * Implement this interface to provide {describe what implementations do}.
4
+ * @author Generated by Apex Class Writer Skill
5
+ *
6
+ * @example
7
+ * public class EmailNotificationService implements {InterfaceName} {
8
+ * public void execute(Map<String, Object> params) {
9
+ * // Implementation
10
+ * }
11
+ * }
12
+ */
13
+ public interface {InterfaceName} {
14
+
15
+ /**
16
+ * {Describe what this method should do}
17
+ * @param params {Describe the parameter}
18
+ * @return {Describe the return value}
19
+ */
20
+ // TODO: Define interface methods
21
+ // Example:
22
+ // void execute(Map<String, Object> params);
23
+ // Boolean isEligible(SObject record);
24
+ // List<SObject> process(List<SObject> records);
25
+ }
@@ -0,0 +1,115 @@
1
+ /**
2
+ * Invocable Apex action for {describe the action}.
3
+ * Callable from Flows, Process Builder, and Agentforce.
4
+ * Accepts bulkified List<Request>, returns List<Response>.
5
+ * @author Generated by Apex Class Writer Skill
6
+ */
7
+ public with sharing class {ClassName} {
8
+
9
+ // ─── Invocable Method ────────────────────────────────────────────────
10
+
11
+ /**
12
+ * {Describe what this action does}
13
+ * @param requests List of Request inputs from the calling Flow
14
+ * @return List of Response outputs returned to the calling Flow
15
+ */
16
+ @InvocableMethod(
17
+ label='{Display Name}'
18
+ description='{Describe the action for Flow Builder}'
19
+ category='{Category}'
20
+ )
21
+ public static List<Response> execute(List<Request> requests) {
22
+ List<Response> responses = new List<Response>();
23
+
24
+ // Collect all Ids upfront for bulkified query
25
+ Set<Id> allRecordIds = new Set<Id>();
26
+ for (Request req : requests) {
27
+ if (req.recordId != null) {
28
+ allRecordIds.add(req.recordId);
29
+ }
30
+ }
31
+
32
+ // Single bulkified query outside the loop
33
+ Map<Id, {SObject}> recordMap = allRecordIds.isEmpty()
34
+ ? new Map<Id, {SObject}>()
35
+ : new Map<Id, {SObject}>([
36
+ SELECT Id, Name
37
+ // TODO: Add required fields
38
+ FROM {SObject}
39
+ WHERE Id IN :allRecordIds
40
+ WITH USER_MODE
41
+ ]);
42
+
43
+ // Process each request
44
+ for (Request req : requests) {
45
+ responses.add(processRequest(req, recordMap));
46
+ }
47
+
48
+ return responses;
49
+ }
50
+
51
+ // ─── Private Helpers ─────────────────────────────────────────────────
52
+
53
+ /**
54
+ * Processes a single request and returns a response.
55
+ * Errors are captured in the response, not thrown.
56
+ * @param req The input request
57
+ * @param recordMap Pre-queried records keyed by Id
58
+ * @return A Response with success/error information
59
+ */
60
+ private static Response processRequest(Request req, Map<Id, {SObject}> recordMap) {
61
+ Response res = new Response();
62
+
63
+ try {
64
+ {SObject} record = recordMap.get(req.recordId);
65
+ if (record == null) {
66
+ res.isSuccess = false;
67
+ res.errorMessage = 'Record not found: ' + req.recordId;
68
+ res.errorType = 'NOT_FOUND';
69
+ return res;
70
+ }
71
+
72
+ // TODO: Implement business logic
73
+
74
+ res.isSuccess = true;
75
+ } catch (Exception e) {
76
+ res.isSuccess = false;
77
+ res.errorMessage = e.getMessage();
78
+ res.errorType = e.getTypeName();
79
+ }
80
+
81
+ return res;
82
+ }
83
+
84
+ // ─── Request / Response DTOs ─────────────────────────────────────────
85
+
86
+ /**
87
+ * Input parameters from the calling Flow
88
+ */
89
+ public class Request {
90
+ @InvocableVariable(label='Record Id' description='The Id of the record to process' required=true)
91
+ public Id recordId;
92
+
93
+ // TODO: Add additional input variables
94
+ // @InvocableVariable(label='Field Value' description='Value to set' required=false)
95
+ // public String fieldValue;
96
+ }
97
+
98
+ /**
99
+ * Output results returned to the calling Flow
100
+ */
101
+ public class Response {
102
+ @InvocableVariable(label='Success' description='Whether the action succeeded')
103
+ public Boolean isSuccess;
104
+
105
+ @InvocableVariable(label='Error Message' description='Error details if the action failed')
106
+ public String errorMessage;
107
+
108
+ @InvocableVariable(label='Error Type' description='Exception type name if the action failed')
109
+ public String errorType;
110
+
111
+ // TODO: Add additional output variables
112
+ // @InvocableVariable(label='Result Id' description='Id of the created/updated record')
113
+ // public Id resultId;
114
+ }
115
+ }