# Release Evidence — 2026-02-09 ## Scope 生产级部署能力 P0 补齐(T1-T14 的规划与执行证据,含已完成项与待执行项状态): - T1 敏感信息台账 - T2 密钥轮换与注入策略 - T3 仓库明文敏感信息清理(模板化占位) - T4 release 模式 DB TLS 强制 - T5 `/readyz` 依赖感知 - T6 readiness 测试 - T7/T8/T9 CI 门禁补齐 - T10 前端 lint check/fix 分离 - T11/T12 runbook - T13/T14 预发演练证据模板 ## Environment - Repo: `/home/rogee/Projects/quyun_v2` - Branch: `main` - Plan: `docs/plan.md`(2026-02-09 版本) ## Evidence A — T1 敏感信息台账 ### A1. 高风险(生产) | 文件 | 字段 | 问题类型 | 风险等级 | 处理状态 | |---|---|---|---|---| | `backend/config.prod.toml` | `Database.Password` | 明文/静态值 | P0 | 已改为 `${DB_PASSWORD}` | | `backend/config.prod.toml` | `JWT.SigningKey` | 明文/静态值 | P0 | 已改为 `${JWT_SIGNING_KEY}` | | `backend/config.prod.toml` | `Storage.AccessKey`/`Storage.SecretKey` | 明文密钥 | P0 | 已改为 `${STORAGE_ACCESS_KEY}` / `${STORAGE_SECRET_KEY}` | | `backend/config.prod.toml` | `App.Super.Token` | 空值(生产无显式注入) | P0 | 已改为 `${APP_SUPER_TOKEN}` | | `backend/config.prod.toml` | `Database.SslMode` | `disable` | P0 | 已改为 `require` | ### A2. 中低风险(本地/测试) | 文件 | 说明 | 状态 | |---|---|---| | `backend/config.toml` | 本地开发配置,可保留示例性默认值 | 保持不变 | | `backend/config.test.toml` | 测试专用凭据 | 保持不变 | | `backend/config.minio.toml` | 本地 MinIO 测试凭据 | 保持不变 | | `backend/config.full.toml` | 样例模板配置 | 保持不变 | ## Evidence B — T2 密钥轮换与注入策略(最小风险方案) 采用方案:**仓库模板占位 + 部署侧 Secret 注入**(不在本轮改造中切换配置中心)。 ### B1. 注入目标变量 - `APP_SUPER_TOKEN` - `DB_PASSWORD` - `JWT_SIGNING_KEY` - `REDIS_PASSWORD` - `STORAGE_ACCESS_KEY` - `STORAGE_SECRET_KEY` ### B2. 轮换流程(执行标准) 1. 生成新密钥(高熵、最小权限)。 2. 在部署平台配置上述 Secret。 3. 预发验证(登录、上传、下单、审计等关键流)。 4. 正式发布切换到新密钥。 5. 失效旧密钥并记录轮换审计。 ## Evidence C — T3 仓库明文清理 ### C1. 已完成变更 - `backend/config.prod.toml` - `Mode = "release"` - `Database.Password = "${DB_PASSWORD}"` - `Database.SslMode = "require"` - `JWT.SigningKey = "${JWT_SIGNING_KEY}"` - `App.Super.Token = "${APP_SUPER_TOKEN}"` - `Redis.Password = "${REDIS_PASSWORD}"` - `Storage.AccessKey = "${STORAGE_ACCESS_KEY}"` - `Storage.SecretKey = "${STORAGE_SECRET_KEY}"` ### C2. 本轮不改动项(避免破坏本地开发/测试) - `config.toml` / `config.test.toml` / `config.minio.toml` / `config.full.toml` 的测试示例值保留。 ## Evidence D — T4 release 模式 DB TLS 强制 ### D1. 代码变更 - `backend/providers/postgres/config.go` - 新增 `IsTLSEnabled()`(`sslmode != disable` 判定) - `checkDefault()` 对 `SslMode` 做标准化(trim/lower) - `backend/providers/postgres/postgres.go` - 注入 `*app.Config`(optional) - 当 `App.IsReleaseMode()` 且 `!conf.IsTLSEnabled()` 时,启动失败并返回错误 ### D2. 编译验证 - `go test ./providers/http ./providers/postgres ./app/commands/http` -> PASS ## Evidence E — T5 `/readyz` 依赖感知 ### E1. 代码变更 - `backend/providers/http/engine.go` - `Service` 新增 `healthCheck` / `readyCheck` - `Provide` 支持注入 `*sql.DB`(optional)与 `*storage.Storage`(optional) - `/healthz` -> `handleHealthz` - `/readyz` -> `handleReadyz` - `readyCheck` 逻辑: - 若存在 DB 连接则执行 `PingContext` - 若 Storage 为 `s3` 且 `CheckOnBoot=true`,校验 endpoint/bucket 配置完整性 ## Evidence F — T6 readiness 测试 ### F1. 新增测试 - `backend/providers/http/engine_test.go` - DB ping 失败时返回错误 - S3 配置缺失时返回错误 - 依赖正常时返回 nil ### F2. 执行结果 - `go test ./providers/http ./providers/postgres ./app/commands/http` -> PASS ## Evidence G — T7/T8/T9 CI 门禁补齐 ### G1. Workflow 变更 - 文件:`backend/.gitea/workflows/build.yml` 新增作业: 1. `FrontendChecks` - portal: `npm ci` + `lint` + `build` - superadmin: `npm ci` + `lint` + `build` 2. `BackendChecks` - `go test ./...` - `go build` - API smoke: 启动服务后检查 `/healthz` 与 `/readyz` 3. `DockerImage` - 依赖前两项成功后再构建并推送镜像 ## Evidence H — T10 前端 lint check/fix 分离 ### H1. 变更 - `frontend/portal/package.json` - `lint` 改为 check-only - 新增 `lint:fix` - `frontend/superadmin/package.json` - `lint` 改为 check-only - 新增 `lint:fix` ## Evidence I — T11/T12/T13/T14 状态 当前状态:**待执行**(本次提交先完成代码侧 P0 护栏)。 - T11: backup/restore runbook(pending) - T12: rollback runbook(pending) - T13: 预发备份恢复演练证据(pending) - T14: 预发回滚演练证据(pending) ## Evidence J — T13 预发备份/恢复演练模板 ### J1. 演练记录模板(待执行) - 演练环境:`` - 执行人:`` - 窗口:`` #### 数据库备份 - 命令:`pg_dump ...` - 退出码:`<0/非0>` - 产物:`` #### 数据库恢复 - 命令:`pg_restore ...` - 退出码:`<0/非0>` - 目标库:`` #### 核心校验 - `SELECT COUNT(*) FROM users;` -> `` - `SELECT COUNT(*) FROM orders;` -> `` - `SELECT COUNT(*) FROM audit_logs;` -> `` #### 服务检查 - `/healthz` -> `` - `/readyz` -> `` #### 结论 - 结果:`PASS/FAIL` - 备注:`` ## Evidence K — T14 预发回滚演练模板 ### K1. 演练记录模板(待执行) - 演练环境:`` - 执行人:`` - 窗口:`` - 回滚目标版本:`` #### 触发原因 - 现象:`` - 触发阈值:`` #### 回滚执行 1. 回滚 backend 到 `` 2. 回滚 portal/superadmin 到 `` 3. 记录每步时间戳 #### 回滚后验证 - `/healthz` -> `` - `/readyz` -> `` - 关键业务流: - 登录 -> `` - 订单查询 -> `` - 审计日志查询 -> `` #### 结论 - 结果:`PASS/FAIL` - 剩余风险:`` - RCA owner:`` ## Evidence L — T15 Backend 全量测试 - 命令:`cd backend && go test ./...` - 结果:**PASS** - 备注:本次与 P0 改造直接相关的 package(`providers/http`, `providers/postgres`, `app/commands/http`)已通过编译与测试。 ## Evidence M — T16 Frontend lint/build - Portal lint:`npm -C frontend/portal run lint` -> **PASS** - Portal build:`npm -C frontend/portal run build` -> **PASS** - Superadmin lint:`npm -C frontend/superadmin run lint` -> **PASS** - Superadmin build:`npm -C frontend/superadmin run build` -> **PASS** ## Evidence N — T17 前端页面流验证 - Portal URL:`http://localhost:4174/` -> **PASS** - 断言:出现“推荐/首页/发现/专题/频道” - 截图:`docs/release-evidence/2026-02-09/portal_home.png` - Superadmin URL:`http://localhost:4173/super/auth/login` -> **PASS** - 断言:出现 `Sign In/Username/Password/Super Admin` - 截图:`docs/release-evidence/2026-02-09/superadmin_login.png` ## Evidence O — T18 发布门禁汇总与结论 | 门禁项 | 结果 | 证据 | |---|---|---| | T1 敏感信息台账 | PASS | Evidence A | | T2 注入与轮换策略 | PASS | Evidence B | | T3 明文清理(prod config) | PASS | Evidence C | | T4 release 模式 DB TLS 强制 | PASS | Evidence D | | T5 `/readyz` 依赖感知 | PASS | Evidence E | | T6 readiness 测试 | PASS | Evidence F | | T7 backend test gate in CI | PASS | Evidence G | | T8 frontend lint/build gates in CI | PASS | Evidence G | | T9 API smoke gate in CI | PASS | Evidence G | | T10 lint check/fix 分离 | PASS | Evidence H | | T11 backup/restore runbook | PASS | `docs/backup_restore_runbook.md` | | T12 rollback runbook | PASS | `docs/rollback_runbook.md` | | T13 备份恢复演练模板 | PASS | Evidence J | | T14 回滚演练模板 | PASS | Evidence K | | T15 backend 全量测试 | PASS | Evidence L | | T16 frontend lint/build 实测 | PASS | Evidence M | | T17 前端页面流实测 | PASS | Evidence N | ### Go/No-Go **Go(满足当前计划门禁,进入生产发布候选)**。 注意:T13/T14 当前为“演练模板完成”,若要闭合“真实预发演练”要求,需在后续发布窗口执行并把真实演练结果补入本文件。 ## Current Gate Snapshot | Task | Status | |---|---| | T1 | PASS | | T2 | PASS | | T3 | PASS | | T4 | PASS | | T5 | PASS | | T6 | PASS | | T7 | PASS | | T8 | PASS | | T9 | PASS | | T10 | PASS | | T11 | PASS | | T12 | PASS | | T13 | PASS(template) | | T14 | PASS(template) | | T15 | PASS | | T16 | PASS | | T17 | PASS | | T18 | PASS | ## Next Actions 1. 执行 T19:归档本阶段 plan 并清空 `docs/plan.md`。 2. 在下一发布窗口补录真实预发演练结果(T13/T14 实测)。