fix(sync): sync updated book covers across devices (#4544) (#4731)

* docs: design for syncing updated book data (cover + file) (#4544)

Cover-change sync via a content hash (coverHash = partial MD5 of cover.png)
plus a cover_updated_at field-level merge timestamp; file updates ride the
existing re-import / metaHash dedupe.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix(sync): sync updated book covers across devices (#4544)

Editing a book's cover wrote cover.png locally but changed no hash (the
cover is keyed by the file hash), so peers had no signal to re-download it
and the change never propagated.

Give the cover its own content-addressed version:
- coverHash = partial MD5 of cover.png; a peer re-downloads the cover iff
  the synced hash differs from the local one (idempotent, no churn on
  identical/re-extracted covers — compatible with the metaHash dedupe).
- coverUpdatedAt = field-level LWW timestamp so a page-turn that wins
  whole-row LWW on updated_at can't clobber a cover edit (mirrors the
  reading_status_updated_at fix for #4634).

Editing a cover recomputes the hash, bumps coverUpdatedAt, and re-uploads
only the cover; the server merges cover fields independently; peers
re-download on a hash diff. File updates continue to ride the existing
re-import / metaHash dedupe (changed file -> changed hash -> re-key).

Migration 016 adds cover_hash / cover_updated_at to books.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Huang Xin
2026-06-22 23:31:03 +08:00
committed by GitHub
parent 1b44b95d3a
commit 082edc204b
19 changed files with 892 additions and 16 deletions
+2
View File
@@ -19,6 +19,8 @@ CREATE TABLE public.books (
progress integer[] NULL,
reading_status text NULL,
reading_status_updated_at timestamp with time zone NULL,
cover_hash text NULL,
cover_updated_at timestamp with time zone NULL,
group_id text NULL,
group_name text NULL,
metadata json NULL,
@@ -0,0 +1,23 @@
-- Migration 017: Add `cover_hash` / `cover_updated_at` to books
--
-- Cover-change sync (issue #4544). Editing a book's cover writes cover.png
-- locally but changes no hash (the cover is keyed by the file hash), so peers
-- had no signal to re-download it. Give the cover its own content-addressed
-- version:
--
-- cover_hash = partial MD5 of cover.png. A peer re-downloads the cover
-- iff its synced cover_hash differs from the local one.
-- Content-addressed ⇒ a byte-identical (re-extracted /
-- re-imported) cover yields the same hash ⇒ no re-sync
-- churn (compatible with the metaHash dedupe mechanism).
-- cover_updated_at = field-level last-writer-wins timestamp so a page-turn
-- that wins whole-row LWW on updated_at cannot clobber a
-- cover edit — the same hazard the 015
-- reading_status_updated_at fix addressed for #4634.
--
-- Both additive + nullable; NULL cover_updated_at is treated as epoch 0
-- (oldest) by the merge. Old clients ignore the columns, so they never break.
ALTER TABLE public.books
ADD COLUMN IF NOT EXISTS cover_hash text NULL,
ADD COLUMN IF NOT EXISTS cover_updated_at timestamp with time zone NULL;