-- Per-user reading progress and uploader attribution. -- -- Reading progress is the simplest shape that supports "jump to last -- read chapter" — one row per (user, manga). The reader writes -- through on chapter open and on page advance (debounced); the -- history view shows them sorted by most-recently-touched. -- -- Uploader attribution adds nullable `uploaded_by` columns to the two -- upload sinks. Historical rows have NULL because the original -- handlers didn't track this; new uploads stamp the current user. CREATE TABLE read_progress ( user_id uuid NOT NULL REFERENCES users(id) ON DELETE CASCADE, manga_id uuid NOT NULL REFERENCES mangas(id) ON DELETE CASCADE, -- Chapter is nullable so a deleted chapter doesn't blow away -- the user's progress row entirely — they just see "(chapter -- removed)" in the history UI. chapter_id uuid REFERENCES chapters(id) ON DELETE SET NULL, page integer NOT NULL DEFAULT 1 CHECK (page >= 1), updated_at timestamptz NOT NULL DEFAULT now(), PRIMARY KEY (user_id, manga_id) ); -- Most queries on this table want "most recent first" per user; the -- composite index makes both filter and sort index-only. CREATE INDEX read_progress_user_idx ON read_progress (user_id, updated_at DESC); ALTER TABLE mangas ADD COLUMN uploaded_by uuid REFERENCES users(id) ON DELETE SET NULL; CREATE INDEX mangas_uploaded_by_idx ON mangas (uploaded_by, created_at DESC) WHERE uploaded_by IS NOT NULL; ALTER TABLE chapters ADD COLUMN uploaded_by uuid REFERENCES users(id) ON DELETE SET NULL; CREATE INDEX chapters_uploaded_by_idx ON chapters (uploaded_by, created_at DESC) WHERE uploaded_by IS NOT NULL;