scc-universal 1.1.0

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 (271) hide show
  1. package/.claude-plugin/plugin.json +44 -0
  2. package/.cursor/agents/deep-researcher.md +142 -0
  3. package/.cursor/agents/doc-updater.md +219 -0
  4. package/.cursor/agents/eval-runner.md +335 -0
  5. package/.cursor/agents/learning-engine.md +210 -0
  6. package/.cursor/agents/loop-operator.md +245 -0
  7. package/.cursor/agents/refactor-cleaner.md +119 -0
  8. package/.cursor/agents/sf-admin-agent.md +127 -0
  9. package/.cursor/agents/sf-agentforce-agent.md +126 -0
  10. package/.cursor/agents/sf-apex-agent.md +117 -0
  11. package/.cursor/agents/sf-architect.md +426 -0
  12. package/.cursor/agents/sf-aura-reviewer.md +369 -0
  13. package/.cursor/agents/sf-bugfix-agent.md +101 -0
  14. package/.cursor/agents/sf-flow-agent.md +155 -0
  15. package/.cursor/agents/sf-integration-agent.md +141 -0
  16. package/.cursor/agents/sf-lwc-agent.md +123 -0
  17. package/.cursor/agents/sf-review-agent.md +357 -0
  18. package/.cursor/agents/sf-visualforce-reviewer.md +465 -0
  19. package/.cursor/hooks/adapter.js +81 -0
  20. package/.cursor/hooks/after-file-edit.js +26 -0
  21. package/.cursor/hooks/after-mcp-execution.js +12 -0
  22. package/.cursor/hooks/after-shell-execution.js +30 -0
  23. package/.cursor/hooks/after-tab-file-edit.js +12 -0
  24. package/.cursor/hooks/before-mcp-execution.js +11 -0
  25. package/.cursor/hooks/before-read-file.js +13 -0
  26. package/.cursor/hooks/before-shell-execution.js +29 -0
  27. package/.cursor/hooks/before-submit-prompt.js +23 -0
  28. package/.cursor/hooks/pre-compact.js +7 -0
  29. package/.cursor/hooks/session-end.js +10 -0
  30. package/.cursor/hooks/session-start.js +10 -0
  31. package/.cursor/hooks/stop.js +18 -0
  32. package/.cursor/hooks/subagent-start.js +10 -0
  33. package/.cursor/hooks/subagent-stop.js +10 -0
  34. package/.cursor/hooks.json +107 -0
  35. package/.cursor/skills/aside/SKILL.md +115 -0
  36. package/.cursor/skills/checkpoint/SKILL.md +50 -0
  37. package/.cursor/skills/configure-scc/SKILL.md +160 -0
  38. package/.cursor/skills/continuous-agent-loop/SKILL.md +260 -0
  39. package/.cursor/skills/mcp-server-patterns/SKILL.md +142 -0
  40. package/.cursor/skills/model-route/SKILL.md +81 -0
  41. package/.cursor/skills/prompt-optimizer/SKILL.md +366 -0
  42. package/.cursor/skills/refactor-clean/SKILL.md +133 -0
  43. package/.cursor/skills/resume-session/SKILL.md +111 -0
  44. package/.cursor/skills/save-session/SKILL.md +183 -0
  45. package/.cursor/skills/search-first/SKILL.md +140 -0
  46. package/.cursor/skills/security-scan/SKILL.md +142 -0
  47. package/.cursor/skills/sessions/SKILL.md +124 -0
  48. package/.cursor/skills/sf-agentforce-development/SKILL.md +449 -0
  49. package/.cursor/skills/sf-apex-async-patterns/SKILL.md +324 -0
  50. package/.cursor/skills/sf-apex-best-practices/SKILL.md +421 -0
  51. package/.cursor/skills/sf-apex-constraints/SKILL.md +79 -0
  52. package/.cursor/skills/sf-apex-cursor/SKILL.md +336 -0
  53. package/.cursor/skills/sf-apex-enterprise-patterns/SKILL.md +344 -0
  54. package/.cursor/skills/sf-apex-testing/SKILL.md +407 -0
  55. package/.cursor/skills/sf-api-design/SKILL.md +237 -0
  56. package/.cursor/skills/sf-approval-processes/SKILL.md +312 -0
  57. package/.cursor/skills/sf-aura-development/SKILL.md +260 -0
  58. package/.cursor/skills/sf-build-fix/SKILL.md +120 -0
  59. package/.cursor/skills/sf-data-modeling/SKILL.md +274 -0
  60. package/.cursor/skills/sf-debugging/SKILL.md +362 -0
  61. package/.cursor/skills/sf-deployment/SKILL.md +291 -0
  62. package/.cursor/skills/sf-deployment-constraints/SKILL.md +153 -0
  63. package/.cursor/skills/sf-devops-ci-cd/SKILL.md +322 -0
  64. package/.cursor/skills/sf-docs-lookup/SKILL.md +100 -0
  65. package/.cursor/skills/sf-e2e-testing/SKILL.md +321 -0
  66. package/.cursor/skills/sf-experience-cloud/SKILL.md +248 -0
  67. package/.cursor/skills/sf-flow-development/SKILL.md +376 -0
  68. package/.cursor/skills/sf-governor-limits/SKILL.md +319 -0
  69. package/.cursor/skills/sf-harness-audit/SKILL.md +139 -0
  70. package/.cursor/skills/sf-help/SKILL.md +156 -0
  71. package/.cursor/skills/sf-integration/SKILL.md +479 -0
  72. package/.cursor/skills/sf-lwc-constraints/SKILL.md +128 -0
  73. package/.cursor/skills/sf-lwc-development/SKILL.md +302 -0
  74. package/.cursor/skills/sf-lwc-testing/SKILL.md +387 -0
  75. package/.cursor/skills/sf-metadata-management/SKILL.md +285 -0
  76. package/.cursor/skills/sf-platform-events-cdc/SKILL.md +372 -0
  77. package/.cursor/skills/sf-quickstart/SKILL.md +170 -0
  78. package/.cursor/skills/sf-security/SKILL.md +330 -0
  79. package/.cursor/skills/sf-security-constraints/SKILL.md +125 -0
  80. package/.cursor/skills/sf-soql-constraints/SKILL.md +129 -0
  81. package/.cursor/skills/sf-soql-optimization/SKILL.md +353 -0
  82. package/.cursor/skills/sf-tdd-workflow/SKILL.md +332 -0
  83. package/.cursor/skills/sf-testing-constraints/SKILL.md +198 -0
  84. package/.cursor/skills/sf-trigger-constraints/SKILL.md +88 -0
  85. package/.cursor/skills/sf-trigger-frameworks/SKILL.md +343 -0
  86. package/.cursor/skills/sf-visualforce-development/SKILL.md +259 -0
  87. package/.cursor/skills/strategic-compact/SKILL.md +205 -0
  88. package/.cursor/skills/update-docs/SKILL.md +162 -0
  89. package/.cursor/skills/update-platform-docs/SKILL.md +86 -0
  90. package/.cursor-plugin/plugin.json +26 -0
  91. package/LICENSE +21 -0
  92. package/README.md +522 -0
  93. package/agents/deep-researcher.md +145 -0
  94. package/agents/doc-updater.md +222 -0
  95. package/agents/eval-runner.md +340 -0
  96. package/agents/learning-engine.md +211 -0
  97. package/agents/loop-operator.md +247 -0
  98. package/agents/refactor-cleaner.md +122 -0
  99. package/agents/sf-admin-agent.md +131 -0
  100. package/agents/sf-agentforce-agent.md +132 -0
  101. package/agents/sf-apex-agent.md +124 -0
  102. package/agents/sf-architect.md +435 -0
  103. package/agents/sf-aura-reviewer.md +372 -0
  104. package/agents/sf-bugfix-agent.md +105 -0
  105. package/agents/sf-flow-agent.md +159 -0
  106. package/agents/sf-integration-agent.md +146 -0
  107. package/agents/sf-lwc-agent.md +127 -0
  108. package/agents/sf-review-agent.md +366 -0
  109. package/agents/sf-visualforce-reviewer.md +468 -0
  110. package/assets/logo.svg +18 -0
  111. package/docs/ARCHITECTURE.md +133 -0
  112. package/docs/authoring-guide.md +373 -0
  113. package/docs/hook-development.md +578 -0
  114. package/docs/token-optimization.md +139 -0
  115. package/docs/workflow-examples.md +645 -0
  116. package/examples/agentforce-action/README.md +227 -0
  117. package/examples/apex-trigger-handler/README.md +114 -0
  118. package/examples/devops-pipeline/README.md +325 -0
  119. package/examples/flow-automation/README.md +188 -0
  120. package/examples/integration-pattern/README.md +416 -0
  121. package/examples/lwc-component/README.md +180 -0
  122. package/examples/platform-events/README.md +492 -0
  123. package/examples/scratch-org-setup/README.md +138 -0
  124. package/examples/security-audit/README.md +244 -0
  125. package/examples/visualforce-migration/README.md +314 -0
  126. package/hooks/hooks.json +338 -0
  127. package/hooks/memory-persistence/README.md +73 -0
  128. package/manifests/install-modules.json +217 -0
  129. package/manifests/install-profiles.json +17 -0
  130. package/mcp-configs/mcp-servers.json +19 -0
  131. package/package.json +89 -0
  132. package/schemas/hooks.schema.json +123 -0
  133. package/schemas/install-modules.schema.json +76 -0
  134. package/schemas/install-profiles.schema.json +28 -0
  135. package/schemas/install-state.schema.json +73 -0
  136. package/schemas/package-manager.schema.json +18 -0
  137. package/schemas/plugin.schema.json +112 -0
  138. package/schemas/scc-install-config.schema.json +29 -0
  139. package/schemas/state-store.schema.json +111 -0
  140. package/scripts/cli/install-apply.js +170 -0
  141. package/scripts/cli/uninstall.js +193 -0
  142. package/scripts/hooks/check-console-log.js +101 -0
  143. package/scripts/hooks/check-hook-enabled.js +17 -0
  144. package/scripts/hooks/check-platform-docs-age.js +48 -0
  145. package/scripts/hooks/cost-tracker.js +78 -0
  146. package/scripts/hooks/doc-file-warning.js +63 -0
  147. package/scripts/hooks/evaluate-session.js +98 -0
  148. package/scripts/hooks/governor-check.js +220 -0
  149. package/scripts/hooks/learning-observe.sh +206 -0
  150. package/scripts/hooks/mcp-health-check.js +588 -0
  151. package/scripts/hooks/post-bash-build-complete.js +34 -0
  152. package/scripts/hooks/post-bash-pr-created.js +43 -0
  153. package/scripts/hooks/post-edit-console-warn.js +61 -0
  154. package/scripts/hooks/post-edit-format.js +79 -0
  155. package/scripts/hooks/post-edit-typecheck.js +98 -0
  156. package/scripts/hooks/post-write.js +168 -0
  157. package/scripts/hooks/pre-bash-git-push-reminder.js +35 -0
  158. package/scripts/hooks/pre-bash-tmux-reminder.js +47 -0
  159. package/scripts/hooks/pre-compact.js +51 -0
  160. package/scripts/hooks/pre-tool-use.js +163 -0
  161. package/scripts/hooks/pre-write-doc-warn.js +9 -0
  162. package/scripts/hooks/quality-gate.js +251 -0
  163. package/scripts/hooks/run-with-flags-shell.sh +32 -0
  164. package/scripts/hooks/run-with-flags.js +135 -0
  165. package/scripts/hooks/session-end-marker.js +29 -0
  166. package/scripts/hooks/session-end.js +311 -0
  167. package/scripts/hooks/session-start.js +202 -0
  168. package/scripts/hooks/sfdx-scanner-check.js +142 -0
  169. package/scripts/hooks/sfdx-validate.js +119 -0
  170. package/scripts/hooks/stop-hook.js +170 -0
  171. package/scripts/hooks/suggest-compact.js +67 -0
  172. package/scripts/lib/agent-adapter.js +82 -0
  173. package/scripts/lib/apex-analysis.js +194 -0
  174. package/scripts/lib/hook-flags.js +74 -0
  175. package/scripts/lib/install-config.js +73 -0
  176. package/scripts/lib/install-executor.js +363 -0
  177. package/scripts/lib/install-state.js +121 -0
  178. package/scripts/lib/orchestration-session.js +299 -0
  179. package/scripts/lib/package-manager.js +124 -0
  180. package/scripts/lib/project-detect.js +228 -0
  181. package/scripts/lib/schema-validator.js +190 -0
  182. package/scripts/lib/skill-adapter.js +100 -0
  183. package/scripts/lib/state-store.js +376 -0
  184. package/scripts/lib/tmux-worktree-orchestrator.js +598 -0
  185. package/scripts/lib/utils.js +313 -0
  186. package/scripts/scc.js +164 -0
  187. package/skills/_reference/AGENTFORCE_PATTERNS.md +112 -0
  188. package/skills/_reference/APEX_CURSOR.md +159 -0
  189. package/skills/_reference/API_VERSIONS.md +78 -0
  190. package/skills/_reference/APPROVAL_PROCESSES.md +105 -0
  191. package/skills/_reference/ASYNC_PATTERNS.md +163 -0
  192. package/skills/_reference/AURA_COMPONENTS.md +146 -0
  193. package/skills/_reference/DATA_MIGRATION_PATTERNS.md +151 -0
  194. package/skills/_reference/DATA_MODELING.md +124 -0
  195. package/skills/_reference/DEBUGGING_TOOLS.md +140 -0
  196. package/skills/_reference/DEPLOYMENT_CHECKLIST.md +87 -0
  197. package/skills/_reference/DEPRECATIONS.md +79 -0
  198. package/skills/_reference/DOCKER_CI_PATTERNS.md +138 -0
  199. package/skills/_reference/ENTERPRISE_PATTERNS.md +122 -0
  200. package/skills/_reference/EXPERIENCE_CLOUD.md +143 -0
  201. package/skills/_reference/FLOW_PATTERNS.md +113 -0
  202. package/skills/_reference/GOVERNOR_LIMITS.md +77 -0
  203. package/skills/_reference/INTEGRATION_PATTERNS.md +105 -0
  204. package/skills/_reference/LWC_PATTERNS.md +79 -0
  205. package/skills/_reference/METADATA_TYPES.md +115 -0
  206. package/skills/_reference/NAMING_CONVENTIONS.md +84 -0
  207. package/skills/_reference/PACKAGE_DEVELOPMENT.md +150 -0
  208. package/skills/_reference/PLATFORM_EVENTS.md +121 -0
  209. package/skills/_reference/REPORTING_API.md +143 -0
  210. package/skills/_reference/SCRATCH_ORG_PATTERNS.md +126 -0
  211. package/skills/_reference/SECURITY_PATTERNS.md +127 -0
  212. package/skills/_reference/SHARING_MODEL.md +120 -0
  213. package/skills/_reference/SOQL_PATTERNS.md +119 -0
  214. package/skills/_reference/TESTING_STANDARDS.md +96 -0
  215. package/skills/_reference/TRIGGER_PATTERNS.md +114 -0
  216. package/skills/_reference/VISUALFORCE_PATTERNS.md +121 -0
  217. package/skills/aside/SKILL.md +118 -0
  218. package/skills/checkpoint/SKILL.md +53 -0
  219. package/skills/configure-scc/SKILL.md +163 -0
  220. package/skills/continuous-agent-loop/SKILL.md +264 -0
  221. package/skills/mcp-server-patterns/SKILL.md +146 -0
  222. package/skills/model-route/SKILL.md +84 -0
  223. package/skills/prompt-optimizer/SKILL.md +369 -0
  224. package/skills/refactor-clean/SKILL.md +136 -0
  225. package/skills/resume-session/SKILL.md +114 -0
  226. package/skills/save-session/SKILL.md +186 -0
  227. package/skills/search-first/SKILL.md +144 -0
  228. package/skills/security-scan/SKILL.md +146 -0
  229. package/skills/sessions/SKILL.md +127 -0
  230. package/skills/sf-agentforce-development/SKILL.md +450 -0
  231. package/skills/sf-apex-async-patterns/SKILL.md +326 -0
  232. package/skills/sf-apex-best-practices/SKILL.md +425 -0
  233. package/skills/sf-apex-constraints/SKILL.md +81 -0
  234. package/skills/sf-apex-cursor/SKILL.md +338 -0
  235. package/skills/sf-apex-enterprise-patterns/SKILL.md +348 -0
  236. package/skills/sf-apex-testing/SKILL.md +409 -0
  237. package/skills/sf-api-design/SKILL.md +238 -0
  238. package/skills/sf-approval-processes/SKILL.md +315 -0
  239. package/skills/sf-aura-development/SKILL.md +263 -0
  240. package/skills/sf-build-fix/SKILL.md +121 -0
  241. package/skills/sf-data-modeling/SKILL.md +278 -0
  242. package/skills/sf-debugging/SKILL.md +363 -0
  243. package/skills/sf-deployment/SKILL.md +295 -0
  244. package/skills/sf-deployment-constraints/SKILL.md +155 -0
  245. package/skills/sf-devops-ci-cd/SKILL.md +325 -0
  246. package/skills/sf-docs-lookup/SKILL.md +103 -0
  247. package/skills/sf-e2e-testing/SKILL.md +324 -0
  248. package/skills/sf-experience-cloud/SKILL.md +249 -0
  249. package/skills/sf-flow-development/SKILL.md +377 -0
  250. package/skills/sf-governor-limits/SKILL.md +323 -0
  251. package/skills/sf-harness-audit/SKILL.md +142 -0
  252. package/skills/sf-help/SKILL.md +159 -0
  253. package/skills/sf-integration/SKILL.md +483 -0
  254. package/skills/sf-lwc-constraints/SKILL.md +130 -0
  255. package/skills/sf-lwc-development/SKILL.md +303 -0
  256. package/skills/sf-lwc-testing/SKILL.md +388 -0
  257. package/skills/sf-metadata-management/SKILL.md +288 -0
  258. package/skills/sf-platform-events-cdc/SKILL.md +375 -0
  259. package/skills/sf-quickstart/SKILL.md +173 -0
  260. package/skills/sf-security/SKILL.md +334 -0
  261. package/skills/sf-security-constraints/SKILL.md +127 -0
  262. package/skills/sf-soql-constraints/SKILL.md +131 -0
  263. package/skills/sf-soql-optimization/SKILL.md +354 -0
  264. package/skills/sf-tdd-workflow/SKILL.md +336 -0
  265. package/skills/sf-testing-constraints/SKILL.md +200 -0
  266. package/skills/sf-trigger-constraints/SKILL.md +90 -0
  267. package/skills/sf-trigger-frameworks/SKILL.md +347 -0
  268. package/skills/sf-visualforce-development/SKILL.md +260 -0
  269. package/skills/strategic-compact/SKILL.md +208 -0
  270. package/skills/update-docs/SKILL.md +165 -0
  271. package/skills/update-platform-docs/SKILL.md +90 -0
