Cover bytes move to a content-addressed filesystem store #56
Reference in New Issue
Block a user
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Parent
Spec: #55. Originating bug: #47. Architecture and rejected alternatives:
docs/adr/0007-backend-hosts-cover-bytes.md. Domain vocabulary:CONTEXT.md.Do not close #47 or #55 from this ticket.
What to build
Cover bytes stop living in the database and start living on a filesystem volume, addressed by their content. From a Reader point of view nothing changes at all: kagane Covers still render in the web UI, still behind the session, still fetched through the browser sidecar when they are missing, still absent when no sidecar is configured. This ticket is the foundation every later ticket writes through, and it is deliberately shaped so that it can land without any user-visible behaviour changing — if a Reader can tell this shipped, something is wrong.
Underneath, a stored Cover becomes an immutable object keyed by the SHA-256 of the URL its bytes came from. The bytes are written to a path derived from that hash, sharded two levels deep so no single directory ever accumulates thousands of entries, under a directory given by new configuration. The database keeps the content address, the path and the content type — not the bytes.
Content addressing is the load-bearing choice here, and it is worth understanding before implementing: because the address changes whenever the image changes, a stored object can never be stale, which is what makes the long-lived immutable cache headers correct and removes the need for any invalidation logic anywhere in the system — including for the admin refetch deferred to #54. Do not substitute a Series-keyed path; it reintroduces the invalidation problem this avoids.
The existing byte column is removed. Its rows are dropped, not migrated: the kagane path already re-fetches a missing Cover on demand, so a migration would be careful work to preserve a cache that rebuilds itself for free.
Configuration gains the storage directory, and Compose gains a volume for it beside the database volume. The directory is required — a deployment without it cannot store anything, so startup must fail loudly rather than serve broken addresses later.
Acceptance criteria
go test ./...is greenBlocked by
sulthan referenced this issue2026-08-09 23:12:11 +07:00
Implemented on branch issue-56-cover-filesystem.
Acceptance criteria:
Verification: CGO_ENABLED=0 go build ./..., docker build -t manga-bookmark-cover-check ./backend, and docker compose config --services all pass. Parents #47 and #55 remain open as required.