Skip to main content

Persistent data model

Tayho has three persistent domains: API control, keeper coordination, and on-chain projection. Redis is not a fourth authority.

API control domain

Owner: API Drizzle schema and internal API-key CLI. Key plaintext is returned once at creation and is not stored. The API uses a short positive cache; revocation and suspension remain database-authoritative. Source: apps/api/src/auth/schema.ts.

Keeper coordination domain

Owner: keeper Drizzle schema; migrations and database grants define sub-ownership. Relationships:
  • one logical job has many immutable attempts and zero or more same-nonce transaction lineage rows;
  • one outbox row delivers one stable logical delivery into BullMQ;
  • one intent/action has append-only events plus a current lifecycle row;
  • an intent can hold reservations/cancellation state and emit reference-only relayer jobs;
  • a signer lane and nonce row serialize all replicas using that address.
Source: apps/keeper/src/db/schema.ts.

On-chain projection domain

Owner: one Ponder writer per deployment schema. The schema currently contains these groups: Every history row carries chain/block/transaction/log identity. Current tables retain the block and transaction that last updated them. Ponder owns rollback and replay. Source: apps/indexer/ponder.schema.ts.

Migration ownership

  • Generate API migrations with apps/api db:generate; check and apply them with the API Drizzle config.
  • Generate keeper migrations with apps/keeper db:generate; the one-shot migration service applies them under advisory lock and verifies least-privilege grants.
  • Ponder manages deployment-isolated schemas and stable views; do not hand-author application migrations against an active Ponder schema.
  • Runtime services never receive schema-owner credentials or run migrations at startup.
Schema changes must be forward-deployable with the current release workflow. Because Tayho is pre-launch, remove obsolete fields and update all callers atomically rather than retaining shadow columns or compatibility reads.

Retention and reconstruction

Keep immutable intent/action events, transaction lineage, operator/audit evidence, and signer history for their configured compliance/incident window. Do not delete active ciphertext while a nonterminal job, receipt, replacement lineage, reorg lookback, or key-retirement proof depends on it. BullMQ jobs, Redis indexes, admission counters, leases, and realtime events are reconstructable. After Redis loss, the PostgreSQL outbox republishes stable delivery IDs; authoritative snapshots reseed realtime. PostgreSQL and Ponder require PITR, backups, and restore drills as separate logical recovery domains.
Last modified on July 23, 2026