Persist kagane covers so they survive restarts and a sleeping browser #43
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?
Part of #38
What to build
A kagane cover, once fetched, is served from the backend's own storage forever after — including
across restarts and while the headless browser is asleep or unreachable.
Today covers live in an in-process map. Every backend restart empties it, and every miss goes back
through the browser. After this ticket the first request for a given cover reaches the browser at
most once ever; a deploy no longer blanks the library.
Implementation decisions
coverstable keyed by the kagane image id, holding the image bytes, the content type, anda fetch timestamp. Keyed by image id because that is the identifier the request actually carries:
serving becomes a primary-key lookup rather than a scan for the series row whose stored cover URL
happens to contain that UUID.
series. It is then structurally impossiblefor a future query or a
SELECT *to drag image bytes into the poller's hot path, instead ofrelying on the convention that a column list stays explicit. Orphan rows are theoretical —
nothing in the store deletes a series row, and a test already pins that.
list used by the due query.
today and writes through to the store.
ponytail:note are deleted. The store is thecache now, and unlike the map it survives a restart.
tests and their counting fake keep working.
client-supplied, so the id is validated before it reaches either the database or the browser), the
content-type allowlist, the session gate, and the long immutable cache headers.
Acceptance criteria
from storage with no further browser call.
would fail if called.
trailing path segment, a challenged fetch, a content type outside the allowlist, a
path-traversal attempt, an unauthenticated request.
go test ./...passes.Blocked by
None — can start immediately.
Implemented on branch issue-43. Added Postgres-backed covers storage with migration 0007, store-first serving, write-through persistence, and restart coverage; removed the in-process cover cache. Preserved UUID/session/content-type/traversal rejection paths and immutable cache headers. Verification: go test ./... and CGO_ENABLED=0 go build ./... pass. Pull request follows.
PR #49 opened: #49. It targets main and includes Closes #43; issue will close when merged.