Files
book-comic-library/docs/README_zh.md
T

4.3 KiB

Book & Comic Library

个人书库/漫画库:Go+Gin 后端(扫描/上传入库、多用户 JWT、阅读进度、磁盘+Redis 缓存)+ Docker Compose 部署。设计见 superpowers/specs/2026-09-04-book-comic-library-design.md;部署规范见 superpowers/specs/2026-09-07-docker-deploy-spec-design.md。英文镜像:README.md。

Deploy mode

  • release:deploy/docker-compose.yml — 多阶段 backend|frontend/Dockerfile.prod(target runner)编译产物,不挂源码;infra 端口只在容器网络。
  • dev:deploy/docker-compose.dev.yml — 四服务全容器化,源码挂 ../backend:/app、../frontend:/app(web 服务带匿名 node_modules 卷),target: dev 镜像;api 跑 go mod download && dlv debug ./cmd/webui(热重启不 rebuild,delve :2345);infra 暴露宿主 PG 5432 / Redis 6379;healthcheck 门控。

Volume Mount

  • 共享 named volumes:booklib_postgres_data、booklib_redis_data(两个 compose 同名,dev/release 看到同一份数据;仅 down -v 清除)。
  • 配置/日志绑定挂载:deploy/nginx/{nginx.conf,conf.d/default.conf}、deploy/redis/redis.conf(:ro)与 deploy/logs/nginx —— 全部来自 deploy/prepare.sh(模板在各产物同目录的 *.tpl),容器里配置不对/缺失 = 忘了重跑它。
  • 文件存储:deploy/api/storage → 容器 /data/books(缓存写 /data/books/cache)。

跑起来(生产形态)

cp deploy/.env.example deploy/.env   # 填 JWT_SECRET、ADMIN_USER、ADMIN_PASSWORD(≥8 位,低于 8 位 seed 会跳过并 log)
deploy/prepare.sh
docker compose -f deploy/docker-compose.yml up -d --build
bash scripts/smoke.sh && bash scripts/smoke-web.sh
  • web: http://localhost:8080(WEB_PORT 可改),API 走 nginx /api/ 前缀反代到无状态 api 副本(--scale api=N)。
  • 原始书放进 deploy/api/storage/(挂到 /data/books),scanner 周期入库(默认 60s)。
  • nginx access/error 日志:deploy/logs/nginx/。

开发

deploy/prepare.sh
docker compose -f deploy/docker-compose.dev.yml up -d --build
  • 前端: http://localhost:5173(vite,HMR 直接生效;/api 代理到容器内 api)。
  • Go 改码后:docker compose -f deploy/docker-compose.dev.yml restart api(重编译挂载源码,无需 rebuild)。
  • 断点调试:delve headless 在 localhost:2345(VSCode launch:{"type":"go","request":"attach","mode":"remote","host":"localhost","port":2345,"substitutePath":[{"from":"${workspaceFolder}/backend","to":"/app"}]};命中断点后用 dlv 命令继续)。
  • 直连基础设施跑测试:PG localhost:5432(lib/lib/lib)、Redis localhost:6379:
cd backend
export DATABASE_URL='postgres://lib:lib@localhost:5432/lib?sslmode=disable'
export REDIS_URL='redis://localhost:6379'
go vet ./... && gofmt -l .
go test -p 1 -count=1 ./...

-p 1 是必须的:集成测试共用同一个 PG 库,各自 DELETE FROM ... 清表——并行跑会互相删数据导致随机失败。dev 栈起停用 down(不是 rm),否则匿名 node_modules 卷成孤儿。无 PG/Redis 时依赖它们的测试自动 skip;Redis 挂掉不影响功能(全链路降级为 miss/放行,见 spec §9)。

前端门槛:cd frontend && npm run check(tsc + vitest + vite build)。

旧卷迁移(一次性,升级自上一版部署)

# 老 PG 数据 → 新共享卷
docker run --rm -v book-comic-library_pgdata:/from -v booklib_postgres_data:/to alpine cp -a /from/. /to/
# 老 cache 卷是封面/解压派生数据,直接丢弃(自动重建)
docker volume rm book-comic-library_pgdata book-comic-library_cache

书库文件:原宿主 ./library/ 的内容移入 deploy/api/storage/。

可信代理与限流

  • nginx 在 compose 网络内,api 的 ClientIP 只信 TRUSTED_PROXY_CIDRS(逗号分隔 CIDR,默认 172.16.0.0/12,即 compose 网段)。外部伪造 X-Forwarded-For 换不掉限流桶;换部署网络时改这个 env。
  • 登录限流 5 次/分钟/IP 按尝试计数,成功登录也计——爆破和正常高频登录同账。

改 schema 前必读

db.Migrate 只执行 schema.sql 的 CREATE TABLE IF NOT EXISTS——对已存在的库加列/改列不会生效。任何列变更之前,必须先引入 schema_migrations 版本表 + 有序迁移脚本,否则老部署会静默跑在旧结构上。

PWA

不可变资源(封面/CBZ 页/原文件)SW cache-first,读过的内容离线可翻;登出会清 SW 缓存。