slashdev 1.1.0 → 1.3.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.
- package/CLAUDE.md +1 -1
- package/claude-skills/hormozi/SKILL.md +133 -0
- package/claude-skills/hormozi/references/core-four-leads.md +195 -0
- package/claude-skills/hormozi/references/critique-rubric.md +132 -0
- package/claude-skills/hormozi/references/enhancements.md +161 -0
- package/claude-skills/hormozi/references/examples.md +208 -0
- package/claude-skills/hormozi/references/grand-slam-offer.md +105 -0
- package/claude-skills/hormozi/references/lead-magnets.md +115 -0
- package/claude-skills/hormozi/references/problem-solution-stack.md +125 -0
- package/claude-skills/hormozi/references/value-equation.md +105 -0
- package/claude-skills/salesforce-development/SKILL.md +341 -0
- package/claude-skills/salesforce-development/references/apex-patterns.md +388 -0
- package/claude-skills/salesforce-development/references/lwc-patterns.md +374 -0
- package/claude-skills/salesforce-development/references/testing-patterns.md +438 -0
- package/package.json +1 -1
|
@@ -0,0 +1,341 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: salesforce-development
|
|
3
|
+
description: >
|
|
4
|
+
Use this skill whenever you are working with Salesforce development — Apex classes, triggers,
|
|
5
|
+
Lightning Web Components (LWC), Flows, SOQL/SOSL queries, or Salesforce integrations. Trigger
|
|
6
|
+
this skill when you encounter ANY of the following: editing .cls, .trigger, or .apex files;
|
|
7
|
+
working inside LWC bundles (.js/.html/.css paired with .js-meta.xml); any code inside a
|
|
8
|
+
force-app/ directory or an sfdx-project.json workspace; mentions of Apex, Salesforce, SFDX,
|
|
9
|
+
SF CLI, Lightning Web Components, governor limits, SObject triggers, validation rules,
|
|
10
|
+
permission sets, sharing rules, Connected Apps, Named Credentials, Custom Metadata Types,
|
|
11
|
+
Platform Events, or Change Data Capture — even without the explicit words "Salesforce
|
|
12
|
+
development." Salesforce is a multi-tenant platform where code that looks correct by general
|
|
13
|
+
programming standards WILL fail in production without platform-specific patterns. Consult
|
|
14
|
+
this skill rather than relying on general programming instincts.
|
|
15
|
+
version: "1.0"
|
|
16
|
+
owner: michael@slashdev.io
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
# Salesforce Development
|
|
20
|
+
|
|
21
|
+
Salesforce is a multi-tenant platform. Every line of Apex runs inside shared infrastructure
|
|
22
|
+
with hard governor limits — CPU time, heap size, SOQL queries, DML statements, callouts — all
|
|
23
|
+
capped per transaction. Code that works in a unit test with 1 record will blow up when a data
|
|
24
|
+
loader pushes 200. These five rules are non-negotiable.
|
|
25
|
+
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
## Non-Negotiable Rules
|
|
29
|
+
|
|
30
|
+
### 1. Bulkify everything
|
|
31
|
+
|
|
32
|
+
Triggers fire on batches of up to 200 records. A single SOQL query or DML statement inside a
|
|
33
|
+
loop means 200 queries or 200 DML operations — both exceed the 100-query / 150-DML governor
|
|
34
|
+
limit and throw a runtime exception.
|
|
35
|
+
|
|
36
|
+
```apex
|
|
37
|
+
// WRONG — SOQL inside a loop
|
|
38
|
+
trigger SetAccountRating on Contact (after insert) {
|
|
39
|
+
for (Contact c : Trigger.new) {
|
|
40
|
+
Account a = [SELECT Id, Rating FROM Account WHERE Id = :c.AccountId];
|
|
41
|
+
a.Rating = 'Hot';
|
|
42
|
+
update a;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// RIGHT — collect, query once, DML once
|
|
47
|
+
trigger SetAccountRating on Contact (after insert) {
|
|
48
|
+
Set<Id> accountIds = new Set<Id>();
|
|
49
|
+
for (Contact c : Trigger.new) {
|
|
50
|
+
accountIds.add(c.AccountId);
|
|
51
|
+
}
|
|
52
|
+
List<Account> accounts = [SELECT Id, Rating FROM Account WHERE Id IN :accountIds];
|
|
53
|
+
for (Account a : accounts) {
|
|
54
|
+
a.Rating = 'Hot';
|
|
55
|
+
}
|
|
56
|
+
update accounts;
|
|
57
|
+
}
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
### 2. Tests are not optional, and coverage is not the goal
|
|
61
|
+
|
|
62
|
+
Salesforce enforces 75% code coverage for production deployment, but passing that bar with
|
|
63
|
+
empty assertions is worthless. Every test must:
|
|
64
|
+
|
|
65
|
+
- **Create its own data** — never use `@IsTest(SeeAllData=true)`.
|
|
66
|
+
- **Test the bulk path** — insert 200+ records to prove bulkification.
|
|
67
|
+
- **Use `Test.startTest()` / `Test.stopTest()`** — resets governor limits and forces async
|
|
68
|
+
jobs to complete synchronously.
|
|
69
|
+
- **Assert on outcomes** — verify field values, record counts, error messages. A test
|
|
70
|
+
without assertions is not a test.
|
|
71
|
+
|
|
72
|
+
```apex
|
|
73
|
+
@IsTest
|
|
74
|
+
private class SetAccountRatingTest {
|
|
75
|
+
@IsTest
|
|
76
|
+
static void shouldSetRatingForBulkContacts() {
|
|
77
|
+
List<Account> accounts = TestDataFactory.createAccounts(5, true);
|
|
78
|
+
List<Contact> contacts = new List<Contact>();
|
|
79
|
+
for (Account a : accounts) {
|
|
80
|
+
for (Integer i = 0; i < 50; i++) {
|
|
81
|
+
contacts.add(new Contact(FirstName = 'Test', LastName = 'Contact' + i, AccountId = a.Id));
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
Test.startTest();
|
|
86
|
+
insert contacts; // 250 contacts — proves bulk handling
|
|
87
|
+
Test.stopTest();
|
|
88
|
+
|
|
89
|
+
List<Account> updated = [SELECT Rating FROM Account WHERE Id IN :accounts];
|
|
90
|
+
for (Account a : updated) {
|
|
91
|
+
Assert.areEqual('Hot', a.Rating, 'Account rating should be Hot after contact insert');
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
### 3. Respect the security model
|
|
98
|
+
|
|
99
|
+
Apex runs in **system mode** by default — it bypasses field-level security and sharing rules.
|
|
100
|
+
This is a security risk in any context where user-supplied data or user-facing UI is involved.
|
|
101
|
+
|
|
102
|
+
- **Default every class to `with sharing`**. This enforces the running user's record-level
|
|
103
|
+
access (sharing rules, org-wide defaults, role hierarchy).
|
|
104
|
+
- **Use `without sharing` only with a documented reason** — e.g., a service class that must
|
|
105
|
+
aggregate data across all accounts for a rollup.
|
|
106
|
+
- **Enforce FLS** on every SOQL query that surfaces data to users:
|
|
107
|
+
- `WITH SECURITY_ENFORCED` in the query (throws if user lacks field access)
|
|
108
|
+
- `Security.stripInaccessible(AccessType.READABLE, records)` after the query (silently
|
|
109
|
+
strips inaccessible fields)
|
|
110
|
+
|
|
111
|
+
```apex
|
|
112
|
+
// RIGHT — with sharing + FLS enforcement
|
|
113
|
+
public with sharing class AccountService {
|
|
114
|
+
public List<Account> getVisibleAccounts() {
|
|
115
|
+
return [SELECT Id, Name, Industry FROM Account WITH SECURITY_ENFORCED];
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
### 4. Never hardcode endpoints or credentials
|
|
121
|
+
|
|
122
|
+
All HTTP callouts go through **Named Credentials**. Named Credentials manage the endpoint URL,
|
|
123
|
+
authentication scheme (OAuth, certificate, password), and per-user or per-org identity — all
|
|
124
|
+
configured in Setup, not in code.
|
|
125
|
+
|
|
126
|
+
```apex
|
|
127
|
+
// WRONG — hardcoded endpoint and bearer token
|
|
128
|
+
HttpRequest req = new HttpRequest();
|
|
129
|
+
req.setEndpoint('https://api.example.com/v1/accounts');
|
|
130
|
+
req.setHeader('Authorization', 'Bearer ' + myToken);
|
|
131
|
+
|
|
132
|
+
// RIGHT — Named Credential handles URL + auth
|
|
133
|
+
HttpRequest req = new HttpRequest();
|
|
134
|
+
req.setEndpoint('callout:ExampleAPI/v1/accounts');
|
|
135
|
+
req.setMethod('GET');
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
### 5. Prefer declarative over code
|
|
139
|
+
|
|
140
|
+
Before writing Apex, evaluate whether the requirement can be met with:
|
|
141
|
+
|
|
142
|
+
- **Flow** — screen flows for user input, record-triggered flows for automation, scheduled
|
|
143
|
+
flows for batch-like processing
|
|
144
|
+
- **Validation rules** — field-level constraints with error messages
|
|
145
|
+
- **Formula fields** — derived values without storage cost
|
|
146
|
+
- **Roll-up summary fields** — aggregations on master-detail relationships
|
|
147
|
+
|
|
148
|
+
Apex is justified when you need: complex branching logic, HTTP callouts with custom error
|
|
149
|
+
handling, Batch Apex for high-volume processing, or unit-testable mocking of dependencies.
|
|
150
|
+
|
|
151
|
+
---
|
|
152
|
+
|
|
153
|
+
## Apex Patterns
|
|
154
|
+
|
|
155
|
+
### One trigger per object, handler class delegation
|
|
156
|
+
|
|
157
|
+
Never put logic in a `.trigger` file. Delegate to a handler class so logic is testable,
|
|
158
|
+
bypassable, and composable.
|
|
159
|
+
|
|
160
|
+
```apex
|
|
161
|
+
// AccountTrigger.trigger
|
|
162
|
+
trigger AccountTrigger on Account (before insert, before update, after insert, after update) {
|
|
163
|
+
new AccountTriggerHandler().run();
|
|
164
|
+
}
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
The handler extends a `TriggerHandler` base class with virtual methods for each context
|
|
168
|
+
(`beforeInsert`, `afterUpdate`, etc.). See `references/apex-patterns.md` for the full base
|
|
169
|
+
class with bypass and recursion control.
|
|
170
|
+
|
|
171
|
+
### SOQL guidance
|
|
172
|
+
|
|
173
|
+
- **Use indexed filters** — `Id`, `Name`, `CreatedDate`, `SystemModstamp`, `RecordTypeId`,
|
|
174
|
+
`foreign key fields`, and any field with a custom index.
|
|
175
|
+
- **Use bind variables** — `WHERE Id IN :idSet` — never concatenate strings into queries.
|
|
176
|
+
- **Be selective** — queries on large objects must return < 100K rows or use a selective filter
|
|
177
|
+
that narrows via an indexed field first.
|
|
178
|
+
- **Never use `SELECT *`** — Apex doesn't support it, but don't emulate it with
|
|
179
|
+
`DescribeSObjectResult.getFields()` loops. Explicitly list fields.
|
|
180
|
+
|
|
181
|
+
### Async flavor selection
|
|
182
|
+
|
|
183
|
+
| Pattern | Use when | Key constraint |
|
|
184
|
+
|---------|----------|----------------|
|
|
185
|
+
| `@future` | Legacy — simple fire-and-forget | No chaining, no complex types, 50 calls/txn |
|
|
186
|
+
| `Queueable` | **Default async choice** — callouts, chaining, complex types | 50 enqueued/txn, chain depth varies by edition |
|
|
187
|
+
| `Batch Apex` | Processing > 50K records | 5 concurrent batches, scope of 200 default |
|
|
188
|
+
| `Schedulable` | Cron-based execution | Enqueue a Queueable or start a Batch from `execute()` |
|
|
189
|
+
|
|
190
|
+
**Triggers cannot make synchronous callouts.** From a trigger, enqueue a `Queueable` with
|
|
191
|
+
`Database.AllowsCallouts` or call an `@future(callout=true)` method.
|
|
192
|
+
|
|
193
|
+
---
|
|
194
|
+
|
|
195
|
+
## Lightning Web Components
|
|
196
|
+
|
|
197
|
+
### Bundle structure
|
|
198
|
+
|
|
199
|
+
Every LWC lives in a directory under `force-app/main/default/lwc/`:
|
|
200
|
+
|
|
201
|
+
```
|
|
202
|
+
myComponent/
|
|
203
|
+
├── myComponent.js // Controller — class extending LightningElement
|
|
204
|
+
├── myComponent.html // Template — HTML with lwc directives
|
|
205
|
+
├── myComponent.css // Scoped styles (optional)
|
|
206
|
+
└── myComponent.js-meta.xml // Metadata — API version, targets, visibility
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
The `.js-meta.xml` is required. Without it, the component won't deploy.
|
|
210
|
+
|
|
211
|
+
### @wire vs imperative Apex
|
|
212
|
+
|
|
213
|
+
- **`@wire`** — for **reads**. Cacheable, reactive, automatically re-fetches when reactive
|
|
214
|
+
parameters change. The Apex method must be annotated `@AuraEnabled(cacheable=true)`.
|
|
215
|
+
- **Imperative** — for **writes** or when you need fine-grained control over timing. Call
|
|
216
|
+
the imported Apex method as a promise. The method needs `@AuraEnabled` but NOT `cacheable`.
|
|
217
|
+
|
|
218
|
+
```javascript
|
|
219
|
+
import getAccounts from '@salesforce/apex/AccountController.getAccounts';
|
|
220
|
+
import saveAccount from '@salesforce/apex/AccountController.saveAccount';
|
|
221
|
+
|
|
222
|
+
// Wire for reads
|
|
223
|
+
@wire(getAccounts, { industry: '$selectedIndustry' })
|
|
224
|
+
wiredAccounts;
|
|
225
|
+
|
|
226
|
+
// Imperative for writes
|
|
227
|
+
async handleSave() {
|
|
228
|
+
try {
|
|
229
|
+
await saveAccount({ account: this.record });
|
|
230
|
+
this.dispatchEvent(new ShowToastEvent({ title: 'Saved', variant: 'success' }));
|
|
231
|
+
} catch (error) {
|
|
232
|
+
this.dispatchEvent(new ShowToastEvent({ title: 'Error', message: reduceErrors(error).join(', '), variant: 'error' }));
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
### Prefer SLDS base components
|
|
238
|
+
|
|
239
|
+
Use `lightning-input`, `lightning-datatable`, `lightning-combobox`, `lightning-card`,
|
|
240
|
+
`lightning-button`, and other base components over custom HTML. They handle accessibility,
|
|
241
|
+
responsive layout, and Salesforce theming automatically.
|
|
242
|
+
|
|
243
|
+
See `references/lwc-patterns.md` for parent-child communication, Lightning Message Service,
|
|
244
|
+
`refreshApex`, navigation, and `@salesforce/*` imports.
|
|
245
|
+
|
|
246
|
+
---
|
|
247
|
+
|
|
248
|
+
## Flow vs Apex Decision Framework
|
|
249
|
+
|
|
250
|
+
| Criteria | Use Flow | Use Apex |
|
|
251
|
+
|----------|----------|----------|
|
|
252
|
+
| Simple field updates on save | Yes | No |
|
|
253
|
+
| Screen-based user input | Yes | No |
|
|
254
|
+
| Complex branching (> 5 decision nodes) | No | Yes |
|
|
255
|
+
| HTTP callouts with error handling | No | Yes |
|
|
256
|
+
| Processing > 50K records | No | Yes (Batch Apex) |
|
|
257
|
+
| Need unit-testable mocking | No | Yes |
|
|
258
|
+
| Team has no Apex developers | Yes | No |
|
|
259
|
+
|
|
260
|
+
Flows and Apex compose: expose Apex logic as `@InvocableMethod` for Flows to call, or invoke
|
|
261
|
+
a Flow from Apex via `Flow.Interview`.
|
|
262
|
+
|
|
263
|
+
---
|
|
264
|
+
|
|
265
|
+
## Project Structure and Metadata
|
|
266
|
+
|
|
267
|
+
Standard SFDX source format layout:
|
|
268
|
+
|
|
269
|
+
```
|
|
270
|
+
force-app/
|
|
271
|
+
└── main/
|
|
272
|
+
└── default/
|
|
273
|
+
├── classes/ // Apex classes (.cls + .cls-meta.xml)
|
|
274
|
+
├── triggers/ // Apex triggers (.trigger + .trigger-meta.xml)
|
|
275
|
+
├── lwc/ // LWC bundles (one directory per component)
|
|
276
|
+
├── aura/ // Aura components (legacy — do not create new ones)
|
|
277
|
+
├── objects/ // Custom objects and fields
|
|
278
|
+
├── flows/ // Flow definitions (.flow-meta.xml)
|
|
279
|
+
├── permissionsets/ // Permission sets
|
|
280
|
+
├── namedCredentials/ // Named Credentials
|
|
281
|
+
├── customMetadata/ // Custom Metadata Type records
|
|
282
|
+
├── layouts/ // Page layouts
|
|
283
|
+
├── flexipages/ // Lightning pages
|
|
284
|
+
└── staticresources/ // Static resources
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
Key conventions:
|
|
288
|
+
- Every `.cls` and `.trigger` file requires a companion `-meta.xml` file
|
|
289
|
+
- Custom objects end in `__c`, custom fields in `__c`, custom metadata types in `__mdt`
|
|
290
|
+
- `sfdx-project.json` at the repo root defines package directories and API version
|
|
291
|
+
- `.forceignore` works like `.gitignore` — controls what deploys
|
|
292
|
+
|
|
293
|
+
---
|
|
294
|
+
|
|
295
|
+
## Anti-Patterns to Reject
|
|
296
|
+
|
|
297
|
+
- **SOQL or DML inside loops** — governor limit violation waiting to happen
|
|
298
|
+
- **Logic in `.trigger` files** — untestable, unbypassable, unmaintainable
|
|
299
|
+
- **`@IsTest(SeeAllData=true)`** — couples tests to org data, breaks in sandboxes
|
|
300
|
+
- **Hardcoded credentials or endpoints** — use Named Credentials
|
|
301
|
+
- **Undocumented `without sharing`** — security risk; always comment why
|
|
302
|
+
- **New Aura components** — use LWC; Aura is legacy
|
|
303
|
+
- **Process Builder or Workflow Rules** — use Flow; both are deprecated
|
|
304
|
+
- **Tests with no assertions** — 75% coverage of nothing
|
|
305
|
+
- **Tests that depend on execution order** — each test must be independent
|
|
306
|
+
- **Catching and swallowing `DmlException`** — masks data integrity failures; catch, log/surface, then handle or rethrow
|
|
307
|
+
- **`SELECT` with string concatenation** — SOQL injection risk; use bind variables
|
|
308
|
+
- **Recursive triggers without recursion guards** — infinite loop potential
|
|
309
|
+
|
|
310
|
+
---
|
|
311
|
+
|
|
312
|
+
## When to Load Reference Files
|
|
313
|
+
|
|
314
|
+
- **`references/apex-patterns.md`** — full TriggerHandler base class, Queueable with chaining,
|
|
315
|
+
Batch Apex, Schedulable, integration callout patterns, custom exceptions
|
|
316
|
+
- **`references/lwc-patterns.md`** — parent-child communication, Lightning Message Service,
|
|
317
|
+
@wire with refreshApex, uiRecordApi vs Apex, error handling, NavigationMixin, @salesforce imports
|
|
318
|
+
- **`references/testing-patterns.md`** — TestDataFactory class, bulk testing, HTTP callout
|
|
319
|
+
mocking, async testing, System.runAs, @testSetup, modern Assert patterns
|
|
320
|
+
|
|
321
|
+
---
|
|
322
|
+
|
|
323
|
+
## Deployment Checklist
|
|
324
|
+
|
|
325
|
+
Before marking any Salesforce task as complete, verify:
|
|
326
|
+
|
|
327
|
+
1. **Test coverage** — run tests for all modified classes. Minimum 75% overall, aim for 85%+
|
|
328
|
+
on new code. Every test has meaningful assertions.
|
|
329
|
+
2. **Permission sets** — if you created new custom fields or objects, create or update a
|
|
330
|
+
permission set granting access. Do NOT modify profiles directly — profiles are org-specific
|
|
331
|
+
and cause deployment conflicts. Propose permission sets instead and flag profile changes as
|
|
332
|
+
risky.
|
|
333
|
+
3. **`.forceignore`** — respect it. Do not deploy files listed there.
|
|
334
|
+
4. **Meta.xml files** — every Apex class and trigger has a companion `-meta.xml` with the
|
|
335
|
+
correct API version.
|
|
336
|
+
5. **Ask about deployment workflow** — do not assume. The team may use SF CLI (`sf project
|
|
337
|
+
deploy start`), Change Sets, unlocked packages, Gearset, Copado, or another tool. Ask
|
|
338
|
+
before suggesting deployment commands.
|
|
339
|
+
6. **No hardcoded IDs** — record type IDs, user IDs, and org IDs vary between environments.
|
|
340
|
+
Use `Schema.SObjectType.Account.getRecordTypeInfosByDeveloperName()` or Custom Metadata
|
|
341
|
+
Types for environment-specific values.
|