slashdev 1.0.0 → 1.2.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 +5 -4
- package/GETTING-STARTED.md +68 -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/claude-skills/secure-deploy/SKILL.md +219 -0
- package/hooks/pre-install-guard.sh +88 -0
- package/package.json +1 -1
- package/src/commands/setup-internals.js +84 -0
- package/src/commands/setup.js +8 -2
- package/src/commands/update.js +5 -1
package/CLAUDE.md
CHANGED
|
@@ -45,11 +45,12 @@ The skill runner loads the system prompt, gathers project context via `codebase.
|
|
|
45
45
|
**Auth (`src/auth/`):** Interactive login with API key validation, stored separately in credentials config.
|
|
46
46
|
|
|
47
47
|
**Claude Code integration (`src/commands/` + `hooks/` + `claude-skills/`):**
|
|
48
|
-
- `src/commands/setup.js` — Prompts for `@slashdev.io` email, writes `~/.slashdev/config.json`, copies hooks to `~/.claude/hooks/`, copies skills to `~/.claude/skills/`, registers Stop
|
|
49
|
-
- `src/commands/update.js` — Re-copies hooks/skills without re-prompting for email, updates packageVersion in config
|
|
50
|
-
- `src/commands/setup-internals.js` — Shared `installHooks()` and `
|
|
48
|
+
- `src/commands/setup.js` — Prompts for `@slashdev.io` email, writes `~/.slashdev/config.json`, copies hooks to `~/.claude/hooks/`, copies skills to `~/.claude/skills/`, registers Stop + PreToolUse hooks in `~/.claude/settings.json`, writes Slashdev rules section to `~/.claude/CLAUDE.md`
|
|
49
|
+
- `src/commands/update.js` — Re-copies hooks/skills without re-prompting for email, updates packageVersion in config, refreshes the Slashdev rules section in `~/.claude/CLAUDE.md`
|
|
50
|
+
- `src/commands/setup-internals.js` — Shared `installHooks()`, `installSkills()`, `installGstack()`, and `writeGlobalClaudeMd()` used by both setup and update. The global CLAUDE.md writer is idempotent — it manages a single section bracketed by `<!-- SLASHDEV:RULES:START -->` / `<!-- SLASHDEV:RULES:END -->` markers, leaving any other user content untouched.
|
|
51
51
|
- `hooks/post-response.sh` — Claude Code Stop hook that reads JSON from stdin, extracts session/prompt/response, POSTs to Slashdev logging API (fire-and-forget, async curl)
|
|
52
|
-
- `
|
|
52
|
+
- `hooks/pre-install-guard.sh` — Claude Code PreToolUse hook for the Bash tool. Reads tool-call JSON from stdin, detects bare dependency install commands (`npm/pnpm/yarn/bun install`, `composer install`, `pip install`, etc.), and returns `{"permissionDecision":"deny","message":"..."}` to force a retry with the `sfw` (Socket Firewall) prefix. Strips leading `cd <dir> &&` and env-var prefixes before matching. Fails open on parse errors so it can never break Claude Code. Smoke tests: `echo '{"tool_name":"Bash","tool_input":{"command":"npm install lodash"}}' | bash hooks/pre-install-guard.sh`.
|
|
53
|
+
- `claude-skills/` — Claude Code skill files (SKILL.md with YAML frontmatter) copied to `~/.claude/skills/` during setup. Current skills: agentswarm, code-review, pr-description, scope-estimate, bug-diagnosis, frontend-design, secure-deploy. The `secure-deploy` skill walks Claude through retrofitting CI/CD configs (GitHub Actions, Dockerfiles, GitLab CI, deploy scripts, package.json) to wrap dependency installs with `sfw`.
|
|
53
54
|
- `bin/check-setup.js` — Postinstall script that prints setup reminder if `~/.slashdev/config.json` is missing
|
|
54
55
|
|
|
55
56
|
**Connections system (`src/connections/`):**
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# Slashdev CLI — Getting Started
|
|
2
|
+
|
|
3
|
+
## Install
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
npm install -g slashdev
|
|
7
|
+
slashdev setup
|
|
8
|
+
```
|
|
9
|
+
|
|
10
|
+
You'll be prompted for your `@slashdev.io` email. After setup, all skills are immediately available in Claude Code.
|
|
11
|
+
|
|
12
|
+
## The Big One: Agentswarm
|
|
13
|
+
|
|
14
|
+
In any project, open Claude Code and run:
|
|
15
|
+
|
|
16
|
+
```
|
|
17
|
+
/agentswarm "describe your task here"
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
This launches a full agent team that automatically:
|
|
21
|
+
1. **Analyzes** your codebase and detects the stack
|
|
22
|
+
2. **Plans** the implementation with test coverage
|
|
23
|
+
3. **Implements** the code (backend + frontend in parallel)
|
|
24
|
+
4. **Reviews** code quality, security, and performance
|
|
25
|
+
5. **QA tests** — verifies test quality and audits API request counts per page
|
|
26
|
+
|
|
27
|
+
It works with Laravel, React, Flutter, and whatever else is in the project.
|
|
28
|
+
|
|
29
|
+
## Other Slashdev Skills
|
|
30
|
+
|
|
31
|
+
| Command | What it does |
|
|
32
|
+
|---------|-------------|
|
|
33
|
+
| `/frontend-design` | Distinctive UI design — avoids generic AI aesthetics |
|
|
34
|
+
| `/code-review` | Security, performance, and maintainability review |
|
|
35
|
+
| `/pr-description` | Generate PR descriptions from your diff |
|
|
36
|
+
| `/scope-estimate` | Effort estimation for tasks |
|
|
37
|
+
| `/bug-diagnosis` | Systematic root-cause analysis |
|
|
38
|
+
|
|
39
|
+
## gstack Skills (Bundled)
|
|
40
|
+
|
|
41
|
+
We've bundled [gstack](https://github.com/garrytan/gstack) — 29 additional skills from Garry Tan. Highlights:
|
|
42
|
+
|
|
43
|
+
| Command | What it does |
|
|
44
|
+
|---------|-------------|
|
|
45
|
+
| `/plan-ceo-review` | CEO-level plan review — challenges premises, finds the 10-star product |
|
|
46
|
+
| `/plan-eng-review` | Eng manager review — locks in architecture and edge cases |
|
|
47
|
+
| `/qa` | Opens a real browser, finds bugs, fixes them, re-verifies |
|
|
48
|
+
| `/ship` | Automates testing, review, version bump, and PR creation |
|
|
49
|
+
| `/review` | Pre-landing PR review for production bugs |
|
|
50
|
+
| `/cso` | Security audit with OWASP Top 10 and secrets archaeology |
|
|
51
|
+
| `/investigate` | Systematic debugging — no fixes without root cause |
|
|
52
|
+
| `/design-consultation` | Builds a complete design system from scratch |
|
|
53
|
+
| `/retro` | Weekly engineering retrospective with metrics |
|
|
54
|
+
| `/careful` | Warns before destructive commands |
|
|
55
|
+
|
|
56
|
+
All gstack skills are available immediately after `slashdev setup`.
|
|
57
|
+
|
|
58
|
+
## Heads Up: Prompt Logging
|
|
59
|
+
|
|
60
|
+
All prompts and responses in Claude Code are logged to our API so we can run analytics and help improve the team's prompting. This happens automatically via a background hook — no action needed on your part.
|
|
61
|
+
|
|
62
|
+
## Updating
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
slashdev update
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
This pulls the latest skills and hooks. If you run into issues, `slashdev setup` will re-initialize everything.
|
|
@@ -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.
|