@salesforce/afv-skills 1.5.1 → 1.5.3

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 (78) hide show
  1. package/README.md +16 -416
  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 +342 -189
  11. package/skills/generating-apex/assets/abstract.cls +12 -9
  12. package/skills/generating-apex/assets/batch.cls +7 -8
  13. package/skills/generating-apex/assets/domain.cls +5 -6
  14. package/skills/generating-apex/assets/dto.cls +11 -12
  15. package/skills/generating-apex/assets/exception.cls +1 -2
  16. package/skills/generating-apex/assets/interface.cls +2 -3
  17. package/skills/generating-apex/assets/invocable.cls +114 -0
  18. package/skills/generating-apex/assets/queueable.cls +6 -7
  19. package/skills/generating-apex/assets/rest-resource.cls +300 -0
  20. package/skills/generating-apex/assets/schedulable.cls +7 -8
  21. package/skills/generating-apex/assets/selector.cls +7 -8
  22. package/skills/generating-apex/assets/service.cls +4 -5
  23. package/skills/generating-apex/assets/trigger.cls +45 -0
  24. package/skills/generating-apex/assets/utility.cls +5 -6
  25. package/skills/generating-apex/references/AccountDeduplicationBatch.cls +7 -8
  26. package/skills/generating-apex/references/AccountSelector.cls +10 -11
  27. package/skills/generating-apex/references/AccountService.cls +9 -10
  28. package/skills/generating-apex-test/CREDITS.md +30 -0
  29. package/skills/generating-apex-test/SKILL.md +165 -74
  30. package/skills/generating-apex-test/assets/test-class-template.cls +25 -56
  31. package/skills/generating-apex-test/assets/test-data-factory-template.cls +0 -1
  32. package/skills/generating-apex-test/references/assertion-patterns.md +38 -95
  33. package/skills/generating-apex-test/references/async-testing.md +59 -142
  34. package/skills/generating-apex-test/references/mocking-patterns.md +77 -76
  35. package/skills/generating-apex-test/references/test-data-factory.md +29 -130
  36. package/skills/generating-experience-react-site/SKILL.md +9 -9
  37. package/skills/generating-experience-react-site/docs/configure-metadata-digital-experience.md +1 -1
  38. package/skills/generating-flexipage/SKILL.md +28 -12
  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 +1 -1
  46. package/skills/uplifting-components-to-slds2/SKILL.md +236 -0
  47. package/skills/uplifting-components-to-slds2/references/color-hooks-decision-guide.md +438 -0
  48. package/skills/uplifting-components-to-slds2/references/common-patterns.md +87 -0
  49. package/skills/uplifting-components-to-slds2/references/examples.md +443 -0
  50. package/skills/uplifting-components-to-slds2/references/migration-checklist.md +67 -0
  51. package/skills/uplifting-components-to-slds2/references/non-color-hooks-decision-guide.md +333 -0
  52. package/skills/uplifting-components-to-slds2/references/rule-lwc-token-to-slds-hook.md +135 -0
  53. package/skills/uplifting-components-to-slds2/references/rule-no-deprecated-tokens-slds1.md +211 -0
  54. package/skills/uplifting-components-to-slds2/references/rule-no-hardcoded-values.md +160 -0
  55. package/skills/uplifting-components-to-slds2/references/rule-no-slds-class-overrides.md +126 -0
  56. package/skills/{using-webapp-salesforce-data → using-ui-bundle-salesforce-data}/SKILL.md +52 -25
  57. package/skills/using-ui-bundle-salesforce-data/references/mutation-query-generation.md +140 -0
  58. package/skills/using-ui-bundle-salesforce-data/references/query-testing.md +78 -0
  59. package/skills/using-ui-bundle-salesforce-data/references/read-query-generation.md +307 -0
  60. package/skills/using-ui-bundle-salesforce-data/references/schema-introspection.md +53 -0
  61. package/skills/using-ui-bundle-salesforce-data/references/ui-bundle-integration.md +221 -0
  62. package/skills/{using-webapp-salesforce-data → using-ui-bundle-salesforce-data/scripts}/graphql-search.sh +75 -23
  63. package/skills/building-webapp-data-visualization/SKILL.md +0 -72
  64. package/skills/building-webapp-data-visualization/implementation/bar-line-chart.md +0 -316
  65. package/skills/building-webapp-data-visualization/implementation/dashboard-layout.md +0 -189
  66. package/skills/building-webapp-data-visualization/implementation/donut-chart.md +0 -181
  67. package/skills/building-webapp-data-visualization/implementation/stat-card.md +0 -150
  68. package/skills/building-webapp-react-components/SKILL.md +0 -96
  69. package/skills/configuring-webapp-csp-trusted-sites/SKILL.md +0 -90
  70. package/skills/configuring-webapp-metadata/SKILL.md +0 -158
  71. package/skills/creating-webapp/SKILL.md +0 -138
  72. package/skills/deploying-webapp-to-salesforce/SKILL.md +0 -226
  73. package/skills/installing-webapp-features/SKILL.md +0 -210
  74. /package/skills/{building-webapp-react-components → building-ui-bundle-frontend}/implementation/header-footer.md +0 -0
  75. /package/skills/{building-webapp-react-components → building-ui-bundle-frontend}/implementation/page.md +0 -0
  76. /package/skills/{configuring-webapp-csp-trusted-sites/implementation/metadata-format.md → generating-ui-bundle-metadata/implementation/csp-metadata-format.md} +0 -0
  77. /package/skills/{managing-webapp-agentforce-conversation-client → implementing-ui-bundle-agentforce-conversation-client}/references/style-tokens.md +0 -0
  78. /package/skills/{managing-webapp-agentforce-conversation-client → implementing-ui-bundle-agentforce-conversation-client}/references/troubleshooting.md +0 -0
