-- One row per person. Keyed by their Discord user ID; carries the SHA-256 of -- their userscript token and when they were created. Hashed because a token -- in the database is a token anyone with the database can replay; SHA-256 is -- enough because the tokens are high-entropy random values with nothing to -- brute-force. No one can register yet, so this table holds exactly the one -- owner row the seed creates at startup (see Store.Open). CREATE TABLE readers ( id bigserial PRIMARY KEY, discord_id text NOT NULL UNIQUE, token_sha256 bytea NOT NULL UNIQUE, created_at timestamptz NOT NULL DEFAULT now() ); -- Every bookmark now belongs to a reader. Added nullable: rows created before -- this migration have no owner yet — 0004 attaches them to the seeded owner -- before NOT NULL and the composite key land. ALTER TABLE bookmarks ADD COLUMN reader_id bigint;