Entity Auth

Real-time Bridge Architecture

Understand the left/middle/right bridge spans and the event contracts that power the replicator.

Real-time Bridge Architecture

┌─────────────────────┐        websocket feed        ┌─────────────────────┐
│  Left Bridge        │   (Convex subscription +     │  Right Bridge       │
│  Entity Auth Core   │────── versioned events ─────▶│  Customer Replicator│
│  (Convex mutations) │                              │  + Local DB Adapter  │
└─────────────────────┘◀──── applyExternalMutation ──└─────────────────────┘
               ▲                                          │
               │                                          ▼
        Convex actions / queries                 Customer application + DB

Data flows

Outbound (Entity Auth → Customer DB)

  1. Convex mutation writes canonical data and calls appendWorkspaceEvent.
  2. Event stored in workspace_events with { workspaceTenantId, version, payload }.
  3. Replicator fetches ordered events via websocket subscription.
  4. Adapter applies event inside customer DB and advances the cursor.

Inbound (Customer DB → Entity Auth)

  1. Local change triggers call to applyExternalMutation with { eventType, payload, dedupeKey }.
  2. Convex action authenticates, validates, and invokes the canonical mutation.
  3. Mutation emits the same event path; all replicas observe convergence.

Event envelope

export type WorkspaceEvent = {
  workspaceTenantId: string;
  version: number;
  entityKind: string;
  entityId: string;
  eventType: string;
  payload: Json;
  source: {
    mutation: string;
    actorId: string | null;
    origin: "entity-auth" | "customer-replicator";
  };
  emittedAt: number;
  traceId?: string;
  schemaVersion?: number;
};

Payload schemas live in docs/internal/workspace-events.md and are mirrored inside the replicator adapters.

Guarantees

  • Ordering: lamport-style version per workspace; resume via afterVersion.
  • Idempotency: adapters upsert/delete with version checks.
  • Replay: offset store persists last version and supports catch-up.
  • Conflict resolution: Entity Auth stays authoritative; inbound mutations reuse canonical validation.

Replicator runtime internals

  • runBridge(options) orchestrates subscription polling, adapter application, and cursor updates.
  • adapters/ directory exposes helpers like createPrismaAdapter() and memoryAdapter().
  • storage/sqlite.ts persists offsets by default; implement custom stores as needed.
  • Lifecycle hooks (onEvent, onBatchProcessed, onHeartbeat, onExit) provide monitoring points.

Deployment shapes

  • Long-running worker: run node runner.mjs under system supervisors.
  • Serverless batch: instantiate runBridge with custom waitFn for single-use batch jobs.
  • Edge/adapter-specific: tune eventsPerBatch and handler logic to match latency requirements.

See the playbooks for concrete integrations.