@@ -0,0 +1,300 @@
1
+ /**
2
+ * REST API endpoint for {SObject} operations.
3
+ * Exposes CRUD operations via @RestResource at /services/apexrest/{urlPath}/v1/*.
4
+ * Uses versioned URL mapping for future-proof API evolution.
5
+ * All queries use WITH USER_MODE for CRUD/FLS enforcement.
6
+ *
7
+ * Authentication: OAuth 2.0 via Connected App
8
+ * Base URL: /services/apexrest/{urlPath}/v1/
9
+ */
10
+ @RestResource(urlMapping='/{urlPath}/v1/*')
11
+ global with sharing class {ClassName} {
12
+
13
+ // ─── Constants ────────────────────────────────────────────────────────
14
+ private static final Integer DEFAULT_PAGE_SIZE = 20;
15
+ private static final Integer MAX_PAGE_SIZE = 200;
16
+ private static final String ERROR_MISSING_ID = 'Record Id is required in the URL path.';
17
+ private static final String ERROR_INVALID_ID = 'Invalid Salesforce Id format.';
18
+ private static final String ERROR_MISSING_BODY = 'Request body is required.';
19
+ private static final String ERROR_NOT_FOUND = '{SObject} record not found.';
20
+ private static final String ERROR_INSUFFICIENT_ACCESS = 'Insufficient access to perform this operation.';
21
+
22
+ // ─── GET — Retrieve ───────────────────────────────────────────────────
23
+
24
+ /**
25
+ * Retrieves a single {SObject} by Id (URL path) or a paginated list (query params).
26
+ * Single: GET /services/apexrest/{urlPath}/v1/{recordId}
27
+ * List: GET /services/apexrest/{urlPath}/v1?pageSize=20&offset=0
28
+ * @return ApiResponse containing the requested data
29
+ */
30
+ @HttpGet
31
+ global static ApiResponse doGet() {
32
+ RestRequest req = RestContext.request;
33
+ RestResponse res = RestContext.response;
34
+
35
+ try {
36
+ String recordId = extractIdFromUri(req.requestURI);
37
+
38
+ if (String.isNotBlank(recordId)) {
39
+ return getSingleRecord(recordId, res);
40
+ }
41
+ return getRecordList(req, res);
42
+
43
+ } catch (Exception e) {
44
+ return handleError(res, 500, e.getMessage());
45
+ }
46
+ }
47
+
48
+ // ─── POST — Create ───────────────────────────────────────────────────
49
+
50
+ /**
51
+ * Creates a new {SObject} record from the JSON request body.
52
+ * POST /services/apexrest/{urlPath}/v1/
53
+ * @return ApiResponse with the created record Id
54
+ */
55
+ @HttpPost
56
+ global static ApiResponse doPost() {
57
+ RestRequest req = RestContext.request;
58
+ RestResponse res = RestContext.response;
59
+
60
+ try {
61
+ if (req.requestBody == null || String.isBlank(req.requestBody.toString())) {
62
+ return handleError(res, 400, ERROR_MISSING_BODY);
63
+ }
64
+
65
+ {ClassName}Request payload = ({ClassName}Request) JSON.deserialize(
66
+ req.requestBody.toString(),
67
+ {ClassName}Request.class
68
+ );
69
+
70
+ // TODO: Map request payload to SObject fields
71
+ {SObject} record = new {SObject}(
72
+ Name = payload.name
73
+ );
74
+
75
+ Database.SaveResult saveResult = Database.insert(record, true);
76
+ if (saveResult.isSuccess()) {
77
+ res.statusCode = 201;
78
+ return new ApiResponse(true, 'Record created successfully.', record.Id);
79
+ }
80
+
81
+ return handleError(res, 422, saveResult.getErrors()[0].getMessage());
82
+
83
+ } catch (JSONException e) {
84
+ return handleError(res, 400, 'Malformed JSON: ' + e.getMessage());
85
+ } catch (DmlException e) {
86
+ return handleError(res, 422, 'Validation failed: ' + e.getDmlMessage(0));
87
+ } catch (Exception e) {
88
+ return handleError(res, 500, e.getMessage());
89
+ }
90
+ }
91
+
92
+ // ─── PATCH — Partial Update ───────────────────────────────────────────
93
+
94
+ /**
95
+ * Partially updates an existing {SObject} record.
96
+ * PATCH /services/apexrest/{urlPath}/v1/{recordId}
97
+ * @return ApiResponse confirming the update
98
+ */
99
+ @HttpPatch
100
+ global static ApiResponse doPatch() {
101
+ RestRequest req = RestContext.request;
102
+ RestResponse res = RestContext.response;
103
+
104
+ try {
105
+ String recordId = extractIdFromUri(req.requestURI);
106
+ if (String.isBlank(recordId)) {
107
+ return handleError(res, 400, ERROR_MISSING_ID);
108
+ }
109
+ if (!isValidSalesforceId(recordId)) {
110
+ return handleError(res, 400, ERROR_INVALID_ID);
111
+ }
112
+ if (req.requestBody == null || String.isBlank(req.requestBody.toString())) {
113
+ return handleError(res, 400, ERROR_MISSING_BODY);
114
+ }
115
+
116
+ List<{SObject}> existing = [
117
+ SELECT Id FROM {SObject} WHERE Id = :recordId WITH USER_MODE LIMIT 1
118
+ ];
119
+ if (existing.isEmpty()) {
120
+ return handleError(res, 404, ERROR_NOT_FOUND);
121
+ }
122
+
123
+ Map<String, Object> fieldUpdates = (Map<String, Object>) JSON.deserializeUntyped(
124
+ req.requestBody.toString()
125
+ );
126
+
127
+ {SObject} record = existing[0];
128
+ // TODO: Apply allowed field updates from the payload to the record
129
+ // for (String fieldName : fieldUpdates.keySet()) {
130
+ // record.put(fieldName, fieldUpdates.get(fieldName));
131
+ // }
132
+
133
+ Database.SaveResult saveResult = Database.update(record, true);
134
+ if (saveResult.isSuccess()) {
135
+ res.statusCode = 200;
136
+ return new ApiResponse(true, 'Record updated successfully.', record.Id);
137
+ }
138
+
139
+ return handleError(res, 422, saveResult.getErrors()[0].getMessage());
140
+
141
+ } catch (JSONException e) {
142
+ return handleError(res, 400, 'Malformed JSON: ' + e.getMessage());
143
+ } catch (DmlException e) {
144
+ return handleError(res, 422, 'Validation failed: ' + e.getDmlMessage(0));
145
+ } catch (Exception e) {
146
+ return handleError(res, 500, e.getMessage());
147
+ }
148
+ }
149
+
150
+ // ─── DELETE — Remove ──────────────────────────────────────────────────
151
+
152
+ /**
153
+ * Deletes a {SObject} record by Id.
154
+ * DELETE /services/apexrest/{urlPath}/v1/{recordId}
155
+ * @return ApiResponse confirming the deletion
156
+ */
157
+ @HttpDelete
158
+ global static ApiResponse doDelete() {
159
+ RestRequest req = RestContext.request;
160
+ RestResponse res = RestContext.response;
161
+
162
+ try {
163
+ String recordId = extractIdFromUri(req.requestURI);
164
+ if (String.isBlank(recordId)) {
165
+ return handleError(res, 400, ERROR_MISSING_ID);
166
+ }
167
+ if (!isValidSalesforceId(recordId)) {
168
+ return handleError(res, 400, ERROR_INVALID_ID);
169
+ }
170
+
171
+ List<{SObject}> existing = [
172
+ SELECT Id FROM {SObject} WHERE Id = :recordId WITH USER_MODE LIMIT 1
173
+ ];
174
+ if (existing.isEmpty()) {
175
+ return handleError(res, 404, ERROR_NOT_FOUND);
176
+ }
177
+
178
+ Database.DeleteResult deleteResult = Database.delete(existing[0], true);
179
+ if (deleteResult.isSuccess()) {
180
+ res.statusCode = 200;
181
+ return new ApiResponse(true, 'Record deleted successfully.', recordId);
182
+ }
183
+
184
+ return handleError(res, 422, deleteResult.getErrors()[0].getMessage());
185
+
186
+ } catch (DmlException e) {
187
+ return handleError(res, 422, e.getDmlMessage(0));
188
+ } catch (Exception e) {
189
+ return handleError(res, 500, e.getMessage());
190
+ }
191
+ }
192
+
193
+ // ─── Private Helpers ──────────────────────────────────────────────────
194
+
195
+ private static ApiResponse getSingleRecord(String recordId, RestResponse res) {
196
+ if (!isValidSalesforceId(recordId)) {
197
+ return handleError(res, 400, ERROR_INVALID_ID);
198
+ }
199
+
200
+ List<{SObject}> records = [
201
+ SELECT Id, Name, CreatedDate, LastModifiedDate
202
+ FROM {SObject}
203
+ WHERE Id = :recordId
204
+ WITH USER_MODE
205
+ LIMIT 1
206
+ ];
207
+
208
+ if (records.isEmpty()) {
209
+ return handleError(res, 404, ERROR_NOT_FOUND);
210
+ }
211
+
212
+ res.statusCode = 200;
213
+ ApiResponse response = new ApiResponse(true, 'Record retrieved successfully.', recordId);
214
+ response.data = records[0];
215
+ return response;
216
+ }
217
+
218
+ private static ApiResponse getRecordList(RestRequest req, RestResponse res) {
219
+ Integer pageSize = getIntParam(req, 'pageSize', DEFAULT_PAGE_SIZE);
220
+ Integer offset = getIntParam(req, 'offset', 0);
221
+
222
+ pageSize = Math.min(pageSize, MAX_PAGE_SIZE);
223
+
224
+ List<{SObject}> records = [
225
+ SELECT Id, Name, CreatedDate, LastModifiedDate
226
+ FROM {SObject}
227
+ WITH USER_MODE
228
+ ORDER BY Name ASC
229
+ LIMIT :pageSize
230
+ OFFSET :offset
231
+ ];
232
+
233
+ res.statusCode = 200;
234
+ ApiResponse response = new ApiResponse(true, 'Records retrieved successfully.', null);
235
+ response.records = records;
236
+ response.pageSize = pageSize;
237
+ response.offset = offset;
238
+ return response;
239
+ }
240
+
241
+ private static String extractIdFromUri(String uri) {
242
+ String lastSegment = uri.substringAfterLast('/');
243
+ if (String.isBlank(lastSegment) || lastSegment == 'v1') {
244
+ return null;
245
+ }
246
+ return lastSegment;
247
+ }
248
+
249
+ private static Boolean isValidSalesforceId(String idValue) {
250
+ return Pattern.matches('[a-zA-Z0-9]{15,18}', idValue);
251
+ }
252
+
253
+ private static Integer getIntParam(RestRequest req, String paramName, Integer defaultValue) {
254
+ String paramValue = req.params.get(paramName);
255
+ if (String.isBlank(paramValue)) {
256
+ return defaultValue;
257
+ }
258
+ try {
259
+ return Integer.valueOf(paramValue);
260
+ } catch (TypeException e) {
261
+ return defaultValue;
262
+ }
263
+ }
264
+
265
+ private static ApiResponse handleError(RestResponse res, Integer statusCode, String message) {
266
+ res.statusCode = statusCode;
267
+ return new ApiResponse(false, message, null);
268
+ }
269
+
270
+ // ─── Request / Response DTOs ──────────────────────────────────────────
271
+
272
+ /**
273
+ * Inbound request payload for POST operations.
274
+ * Extend with additional fields as needed.
275
+ */
276
+ global class {ClassName}Request {
277
+ global String name;
278
+ // TODO: Add fields matching the expected JSON request body
279
+ }
280
+
281
+ /**
282
+ * Standardized API response envelope.
283
+ * All endpoints return this structure for consistent client parsing.
284
+ */
285
+ global class ApiResponse {
286
+ global Boolean success;
287
+ global String message;
288
+ global String recordId;
289
+ global SObject data;
290
+ global List<SObject> records;
291
+ global Integer pageSize;
292
+ global Integer offset;
293
+
294
+ global ApiResponse(Boolean success, String message, String recordId) {
295
+ this.success = success;
296
+ this.message = message;
297
+ this.recordId = recordId;
298
+ }
299
+ }
300
+ }
@@ -1,8 +1,7 @@
1
1
  /**
2
- * @description Schedulable Apex class for {describe the scheduled operation}.
2
+ * Schedulable Apex class for {describe the scheduled operation}.
3
3
  * Delegates heavy processing to a Batch or Queueable job.
4
4
  * Keep execute() lightweight — it should only launch other jobs.
5
- * @author Generated by Apex Class Writer Skill
6
5
  *
7
6
  * @example
8
7
  * // Schedule to run daily at 2 AM
@@ -20,19 +19,19 @@ public with sharing class {ClassName} implements Schedulable {
20
19
  // ─── CRON Expressions ────────────────────────────────────────────────
21
20
  // Seconds Minutes Hours Day_of_month Month Day_of_week Optional_year
22
21
 
23
- /** @description Runs daily at 2:00 AM */
22
+ /** Runs daily at 2:00 AM */
24
23
  public static final String CRON_DAILY_2AM = '0 0 2 * * ?';