@@ -0,0 +1,227 @@
1
+ # Agentforce Custom Action
2
+
3
+ Custom Agentforce action using `@InvocableMethod` with structured inputs/outputs for Flow and Agent integration. Requires API version 66.0+ (Spring '26).
4
+
5
+ ## When to Use This Pattern
6
+
7
+ - Building custom actions for Agentforce agents
8
+ - Exposing Apex logic to Flows as invocable actions
9
+ - Creating reusable automation building blocks with typed inputs and outputs
10
+ - Integrating external services into Agentforce conversations
11
+
12
+ ## Structure
13
+
14
+ ```text
15
+ force-app/main/default/
16
+ classes/
17
+ CreateCaseAction.cls # Invocable action class
18
+ CreateCaseAction_Test.cls # Test class with mock data
19
+ ```
20
+
21
+ ## Invocable Action Class
22
+
23
+ ```apex
24
+ public with sharing class CreateCaseAction {
25
+
26
+ public class ActionInput {
27
+ @InvocableVariable(required=true label='Subject' description='Case subject line')
28
+ public String subject;
29
+
30
+ @InvocableVariable(required=true label='Description' description='Detailed case description')
31
+ public String description;
32
+
33
+ @InvocableVariable(label='Priority' description='Case priority: Low, Medium, High, Critical')
34
+ public String priority;
35
+
36
+ @InvocableVariable(label='Account ID' description='Related account ID')
37
+ public Id accountId;
38
+
39
+ @InvocableVariable(label='Contact ID' description='Related contact ID')
40
+ public Id contactId;
41
+ }
42
+
43
+ public class ActionOutput {
44
+ @InvocableVariable(label='Case ID' description='ID of the created case')
45
+ public Id caseId;
46
+
47
+ @InvocableVariable(label='Case Number' description='Auto-generated case number')
48
+ public String caseNumber;
49
+
50
+ @InvocableVariable(label='Success' description='Whether the action succeeded')
51
+ public Boolean success;
52
+
53
+ @InvocableVariable(label='Error Message' description='Error details if action failed')
54
+ public String errorMessage;
55
+ }
56
+
57
+ @InvocableMethod(
58
+ label='Create Support Case'
59
+ description='Creates a new support case from Agentforce or Flow input'
60
+ category='Support'
61
+ )
62
+ public static List<ActionOutput> createCase(List<ActionInput> inputs) {
63
+ List<ActionOutput> outputs = new List<ActionOutput>();
64
+
65
+ for (ActionInput input : inputs) {
66
+ ActionOutput output = new ActionOutput();
67
+ try {
68
+ Case newCase = new Case(
69
+ Subject = input.subject,
70
+ Description = input.description,
71
+ Priority = String.isNotBlank(input.priority) ? input.priority : 'Medium',
72
+ Status = 'New',
73
+ Origin = 'Agentforce',
74
+ AccountId = input.accountId,
75
+ ContactId = input.contactId
76
+ );
77
+ insert newCase;
78
+
79
+ // Re-query for auto-generated fields
80
+ newCase = [SELECT Id, CaseNumber FROM Case WHERE Id = :newCase.Id LIMIT 1];
81
+
82
+ output.caseId = newCase.Id;
83
+ output.caseNumber = newCase.CaseNumber;
84
+ output.success = true;
85
+ } catch (Exception e) {
86
+ output.success = false;
87
+ output.errorMessage = e.getMessage();
88
+ }
89
+ outputs.add(output);
90
+ }
91
+
92
+ return outputs;
93
+ }
94
+ }
95
+ ```
96
+
97
+ ## Test Class
98
+
99
+ ```apex
100
+ @IsTest
101
+ private class CreateCaseAction_Test {
102
+
103
+ @TestSetup
104
+ static void setupData() {
105
+ Account testAccount = new Account(Name = 'Test Corp');
106
+ insert testAccount;
107
+
108
+ Contact testContact = new Contact(
109
+ FirstName = 'Jane',
110
+ LastName = 'Doe',
111
+ AccountId = testAccount.Id,
112
+ Email = 'jane.doe@testcorp.com'
113
+ );
114
+ insert testContact;
115
+ }
116
+
117
+ @IsTest
118
+ static void testCreateCase_Success() {
119
+ Account acct = [SELECT Id FROM Account LIMIT 1];
120
+ Contact con = [SELECT Id FROM Contact LIMIT 1];
121
+
122
+ CreateCaseAction.ActionInput input = new CreateCaseAction.ActionInput();
123
+ input.subject = 'Login issue';
124
+ input.description = 'Customer cannot log in to portal';
125
+ input.priority = 'High';
126
+ input.accountId = acct.Id;
127
+ input.contactId = con.Id;
128
+
129
+ Test.startTest();
130
+ List<CreateCaseAction.ActionOutput> results =
131
+ CreateCaseAction.createCase(new List<CreateCaseAction.ActionInput>{ input });
132
+ Test.stopTest();
133
+
134
+ System.assertEquals(1, results.size());
135
+ System.assertEquals(true, results[0].success);
136
+ System.assertNotEquals(null, results[0].caseId);
137
+ System.assertNotEquals(null, results[0].caseNumber);
138
+
139
+ Case created = [SELECT Subject, Priority, Origin FROM Case WHERE Id = :results[0].caseId];
140
+ System.assertEquals('Login issue', created.Subject);
141
+ System.assertEquals('High', created.Priority);
142
+ System.assertEquals('Agentforce', created.Origin);
143
+ }
144
+
145
+ @IsTest
146
+ static void testCreateCase_DefaultPriority() {
147
+ CreateCaseAction.ActionInput input = new CreateCaseAction.ActionInput();
148
+ input.subject = 'General inquiry';
149
+ input.description = 'Question about features';
150
+
151
+ Test.startTest();
152
+ List<CreateCaseAction.ActionOutput> results =
153
+ CreateCaseAction.createCase(new List<CreateCaseAction.ActionInput>{ input });
154
+ Test.stopTest();
155
+
156
+ System.assertEquals(true, results[0].success);
157
+ Case created = [SELECT Priority FROM Case WHERE Id = :results[0].caseId];
158
+ System.assertEquals('Medium', created.Priority);
159
+ }
160
+
161
+ @IsTest
162
+ static void testCreateCase_BulkInvocation() {
163
+ List<CreateCaseAction.ActionInput> inputs = new List<CreateCaseAction.ActionInput>();
164
+ for (Integer i = 0; i < 50; i++) {
165
+ CreateCaseAction.ActionInput input = new CreateCaseAction.ActionInput();
166
+ input.subject = 'Bulk case ' + i;
167
+ input.description = 'Description for case ' + i;
168
+ inputs.add(input);
169
+ }
170
+
171
+ Test.startTest();
172
+ List<CreateCaseAction.ActionOutput> results = CreateCaseAction.createCase(inputs);
173
+ Test.stopTest();
174
+
175
+ System.assertEquals(50, results.size());
176
+ for (CreateCaseAction.ActionOutput output : results) {
177
+ System.assertEquals(true, output.success);
178
+ }
179
+ }
180
+ }
181
+ ```
182
+
183
+ ## Flow Integration
184
+
185
+ Once the action is deployed, it appears in Flow Builder under **Action** elements:
186
+
187
+ 1. Open Flow Builder and add an **Action** element
188
+ 2. Search for "Create Support Case"
189
+ 3. Map Flow variables to the `ActionInput` fields
190
+ 4. Use the `ActionOutput` fields in subsequent Flow elements
191
+
192
+ ```text
193
+ Flow: Case Creation from Chat
194
+ Step 1: Get Input (Screen / Agentforce prompt)
195
+ Step 2: Action → Create Support Case
196
+ - Subject = {!chatSubject}
197
+ - Description = {!chatDescription}
198
+ - Priority = {!selectedPriority}
199
+ - Account ID = {!currentAccountId}
200
+ Step 3: Decision → Check {!ActionOutput.success}
201
+ - True → Display confirmation with {!ActionOutput.caseNumber}
202
+ - False → Display {!ActionOutput.errorMessage}
203
+ ```
204
+
205
+ ## Key Principles
206
+
207
+ - Always use `with sharing` to enforce record-level security
208
+ - Mark required inputs with `required=true` on `@InvocableVariable`
209
+ - Provide `label` and `description` on every variable for Flow/Agent discoverability
210
+ - Handle errors gracefully and return them in the output rather than throwing exceptions
211
+ - Design for bulk invocation: the method receives and returns `List<>`, not single records
212
+ - Re-query for auto-number fields after insert
213
+
214
+ ## Common Pitfalls
215
+
216
+ - Forgetting to bulkify: inserting records inside a loop hits governor limits
217
+ - Not handling null optional inputs, which causes NullPointerException
218
+ - Missing `label` and `description` makes the action hard to find in Flow Builder
219
+ - Throwing unhandled exceptions breaks the entire Flow/Agent transaction
220
+ - Using `without sharing` inadvertently bypasses record access controls
221
+
222
+ ## SCC Skills
223
+
224
+ - `/sf-agentforce-development` -- scaffold and review Agentforce actions
225
+ - `/sf-apex-best-practices` -- review the action class for best practices
226
+ - `/sf-tdd-workflow` -- write tests first, then implement the action
227
+ - `/sf-governor-limits` -- check governor limit compliance in bulk scenarios
@@ -0,0 +1,114 @@
1
+ # Apex Trigger Handler Pattern
2
+
3
+ Enterprise-grade trigger handler pattern with one trigger per object. Compatible with API version 66.0 (Spring '26).
4
+
5
+ ## Structure
6
+
7
+ ```text
8
+ force-app/main/default/
9
+ classes/
10
+ TriggerHandler.cls # Base handler class
11
+ AccountTriggerHandler.cls # Account-specific handler
12
+ AccountTriggerHandler_Test.cls
13
+ triggers/
14
+ AccountTrigger.trigger # Thin trigger — delegates to handler
15
+ ```
16
+
17
+ ## Base Handler
18
+
19
+ ```apex
20
+ public virtual class TriggerHandler {
21
+
22
+ @TestVisible private Boolean isTriggerExecuting;
23
+ @TestVisible private Integer batchSize;
24
+
25
+ public TriggerHandler() {
26
+ this.isTriggerExecuting = Trigger.isExecuting;
27
+ this.batchSize = Trigger.size;
28
+ }
29
+
30
+ public void run() {
31
+ if (!validateRun()) return;
32
+
33
+ switch on Trigger.operationType {
34
+ when BEFORE_INSERT { beforeInsert(Trigger.new); }
35
+ when BEFORE_UPDATE { beforeUpdate(Trigger.new, Trigger.oldMap); }
36
+ when BEFORE_DELETE { beforeDelete(Trigger.old, Trigger.oldMap); }
37
+ when AFTER_INSERT { afterInsert(Trigger.new, Trigger.newMap); }
38
+ when AFTER_UPDATE { afterUpdate(Trigger.new, Trigger.oldMap, Trigger.newMap); }
39
+ when AFTER_DELETE { afterDelete(Trigger.old, Trigger.oldMap); }
40
+ when AFTER_UNDELETE { afterUndelete(Trigger.new, Trigger.newMap); }
41
+ }
42
+ }
43
+
44
+ @TestVisible
45
+ protected virtual Boolean validateRun() {
46
+ if (!this.isTriggerExecuting) {
47
+ throw new TriggerHandlerException('Trigger handler called outside of trigger execution');
48
+ }
49
+ return true;
50
+ }
51
+
52
+ // Override these in subclasses
53
+ protected virtual void beforeInsert(List<SObject> newRecords) {}
54
+ protected virtual void beforeUpdate(List<SObject> newRecords, Map<Id, SObject> oldMap) {}
55
+ protected virtual void beforeDelete(List<SObject> oldRecords, Map<Id, SObject> oldMap) {}
56
+ protected virtual void afterInsert(List<SObject> newRecords, Map<Id, SObject> newMap) {}
57
+ protected virtual void afterUpdate(List<SObject> newRecords, Map<Id, SObject> oldMap, Map<Id, SObject> newMap) {}
58
+ protected virtual void afterDelete(List<SObject> oldRecords, Map<Id, SObject> oldMap) {}
59
+ protected virtual void afterUndelete(List<SObject> newRecords, Map<Id, SObject> newMap) {}
60
+
61
+ public class TriggerHandlerException extends Exception {}
62
+ }
63
+ ```
64
+
65
+ ## Trigger (Thin)
66
+
67
+ ```apex
68
+ trigger AccountTrigger on Account (
69
+ before insert, before update, before delete,
70
+ after insert, after update, after delete, after undelete
71
+ ) {
72
+ new AccountTriggerHandler().run();
73
+ }
74
+ ```
75
+
76
+ ## Handler Implementation
77
+
78
+ ```apex
79
+ public class AccountTriggerHandler extends TriggerHandler {
80
+
81
+ protected override void beforeInsert(List<SObject> newRecords) {
82
+ List<Account> accounts = (List<Account>) newRecords;
83
+ for (Account acc : accounts) {
84
+ if (String.isBlank(acc.Industry)) {
85
+ acc.Industry = 'Other';
86
+ }
87
+ }
88
+ }
89
+
90
+ protected override void afterUpdate(List<SObject> newRecords, Map<Id, SObject> oldMap, Map<Id, SObject> newMap) {
91
+ List<Account> accounts = (List<Account>) newRecords;
92
+ List<Account> changedAccounts = new List<Account>();
93
+
94
+ for (Account acc : accounts) {
95
+ Account oldAcc = (Account) oldMap.get(acc.Id);
96
+ if (acc.OwnerId != oldAcc.OwnerId) {
97
+ changedAccounts.add(acc);
98
+ }
99
+ }
100
+
101
+ if (!changedAccounts.isEmpty()) {
102
+ AccountService.handleOwnerChanges(changedAccounts);
103
+ }
104
+ }
105
+ }
106
+ ```
107
+
108
+ ## Key Principles
109
+
110
+ - One trigger per object
111
+ - Trigger delegates to handler — no logic in the trigger itself
112
+ - Handler methods receive proper context (newRecords, oldMap, etc.)
113
+ - All operations are bulkified (iterate over collections)
114
+ - Business logic extracted to Service classes
@@ -0,0 +1,325 @@
1
+ # CI/CD Pipeline for Salesforce
2
+
3
+ End-to-end DevOps pipeline with scratch org creation, source deployment, test execution, PMD scanning, and production deployment using GitHub Actions. Targets API version 66.0 (Spring '26).
4
+
5
+ ## When to Use This Pattern
6
+
7
+ - Setting up continuous integration for a Salesforce DX project
8
+ - Automating test execution and code quality checks on every pull request
9
+ - Building a repeatable deployment pipeline from development to production
10
+ - Enforcing quality gates before merging code changes
11
+
12
+ ## Structure
13
+
14
+ ```text
15
+ .github/
16
+ workflows/
17
+ ci.yml # Pull request validation pipeline
18
+ deploy-production.yml # Production deployment pipeline
19
+ scripts/
20
+ scratch-org-setup.sh # Scratch org creation and data load
21
+ run-tests.sh # Test execution with coverage reporting
22
+ config/
23
+ project-scratch-def.json # Scratch org definition
24
+ sfdx-project.json # Project configuration
25
+ ```
26
+
27
+ ## Scratch Org Creation Script
28
+
29
+ ```bash
30
+ #!/bin/bash
31
+ # scripts/scratch-org-setup.sh
32
+ # Creates a scratch org, pushes source, assigns permission sets, and loads data.
33
+
34
+ set -euo pipefail
35
+
36
+ ORG_ALIAS="${1:-ci-scratch}"
37
+ DURATION="${2:-1}"
38
+
39
+ echo "==> Creating scratch org: ${ORG_ALIAS} (duration: ${DURATION} days)"
40
+ sf org create scratch \
41
+ --definition-file config/project-scratch-def.json \
42
+ --alias "${ORG_ALIAS}" \
43
+ --duration-days "${DURATION}" \
44
+ --set-default \
45
+ --wait 10
46
+
47
+ echo "==> Pushing source to scratch org"
48
+ sf project deploy start --target-org "${ORG_ALIAS}" --wait 30
49
+
50
+ echo "==> Assigning permission sets"
51
+ sf org assign permset \
52
+ --name AppAdmin \
53
+ --target-org "${ORG_ALIAS}"
54
+
55
+ sf org assign permset \
56
+ --name IntegrationUser \
57
+ --target-org "${ORG_ALIAS}"
58
+
59
+ echo "==> Loading sample data"
60
+ sf data import tree \
61
+ --files data/Account.json,data/Contact.json,data/Opportunity.json \
62
+ --target-org "${ORG_ALIAS}"
63
+
64
+ echo "==> Scratch org ready: ${ORG_ALIAS}"
65
+ sf org open --target-org "${ORG_ALIAS}"
66
+ ```
67
+
68
+ ## Scratch Org Definition
69
+
70
+ ```json
71
+ {
72
+ "orgName": "SCC CI Scratch Org",
73
+ "edition": "Developer",
74
+ "features": ["EnableSetPasswordInApi", "Communities", "ServiceCloud"],
75
+ "settings": {
76
+ "lightningExperienceSettings": {
77
+ "enableS1DesktopEnabled": true
78
+ },
79
+ "securitySettings": {
80
+ "passwordPolicies": {
81
+ "enableSetPasswordInApi": true
82
+ }
83
+ },
84
+ "languageSettings": {
85
+ "enableTranslationWorkbench": true
86
+ }
87
+ }
88
+ }
89
+ ```
90
+
91
+ ## Test Execution Script
92
+
93
+ ```bash
94
+ #!/bin/bash
95
+ # scripts/run-tests.sh
96
+ # Runs all Apex tests with coverage and fails if coverage is below threshold.
97
+
98
+ set -euo pipefail
99
+
100
+ ORG_ALIAS="${1:-ci-scratch}"
101
+ COVERAGE_THRESHOLD="${2:-75}"
102
+
103
+ echo "==> Running all Apex tests with code coverage"
104
+ sf apex run test \
105
+ --target-org "${ORG_ALIAS}" \
106
+ --code-coverage \
107
+ --result-format human \
108
+ --output-dir test-results \
109
+ --wait 30 \
110
+ --test-level RunLocalTests
111
+
112
+ echo "==> Checking coverage threshold (${COVERAGE_THRESHOLD}%)"
113
+ COVERAGE=$(cat test-results/test-result-codecoverage.json \
114
+ | python3 -c "
115
+ import json, sys
116
+ data = json.load(sys.stdin)
117
+ total_lines = sum(r.get('totalLines', 0) for r in data)
118
+ covered_lines = sum(r.get('totalCovered', 0) for r in data)
119
+ pct = (covered_lines / total_lines * 100) if total_lines > 0 else 0
120
+ print(f'{pct:.1f}')
121
+ ")
122
+
123
+ echo "==> Overall coverage: ${COVERAGE}%"
124
+
125
+ if (( $(echo "${COVERAGE} < ${COVERAGE_THRESHOLD}" | bc -l) )); then
126
+ echo "ERROR: Coverage ${COVERAGE}% is below threshold ${COVERAGE_THRESHOLD}%"
127
+ exit 1
128
+ fi
129
+
130
+ echo "==> Coverage check passed"
131
+ ```
132
+
133
+ ## PMD Scanning Integration
134
+
135
+ ```bash
136
+ #!/bin/bash
137
+ # Run SFDX Scanner with PMD rules as a CI gate
138
+
139
+ set -euo pipefail
140
+
141
+ echo "==> Running PMD security and best practices scan"
142
+ sf scanner run \
143
+ --target "force-app/main/default/classes/**/*.cls" \
144
+ --category "Security,Best Practices,Performance" \
145
+ --engine pmd \
146
+ --format json \
147
+ --outfile scanner-results.json \
148
+ --severity-threshold 2
149
+
150
+ VIOLATIONS=$(cat scanner-results.json | python3 -c "
151
+ import json, sys
152
+ data = json.load(sys.stdin)
153
+ count = len(data) if isinstance(data, list) else 0
154
+ print(count)
155
+ ")
156
+
157
+ echo "==> Found ${VIOLATIONS} violation(s)"
158
+
159
+ if [ "${VIOLATIONS}" -gt 0 ]; then
160
+ echo "==> Violations found. See scanner-results.json for details."
161
+ sf scanner run \
162
+ --target "force-app/main/default/classes/**/*.cls" \
163
+ --category "Security,Best Practices,Performance" \
164
+ --engine pmd \
165
+ --format table \
166
+ --severity-threshold 2
167
+ exit 1
168
+ fi
169
+
170
+ echo "==> PMD scan passed"
171
+ ```
172
+
173
+ ## GitHub Actions: Pull Request Validation
174
+
175
+ ```yaml
176
+ # .github/workflows/ci.yml
177
+ name: Salesforce CI
178
+
179
+ on:
180
+ pull_request:
181
+ branches: [main, develop]
182
+ paths:
183
+ - 'force-app/**'
184
+ - 'config/**'
185
+ - 'sfdx-project.json'
186
+
187
+ jobs:
188
+ validate:
189
+ runs-on: ubuntu-latest
190
+ steps:
191
+ - name: Checkout
192
+ uses: actions/checkout@v4
193
+
194
+ - name: Install Salesforce CLI
195
+ run: npm install -g @salesforce/cli
196
+
197
+ - name: Install SFDX Scanner
198
+ run: sf plugins install @salesforce/sfdx-scanner
199
+
200
+ - name: Authenticate Dev Hub
201
+ run: |
202
+ echo "${SFDX_AUTH_URL}" > auth.txt
203
+ sf org login sfdx-url --sfdx-url-file auth.txt --alias devhub --set-default-dev-hub
204
+ rm auth.txt
205
+ env:
206
+ SFDX_AUTH_URL: ${{ secrets.SFDX_DEVHUB_AUTH_URL }}
207
+
208
+ - name: Create Scratch Org
209
+ run: |
210
+ sf org create scratch \
211
+ --definition-file config/project-scratch-def.json \
212
+ --alias ci-scratch \
213
+ --duration-days 1 \
214
+ --set-default \
215
+ --wait 15
216
+
217
+ - name: Deploy Source
218
+ run: sf project deploy start --target-org ci-scratch --wait 30
219
+
220
+ - name: Run Apex Tests
221
+ run: |
222
+ sf apex run test \
223
+ --target-org ci-scratch \
224
+ --code-coverage \
225
+ --result-format human \
226
+ --output-dir test-results \
227
+ --wait 30 \
228
+ --test-level RunLocalTests
229
+
230
+ - name: Upload Test Results
231
+ if: always()
232
+ uses: actions/upload-artifact@v4
233
+ with:
234
+ name: apex-test-results
235
+ path: test-results/
236
+
237
+ - name: Run PMD Scanner
238
+ run: |
239
+ sf scanner run \
240
+ --target "force-app/main/default/classes/**/*.cls" \
241
+ --category "Security,Best Practices" \
242
+ --engine pmd \
243
+ --format table \
244
+ --severity-threshold 2
245
+
246
+ - name: Delete Scratch Org
247
+ if: always()
248
+ run: sf org delete scratch --target-org ci-scratch --no-prompt
249
+ ```
250
+
251
+ ## GitHub Actions: Production Deployment
252
+
253
+ ```yaml
254
+ # .github/workflows/deploy-production.yml
255
+ name: Deploy to Production
256
+
257
+ on:
258
+ push:
259
+ branches: [main]
260
+ paths:
261
+ - 'force-app/**'
262
+
263
+ jobs:
264
+ deploy:
265
+ runs-on: ubuntu-latest
266
+ environment: production
267
+ steps:
268
+ - name: Checkout
269
+ uses: actions/checkout@v4
270
+
271
+ - name: Install Salesforce CLI
272
+ run: npm install -g @salesforce/cli
273
+
274
+ - name: Authenticate Production
275
+ run: |
276
+ echo "${SFDX_AUTH_URL}" > auth.txt
277
+ sf org login sfdx-url --sfdx-url-file auth.txt --alias production
278
+ rm auth.txt
279
+ env:
280
+ SFDX_AUTH_URL: ${{ secrets.SFDX_PROD_AUTH_URL }}
281
+
282
+ - name: Validate Deployment (Check Only)
283
+ run: |
284
+ sf project deploy start \
285
+ --target-org production \
286
+ --test-level RunLocalTests \
287
+ --dry-run \
288
+ --wait 60
289
+
290
+ - name: Deploy to Production
291
+ run: |
292
+ sf project deploy start \
293
+ --target-org production \
294
+ --test-level RunLocalTests \
295
+ --wait 60
296
+
297
+ - name: Verify Deployment
298
+ run: |
299
+ sf project deploy report --target-org production
300
+ ```
301
+
302
+ ## Key Principles
303
+
304
+ - Every pull request validates in a fresh scratch org to catch deployment issues early
305
+ - Tests run with `RunLocalTests` to avoid executing managed package tests
306
+ - PMD scanning gates the pipeline: violations above a severity threshold fail the build
307
+ - Production deployments use a `--dry-run` validation step before the real deploy
308
+ - Scratch orgs are deleted after each CI run to conserve limits
309
+ - Auth URLs are stored as encrypted GitHub Secrets, never committed to source
310
+
311
+ ## Common Pitfalls
312
+
313
+ - Not deleting scratch orgs in CI, which exhausts the daily scratch org limit
314
+ - Hardcoding the Dev Hub username instead of using auth URL files
315
+ - Skipping `RunLocalTests` in validation, then discovering test failures during real deploy
316
+ - Forgetting to install required plugins (scanner) in the CI environment
317
+ - Not setting `--wait` timeouts, causing CI jobs to hang indefinitely
318
+ - Storing SFDX auth URLs or tokens in the repository instead of secrets
319
+
320
+ ## SCC Skills
321
+
322
+ - `/sf-deployment` -- validate and deploy metadata to a target org
323
+ - `/sf-devops-ci-cd` -- CI/CD pipeline patterns with scratch orgs
324
+ - `/sf-build-fix` -- diagnose and fix deployment failures
325
+ - `/sf-apex-testing` -- run Apex tests with coverage analysis