Core payment state
The idempotency row is written before an outer transaction is submitted. If an
RPC response is lost, the stored hash is polled before any retry decision. A
replica cannot lease the same channel account while another fencing token is
current.
Catalog and analytics state
Catalog declaration and payment-option rows are not overwritten when a seller
changes price or metadata. This preserves the terms associated with historical
payments and allows an operator to explain why one version was active.
Search state
search_model_generations records provider, logical model ID, revision,
dimension, pooling, normalization, checksum, and lifecycle status. Exactly one
generation may be active. Each generation has a typed table named
catalog_embeddings_g<id> with a dimension-specific vector column and HNSW
cosine index. Separate tables make dimension mixing structurally impossible.
The shared catalog_index_jobs queue has leases, attempts, backoff, fencing
tokens, completion state, and dead-letter reasons. search_impressions records
query session, mode, reranking, generation, ranking configuration, resource
position, score, degraded branches, latency, and timestamp. Migration 006 adds
search_sessions and search_resource_fetches for page/fetch attribution.
Migration order
Migrations are forward-only and numbered:001_core.sql— keys, channels, idempotency, budgets, audit.002_catalog.sql— catalog, payment events, daily totals, lexical document, and index-job queue.003_search.sql— optional pgvector, generations, typed embedding storage, impressions, evaluation tables, and job lifecycle extensions.004_weighted_search.sql— weighted lexical fields and phrase-aware search.005_stuffing_resistance.sql— unique-lexeme lexical projection so repeated seller keywords cannot increase rank.006_search_feedback.sql— sessions and explicit resource fetch telemetry.
schema_migrations table and a PostgreSQL
advisory lock. Do not edit an applied migration; add the next numbered file.
pgvector is optional
Migration 003 attempts to installvector inside an exception block. If the
operator cannot install the extension, no embedding table is created, no
embedding job is claimed, and discovery search falls back to PostgreSQL FTS.
The default Compose image includes pgvector, but lexical-only operation is a
supported mode rather than a startup failure.
Backup and restore
Back up the PostgreSQL database, the encrypted key-encryption secret, and the operator configuration together. A database backup without the encryption key cannot decrypt managed sponsor/channel keys; a key backup without the database cannot recover idempotency or sequence state safely. Before restore:- stop settlement traffic or put the service in a maintenance window;
- restore PostgreSQL and verify migration version;
- restore the exact key-encryption secret and configuration generation;
- mark any in-flight
preparing,submitting,pending, orunknownrows for hash polling rather than resubmission; - verify channel-account sequence state against Stellar RPC;
- run
/health/ready,/analytics/v1/search/status, and a signed testnet verification before reopening traffic.