Claude-code-plugins salesloft-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/salesloft-pack/skills/salesloft-reference-architecture" ~/.claude/skills/jeremylongshore-claude-code-plugins-salesloft-reference-architecture && rm -rf "$T"
manifest:
plugins/saas-packs/salesloft-pack/skills/salesloft-reference-architecture/SKILL.mdsource content
SalesLoft Reference Architecture
Overview
Production architecture for SalesLoft API integrations: typed API client, service layer with caching, webhook processor, and background sync. Designed around SalesLoft's REST API v2 with cost-based rate limiting.
Project Structure
salesloft-integration/ ├── src/ │ ├── salesloft/ │ │ ├── client.ts # Axios wrapper with rate-limit handling │ │ ├── types.ts # Person, Cadence, Activity types │ │ ├── paginator.ts # AsyncGenerator pagination │ │ └── errors.ts # SalesloftApiError class │ ├── services/ │ │ ├── people-sync.ts # Bidirectional people sync │ │ ├── cadence-manager.ts # Cadence CRUD + enrollment │ │ └── activity-tracker.ts # Email/call activity aggregation │ ├── webhooks/ │ │ ├── handler.ts # Signature verification + routing │ │ └── processors/ # Per-event-type processors │ ├── jobs/ │ │ ├── incremental-sync.ts # Cron: sync changed records │ │ └── engagement-report.ts# Cron: aggregate daily metrics │ └── api/ │ ├── health.ts # /health endpoint │ └── webhooks.ts # /webhooks/salesloft endpoint ├── config/ │ ├── default.json │ ├── production.json │ └── test.json └── tests/ ├── unit/ └── integration/
Architecture Diagram
┌─────────────────────────────────┐ │ API Layer │ │ /health /webhooks/salesloft │ ├─────────────────────────────────┤ │ Service Layer │ │ PeopleSync CadenceManager │ │ ActivityTracker │ ├─────────────────────────────────┤ │ SalesLoft Client │ │ Typed API Pagination Retry │ ├─────────────────────────────────┤ │ Infrastructure │ │ Redis Cache BullMQ Jobs │ │ PostgreSQL Prometheus │ └─────────────────────────────────┘ │ ▲ ▼ │ ┌─────────────────────────────────┐ │ SalesLoft REST API v2 │ │ /people /cadences /webhooks │ │ Rate: 600 cost/min │ └─────────────────────────────────┘
Key Components
Typed API Models
// src/salesloft/types.ts export interface SalesloftPerson { id: number; display_name: string; email_address: string; first_name: string; last_name: string; title: string | null; company_name: string | null; phone: string | null; city: string | null; state: string | null; tags: string[]; created_at: string; updated_at: string; } export interface SalesloftCadence { id: number; name: string; current_state: 'draft' | 'active' | 'paused' | 'archived'; team_cadence: boolean; counts: { people_count: number }; } export interface SalesloftActivity { id: number; action_type: 'email' | 'phone' | 'other' | 'integration'; person_id: number; cadence_id: number | null; created_at: string; }
Service Layer Pattern
// src/services/people-sync.ts export class PeopleSyncService { constructor( private salesloft: SalesloftClient, private db: Database, private cache: LRUCache<string, any>, ) {} async syncIncremental(): Promise<{ created: number; updated: number }> { const lastSync = await this.db.getLastSyncTime('people'); const stats = { created: 0, updated: 0 }; for await (const person of this.salesloft.paginate<SalesloftPerson>( '/people.json', { updated_at: { gt: lastSync } } )) { const existing = await this.db.findPersonBySlId(person.id); if (existing) { await this.db.updatePerson(person); stats.updated++; } else { await this.db.createPerson(person); stats.created++; } this.cache.delete(`person:${person.email_address}`); } await this.db.setLastSyncTime('people', new Date().toISOString()); return stats; } }
Background Job
// src/jobs/incremental-sync.ts import { CronJob } from 'cron'; new CronJob('*/5 * * * *', async () => { // Every 5 minutes const service = new PeopleSyncService(salesloft, db, cache); const stats = await service.syncIncremental(); console.log(`Sync: +${stats.created} created, ~${stats.updated} updated`); }).start();
Error Handling
| Component | Failure Mode | Recovery |
|---|---|---|
| API Client | 429 rate limit | Automatic retry with |
| Webhook Handler | Invalid signature | Reject 401, log for investigation |
| Sync Job | Partial failure | Resume from last successful |
| Cache | Redis unavailable | Fall through to API (graceful degradation) |
Resources
Next Steps
See individual skill docs for deep-dives on each component.