feat(deploy): D1 后端部署就绪(配置外置 + prod fail-fast + 自包含 Compose + 冒烟/回滚)

为什么:用户下午要部署,但全仓没有任何部署产物;且生产漏配密钥会静默使用代码里的 dev 默认值,
属上线阻塞项(04-部署架构 / 12-上线检查清单)。

- 配置外置(三件):DB_URL、JWT 双密钥(**发现 app-secret 此前没外置,一直用 dev 默认值**)、
  MEDIA_SIGNATURE_SECRET、MEDIA_SIGNATURE_REQUIRED、CORS_ALLOWED_ORIGINS、MEDIA_ROOT_DIR
- 新增三份 application-prod.yml:签名强制开启、CORS 收紧、媒资指向挂载点、日志级别
- 新增 ProdSecretGuard(@Profile("prod")):密钥缺失/仍是 dev 默认值/不足 32 位、签名未开、
  DB_URL 或 CORS 为空 → 一次列全并终止启动(exit 1)
- 新增 /healthz 轻量健康端点:查明 /actuator/health 的"超时"是旧 jar 未重启所致,项目本就
  没有 actuator 依赖,故不引新依赖;同时把 /healthz 加进安全白名单
- Docker 化:多阶段 Dockerfile(非 root、tini、依赖层缓存、ffmpeg 只给 worker)、.dockerignore、
  自包含 docker-compose.yml(含 PostgreSQL 18 + Redis + 命名卷 + 按序初始化 sql + healthcheck)
- tools/smoke.sh(失败非 0 退出)+ DEPLOY.md(Compose 主线 / 裸 jar 兜底 / 回滚 / 故障速查)
- 实测:mvn test 83 条全过;两入口 package 通过;prod 缺密钥退出码 1 且报错明确、配齐后正常启动;
  冒烟脚本全 PASS;本机无 Docker,镜像与 compose 未经构建验证(已在回执如实标注)
This commit is contained in:
jianghaifeng committed 2026-10-16 13:01:08 +08:00
1 parent 9f76302e53
commit b567365460
16 files changed
+814 -9

No files matched your search

@@ -10,7 +10,8 @@ spring:
exclude: org.springframework.boot.autoconfigure.security.servlet.UserDetailsServiceAutoConfiguration
datasource:
driver-class-name: org.postgresql.Driver
url: jdbc:postgresql://127.0.0.1:5432/fruitshorts
# 地址外置:生产用 DB_URL 注入(prod profile 会校验非空)
url: ${DB_URL:jdbc:postgresql://127.0.0.1:5432/fruitshorts}
username: ${DB_USER:fruitshorts}
password: ${DB_PASSWORD:fruitshorts}
jackson:
@@ -40,16 +41,23 @@ mybatis-plus:
fruitshorts:
media:
# 本地媒资目录(相对应用启动目录),通过 /files/** 访问
root-dir: ./data/uploads
# 媒资目录:容器里指向挂载卷;本地默认 ./data/uploads
root-dir: ${MEDIA_ROOT_DIR:./data/uploads}
public-prefix: /files
chunk-size: 5242880
max-file-size: 2147483648
signature-secret: ${MEDIA_SIGNATURE_SECRET:fruitshorts-media-dev-secret-change-me-in-production-32b}
signature-required: ${MEDIA_SIGNATURE_REQUIRED:false}
signature-ttl-minutes: 15
jwt:
# 双密钥都要外置:只配 admin 而漏配 app,生产会静默用 dev 默认值(prod fail-fast 会拦住)
admin-secret: ${JWT_ADMIN_SECRET:fruitshorts-admin-dev-secret-change-me-in-production-32b}
admin-ttl-hours: 12
app-secret: ${JWT_APP_SECRET:fruitshorts-app-dev-secret-change-me-in-production-32bytes}
app-access-ttl-minutes: 120
app-refresh-ttl-days: 30
cors:
allowed-origins: http://localhost:3005,http://127.0.0.1:3005
allowed-origins: ${CORS_ALLOWED_ORIGINS:http://localhost:3005,http://127.0.0.1:3005}
springdoc:
swagger-ui: