Claude-code-plugins-plus-skills salesforce-reference-architecture
install
source · Clone the upstream repo
git clone https://github.com/jeremylongshore/claude-code-plugins-plus-skills
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/jeremylongshore/claude-code-plugins-plus-skills "$T" && mkdir -p ~/.claude/skills && cp -r "$T/plugins/saas-packs/salesforce-pack/skills/salesforce-reference-architecture" ~/.claude/skills/jeremylongshore-claude-code-plugins-plus-skills-salesforce-reference-architectur && rm -rf "$T"
manifest:
plugins/saas-packs/salesforce-pack/skills/salesforce-reference-architecture/SKILL.mdsource content
Salesforce Reference Architecture
Overview
Production-ready architecture patterns for Salesforce integrations, covering Node.js integration apps, SFDX metadata projects, and event-driven sync architectures.
Prerequisites
- Understanding of layered architecture
- jsforce and Salesforce CLI experience
- TypeScript project setup
- Decision on sync model (polling vs event-driven)
Project Structure
Node.js Integration App
my-sf-integration/ ├── src/ │ ├── salesforce/ │ │ ├── connection.ts # Singleton jsforce connection with auto-refresh │ │ ├── types.ts # Typed sObject interfaces (Account, Contact, etc.) │ │ ├── queries.ts # SOQL query builders │ │ ├── mutations.ts # Create/update/delete operations │ │ └── events.ts # CDC and Platform Event subscribers │ ├── services/ │ │ ├── account-sync.ts # Business logic for Account sync │ │ ├── contact-sync.ts # Business logic for Contact sync │ │ └── opportunity-sync.ts # Pipeline/forecast sync │ ├── api/ │ │ ├── routes.ts # Express/Fastify routes │ │ └── health.ts # Health check with SF connectivity │ ├── jobs/ │ │ ├── full-sync.ts # Scheduled full data sync │ │ └── incremental-sync.ts # CDC-based incremental sync │ └── index.ts ├── tests/ │ ├── unit/ # Mocked jsforce tests │ └── integration/ # Live sandbox tests ├── config/ │ ├── default.json # Shared config │ └── production.json # Production overrides └── package.json
SFDX Metadata Project (Apex, LWC, Triggers)
my-sf-app/ ├── force-app/main/default/ │ ├── classes/ # Apex classes │ │ ├── AccountTriggerHandler.cls │ │ ├── ContactService.cls │ │ └── IntegrationService.cls │ ├── triggers/ # Apex triggers │ │ └── AccountTrigger.trigger │ ├── lwc/ # Lightning Web Components │ │ └── accountList/ │ ├── objects/ # Custom object metadata │ │ └── Integration_Log__c/ │ ├── permissionsets/ │ │ └── Integration_API_Access.permissionset-meta.xml │ └── flows/ # Screen/record-triggered flows ├── scripts/apex/ # Anonymous Apex scripts ├── config/ │ └── project-scratch-def.json └── sfdx-project.json
Integration Patterns
Pattern A: Polling-Based Sync
┌─────────────┐ SOQL Query ┌─────────────┐ │ Your App │ ──────────────────▶ │ Salesforce │ │ (cron job) │ SELECT ... WHERE │ Org │ │ │ ◀────────────────── │ │ │ │ JSON Records │ │ └─────────────┘ └─────────────┘ Pros: Simple, works with any edition Cons: Latency (polling interval), wastes API calls on empty polls Use: Small data volumes, non-real-time requirements
Pattern B: Event-Driven Sync (Recommended)
┌─────────────┐ ┌─────────────┐ │ Your App │ ◀─── CDC Events ─── │ Salesforce │ │ (listener) │ /data/Change* │ Org │ │ │ │ │ │ │ ── REST API ───────▶ │ │ │ │ Write-back │ │ └─────────────┘ └─────────────┘ Pros: Real-time, no wasted API calls, scalable Cons: Requires Enterprise+, CDC setup, event replay handling Use: Real-time sync, high-volume changes
Pattern C: Bi-Directional Sync (Heroku Connect)
┌─────────────┐ SQL Queries ┌─────────────┐ │ Your App │ ──────────────────▶ │ Postgres │ │ │ ◀────────────────── │ (Heroku DB) │ └─────────────┘ └──────┬───────┘ │ Heroku Connect (automatic sync) │ ┌──────▼───────┐ │ Salesforce │ │ Org │ └─────────────┘ Pros: Zero API calls from your app, automatic bi-directional sync Cons: Heroku cost, 10-min sync delay, limited to standard objects Use: Heavy read/write, SQL-friendly teams
Key Architecture Decisions
| Decision | Recommendation | Rationale |
|---|---|---|
| Connection management | Singleton with auto-refresh | 1 connection per process, handles token expiry |
| SOQL queries | Typed query builders | Prevents field name typos, enables refactoring |
| Bulk operations | Bulk API 2.0 for 10K+, Collections for <200 | Optimizes API call consumption |
| Error handling | Map SF error codes to domain errors | → , etc. |
| Real-time sync | CDC over polling | No wasted API calls, sub-second latency |
| Data mapping | Explicit field mapping layer | Decouples app schema from SF schema |
| Testing | Mock jsforce in unit tests | Fast tests without org dependency |
Data Mapping Layer
// src/salesforce/mappers.ts // Decouple your app's domain model from Salesforce field names interface AppContact { id: string; firstName: string; lastName: string; email: string; companyId: string; } function fromSalesforceContact(sf: any): AppContact { return { id: sf.Id, firstName: sf.FirstName || '', lastName: sf.LastName, email: sf.Email || '', companyId: sf.AccountId || '', }; } function toSalesforceContact(app: Partial<AppContact>): Record<string, any> { const sf: Record<string, any> = {}; if (app.firstName !== undefined) sf.FirstName = app.firstName; if (app.lastName !== undefined) sf.LastName = app.lastName; if (app.email !== undefined) sf.Email = app.email; if (app.companyId !== undefined) sf.AccountId = app.companyId; return sf; }
Output
- Node.js integration project with layered architecture
- SFDX metadata project structure
- Integration pattern selected (polling, event-driven, or Heroku Connect)
- Data mapping layer decoupling app from SF schema
Error Handling
| Issue | Cause | Solution |
|---|---|---|
| Tight coupling to SF schema | Direct field access | Add mapping layer |
| N+1 queries | Loop with individual queries | Use relationship SOQL or Collections |
| Stale cache | TTL too long | Use CDC events to invalidate |
| Event loss | No replay tracking | Persist last replayId |
Resources
Next Steps
For multi-environment setup, see
salesforce-multi-env-setup.