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.
- package/License +21 -0
- package/README.md +106 -0
- package/bin/cli.js +85 -0
- package/package.json +44 -0
- package/templates/ai-dir/README.md +155 -0
- package/templates/ai-dir/agentforce.md +213 -0
- package/templates/ai-dir/architecture.md +123 -0
- package/templates/ai-dir/commands.md +276 -0
- package/templates/ai-dir/context-snapshots/TEMPLATE.md +64 -0
- package/templates/ai-dir/conventions.md +242 -0
- package/templates/ai-dir/current-state.md +113 -0
- package/templates/ai-dir/debugging-notes.md +165 -0
- package/templates/ai-dir/deployment.md +161 -0
- package/templates/ai-dir/integrations.md +199 -0
- package/templates/ai-dir/inventory.md +209 -0
- package/templates/ai-dir/known-issues.md +124 -0
- package/templates/ai-dir/org-context.md +110 -0
- package/templates/ai-dir/performance.md +312 -0
- package/templates/ai-dir/prompts/agentforce.md +163 -0
- package/templates/ai-dir/prompts/apex.md +165 -0
- package/templates/ai-dir/prompts/flows.md +125 -0
- package/templates/ai-dir/prompts/lwc.md +230 -0
- package/templates/ai-dir/prompts/security.md +181 -0
- package/templates/ai-dir/prompts/testing.md +269 -0
- package/templates/ai-dir/rules.md +238 -0
- package/templates/ai-dir/scripts/update_state.py +1406 -0
- package/templates/ai-dir/source-of-truth.md +180 -0
- package/templates/ai-dir/templates/Selector.cls +113 -0
- package/templates/ai-dir/templates/Service.cls +132 -0
- package/templates/ai-dir/templates/TestClass.cls +143 -0
- package/templates/ai-dir/templates/TriggerHandler.cls +67 -0
- package/templates/ai-dir/testing-strategy.md +342 -0
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
# Current State
|
|
2
|
+
|
|
3
|
+
> 🤖 **AUTO-UPDATED BY AI AGENTS** — This file is the project's living memory.
|
|
4
|
+
> Agents MUST update this file as they work (see `rules.md` for protocol).
|
|
5
|
+
> Humans: review periodically, correct if needed.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Project Status
|
|
10
|
+
|
|
11
|
+
**Last Updated:** 2026-05-22
|
|
12
|
+
**Sprint/Phase:** [Update with current sprint]
|
|
13
|
+
**Overall Status:** 🟢 On Track
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## Active Work
|
|
18
|
+
|
|
19
|
+
### In Progress
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
### Upcoming
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
### Recently Completed
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
---
|
|
29
|
+
|
|
30
|
+
## Blockers
|
|
31
|
+
|
|
32
|
+
| Blocker | Impact | Severity | Added |
|
|
33
|
+
|---------|--------|----------|-------|
|
|
34
|
+
| _None_ | | | |
|
|
35
|
+
|
|
36
|
+
---
|
|
37
|
+
|
|
38
|
+
## Decisions
|
|
39
|
+
|
|
40
|
+
| Date | Decision | Rationale |
|
|
41
|
+
|------|----------|-----------|
|
|
42
|
+
| | | |
|
|
43
|
+
|
|
44
|
+
---
|
|
45
|
+
|
|
46
|
+
## Files Changed This Session
|
|
47
|
+
|
|
48
|
+
| File | Action | Notes |
|
|
49
|
+
|------|--------|-------|
|
|
50
|
+
| | | |
|
|
51
|
+
|
|
52
|
+
---
|
|
53
|
+
|
|
54
|
+
## Environment State
|
|
55
|
+
|
|
56
|
+
| Environment | Last Deploy | Status | Notes |
|
|
57
|
+
|-------------|-----------|--------|-------|
|
|
58
|
+
| Dev Sandbox | — | 🟢 | |
|
|
59
|
+
| QA Sandbox | — | 🟢 | |
|
|
60
|
+
| UAT Sandbox | — | 🟢 | |
|
|
61
|
+
| Production | — | 🟢 | |
|
|
62
|
+
|
|
63
|
+
---
|
|
64
|
+
|
|
65
|
+
## Governor Limit Watch
|
|
66
|
+
|
|
67
|
+
| Limit | Current Usage | Max | Risk |
|
|
68
|
+
|-------|-------------|-----|------|
|
|
69
|
+
| API Calls (Daily) | 0 | 15,000 | 🟢 |
|
|
70
|
+
| Data Storage | 0 MB | 5 MB | 🟢 |
|
|
71
|
+
| File Storage | 0 MB | 20 MB | 🟢 |
|
|
72
|
+
|
|
73
|
+
---
|
|
74
|
+
|
|
75
|
+
## Technical Debt
|
|
76
|
+
|
|
77
|
+
<!-- Track tech debt items here. Move to known-issues.md if they become bugs. -->
|
|
78
|
+
|
|
79
|
+
| Item | Priority | Effort | Added | Status |
|
|
80
|
+
|------|----------|--------|-------|--------|
|
|
81
|
+
| _None tracked yet_ | | | | |
|
|
82
|
+
|
|
83
|
+
---
|
|
84
|
+
|
|
85
|
+
## Session Log
|
|
86
|
+
|
|
87
|
+
<!-- Agent: Prepend a new entry at the TOP of this section every session.
|
|
88
|
+
Use the format below. This is the project's history. NEVER delete old entries.
|
|
89
|
+
|
|
90
|
+
### YYYY-MM-DD | Agent Name | Session Goal
|
|
91
|
+
- ✅ What was completed
|
|
92
|
+
- 🟡 What's partially done
|
|
93
|
+
- ❌ What failed and why
|
|
94
|
+
- 💡 Key insight or decision
|
|
95
|
+
- **Files:** comma-separated list of files touched
|
|
96
|
+
-->
|
|
97
|
+
|
|
98
|
+
### [First session entry will appear here]
|
|
99
|
+
|
|
100
|
+
_No sessions recorded yet. The AI agent will begin logging here automatically._
|
|
101
|
+
|
|
102
|
+
---
|
|
103
|
+
|
|
104
|
+
## Next Session
|
|
105
|
+
|
|
106
|
+
<!-- Agent: Update this at the END of every session. The next agent reads this FIRST. -->
|
|
107
|
+
|
|
108
|
+
| Field | Value |
|
|
109
|
+
|-------|-------|
|
|
110
|
+
| **What to do first** | _Not set_ |
|
|
111
|
+
| **Context needed** | _Read current-state.md session log_ |
|
|
112
|
+
| **What NOT to do** | _Nothing blocked_ |
|
|
113
|
+
| **Key files to review** | _None_ |
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
# Debugging Notes
|
|
2
|
+
|
|
3
|
+
> Debugging techniques, tools, and log configurations for this Salesforce project.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Debug Log Configuration
|
|
8
|
+
|
|
9
|
+
### Setting Up Trace Flags
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
# Enable debug logging for your user (via CLI)
|
|
13
|
+
sf apex tail log --target-org <target_org>
|
|
14
|
+
|
|
15
|
+
# Get recent logs
|
|
16
|
+
sf apex log list --target-org <target_org>
|
|
17
|
+
|
|
18
|
+
# View a specific log
|
|
19
|
+
sf apex log get --target-org <target_org> --log-id <logId>
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
### Recommended Log Levels
|
|
23
|
+
|
|
24
|
+
| Category | Level | When |
|
|
25
|
+
|----------|-------|------|
|
|
26
|
+
| Apex Code | FINEST | Deep Apex debugging |
|
|
27
|
+
| Apex Code | DEBUG | Standard development |
|
|
28
|
+
| SOQL | INFO | Query performance |
|
|
29
|
+
| Callout | FINER | Integration debugging |
|
|
30
|
+
| Validation | INFO | Rule troubleshooting |
|
|
31
|
+
| Workflow | FINER | Automation debugging |
|
|
32
|
+
| System | DEBUG | General platform |
|
|
33
|
+
| Visualforce | NONE | Unless debugging VF |
|
|
34
|
+
|
|
35
|
+
### Log Level Presets
|
|
36
|
+
|
|
37
|
+
**Standard Dev:**
|
|
38
|
+
```
|
|
39
|
+
ApexCode=DEBUG;ApexProfiling=INFO;Callout=INFO;Database=INFO;System=DEBUG;Validation=INFO;Workflow=INFO
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
**Deep Apex Debug:**
|
|
43
|
+
```
|
|
44
|
+
ApexCode=FINEST;ApexProfiling=FINE;Callout=FINER;Database=FINE;System=DEBUG;Validation=INFO;Workflow=INFO
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
**Integration Debug:**
|
|
48
|
+
```
|
|
49
|
+
ApexCode=DEBUG;Callout=FINEST;System=DEBUG;Database=INFO;Validation=NONE;Workflow=NONE
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
---
|
|
53
|
+
|
|
54
|
+
## Debugging Techniques
|
|
55
|
+
|
|
56
|
+
### 1. System.debug() with Structured Output
|
|
57
|
+
|
|
58
|
+
```apex
|
|
59
|
+
// ✅ Use log levels and structured output
|
|
60
|
+
System.debug(LoggingLevel.INFO, '>>> AccountService.processAccounts');
|
|
61
|
+
System.debug(LoggingLevel.DEBUG, 'Input size: ' + accounts.size());
|
|
62
|
+
System.debug(LoggingLevel.FINE, 'Account IDs: ' + JSON.serialize(accountIds));
|
|
63
|
+
|
|
64
|
+
// ❌ Avoid bare debug statements
|
|
65
|
+
System.debug(accounts); // Hard to find in logs
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### 2. Apex Replay Debugger (VS Code)
|
|
69
|
+
|
|
70
|
+
1. Set up trace flags for your user
|
|
71
|
+
2. Reproduce the issue
|
|
72
|
+
3. Download the debug log
|
|
73
|
+
4. Open in VS Code → "SFDX: Launch Apex Replay Debugger"
|
|
74
|
+
5. Set checkpoints (up to 5 active)
|
|
75
|
+
6. Step through execution line by line
|
|
76
|
+
|
|
77
|
+
### 3. Query Plan Tool
|
|
78
|
+
|
|
79
|
+
```
|
|
80
|
+
/services/data/v66.0/query?explain=SELECT+Id+FROM+Account+WHERE+Name='Test'
|
|
81
|
+
```
|
|
82
|
+
- Check in Developer Console → Query Plan
|
|
83
|
+
- Look for `TableScan` (bad) vs `Index` (good)
|
|
84
|
+
|
|
85
|
+
### 4. Limits Checking in Code
|
|
86
|
+
|
|
87
|
+
```apex
|
|
88
|
+
System.debug('SOQL queries used: ' + Limits.getQueries() + '/' + Limits.getLimitQueries());
|
|
89
|
+
System.debug('DML statements used: ' + Limits.getDmlStatements() + '/' + Limits.getLimitDmlStatements());
|
|
90
|
+
System.debug('CPU time used: ' + Limits.getCpuTime() + 'ms / ' + Limits.getLimitCpuTime() + 'ms');
|
|
91
|
+
System.debug('Heap used: ' + Limits.getHeapSize() + ' / ' + Limits.getLimitHeapSize());
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
### 5. Anonymous Apex for Quick Testing
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
# Run anonymous Apex
|
|
98
|
+
sf apex run --target-org <target_org> --file scripts/apex/debug-script.apex
|
|
99
|
+
|
|
100
|
+
# Or inline
|
|
101
|
+
echo "System.debug(UserInfo.getUserName());" | sf apex run --target-org <target_org>
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
---
|
|
105
|
+
|
|
106
|
+
## Common Issues & Solutions
|
|
107
|
+
|
|
108
|
+
### Governor Limit Errors
|
|
109
|
+
|
|
110
|
+
| Error | Cause | Fix |
|
|
111
|
+
|-------|-------|-----|
|
|
112
|
+
| `Too many SOQL queries: 101` | SOQL in loop | Move query outside loop, use Map pattern |
|
|
113
|
+
| `Too many DML statements: 151` | DML in loop | Collect records, single DML outside loop |
|
|
114
|
+
| `CPU time limit exceeded` | Complex logic in loop | Optimize algorithms, use async |
|
|
115
|
+
| `Heap size exceeded` | Large collections | Process in batches, use `Database.QueryLocator` |
|
|
116
|
+
| `Too many callouts: 101` | Callouts in loop | Batch callouts, use Queueable chaining |
|
|
117
|
+
|
|
118
|
+
### Mixed DML Errors
|
|
119
|
+
|
|
120
|
+
```apex
|
|
121
|
+
// ❌ This fails — User and custom object in same transaction
|
|
122
|
+
insert new User(...);
|
|
123
|
+
insert new Account(...);
|
|
124
|
+
|
|
125
|
+
// ✅ Fix — Use @future or Queueable for the User DML
|
|
126
|
+
@future
|
|
127
|
+
public static void createUser(String email) {
|
|
128
|
+
insert new User(Email = email, ...);
|
|
129
|
+
}
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
### UNABLE_TO_LOCK_ROW
|
|
133
|
+
|
|
134
|
+
- Use `FOR UPDATE` in SOQL sparingly
|
|
135
|
+
- Process parent records before children
|
|
136
|
+
- Reduce transaction size
|
|
137
|
+
- Add retry logic with Queueable
|
|
138
|
+
|
|
139
|
+
---
|
|
140
|
+
|
|
141
|
+
## Monitoring Tools
|
|
142
|
+
|
|
143
|
+
| Tool | Purpose | Access |
|
|
144
|
+
|------|---------|--------|
|
|
145
|
+
| Debug Logs | Apex execution traces | Setup → Debug Logs |
|
|
146
|
+
| Event Monitoring | Login, API, Report events | Shield add-on |
|
|
147
|
+
| Apex Replay Debugger | Step-through debugging | VS Code extension |
|
|
148
|
+
| Developer Console | Quick SOQL, logs, testing | /s/_ui/ForceQueryPage |
|
|
149
|
+
| Query Plan | SOQL performance analysis | Developer Console |
|
|
150
|
+
| `sf apex tail log` | Real-time log streaming | CLI |
|
|
151
|
+
|
|
152
|
+
---
|
|
153
|
+
|
|
154
|
+
## Project-Specific Debug Notes
|
|
155
|
+
|
|
156
|
+
<!-- Add recurring issues and their solutions specific to this project -->
|
|
157
|
+
|
|
158
|
+
```
|
|
159
|
+
<!-- Example:
|
|
160
|
+
- Account trigger: Watch for recursion when AccountService updates related Contacts
|
|
161
|
+
which re-fires the Contact trigger. Use static recursion guard.
|
|
162
|
+
- Integration with ERP: Token expires every 60 min. Check Named Credential
|
|
163
|
+
refresh settings if callouts fail with 401.
|
|
164
|
+
-->
|
|
165
|
+
```
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
# Deployment
|
|
2
|
+
|
|
3
|
+
> Deploy/retrieve workflows, CI/CD configuration, and release processes.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Deployment Strategy
|
|
8
|
+
|
|
9
|
+
**Method:** [Source Deploy (sf CLI) | DevOps Center | Change Sets | Unlocked Packages]
|
|
10
|
+
**Source of Truth:** Git (`main` branch)
|
|
11
|
+
**Branching Model:** [GitFlow | Trunk-Based | Feature Branches]
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## CLI Deploy & Retrieve
|
|
16
|
+
|
|
17
|
+
### Deploy to Org
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
# Full deploy from source
|
|
21
|
+
sf project deploy start --target-org <target_org> --source-dir force-app
|
|
22
|
+
|
|
23
|
+
# Deploy specific metadata
|
|
24
|
+
sf project deploy start --target-org <target_org> --metadata "ApexClass:AccountService"
|
|
25
|
+
|
|
26
|
+
# Deploy with test execution (required for Production)
|
|
27
|
+
sf project deploy start --target-org <target_org> --source-dir force-app \
|
|
28
|
+
--test-level RunLocalTests
|
|
29
|
+
|
|
30
|
+
# Dry run (validate only, no deploy)
|
|
31
|
+
sf project deploy start --target-org <target_org> --source-dir force-app --dry-run
|
|
32
|
+
|
|
33
|
+
# Check deploy status
|
|
34
|
+
sf project deploy report --target-org <target_org>
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
### Retrieve from Org
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
# Retrieve specific metadata
|
|
41
|
+
sf project retrieve start --target-org <target_org> --metadata "ApexClass:AccountService"
|
|
42
|
+
|
|
43
|
+
# Retrieve by manifest
|
|
44
|
+
sf project retrieve start --target-org <target_org> --manifest manifest/package.xml
|
|
45
|
+
|
|
46
|
+
# Retrieve everything in project
|
|
47
|
+
sf project retrieve start --target-org <target_org> --source-dir force-app
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
---
|
|
51
|
+
|
|
52
|
+
## Test Levels
|
|
53
|
+
|
|
54
|
+
| Level | When to Use | Command Flag |
|
|
55
|
+
|-------|------------|-------------|
|
|
56
|
+
| `NoTestRun` | Dev/sandbox only | `--test-level NoTestRun` |
|
|
57
|
+
| `RunSpecifiedTests` | Known affected tests | `--test-level RunSpecifiedTests --tests AccountServiceTest` |
|
|
58
|
+
| `RunLocalTests` | Production deploy (no packages) | `--test-level RunLocalTests` |
|
|
59
|
+
| `RunAllTestsInOrg` | Full validation | `--test-level RunAllTestsInOrg` |
|
|
60
|
+
|
|
61
|
+
---
|
|
62
|
+
|
|
63
|
+
## CI/CD Pipeline
|
|
64
|
+
|
|
65
|
+
### GitHub Actions (Template)
|
|
66
|
+
|
|
67
|
+
```yaml
|
|
68
|
+
# .github/workflows/sf-deploy.yml
|
|
69
|
+
name: Salesforce Deploy
|
|
70
|
+
|
|
71
|
+
on:
|
|
72
|
+
push:
|
|
73
|
+
branches: [main]
|
|
74
|
+
paths: ['force-app/**']
|
|
75
|
+
pull_request:
|
|
76
|
+
branches: [main]
|
|
77
|
+
paths: ['force-app/**']
|
|
78
|
+
|
|
79
|
+
jobs:
|
|
80
|
+
validate:
|
|
81
|
+
runs-on: ubuntu-latest
|
|
82
|
+
steps:
|
|
83
|
+
- uses: actions/checkout@v4
|
|
84
|
+
|
|
85
|
+
- name: Install SF CLI
|
|
86
|
+
run: npm install -g @salesforce/cli
|
|
87
|
+
|
|
88
|
+
- name: Authenticate
|
|
89
|
+
run: |
|
|
90
|
+
echo "${{ secrets.SF_AUTH_URL }}" > authfile.txt
|
|
91
|
+
sf org login sfdx-url --sfdx-url-file authfile.txt --alias ci-org
|
|
92
|
+
|
|
93
|
+
- name: Validate (PR) or Deploy (Push)
|
|
94
|
+
run: |
|
|
95
|
+
if [ "${{ github.event_name }}" == "pull_request" ]; then
|
|
96
|
+
sf project deploy start --target-org ci-org --source-dir force-app \
|
|
97
|
+
--dry-run --test-level RunLocalTests
|
|
98
|
+
else
|
|
99
|
+
sf project deploy start --target-org ci-org --source-dir force-app \
|
|
100
|
+
--test-level RunLocalTests
|
|
101
|
+
fi
|
|
102
|
+
|
|
103
|
+
- name: Run Tests
|
|
104
|
+
if: github.event_name == 'pull_request'
|
|
105
|
+
run: |
|
|
106
|
+
sf apex run test --target-org ci-org --code-coverage \
|
|
107
|
+
--result-format json --output-dir test-results
|
|
108
|
+
|
|
109
|
+
- name: Upload Test Results
|
|
110
|
+
if: always()
|
|
111
|
+
uses: actions/upload-artifact@v4
|
|
112
|
+
with:
|
|
113
|
+
name: test-results
|
|
114
|
+
path: test-results/
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
---
|
|
118
|
+
|
|
119
|
+
## Pre-Deploy Checklist
|
|
120
|
+
|
|
121
|
+
- [ ] All tests pass locally (`sf apex run test`)
|
|
122
|
+
- [ ] Code coverage ≥ 75% (target 90%+)
|
|
123
|
+
- [ ] No SOQL/DML in loops
|
|
124
|
+
- [ ] Security enforced (CRUD/FLS/sharing)
|
|
125
|
+
- [ ] No hardcoded IDs or credentials
|
|
126
|
+
- [ ] Destructive changes handled separately
|
|
127
|
+
- [ ] Dependent metadata deployed in correct order
|
|
128
|
+
- [ ] Rollback plan documented for breaking changes
|
|
129
|
+
|
|
130
|
+
---
|
|
131
|
+
|
|
132
|
+
## Destructive Deployments
|
|
133
|
+
|
|
134
|
+
```bash
|
|
135
|
+
# Create destructiveChanges.xml in manifest/
|
|
136
|
+
# Deploy with destructive changes
|
|
137
|
+
sf project deploy start --target-org <target_org> \
|
|
138
|
+
--manifest manifest/package.xml \
|
|
139
|
+
--post-destructive-changes manifest/destructiveChanges.xml
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
---
|
|
143
|
+
|
|
144
|
+
## Environment Promotion Path
|
|
145
|
+
|
|
146
|
+
```
|
|
147
|
+
Dev Sandbox → QA Sandbox → UAT Sandbox → Production
|
|
148
|
+
↑ ↓
|
|
149
|
+
Feature branches ←── Hotfix branch ←── main branch
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
---
|
|
153
|
+
|
|
154
|
+
## Rollback Procedures
|
|
155
|
+
|
|
156
|
+
| Scenario | Action |
|
|
157
|
+
|----------|--------|
|
|
158
|
+
| Bad Apex deploy | Re-deploy previous version from git |
|
|
159
|
+
| Bad Flow deploy | Deactivate Flow in Setup, deploy fixed version |
|
|
160
|
+
| Bad field/object | Cannot easily rollback — test thoroughly in sandbox |
|
|
161
|
+
| Data corruption | Restore from weekly export or Data Recovery service |
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
# Integrations
|
|
2
|
+
|
|
3
|
+
> External systems, Named Credentials, callout patterns, and data sync strategies.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Integration Inventory
|
|
8
|
+
|
|
9
|
+
| System | Direction | Protocol | Auth Method | Named Credential | Frequency | Status |
|
|
10
|
+
|--------|-----------|----------|-------------|-----------------|-----------|--------|
|
|
11
|
+
| <!-- e.g., SAP ERP --> | Outbound | REST | OAuth 2.0 | `SAP_ERP_API` | Real-time | 🟢 Active |
|
|
12
|
+
| <!-- Add rows --> | | | | | | |
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## Integration Patterns
|
|
17
|
+
|
|
18
|
+
### Outbound REST Callouts
|
|
19
|
+
|
|
20
|
+
**Always use Named Credentials — never hardcode endpoints or credentials.**
|
|
21
|
+
|
|
22
|
+
```apex
|
|
23
|
+
public with sharing class ExternalApiService {
|
|
24
|
+
|
|
25
|
+
private static final String NAMED_CREDENTIAL = 'callout:External_API';
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* @description Makes an outbound REST call using Named Credentials.
|
|
29
|
+
* @param endpoint The API endpoint path (appended to Named Credential URL).
|
|
30
|
+
* @param method HTTP method (GET, POST, PUT, DELETE).
|
|
31
|
+
* @param body Request body (null for GET).
|
|
32
|
+
* @return Parsed response DTO.
|
|
33
|
+
*/
|
|
34
|
+
public static ApiResponseDTO callExternalApi(String endpoint, String method, String body) {
|
|
35
|
+
HttpRequest req = new HttpRequest();
|
|
36
|
+
req.setEndpoint(NAMED_CREDENTIAL + endpoint);
|
|
37
|
+
req.setMethod(method);
|
|
38
|
+
req.setHeader('Content-Type', 'application/json');
|
|
39
|
+
req.setTimeout(10000); // 10 second timeout
|
|
40
|
+
|
|
41
|
+
if (body != null) {
|
|
42
|
+
req.setBody(body);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
try {
|
|
46
|
+
HttpResponse res = new Http().send(req);
|
|
47
|
+
|
|
48
|
+
if (res.getStatusCode() >= 200 && res.getStatusCode() < 300) {
|
|
49
|
+
return (ApiResponseDTO) JSON.deserialize(res.getBody(), ApiResponseDTO.class);
|
|
50
|
+
} else {
|
|
51
|
+
throw new IntegrationException(
|
|
52
|
+
'API call failed: ' + res.getStatusCode() + ' - ' + res.getBody()
|
|
53
|
+
);
|
|
54
|
+
}
|
|
55
|
+
} catch (CalloutException e) {
|
|
56
|
+
Logger.error('Callout to ' + endpoint + ' failed', e);
|
|
57
|
+
throw new IntegrationException('External service unavailable: ' + e.getMessage(), e);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
### Inbound REST API
|
|
64
|
+
|
|
65
|
+
```apex
|
|
66
|
+
@RestResource(urlMapping='/api/v1/accounts/*')
|
|
67
|
+
global with sharing class AccountRestResource {
|
|
68
|
+
|
|
69
|
+
@HttpGet
|
|
70
|
+
global static AccountDTO getAccount() {
|
|
71
|
+
RestRequest req = RestContext.request;
|
|
72
|
+
String accountId = req.requestURI.substringAfterLast('/');
|
|
73
|
+
|
|
74
|
+
List<Account> accounts = AccountSelector.getByIds(new Set<Id>{accountId});
|
|
75
|
+
if (accounts.isEmpty()) {
|
|
76
|
+
RestContext.response.statusCode = 404;
|
|
77
|
+
return null;
|
|
78
|
+
}
|
|
79
|
+
return new AccountDTO(accounts[0]);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
@HttpPost
|
|
83
|
+
global static AccountDTO createAccount(AccountDTO dto) {
|
|
84
|
+
try {
|
|
85
|
+
Account acc = AccountService.createFromDTO(dto);
|
|
86
|
+
RestContext.response.statusCode = 201;
|
|
87
|
+
return new AccountDTO(acc);
|
|
88
|
+
} catch (DmlException e) {
|
|
89
|
+
RestContext.response.statusCode = 400;
|
|
90
|
+
throw e;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
### Async Patterns
|
|
97
|
+
|
|
98
|
+
| Pattern | Use When | Governor-Friendly |
|
|
99
|
+
|---------|----------|-------------------|
|
|
100
|
+
| **Queueable** | Complex types, chaining, < 50k records | ✅ Preferred |
|
|
101
|
+
| **@future** | Simple, fire-and-forget | ⚠️ Limited (no complex types) |
|
|
102
|
+
| **Batch Apex** | 50k+ records, long-running | ✅ QueryLocator = 50M rows |
|
|
103
|
+
| **Platform Events** | Decoupled, cross-system, event-driven | ✅ Excellent |
|
|
104
|
+
| **Scheduled Apex** | Time-based recurring jobs | ✅ Cron expressions |
|
|
105
|
+
|
|
106
|
+
```apex
|
|
107
|
+
// ✅ Preferred — Queueable with chaining
|
|
108
|
+
public class SyncAccountsQueueable implements Queueable, Database.AllowsCallouts {
|
|
109
|
+
|
|
110
|
+
private List<Account> accounts;
|
|
111
|
+
private Integer retryCount;
|
|
112
|
+
|
|
113
|
+
public SyncAccountsQueueable(List<Account> accounts, Integer retryCount) {
|
|
114
|
+
this.accounts = accounts;
|
|
115
|
+
this.retryCount = retryCount;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
public void execute(QueueableContext context) {
|
|
119
|
+
try {
|
|
120
|
+
ExternalApiService.syncAccounts(accounts);
|
|
121
|
+
} catch (IntegrationException e) {
|
|
122
|
+
if (retryCount < 3) {
|
|
123
|
+
System.enqueueJob(new SyncAccountsQueueable(accounts, retryCount + 1));
|
|
124
|
+
} else {
|
|
125
|
+
Logger.error('Max retries exceeded for account sync', e);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
### Platform Events
|
|
133
|
+
|
|
134
|
+
```apex
|
|
135
|
+
// Publishing
|
|
136
|
+
EventBus.publish(new Order_Status_Change__e(
|
|
137
|
+
Order_Id__c = orderId,
|
|
138
|
+
New_Status__c = 'Shipped',
|
|
139
|
+
Changed_By__c = UserInfo.getUserId()
|
|
140
|
+
));
|
|
141
|
+
|
|
142
|
+
// Subscribing (Apex Trigger on Platform Event)
|
|
143
|
+
trigger OrderStatusChangeTrigger on Order_Status_Change__e (after insert) {
|
|
144
|
+
OrderStatusChangeHandler.handle(Trigger.new);
|
|
145
|
+
}
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
---
|
|
149
|
+
|
|
150
|
+
## Named Credential Setup
|
|
151
|
+
|
|
152
|
+
| Setting | Value |
|
|
153
|
+
|---------|-------|
|
|
154
|
+
| **Label** | [Human-readable name] |
|
|
155
|
+
| **URL** | [Base API URL] |
|
|
156
|
+
| **Auth Protocol** | OAuth 2.0 / Named Principal / Per User |
|
|
157
|
+
| **Auth Provider** | [Custom Auth Provider if OAuth] |
|
|
158
|
+
| **Certificate** | [If mTLS required] |
|
|
159
|
+
|
|
160
|
+
### Checklist for New Integration
|
|
161
|
+
|
|
162
|
+
- [ ] Named Credential created in target org
|
|
163
|
+
- [ ] Auth Provider configured (if OAuth)
|
|
164
|
+
- [ ] Remote Site Setting or CSP Trusted Site added (if not using Named Cred)
|
|
165
|
+
- [ ] Callout timeout configured (default 10s, max 120s)
|
|
166
|
+
- [ ] Error handling with retry logic
|
|
167
|
+
- [ ] Logging for all callout responses
|
|
168
|
+
- [ ] Unit tests with `HttpCalloutMock`
|
|
169
|
+
- [ ] Bulk-safe (no callouts in loops)
|
|
170
|
+
|
|
171
|
+
---
|
|
172
|
+
|
|
173
|
+
## Data Sync Strategies
|
|
174
|
+
|
|
175
|
+
| Strategy | Direction | Frequency | Tool |
|
|
176
|
+
|----------|-----------|-----------|------|
|
|
177
|
+
| Real-time push | Outbound | On record change | Trigger → Queueable → REST |
|
|
178
|
+
| Real-time pull | Inbound | On demand | @RestResource |
|
|
179
|
+
| Near real-time | Both | Minutes | Platform Events + CDC |
|
|
180
|
+
| Batch sync | Both | Scheduled | Batch Apex + REST |
|
|
181
|
+
| ETL | Inbound | Nightly | MuleSoft / Informatica / Jitterbit |
|
|
182
|
+
|
|
183
|
+
---
|
|
184
|
+
|
|
185
|
+
## Project-Specific Integrations
|
|
186
|
+
|
|
187
|
+
<!-- Document each integration with details -->
|
|
188
|
+
|
|
189
|
+
### [Integration Name]
|
|
190
|
+
|
|
191
|
+
- **System:**
|
|
192
|
+
- **Direction:** Inbound / Outbound / Bidirectional
|
|
193
|
+
- **Protocol:** REST / SOAP / Platform Event
|
|
194
|
+
- **Named Credential:** `callout:___`
|
|
195
|
+
- **Frequency:** Real-time / Batch / Scheduled
|
|
196
|
+
- **Objects Involved:**
|
|
197
|
+
- **Error Handling:**
|
|
198
|
+
- **Monitoring:**
|
|
199
|
+
- **Owner:**
|