-- Attach every pre-existing bookmark to the owner reader, seeded between the -- two migrate passes (Store.Open). The oldest reader is the owner by -- construction: only the seed creates readers, and it runs once per database. -- Run-once via the version table, like every migration. UPDATE bookmarks SET reader_id = (SELECT id FROM readers ORDER BY id LIMIT 1); -- Ownership lands structurally: reader_id becomes part of the key, so a -- bookmark is one Reader's progress on one Series and a duplicate for the -- same pair is impossible at the database level. Deleting a Reader takes -- their bookmarks with them. The old text key is gone — the wire "key" is -- derived as site:series_id on read, and nothing references the column. -- Dropping it drops the primary key it carried; the composite key replaces -- it, and the FK index the series constraint needs is created automatically. ALTER TABLE bookmarks ALTER COLUMN reader_id SET NOT NULL, DROP COLUMN key, ADD PRIMARY KEY (reader_id, site, series_id), ADD CONSTRAINT bookmarks_reader_fk FOREIGN KEY (reader_id) REFERENCES readers (id) ON DELETE CASCADE;