e8d1cba6c5
Refs #56 ## Summary Moves Kagane cover bytes out of Postgres bytea storage into an immutable, content-addressed filesystem store. Reader-visible behavior remains unchanged: the existing session-gated route serves stored bytes, missing bytes use the existing browser fetch path, and no browser still returns a missing cover. ## Changes - Added migration 0008, which drops the legacy `covers` table and recreates it with only `address`, `path`, and `content_type`. Existing byte rows are intentionally dropped. - Added SHA-256 source-URL addressing with two-level sharding (`ab/cd/<sha256>`). Writes use a temp file plus atomic link; reads validate the stored relative path before opening it. - Made `COVER_DIR` required in runtime config and Compose. Compose passes it as a Docker build argument and volume target, so custom durable paths keep image ownership, runtime config, and the named `cover-data` volume aligned. - Updated every `store.Open` caller and documented configuration, deployment, backup, and troubleshooting behavior. - Added filesystem, restart, migration-drop, no-browser, and content-addressing coverage. ## Verification - `go test ./...` - `CGO_ENABLED=0 go build ./...` - `docker build --build-arg COVER_DIR=/data/covers -t manga-bookmark-cover-check-custom ./backend` - `docker compose config --format json` confirms custom `COVER_DIR` is the volume target - `git diff --check origin/main` - LSP diagnostics clean for touched Go files Parents #47 and #55 remain open as required by #56. Reviewed-on: #65 Co-authored-by: Sulthan Zaki <sultankiki05@gmail.com> Co-committed-by: Sulthan Zaki <sultankiki05@gmail.com>
36 lines
1.1 KiB
Docker
36 lines
1.1 KiB
Docker
# syntax=docker/dockerfile:1
|
|
|
|
# --- build stage: compile a static, CGO-free binary ---
|
|
FROM golang:1.26-alpine AS build
|
|
ARG COVER_DIR=/covers
|
|
WORKDIR /src
|
|
|
|
# Dependencies first for layer caching (changes rarely).
|
|
COPY go.mod go.sum ./
|
|
RUN go mod download
|
|
|
|
# Then source (changes often). internal/web carries the go:embed'd
|
|
# templates/static assets — missing them turns the embed directive into a
|
|
# build error, so the whole tree must land before `go build`.
|
|
COPY *.go ./
|
|
COPY internal/ ./internal/
|
|
|
|
# Static binary: the Postgres driver (jackc/pgx) is pure Go, so CGO_ENABLED=0
|
|
# leaves no libc dependency.
|
|
# -trimpath + -ldflags strip paths and debug info for a smaller image.
|
|
RUN CGO_ENABLED=0 GOOS=linux go build -trimpath -ldflags="-s -w" -o /out/server .
|
|
|
|
# Create the source directory; runtime COPY sets ownership for the named volume.
|
|
RUN mkdir -p "$COVER_DIR"
|
|
|
|
# --- runtime stage: distroless static, non-root ---
|
|
FROM gcr.io/distroless/static:nonroot
|
|
ARG COVER_DIR=/covers
|
|
WORKDIR /
|
|
COPY --from=build --chown=65532:65532 ${COVER_DIR} ${COVER_DIR}
|
|
COPY --from=build /out/server /server
|
|
EXPOSE 8080
|
|
USER nonroot:nonroot
|
|
ENV PORT=8080
|
|
ENTRYPOINT ["/server"]
|