Skip to content

OUTBOX_TABLE

const OUTBOX_TABLE: "pgxsinkit_outbox" = "pgxsinkit_outbox"

Defined in: packages/client/src/schema.ts:77

The Outbox (ADR-0053 decision 2) — the local-only, append-only table where client events are staged until a flush is acknowledged. ONE table for every Event stream (a stream column, not a table per stream), library-owned, never in the sync registry and never replicated, and stream-independent: registering an Event stream changes nothing about this DDL, so it is emitted unconditionally beside the engine’s other internal relations rather than derived from registry.streams.

Its SHAPE IS PUBLIC CONTRACT, because apps compose pending rows with down-synced aggregates into best-guess views. The columns:

  • seq — the durable, monotonically increasing local append ordinal, the ONE ordering key for Outbox selection and batch assembly (UUIDs do not order, occurred_at_us collides at these volumes, and SQL row order is undefined). Local machinery: it is never transmitted. Assigned from OUTBOX_SEQUENCE exactly as the mutation journal’s mutation_seq is.
  • event_id — the library-stamped uuid carried on the wire; the server-side dedupe key that makes at-least-once delivery idempotent end-to-end. UNIQUE: a duplicate would be a library bug.
  • stream — the registered Event-stream name.
  • occurred_at_us — the library-stamped append time (microseconds), carried on the wire. Consumers needing temporal order re-sort on it (ADR-0053 decision 6).
  • payload — the event body as jsonb, validated against the Event stream’s zod schema AT APPEND, so “everything in the Outbox is well-formed” holds for the flush loop and for best-guess views. It is EXACTLY the value the caller passed to appendEvent — never the schema’s parsed.data. The schema is used at append only to VALIDATE (its output is discarded); the one AUTHORITATIVE parse is at ingest, and that output’s JSON-NORMALIZED form is what the consumer receives (a Date becomes its ISO string; a nested undefined property is dropped). The schema therefore executes at both boundaries — so transforms must be pure and deterministic — while a best-guess view here reads back precisely what the app appended.
  • enqueued_at_us — when the row was durably enqueued locally (never transmitted; observability).
  • attempt_count / next_retry_at_us — the per-row DEFERRED backoff (ADR-0053 decision 3): an Event stream the server does not yet know parks its rows here rather than deleting them. A row whose next_retry_at_us is in the future is skipped by batch assembly. NULL = eligible now.
  • last_reason — the most recent server deferred reason, kept on the row it belongs to (never a second, retention-bearing verdict table — ADR-0053 rejects that).