Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions backend/.env.example
Original file line number Diff line number Diff line change
Expand Up @@ -147,3 +147,29 @@ EVENT_POLL_INTERVAL_MS=10000

# Batch size for event replay (number of ledgers per batch)
EVENT_REPLAY_BATCH_SIZE=100

# ── Outbox Pattern Configuration ───────────────────────────────────────────────
# The outbox pattern ensures reliable, at-least-once event delivery by writing
# events to the EventOutbox table as part of business transactions, with a
# background processor that relays them to webhook consumers.
#
# Poll interval for the outbox processor (2 seconds = 2000 ms)
# OUTBOX_POLL_INTERVAL_MS=2000
#
# Maximum number of entries to process per poll cycle
# OUTBOX_BATCH_SIZE=50
#
# Lock timeout for distributed instance-level locking (60 seconds = 60000 ms)
# OUTBOX_LOCK_TIMEOUT_MS=60000
#
# Maximum delivery attempts before moving to dead-letter
# OUTBOX_MAX_ATTEMPTS=3
#
# Retention period for processed entries (7 days = 604800000 ms)
# OUTBOX_RETENTION_MS=604800000
#
# Unique instance identifier for distributed locking (auto-generated if unset)
# OUTBOX_INSTANCE_ID=
#
# Cleanup interval for removing old processed entries (1 hour = 3600000 ms)
# OUTBOX_CLEANUP_INTERVAL_MS=3600000
19 changes: 6 additions & 13 deletions backend/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Binary file modified backend/prisma/dev.db
Binary file not shown.
30 changes: 30 additions & 0 deletions backend/prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -467,6 +467,36 @@ model ApiKey {
// process restarts and are visible to every backend instance in multi-pod
// deployments, letting operators reconstruct partial config changes that
// were prepared but never committed/rolled back before a crash.
// ─── Outbox Pattern for Reliable Event Publishing ────────────────────────────

/// Event outbox table used for reliable event publishing.
/// Events are written here atomically within business transactions,
/// and a background relay processor reads from this table to publish
/// events to downstream consumers (e.g., webhooks).
/// This ensures at-least-once delivery even in the face of crashes.
model EventOutbox {
id String @id
eventType String
payload String // JSON-serialised TransactionEventPayload
status String @default("pending") // pending | relayed | failed | dead_letter
aggregateType String // e.g. "transaction", "vault"
aggregateId String // e.g. transaction id, vault id
attemptCount Int @default(0)
maxAttempts Int @default(3)
lastError String?
lockedAt DateTime? // Used for instance-level locking during relay
lockedBy String? // Instance identifier that holds the lock
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
relayedAt DateTime?

@@index([status])
@@index([status, createdAt])
@@index([aggregateType, aggregateId])
@@index([lockedAt])
@@index([createdAt])
}

model WriteAheadAuditEntry {
id String @id
configType String
Expand Down
Loading
Loading