25
24
 
26
- /** @description Runs every weekday at 6:00 AM */
25
+ /** Runs every weekday at 6:00 AM */
27
26
  public static final String CRON_WEEKDAYS_6AM = '0 0 6 ? * MON-FRI';
28
27
 
29
- /** @description Runs hourly at the top of the hour */
28
+ /** Runs hourly at the top of the hour */
30
29
  public static final String CRON_HOURLY = '0 0 * * * ?';
31
30
 
32
31
  // ─── Schedulable Interface ───────────────────────────────────────────
33
32
 
34
33
  /**
35
- * @description Entry point for the scheduled execution.
34
+ * Entry point for the scheduled execution.
36
35
  * Delegates to a Batch or Queueable for the actual work.
37
36
  * @param sc The schedulable context
38
37
  */
@@ -49,7 +48,7 @@ public with sharing class {ClassName} implements Schedulable {
49
48
  // ─── Convenience Scheduling Methods ──────────────────────────────────
50
49
 
51
50
  /**
52
- * @description Schedules this job to run daily at 2 AM
51
+ * Schedules this job to run daily at 2 AM
53
52
  * @return The scheduled job Id
54
53
  */
55
54
  public static String scheduleDaily() {
@@ -61,7 +60,7 @@ public with sharing class {ClassName} implements Schedulable {
61
60
  }
62
61
 
63
62
  /**
64
- * @description Aborts this scheduled job by name
63
+ * Aborts this scheduled job by name
65
64
  * @param jobName The name used when scheduling
66
65
  */
67
66
  public static void abort(String jobName) {
@@ -1,15 +1,14 @@
1
1
  /**
2
- * @description Selector class for {SObject} queries.
2
+ * Selector class for {SObject} queries.
3
3
  * Encapsulates all SOQL for {SObject} records.
4
4
  * All methods return bulkified results (Lists or Maps).
5
- * @author Generated by Apex Class Writer Skill
6
5
  */
7
- public with sharing class {SObject}Selector {
6
+ public inherited sharing class {SObject}Selector {
8
7
 
9
8
  // ─── Field Lists ─────────────────────────────────────────────────────
10
9
 
11
10
  /**
12
- * @description Returns the default set of fields to query for {SObject}.
11
+ * Returns the default set of fields to query for {SObject}.
13
12
  * Centralizes field references to keep queries DRY.
14
13
  * @return Comma-separated field list as a String
15
14
  */
@@ -29,7 +28,7 @@ public with sharing class {SObject}Selector {
29
28
  // ─── Query Methods ───────────────────────────────────────────────────
30
29
 
31
30
  /**
32
- * @description Selects {SObject} records by their Ids
31
+ * Selects {SObject} records by their Ids
33
32
  * @param recordIds Set of {SObject} Ids to query
34
33
  * @return List of {SObject} records matching the provided Ids
35
34
  * @example
@@ -49,7 +48,7 @@ public with sharing class {SObject}Selector {
49
48
  }
50
49
 
51
50
  /**
52
- * @description Selects {SObject} records as a Map keyed by Id
51
+ * Selects {SObject} records as a Map keyed by Id
53
52
  * @param recordIds Set of {SObject} Ids to query
54
53
  * @return Map of Id to {SObject}
55
54
  */
@@ -58,7 +57,7 @@ public with sharing class {SObject}Selector {
58
57
  }
59
58
 
60
59
  /**
61
- * @description Selects {SObject} records by a specific field value
60
+ * Selects {SObject} records by a specific field value
62
61
  * @param fieldName API name of the field to filter on
63
62
  * @param values Set of values to match
64
63
  * @return List of matching {SObject} records
@@ -86,7 +85,7 @@ public with sharing class {SObject}Selector {
86
85
  // ─── Exception ───────────────────────────────────────────────────────
87
86
 
88
87
  /**
89
- * @description Custom exception for query errors
88
+ * Custom exception for query errors
90
89
  */
91
90
  public class QueryException extends Exception {}
92
91
  }
@@ -1,8 +1,7 @@
1
1
  /**
2
- * @description Service class for {SObject} business logic.
2
+ * Service class for {SObject} business logic.
3
3
  * Follows separation of concerns: delegates queries to {SObject}Selector
4
4
  * and SObject manipulation to {SObject}Domain where applicable.
5
- * @author Generated by Apex Class Writer Skill
6
5
  */
7
6
  public with sharing class {SObject}Service {
8
7
 
@@ -12,7 +11,7 @@ public with sharing class {SObject}Service {
12
11
  // ─── Public API ──────────────────────────────────────────────────────
13
12
 
14
13
  /**
15
- * @description {Describe the primary operation}
14
+ * {Describe the primary operation}
16
15
  * @param recordIds Set of {SObject} Ids to process
17
16
  * @return List of processed {SObject} records
18
17
  * @throws {SObject}ServiceException if processing fails
@@ -47,7 +46,7 @@ public with sharing class {SObject}Service {
47
46
  // ─── Convenience Overloads ───────────────────────────────────────────
48
47
 
49
48
  /**
50
- * @description Single-record convenience overload
49
+ * Single-record convenience overload
51
50
  * @param recordId The {SObject} Id to process
52
51
  * @return The processed {SObject} record
53
52
  */
@@ -63,7 +62,7 @@ public with sharing class {SObject}Service {
63
62
  // ─── Exception ───────────────────────────────────────────────────────
64
63
 
65
64
  /**
66
- * @description Custom exception for {SObject}Service errors
65
+ * Custom exception for {SObject}Service errors
67
66
  */
68
67
  public class {SObject}ServiceException extends Exception {}
69
68
  }
@@ -0,0 +1,45 @@
1
+ /**
2
+ * {SObject} Trigger
3
+ */
4
+ trigger {SObject}Trigger on {SObject} (
5
+ before insert,
6
+ before update,
7
+ before delete,
8
+ after insert,
9
+ after update,
10
+ after delete,
11
+ after undelete
12
+ ) {
13
+ // ─── Option A: Trigger Actions Framework (TAF) ───────────────────────
14
+ // Delegates to Trigger_Action__mdt-registered action classes.
15
+ // Each action class handles one concern in one context.
16
+ //
17
+ // new MetadataTriggerHandler().run();
18
+
19
+ // ─── Option B: Custom Handler Pattern ────────────────────────────────
20
+ // Delegates to a single handler class that routes by context.
21
+ //
22
+ // {SObject}TriggerHandler handler = new {SObject}TriggerHandler();
23
+ //
24
+ // if (Trigger.isBefore) {
25
+ // if (Trigger.isInsert) {
26
+ // handler.beforeInsert(Trigger.new);
27
+ // } else if (Trigger.isUpdate) {
28
+ // handler.beforeUpdate(Trigger.new, Trigger.oldMap);
29
+ // } else if (Trigger.isDelete) {
30
+ // handler.beforeDelete(Trigger.old, Trigger.oldMap);
31
+ // }
32
+ // } else if (Trigger.isAfter) {
33
+ // if (Trigger.isInsert) {
34
+ // handler.afterInsert(Trigger.new, Trigger.newMap);
35
+ // } else if (Trigger.isUpdate) {
36
+ // handler.afterUpdate(Trigger.new, Trigger.oldMap);
37
+ // } else if (Trigger.isDelete) {
38
+ // handler.afterDelete(Trigger.old, Trigger.oldMap);
39
+ // } else if (Trigger.isUndelete) {
40
+ // handler.afterUndelete(Trigger.new, Trigger.newMap);
41
+ // }
42
+ // }
43
+
44
+ // TODO: Uncomment one option above and remove the other
45
+ }
@@ -1,15 +1,14 @@
1
1
  /**
2
- * @description Utility class for {describe the category of utilities: String, Date, Collection, etc.}.
2
+ * Utility class for {describe the category of utilities: String, Date, Collection, etc.}.
3
3
  * All methods are static and side-effect-free (no SOQL, no DML).
4
4
  * Private constructor prevents instantiation.
5
- * @author Generated by Apex Class Writer Skill
6
5
  */
7
6
  public with sharing class {ClassName} {
8
7
 
9
8
  // ─── Private Constructor ─────────────────────────────────────────────
10
9
 
11
10
  /**
12
- * @description Prevents instantiation — use static methods only
11
+ * Prevents instantiation — use static methods only
13
12
  */
14
13
  @TestVisible
15
14
  private {ClassName}() {
@@ -21,7 +20,7 @@ public with sharing class {ClassName} {
21
20
  // TODO: Add utility methods below. Examples:
22
21
 
23
22
  /**
24
- * @description Safely converts a String to an Integer, returning a default if parsing fails
23
+ * Safely converts a String to an Integer, returning a default if parsing fails
25
24
  * @param value The String to parse
26
25
  * @param defaultValue The fallback value if parsing fails
27
26
  * @return The parsed Integer or the default value
@@ -41,7 +40,7 @@ public with sharing class {ClassName} {
41
40
  }
42
41
 
43
42
  /**
44
- * @description Chunks a list into smaller sublists of the specified size.
43
+ * Chunks a list into smaller sublists of the specified size.
45
44
  * Useful for processing records in governor-limit-safe batches.
46
45
  * @param items The list to chunk
47
46
  * @param chunkSize The maximum size of each chunk
@@ -72,7 +71,7 @@ public with sharing class {ClassName} {
72
71
  }
73
72
 
74
73
  /**
75
- * @description Extracts a Set of non-null field values from a list of SObjects
74
+ * Extracts a Set of non-null field values from a list of SObjects
76
75
  * @param records The SObject records to extract from
77
76
  * @param fieldName The API name of the field to extract
78
77
  * @return A Set of non-null String values
@@ -1,9 +1,8 @@
1
1
  /**
2
- * @description Batch Apex class for identifying and flagging duplicate Account records.
2
+ * Batch Apex class for identifying and flagging duplicate Account records.
3
3
  * Compares Accounts by Name and BillingPostalCode to find potential duplicates.
4
4
  * Flags duplicates by setting the Is_Potential_Duplicate__c checkbox.
5
5
  * Implements Database.Stateful to track results across batch chunks.
6
- * @author Generated by Apex Class Writer Skill
7
6
  *
8
7
  * @example
9
8
  * // Run with default batch size (200)
@@ -26,7 +25,7 @@ public with sharing class AccountDeduplicationBatch implements Database.Batchabl
26
25
  // ─── Batchable Interface ─────────────────────────────────────────────
27
26
 
28
27
  /**
29
- * @description Queries all active Accounts that haven't already been flagged
28
+ * Queries all active Accounts that haven't already been flagged
30
29
  * @param bc The batch context
31
30
  * @return QueryLocator scoped to unflagged active Accounts
32
31
  */
@@ -41,7 +40,7 @@ public with sharing class AccountDeduplicationBatch implements Database.Batchabl
41
40
  }
42
41
 
43
42
  /**
44
- * @description Processes each batch by building a duplicate key and checking for matches.
43
+ * Processes each batch by building a duplicate key and checking for matches.
45
44
  * Uses a composite key of normalized Name + BillingPostalCode.
46
45
  * @param bc The batch context
47
46
  * @param scope List of Account records in the current batch
@@ -82,7 +81,7 @@ public with sharing class AccountDeduplicationBatch implements Database.Batchabl
82
81
  }
83
82
 
84
83
  /**
85
- * @description Logs a summary of the deduplication batch run
84
+ * Logs a summary of the deduplication batch run
86
85
  * @param bc The batch context
87
86
  */
88
87
  public void finish(Database.BatchableContext bc) {
@@ -101,7 +100,7 @@ public with sharing class AccountDeduplicationBatch implements Database.Batchabl
101
100
  // ─── Private Helpers ─────────────────────────────────────────────────
102
101
 
103
102
  /**
104
- * @description Builds a normalized composite key for duplicate detection
103
+ * Builds a normalized composite key for duplicate detection
105
104
  * @param acct The Account record
106
105
  * @return Normalized key string, or null if insufficient data
107
106
  */
@@ -117,7 +116,7 @@ public with sharing class AccountDeduplicationBatch implements Database.Batchabl
117
116
  }
118
117
 
119
118
  /**
120
- * @description Processes DML results, tracking successes and failures
119
+ * Processes DML results, tracking successes and failures
121
120
  * @param results List of Database.SaveResult from update operation
122
121
  */
123
122
  private void processResults(List<Database.SaveResult> results) {
@@ -139,7 +138,7 @@ public with sharing class AccountDeduplicationBatch implements Database.Batchabl
139
138
  // ─── Static Helpers ──────────────────────────────────────────────────
140
139
 
141
140
  /**
142
- * @description Convenience method to execute with default batch size
141
+ * Convenience method to execute with default batch size
143
142
  * @return The batch job Id
144
143
  */
145
144
  public static Id run() {