sf-forcekit 1.0.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 (32) hide show
  1. package/License +21 -0
  2. package/README.md +106 -0
  3. package/bin/cli.js +85 -0
  4. package/package.json +44 -0
  5. package/templates/ai-dir/README.md +155 -0
  6. package/templates/ai-dir/agentforce.md +213 -0
  7. package/templates/ai-dir/architecture.md +123 -0
  8. package/templates/ai-dir/commands.md +276 -0
  9. package/templates/ai-dir/context-snapshots/TEMPLATE.md +64 -0
  10. package/templates/ai-dir/conventions.md +242 -0
  11. package/templates/ai-dir/current-state.md +113 -0
  12. package/templates/ai-dir/debugging-notes.md +165 -0
  13. package/templates/ai-dir/deployment.md +161 -0
  14. package/templates/ai-dir/integrations.md +199 -0
  15. package/templates/ai-dir/inventory.md +209 -0
  16. package/templates/ai-dir/known-issues.md +124 -0
  17. package/templates/ai-dir/org-context.md +110 -0
  18. package/templates/ai-dir/performance.md +312 -0
  19. package/templates/ai-dir/prompts/agentforce.md +163 -0
  20. package/templates/ai-dir/prompts/apex.md +165 -0
  21. package/templates/ai-dir/prompts/flows.md +125 -0
  22. package/templates/ai-dir/prompts/lwc.md +230 -0
  23. package/templates/ai-dir/prompts/security.md +181 -0
  24. package/templates/ai-dir/prompts/testing.md +269 -0
  25. package/templates/ai-dir/rules.md +238 -0
  26. package/templates/ai-dir/scripts/update_state.py +1406 -0
  27. package/templates/ai-dir/source-of-truth.md +180 -0
  28. package/templates/ai-dir/templates/Selector.cls +113 -0
  29. package/templates/ai-dir/templates/Service.cls +132 -0
  30. package/templates/ai-dir/templates/TestClass.cls +143 -0
  31. package/templates/ai-dir/templates/TriggerHandler.cls +67 -0
  32. package/templates/ai-dir/testing-strategy.md +342 -0
