Docs v1.0 Get Started

Architecture

A deep-dive into how AlgoBridge works internally.

Overview

AlgoBridge consists of two database layers and a sync engine that runs on a fixed 10-second schedule.

┌─────────────────────────────────────────────────────┐
│                   AlgoBridge Server                 │
│                                                     │
│  ┌─────────────┐        ┌──────────────────────┐   │
│  │  Platform DB │        │     Sync Engine       │   │
│  │  (Neon/RDS) │        │  (runs every 10s)     │   │
│  │             │        │                       │   │
│  │  tenants    │        │  1. Poll _trigger_log │   │
│  │  workspaces │        │  2. Batch → SF API    │   │
│  │  mappings   │        │  3. Write back result │   │
│  └─────────────┘        └──────────────────────┘   │
└─────────────────────────────────────────────────────┘
         │                          │
         ▼                          ▼
  ┌─────────────┐          ┌────────────────┐
  │ Client PG   │          │  Salesforce    │
  │ (your DB)   │◄────────►│  API           │
  │             │          │                │
  │ _trigger_log│          │  SOAP / Bulk   │
  │ contact     │          │  v2            │
  │ opportunity │          └────────────────┘
  └─────────────┘

Two Database Model

AlgoBridge strictly separates two databases:

Platform Database (managed by AlgoBridge)

Stores operational metadata only. Never stores your sync data.

Table Purpose
tenants Workspace accounts
tenant_connections Salesforce + PostgreSQL credentials
tenant_mappings Object-to-table mapping configuration
sync_history Per-batch sync audit log
plans / subscriptions Billing metadata

Client Database (your PostgreSQL)

Your own PostgreSQL instance. AlgoBridge installs a small set of system objects and then works entirely within them.

Object Type Purpose
_trigger_log Table CDC queue — captures every change
_trigger_log_archive Table 31-day audit trail of processed rows
_abmeta Table Schema metadata (mapped columns, sfid mapping)
ab_{table}_logtrigger Trigger Fires on INSERT/UPDATE/DELETE, writes to _trigger_log
ab_{table}_logger() Function Trigger function for the log trigger
ab_{table}_status_trigger Trigger Write-back guard — skips the log trigger during SF→PG writes
ab_{table}_status() Function Checks ab.in_sync session variable

Trigger-Based Change Data Capture

When a row changes in a mapped table, the logger trigger fires and inserts a row into _trigger_log:

-- Installed automatically for each mapped table
CREATE OR REPLACE FUNCTION ab_contact_logger()
RETURNS TRIGGER AS $$
BEGIN
  INSERT INTO _trigger_log (
    txid, table_name, record_id, sfid, action, state, values
  ) VALUES (
    txid_current(),
    'contact',
    NEW.id,
    NEW.sfid,
    TG_OP,           -- 'INSERT', 'UPDATE', or 'DELETE'
    'NEW',
    hstore(NEW) - hstore(OLD)  -- hstore diff: only changed columns
  );
  RETURN NEW;
END;
$$ LANGUAGE plpgsql;

CREATE TRIGGER ab_contact_logtrigger
  AFTER INSERT OR UPDATE OR DELETE ON contact
  FOR EACH ROW EXECUTE FUNCTION ab_contact_logger();

Why hstore (not JSONB)?

hstore stores the column diff as a flat key-value map. This matches the de facto standard for Salesforce sync. The diff (hstore(NEW) - hstore(OLD)) captures only the columns that actually changed, reducing payload size to Salesforce.

State Machine

Every row in _trigger_log moves through a defined state machine:

NEW ──► PENDING ──► SUCCESS
                └──► FAILED
State Meaning
NEW Row inserted by trigger, not yet picked up
PENDING Sync engine has claimed the row, API call in-flight
SUCCESS Salesforce confirmed the operation
FAILED API call failed; _ab_err populated with error detail

The _ab_lastop column on the mapped table itself reflects the outcome:

_ab_lastop Set when
PENDING Row first inserted (trigger sets this)
INSERTED SF confirmed a new record was created
UPDATED SF confirmed an existing record was updated
SYNCED Row written back from Salesforce → PostgreSQL
FAILED Sync failed

Sync Engine — 10-Second Batch

The sync worker runs on a fixed 10-second schedule (not configurable — this matches the de facto standard). Each cycle:

  1. Claim: UPDATE _trigger_log SET state = 'PENDING' WHERE state = 'NEW' RETURNING *
  2. Batch: Group claimed rows by Salesforce object
  3. Route: ≤ 200 records → SOAP API; > 200 records → Bulk API v2
  4. Write back: On success, set state = 'SUCCESS' and _ab_lastop = 'INSERTED' | 'UPDATED'
  5. Guard: Before writing back to the mapped table, set SET LOCAL ab.in_sync = 'true' — the status trigger checks this variable and skips re-logging the write

SOAP vs Bulk API

SOAP API Bulk API v2
Threshold ≤ 200 records per batch > 200 records per batch
Latency Low (~200ms round-trip) Higher (job-based, async)
Best for Small, frequent changes Large initial loads or bulk updates
SF API calls used 1 per record (counted against daily limit) 1 job + chunks (lower per-record cost)

SF → PG Write-Back

When Salesforce pushes changes back (via polling the SF REST API), the sync engine:

  1. Queries Salesforce for records modified since the last systemmodstamp
  2. Upserts rows into the mapped PostgreSQL table
  3. Sets SET LOCAL ab.in_sync = 'true' before each write
  4. The status trigger sees ab.in_sync = 'true' and skips inserting into _trigger_log, preventing a feedback loop
-- Status trigger function (installed per mapped table)
CREATE OR REPLACE FUNCTION ab_contact_status()
RETURNS TRIGGER AS $$
BEGIN
  IF current_setting('ab.in_sync', true) = 'true' THEN
    RETURN NEW;  -- skip logging, this is a write-back
  END IF;
  NEW._ab_lastop := 'PENDING';
  RETURN NEW;
END;
$$ LANGUAGE plpgsql;

31-Day Archive

After a _trigger_log row reaches SUCCESS or FAILED, it is moved to _trigger_log_archive:

INSERT INTO _trigger_log_archive SELECT * FROM _trigger_log WHERE state IN ('SUCCESS', 'FAILED');
DELETE FROM _trigger_log WHERE state IN ('SUCCESS', 'FAILED');

Rows in _trigger_log_archive are purged after 31 days. This gives you a full audit trail without unbounded table growth.

Credential Security

PostgreSQL connection strings are stored in AWS SSM Parameter Store as SecureString values — AES-256 encrypted at rest, never stored in environment variables or the platform database.

Salesforce OAuth tokens are encrypted at rest in the platform database using the workspace’s encryption key.

← Back to AlgoBridge Get Started →