Agent Skills: Salesforce Reference Architecture

|

UncategorizedID: jeremylongshore/claude-code-plugins-plus-skills/salesforce-reference-architecture

Install this agent skill to your local

pnpm dlx add-skill https://github.com/jeremylongshore/claude-code-plugins-plus-skills/tree/HEAD/plugins/saas-packs/salesforce-pack/skills/salesforce-reference-architecture

Skill Files

Browse the full folder contents for salesforce-reference-architecture.

Download Skill

Loading file tree…

plugins/saas-packs/salesforce-pack/skills/salesforce-reference-architecture/SKILL.md

Skill Metadata

Name
salesforce-reference-architecture
Description
|

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 | INVALID_FIELDSchemaError, 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.