@@ -0,0 +1,125 @@
1
+ # Flow Building Rules
2
+
3
+ > Instructions for AI agents when designing or reviewing Salesforce Flows.
4
+
5
+ ---
6
+
7
+ ## Core Rules
8
+
9
+ | Rule | Details |
10
+ |------|---------|
11
+ | **Prefer Record-Triggered Flows** | Over Process Builder (deprecated) and Workflow Rules |
12
+ | **Before-Save for field updates** | No DML consumed — free performance |
13
+ | **After-Save for related records** | Only when you need DML on other objects or platform events |
14
+ | **Fault paths on EVERY DML/callout** | No silent failures |
15
+ | **No hardcoded IDs** | Use Custom Labels or Custom Metadata Types |
16
+ | **No hardcoded strings** | Use Custom Labels for user-facing text |
17
+
18
+ ---
19
+
20
+ ## Flow Naming Convention
21
+
22
+ ```
23
+ {Object}_{TriggerTiming}_{Purpose}
24
+
25
+ Examples:
26
+ Account_BeforeSave_DefaultIndustry
27
+ Contact_AfterSave_SyncToExternalSystem
28
+ Opportunity_BeforeSave_ValidateAmount
29
+ Case_AfterSave_NotifyTeam
30
+ Lead_Scheduled_CleanupStale
31
+ ```
32
+
33
+ For non-record-triggered flows:
34
+ ```
35
+ {Purpose}_{Type}
36
+
37
+ Examples:
38
+ OrderApproval_ScreenFlow
39
+ DataMigration_AutolaunchedFlow
40
+ WeeklyReport_ScheduledFlow
41
+ ```
42
+
43
+ ---
44
+
45
+ ## Before-Save vs After-Save Decision Tree
46
+
47
+ ```
48
+ Need to update ONLY the triggering record's fields?
49
+ → YES → Before-Save Flow (no DML cost)
50
+ → NO → Do you need to:
51
+ • Create/update RELATED records? → After-Save Flow
52
+ • Send emails? → After-Save Flow
53
+ • Publish Platform Events? → After-Save Flow
54
+ • Make callouts? → After-Save Flow (+ Asynchronous path)
55
+ ```
56
+
57
+ ---
58
+
59
+ ## Mandatory Elements
60
+
61
+ ### 1. Fault Paths
62
+
63
+ Every DML element (Create, Update, Delete) and every Action element (Callout, Invocable) MUST have a fault connector.
64
+
65
+ ```
66
+ [Create Records] ──success──→ [Next Element]
67
+
68
+ └──fault──→ [Log Error] → [Notify Admin]
69
+ ```
70
+
71
+ ### 2. Entry Conditions
72
+
73
+ - Be specific with entry conditions to avoid unnecessary executions
74
+ - Use `$Record.FieldName` for current values
75
+ - Use `$Record__Prior.FieldName` for before-update comparisons
76
+ - Filter with `AND`/`OR` to narrow scope
77
+
78
+ ### 3. Bulkification
79
+
80
+ Flows are auto-bulkified for DML, but:
81
+ - Avoid **Get Records** inside loops (SOQL in loop equivalent)
82
+ - Use **Collection Variables** and **Assignment** elements for batch operations
83
+ - Pre-fetch related data before loops
84
+
85
+ ---
86
+
87
+ ## Anti-Patterns (Avoid These)
88
+
89
+ | Anti-Pattern | Why It's Bad | Fix |
90
+ |-------------|-------------|-----|
91
+ | Get Records inside a Loop | SOQL in loop — hits governor limits | Pre-fetch outside loop into Collection Variable |
92
+ | Hardcoded Record Type IDs | Breaks across environments | Use `$Label.RecordTypeName` or CMDT |
93
+ | No fault paths | Silent failures, no debugging | Add fault connector to every DML/callout |
94
+ | After-Save for field updates | Wastes DML, causes recursion | Use Before-Save instead |
95
+ | Overly broad entry conditions | Runs on every update, burns CPU | Narrow with field change conditions |
96
+
97
+ ---
98
+
99
+ ## Flow Testing Checklist
100
+
101
+ - [ ] Test with single record
102
+ - [ ] Test with bulk records (verify no governor limit issues)
103
+ - [ ] Test fault paths (what happens on DML error?)
104
+ - [ ] Test with different user profiles (sharing/FLS)
105
+ - [ ] Verify no recursion (update on same object doesn't re-trigger infinitely)
106
+ - [ ] Test entry conditions (verify flow doesn't fire when it shouldn't)
107
+ - [ ] Validate in sandbox before production
108
+
109
+ ---
110
+
111
+ ## Flow Documentation Template
112
+
113
+ When creating or reviewing a flow, document:
114
+
115
+ ```markdown
116
+ ### Flow: {Flow_Name}
117
+ - **Object:** {Object API Name}
118
+ - **Type:** Record-Triggered (Before/After Save) | Screen | Autolaunched | Scheduled
119
+ - **Entry Conditions:** {Describe when this flow fires}
120
+ - **Purpose:** {What this flow does}
121
+ - **DML Operations:** {List any create/update/delete}
122
+ - **Callouts:** {Any external callouts}
123
+ - **Platform Events:** {Any events published}
124
+ - **Error Handling:** {Fault path behavior}
125
+ ```
@@ -0,0 +1,230 @@
1
+ # LWC Generation Rules
2
+
3
+ > Instructions for AI agents when generating Lightning Web Components.
4
+
5
+ ---
6
+
7
+ ## Before Writing Any LWC
8
+
9
+ 1. **Check `conventions.md`** for naming and styling rules.
10
+ 2. **Check `architecture.md`** for existing components and patterns.
11
+ 3. **Determine data strategy**: Wire Service → LDS → GraphQL → Imperative Apex (in order of preference).
12
+
13
+ ---
14
+
15
+ ## Component Structure
16
+
17
+ Every LWC must have this file structure:
18
+
19
+ ```
20
+ lwc/
21
+ componentName/ ← camelCase, always
22
+ componentName.html ← Template
23
+ componentName.js ← Controller
24
+ componentName.css ← Styles (no inline styles)
25
+ componentName.js-meta.xml ← Metadata config
26
+ __tests__/ ← Jest tests
27
+ componentName.test.js
28
+ ```
29
+
30
+ ---
31
+
32
+ ## Mandatory Patterns
33
+
34
+ ### 1. Three-State Template (Loading, Error, Data)
35
+
36
+ ```html
37
+ <template>
38
+ <!-- Loading State -->
39
+ <template if:true={isLoading}>
40
+ <lightning-spinner
41
+ alternative-text="Loading"
42
+ size="medium">
43
+ </lightning-spinner>
44
+ </template>
45
+
46
+ <!-- Error State -->
47
+ <template if:true={hasError}>
48
+ <div class="slds-illustration slds-illustration_small">
49
+ <p class="slds-text-body_regular slds-text-color_error">
50
+ {errorMessage}
51
+ </p>
52
+ <lightning-button
53
+ label="Retry"
54
+ variant="brand"
55
+ onclick={handleRetry}>
56
+ </lightning-button>
57
+ </div>
58
+ </template>
59
+
60
+ <!-- Data State -->
61
+ <template if:true={hasData}>
62
+ <!-- Component content here -->
63
+ </template>
64
+
65
+ <!-- Empty State -->
66
+ <template if:false={hasData}>
67
+ <template if:false={isLoading}>
68
+ <template if:false={hasError}>
69
+ <div class="slds-align_absolute-center slds-p-around_medium">
70
+ <p class="slds-text-body_regular slds-text-color_weak">
71
+ No records found.
72
+ </p>
73
+ </div>
74
+ </template>
75
+ </template>
76
+ </template>
77
+ </template>
78
+ ```
79
+
80
+ ### 2. Wire Service (Default for Data)
81
+
82
+ ```javascript
83
+ import { LightningElement, api, wire } from 'lwc';
84
+ import getAccounts from '@salesforce/apex/AccountController.getAccounts';
85
+
86
+ export default class AccountList extends LightningElement {
87
+ @api recordId;
88
+
89
+ @wire(getAccounts, { accountId: '$recordId' })
90
+ wiredAccounts;
91
+
92
+ get isLoading() {
93
+ return !this.wiredAccounts.data && !this.wiredAccounts.error;
94
+ }
95
+
96
+ get hasError() {
97
+ return !!this.wiredAccounts.error;
98
+ }
99
+
100
+ get hasData() {
101
+ return this.wiredAccounts.data && this.wiredAccounts.data.length > 0;
102
+ }
103
+
104
+ get errorMessage() {
105
+ return this.wiredAccounts.error?.body?.message || 'An error occurred';
106
+ }
107
+
108
+ get accounts() {
109
+ return this.wiredAccounts.data || [];
110
+ }
111
+ }
112
+ ```
113
+
114
+ ### 3. Imperative Apex (Only When Wire Won't Work)
115
+
116
+ ```javascript
117
+ import { LightningElement, api } from 'lwc';
118
+ import processRecords from '@salesforce/apex/RecordService.processRecords';
119
+ import { ShowToastEvent } from 'lightning/platformShowToastEvent';
120
+
121
+ export default class RecordProcessor extends LightningElement {
122
+ @api recordId;
123
+ isProcessing = false;
124
+
125
+ async handleProcess() {
126
+ this.isProcessing = true;
127
+ try {
128
+ const result = await processRecords({ recordId: this.recordId });
129
+ this.dispatchEvent(new ShowToastEvent({
130
+ title: 'Success',
131
+ message: result.message,
132
+ variant: 'success'
133
+ }));
134
+ } catch (error) {
135
+ this.dispatchEvent(new ShowToastEvent({
136
+ title: 'Error',
137
+ message: error.body?.message || 'Processing failed',
138
+ variant: 'error'
139
+ }));
140
+ } finally {
141
+ this.isProcessing = false;
142
+ }
143
+ }
144
+ }
145
+ ```
146
+
147
+ ### 4. CSS — No Inline Styles
148
+
149
+ ```css
150
+ /* componentName.css */
151
+
152
+ /* Use SLDS design tokens via custom properties */
153
+ :host {
154
+ --card-spacing: var(--lwc-spacingMedium, 1rem);
155
+ }
156
+
157
+ .container {
158
+ padding: var(--card-spacing);
159
+ }
160
+
161
+ .highlight {
162
+ background-color: var(--lwc-colorBackgroundHighlight, #fffbe5);
163
+ border-radius: var(--lwc-borderRadiusMedium, 0.25rem);
164
+ }
165
+
166
+ /* ❌ NEVER do this in the template:
167
+ <div style="padding: 16px; color: red;"> */
168
+ ```
169
+
170
+ ### 5. Meta XML Config
171
+
172
+ ```xml
173
+ <?xml version="1.0" encoding="UTF-8"?>
174
+ <LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
175
+ <apiVersion>66.0</apiVersion>
176
+ <isExposed>true</isExposed>
177
+ <targets>
178
+ <target>lightning__RecordPage</target>
179
+ <target>lightning__AppPage</target>
180
+ <target>lightning__HomePage</target>
181
+ </targets>
182
+ <targetConfigs>
183
+ <targetConfig targets="lightning__RecordPage">
184
+ <objects>
185
+ <object>Account</object>
186
+ </objects>
187
+ <property name="title" type="String" default="Account Summary" />
188
+ </targetConfig>
189
+ </targetConfigs>
190
+ </LightningComponentBundle>
191
+ ```
192
+
193
+ ---
194
+
195
+ ## Event Communication
196
+
197
+ | Pattern | When | Direction |
198
+ |---------|------|-----------|
199
+ | `CustomEvent` | Parent-child | Child → Parent |
200
+ | `@api` property | Parent-child | Parent → Child |
201
+ | Lightning Message Service (LMS) | Cross-component (unrelated) | Any → Any |
202
+ | `pubsub` module | Legacy (avoid) | — |
203
+
204
+ ```javascript
205
+ // Child: dispatch custom event
206
+ this.dispatchEvent(new CustomEvent('recordselected', {
207
+ detail: { recordId: this.selectedId },
208
+ bubbles: false, // Don't bubble by default
209
+ composed: false // Don't cross shadow DOM by default
210
+ }));
211
+
212
+ // Parent: listen in template
213
+ // <c-child-component onrecordselected={handleRecordSelected}></c-child-component>
214
+ handleRecordSelected(event) {
215
+ const selectedId = event.detail.recordId;
216
+ }
217
+ ```
218
+
219
+ ---
220
+
221
+ ## Checklist Before Returning LWC Code
222
+
223
+ - [ ] camelCase component folder name
224
+ - [ ] Handles loading, error, and empty states
225
+ - [ ] Uses `@wire` (imperative only when necessary)
226
+ - [ ] No inline styles — CSS in component `.css` file
227
+ - [ ] Uses SLDS classes and design tokens
228
+ - [ ] Meta XML has correct API version (66.0) and targets
229
+ - [ ] Error messages displayed to user via toast or inline
230
+ - [ ] Event names are lowercase with no hyphens
@@ -0,0 +1,181 @@
1
+ # Security Rules
2
+
3
+ > Instructions for AI agents on security enforcement, CRUD/FLS, sharing, and AppExchange review readiness.
4
+
5
+ ---
6
+
7
+ ## Non-Negotiable Security Rules
8
+
9
+ ### 1. CRUD / FLS Enforcement
10
+
11
+ **Every SOQL query must enforce field-level security.**
12
+
13
+ ```apex
14
+ // ✅ API v60.0+ — Use USER_MODE (preferred)
15
+ List<Account> accounts = [
16
+ SELECT Id, Name, Industry
17
+ FROM Account
18
+ WHERE Id IN :ids
19
+ WITH USER_MODE
20
+ ];
21
+
22
+ // ✅ API v48.0+ — Alternative
23
+ List<Account> accounts = [
24
+ SELECT Id, Name, Industry
25
+ FROM Account
26
+ WHERE Id IN :ids
27
+ WITH SECURITY_ENFORCED
28
+ ];
29
+ ```
30
+
31
+ **DML with FLS enforcement:**
32
+
33
+ ```apex
34
+ // Strip inaccessible fields before DML
35
+ SObjectAccessDecision decision = Security.stripInaccessible(
36
+ AccessType.CREATABLE, recordsToInsert
37
+ );
38
+ insert decision.getRecords();
39
+
40
+ // Check which fields were stripped
41
+ Map<String, Set<String>> removedFields = decision.getRemovedFields();
42
+ if (!removedFields.isEmpty()) {
43
+ Logger.warn('Fields stripped due to FLS: ' + removedFields);
44
+ }
45
+ ```
46
+
47
+ ### 2. Sharing Model
48
+
49
+ ```apex
50
+ // ✅ DEFAULT — Always use with sharing
51
+ public with sharing class AccountService { }
52
+
53
+ // ⚠️ EXCEPTION — Only with documented justification
54
+ // @reason: Needs cross-user visibility for admin batch job
55
+ public without sharing class AdminBatchService { }
56
+
57
+ // ❌ NEVER — Inherited sharing in new code
58
+ public class SomeService { } // Sharing context is unpredictable
59
+ ```
60
+
61
+ ### 3. SOQL Injection Prevention
62
+
63
+ ```apex
64
+ // ✅ CORRECT — Bind variables
65
+ String searchTerm = '%' + String.escapeSingleQuotes(userInput) + '%';
66
+ List<Account> results = [
67
+ SELECT Id, Name
68
+ FROM Account
69
+ WHERE Name LIKE :searchTerm
70
+ WITH USER_MODE
71
+ ];
72
+
73
+ // ✅ For dynamic SOQL — Use Database.query with bind variables
74
+ String query = 'SELECT Id, Name FROM Account WHERE Industry = :industry WITH USER_MODE';
75
+ List<Account> results = Database.query(query);
76
+
77
+ // ❌ NEVER — String concatenation in SOQL
78
+ String query = 'SELECT Id FROM Account WHERE Name = \'' + userInput + '\''; // INJECTION!
79
+ ```
80
+
81
+ ### 4. XSS Prevention (LWC/Aura)
82
+
83
+ ```javascript
84
+ // ✅ LWC automatically escapes template expressions
85
+ // {accountName} in template is auto-escaped
86
+
87
+ // ❌ NEVER use lwc:dom="manual" to insert raw HTML from user input
88
+ // ❌ NEVER use innerHTML with unescaped user data
89
+ ```
90
+
91
+ ### 5. No Hardcoded Secrets
92
+
93
+ ```apex
94
+ // ❌ NEVER
95
+ String apiKey = 'sk-12345abcdef'; // Hardcoded credential!
96
+ String endpoint = 'https://api.external.com/v1'; // Hardcoded endpoint!
97
+
98
+ // ✅ ALWAYS — Named Credentials
99
+ HttpRequest req = new HttpRequest();
100
+ req.setEndpoint('callout:External_API/v1/resource');
101
+ // Auth header is automatically added by Named Credential
102
+ ```
103
+
104
+ ---
105
+
106
+ ## Security Review Checklist (Code Review)
107
+
108
+ Run this checklist on every PR:
109
+
110
+ 1. ✅ **CRUD/FLS enforced** — `WITH USER_MODE` or `WITH SECURITY_ENFORCED` on all SOQL
111
+ 2. ✅ **Sharing enforced** — `with sharing` on all classes (exceptions documented)
112
+ 3. ✅ **No SOQL injection** — Bind variables, `String.escapeSingleQuotes()`
113
+ 4. ✅ **No XSS** — No raw HTML insertion, template auto-escaping used
114
+ 5. ✅ **No hardcoded credentials** — Named Credentials for all external auth
115
+ 6. ✅ **No hardcoded IDs** — Custom Labels or Custom Metadata Types
116
+ 7. ✅ **stripInaccessible** — Used before DML with external/untrusted data
117
+ 8. ✅ **Error messages** — Don't expose internal stack traces to users
118
+ 9. ✅ **Test coverage** — Permission-based tests with `System.runAs()`
119
+
120
+ ---
121
+
122
+ ## AppExchange Security Review Readiness
123
+
124
+ ### Mandatory Scans
125
+
126
+ | Tool | What It Checks | Required? |
127
+ |------|---------------|-----------|
128
+ | **Salesforce Code Analyzer** | PMD rules, Apex best practices | ✅ Recommended |
129
+ | **Checkmarx** | SAST — Apex, VF, Lightning | ✅ Required for AppExchange |
130
+ | **OWASP ZAP / Burp Suite** | DAST — Runtime vulnerabilities | ✅ Required (Chimera retired June 2025) |
131
+
132
+ ### Top Failure Reasons
133
+
134
+ 1. **Missing CRUD/FLS** — Most common failure. Fix: `WITH USER_MODE` everywhere.
135
+ 2. **SOQL Injection** — Dynamic queries without bind variables.
136
+ 3. **XSS** — Unescaped output in Visualforce/Aura.
137
+ 4. **Broken Access Control** — Missing `with sharing`, overly permissive profiles.
138
+ 5. **Insecure Authentication** — Hardcoded credentials, no Named Credentials.
139
+
140
+ ### 2026 Compliance Requirements
141
+
142
+ | Requirement | Deadline | Impact |
143
+ |------------|----------|--------|
144
+ | MFA enforcement | Mid-2026 | All users must have MFA enabled |
145
+ | Phishing-resistant MFA | Mid-2026 | Admin roles require hardware keys or passkeys |
146
+ | Login IP restrictions | Ongoing | Stricter enforcement on elevated profiles |
147
+
148
+ ---
149
+
150
+ ## Security Testing Template
151
+
152
+ ```apex
153
+ @IsTest
154
+ private class SecurityTest {
155
+
156
+ @IsTest
157
+ static void testCrudFls_RestrictedUser() {
158
+ // Create user with minimum permissions
159
+ User restrictedUser = TestDataFactory.createStandardUser();
160
+ insert restrictedUser;
161
+
162
+ System.runAs(restrictedUser) {
163
+ Test.startTest();
164
+
165
+ // Verify FLS is enforced — user shouldn't see sensitive fields
166
+ try {
167
+ List<Account> accounts = AccountSelector.getByIds(
168
+ new Set<Id>{ /* test account IDs */ }
169
+ );
170
+ // Verify restricted fields are not accessible
171
+ } catch (System.QueryException e) {
172
+ // Expected: WITH USER_MODE blocks inaccessible fields
173
+ System.assert(e.getMessage().contains('insufficient access'),
174
+ 'Should enforce FLS for restricted user');
175
+ }
176
+
177
+ Test.stopTest();
178
+ }
179
+ }
180
+ }
181
+ ```