Data & Storage
The server database
PostgreSQL holds the durable spine of Privex — but only public keys, hashes, and ciphertext. Eleven tables, split between a crash-safe half and a leaves-no-trace half.
Think of the server’s database as a public phone book plus a few locked drop-boxes. The phone book lists only the public keys strangers need to message you — never your name, email, or address. The drop-boxes hold sealed envelopes the server can’t open. Nothing here identifies a real person.
The current migrations (0001–0012) create 11 tables. Every stored value is a
public key, a hash, a blinded/HMAC value, or ciphertext. No table has an IP, email, phone, display-name, or
last_seen column. Deleting a key_directory row cascades to a user’s prekeys, OPAQUE
record, recovery shares, and history blobs.
Two kinds of table
Some tables are durable — they survive a power cut, like a filing cabinet bolted to the floor. Others are UNLOGGED — they’re deliberately built on a table that tips over and spills if the server crashes, so nothing sensitive is left behind to recover.
LOGGED tables use the write-ahead log and survive a crash — the WAL only ever holds ciphertext
and px_ ids. UNLOGGED tables skip the WAL entirely and are truncated on an unclean
restart, so transient user data never lands in a journal. kt_log is UNLOGGED but rebuildable
from the durable key_directory on boot.
group_state, relay_nodes) and the legacy pow_challenges are defined but not wired into live code.Every table, in detail
Filter by durability or status. In Technical mode each card lists its full columns; in Plain mode you get the one-line “what it’s for”.
group_state and relay_nodes are
schema-only (no live routes), and pow_challenges is legacy — the live proof-of-work
state lives in Redis (pow:challenge:*). The V2 doc’s history_backup_settings and a
server-side linked_devices table do not exist in the migrations.