为什么:用户要求"写好文档,一定要根据 specs 文档约束好"。把 specs 里与部署相关的 硬约束逐条对照现状后发现 9 条里有 6 条未覆盖或只写了一半,需要一次补齐并如实标注工程缺口。 - 新增 DEPLOY-CHECKLIST.md:环境映射(办公室主机 = test)、域名/HTTPS/反代(含 nginx 与证书建议)、 网络分区、发布与回滚规范(语义化 tag / release→main / 回滚演练)、备份与恢复(specs 目标 vs 现状差距)、 监控与告警现状、密钥托管与轮换、**上线检查清单对照表(docs/12 逐条 ✅⚠️❌ + 责任方)**、 风险/待确认(R1–R10)、上线前必补清单(P0–P2) - DEPLOY.md 增加"本机属于 test 环境"与交叉引用,并单列"上线前必须补的四条"提示 - 对照表里的 ✅ 都带证据(如分区生效先实测 playback_ticket_202610 落分区、_default = 0) - 只写文档,未改任何实现;mvn test 83 条全过、两入口 package 通过
23 KiB
Author: fruit.com.cn
DEPLOY-CHECKLIST —— 部署合规视角(specs 约束逐条结论 + 上线检查清单对照 + 风险/待确认)
这份文档回答两个问题:
1) docs/04-部署架构、docs/08-备份恢复方案、docs/10-安全方案、docs/11-发布与回滚方案、
docs/12-上线检查清单、docs/07-监控告警方案、GIT_WORKFLOW.md、CODING_STANDARDS.md
这些 specs 里跟部署有关的要求,我们现在满足到哪一步;
2) 上线前必须补什么、谁来补。
操作层面的"怎么部署/怎么回滚命令"在 DEPLOY.md(本文件只做结论与对照,避免两份口径分叉)。
结论用三态:✅ 已满足 | ⚠️ 部分满足(能用但有差距)| ❌ 未满足(上线前必补)
一、环境映射(对应 04-部署架构§一)
04-部署架构§一把环境分成四级:
| 环境 | 用途 | 数据 | 访问 |
|---|---|---|---|
| dev | 本地开发 | 本地 PostgreSQL | 内网 |
| test | 测试/联调 | 独立测试库 | 内网/VPN |
| pre | 预发(生产镜像演练) | 接近生产 | 受限 |
| prod | 生产 | 生产库 | 公网 |
当前这台办公室主机 = test 环境,依据三条:
- 用途是"给前端联调 + 内部验收",不是对外生产(
04-部署架构§一 test = 测试/联调); - 访问方式计划是内网/办公网(
admin-api只绑127.0.0.1),而不是公网; - 用的是独立的开发库(
fruitshorts,含种子数据),不是生产库。
规范要求与我们的对应:
docker-compose.yml用 Docker Compose 单机编排 → 对应 §五「第一阶段(dev/test):Docker Compose 单机编排」,✅。- 一台机器上合并 app/api/DB/Redis + worker 独立容器 → 对应 §三「精简方案:test 环境可将 app/api/DB/Redis 合并到 1 台 8C32G,转码 worker 独立 1 台」,✅(worker 是独立容器,但与在线服务同机:资源隔离靠容器限额,真正的分机留到生产)。
- 差距:
pre环境(生产镜像演练)尚未建立 —— 上线前建议在目标机用同一份 compose 跑一次"预发演练",即用生产镜像 + 接近生产的数据走一遍发布流程。状态:❌(流程未建立,不阻塞 test 联调)。
二、域名 / HTTPS / 反向代理(对应 04-部署架构§四 + 10-安全方案§二)
specs 原文:04-部署架构§四「域名/SSL:管理端、客户端 API、媒资分别域名;HTTPS 强制」;
10-安全方案§二「传输安全:HTTPS 强制;密钥环境变量注入」。
当前状态:❌ 未满足。现在的形态是 IP:端口 + HTTP:
| 需要的域名 | 现状 | 上线前必须做 |
|---|---|---|
管理端(后台 Web + /admin/**) |
无域名;admin-api 绑 127.0.0.1:8080,靠内网/SSH 隧道访问 |
申请域名(如 admin.<domain>)+ 证书;nginx 反代 → 127.0.0.1:8080;并保持只允许内网/VPN 来源(见 §三) |
客户端 API(/app/**) |
无域名;app-api 监听 8081(HTTP) |
申请域名(如 api.<domain>)+ 证书;nginx 反代 → 8081,只暴露 /app/**;强制 HTTP→HTTPS 跳转 |
媒资(/files/**) |
无域名;与 app-api 同一端口 | 申请域名(如 media.<domain>)或直接走 CDN 域名;播放地址已带签名参数,CDN 需按签名做缓存策略(04-部署架构§四) |
测试环境(本机)可以先用内网 HTTP 联调(04-部署架构§一 test 是内网/VPN 访问),
但上线(pre/prod)前必须满足上述三条 HTTPS + 独立域名,否则不满足 12-上线检查清单§三「传输安全」。
nginx + 证书的建议做法(上线前照做)
# /etc/nginx/conf.d/fruitshorts.conf(示意;域名与证书路径按实际替换)
server { # 客户端 API
listen 443 ssl http2;
server_name api.example.com;
ssl_certificate /etc/letsencrypt/live/api.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/api.example.com/privkey.pem;
client_max_body_size 20m; # 分片上传,与 admin-api 的 multipart 上限一致
location / { proxy_pass http://127.0.0.1:8081; proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header X-Forwarded-Proto $scheme; }
}
server { # 管理端:只允许内网/VPN 网段
listen 443 ssl http2;
server_name admin.example.com;
allow 10.0.0.0/8; allow 192.168.0.0/16; deny all; # 按实际内网段调整
location / { proxy_pass http://127.0.0.1:8080; proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header X-Forwarded-Proto $scheme; }
}
server { # HTTP 强制跳 HTTPS
listen 80;
server_name api.example.com admin.example.com;
return 301 https://$host$request_uri;
}
证书建议用 Let's Encrypt(certbot) 自动续期(certbot --nginx -d api.example.com -d admin.example.com),
或公司自有证书;无论哪种,到期前必须能自动续,否则接口会整体不可用。
反代配置文件需与本仓库一起纳入版本管理(放目标机的 /etc/nginx/conf.d/,另存一份到运维仓库)。
三、网络分区(对应 04-部署架构§四)
specs 原文:「网络分区:管理后台仅内网/VPN 可访问;客户端 API 公网。」
| 要求 | 现状 | 上线前必须做 |
|---|---|---|
| 管理后台仅内网/VPN | ✅ 已满足:docker-compose.yml 里 admin-api 端口映射为 127.0.0.1:8080:8080(只绑本机,公网访问不到) |
上公网后仍要保证:只经 nginx + allow/deny 内网段暴露(见 §二示例) |
| 客户端 API 公网 | ⚠️ 部分满足:app-api 监听 0.0.0.0:8081,同网段可访问;但还没有反代/域名,也没限制只暴露 /app/** |
反代只放行 /app/**(/files/** 走媒资域名/CDN);不要把 /v3/api-docs、/healthz 直接暴露到公网(/healthz 可留给内网监控) |
注意:/doc.html 与 /v3/api-docs 由 SWAGGER_ENABLED 控制(见 DEPLOY.md)。
联调环境建议 true(前端要看),公网生产建议 false(不暴露接口清单)。
四、发布与回滚规范(对应 11-发布与回滚方案§一/§四 + GIT_WORKFLOW.md§四)
specs 原文:
11-发布与回滚方案§一:「语义化版本v<major>.<minor>.<patch>;分支main(生产)←release/*←develop←feature/*;每次release/hotfix合并main必须打 tag,tag 不可移动/删除。」GIT_WORKFLOW.md§四:「major破坏性变更、minor新功能、patch修复;发布后 tag 不可移动、不可删除(错误版本发新 tag 修正,不覆盖旧 tag)。」11-发布与回滚方案§四:「回滚演练:上线前演练回滚,确保可执行。」「数据库迁移脚本必须可回滚(向前兼容,避免破坏性变更)。」
| 要求 | 现状 | 上线前必须做 |
|---|---|---|
语义化 tag v<x.y.z> |
⚠️ 部分满足:DEPLOY.md 里只是示例式地提到"每次发版打 tag",没有命名规范 |
按 §四 规则打:首个上线版本 v1.0.0;之后功能 v1.1.0、修复 v1.0.1;错误版本发新 tag,绝不移动/删除旧 tag |
| release/hotfix 合并 main | ⚠️ 流程未走过:目前工作都在 develop,main 未动 |
上线时:develop → 建 release/v1.0.0 → 在 test 环境验证 → 合并 main + 打 tag v1.0.0(由用户操作,Codex 不碰 main) |
| 回滚可执行 | ✅ 技术路径已写全(DEPLOY.md§七:切回上一个镜像 tag / git 回上一个 release tag + up -d --build + 重跑冒烟) |
上线前演练一次(在 test 环境故意回滚到上一版本并跑 tools/smoke.sh),把演练记录留档 |
| 数据库迁移可回滚 | ⚠️ 部分满足:sql/*.sql 全是幂等增量(ADD COLUMN IF NOT EXISTS、CREATE TABLE IF NOT EXISTS),没有破坏性变更;upsert 语义的种子脚本也在 |
上线前确认:本次发布不包含 DROP/ALTER TYPE 类破坏性语句(当前没有);如将来有,必须先写"回滚脚本 + 备份"再发 |
| 灰度/放量 | ❌ 未满足(单机 Compose 无灰度能力) | 上线首日按"先内测 → 再小流量(如有网关可切)";正式灰度需要 K8s/网关,属后续阶段(04-部署架构§五:生产上 K8s) |
五、备份与恢复(对应 08-备份恢复方案§二/§三)
specs 目标:全量每日 × 保持 30 天;WAL 归档(实时);可选增量;备份加密 + 异地存储; RPO ≤ 5 分钟、RTO ≤ 30 分钟;每季度至少一次恢复演练。
| 项 | specs 要求 | 现状 | 差距 / 上线前必须补 |
|---|---|---|---|
| 全量备份 | 每日 1 次,保留 30 天 | ⚠️ DEPLOY.md§七 给了手动 pg_dump 命令;没有定时任务、没有保留策略 |
目标机加 cron(或 compose 侧容器)每日 pg_dump,按日期命名保留 30 天;脚本可放 tools/backup.sh(本轮未写,属运维脚本) |
| WAL 归档 | 实时,用于 PITR | ❌ 未配置(PG 默认 archive_mode=off) |
postgresql.conf:wal_level=replica、archive_mode=on、archive_command 推到异地;这是达成 RPO≤5min 的唯一途径 |
| 增量 | 可选 | ❌ 未做 | 有了 WAL 归档即可满足 RPO,增量备份可后补 |
| 加密 | 备份加密 | ❌ 未做 | pg_dump 管道给 age/gpg,或落到加密卷;密钥单独保管(与备份分开) |
| 异地 | 与生产不同可用区/账号 | ❌ 未做(本机 dump 还在同一台机器上) | 推到对象存储(另一账号/另一区);"备份和数据库在同一台机器上"等于没备份 |
| 恢复演练 | 每季度 ≥ 1 次,记录归档 | ❌ 从未做过 | 首次上线前做一次"恢复到新库 + 起服务 + 冒烟",记录耗时(验 RTO)与丢失窗口(验 RPO) |
结论:备份恢复这一项与 specs 差距最大,是上线前必须补的硬缺口(❌)。 当前只有"能手动 dump",距离「RPO≤5min / RTO≤30min / 加密 / 异地 / 季度演练」还差整套机制。 建议排期:上线前至少做到「每日全量 + 异机保存 + 一次恢复演练」;上线后两周内补 WAL 归档与加密。
六、监控与告警现状(对应 07-监控告警方案§七)
specs 原文:07-监控告警§七「Prometheus/Loki/Grafana 尚未部署,第一阶段先用日志 + SlowRequestLogger 兜底」;
§六「告警渠道:飞书/钉钉/邮件 + 值班轮转」;§六「值班表与 Runbook 见 docs/plans/(上线前补)」。
| 项 | 现状 | 上线前必须补 |
|---|---|---|
| 指标(Prometheus) | ❌ 未部署;项目也没引 actuator(/actuator/health 一直是未映射,见 DEPLOY.md§五说明) |
按 §七 的既定路线部署;要暴露指标需先给两个入口加 spring-boot-starter-actuator + micrometer-registry-prometheus(属代码改动,需立项) |
| 日志聚合(Loki) | ❌ 未部署;现在日志在容器 stdout(docker compose logs) |
部署 Loki + Promtail 采集容器日志 |
| 大盘(Grafana) | ❌ 未部署 | 按 §五 大盘定义建面板 |
| 第一阶段兜底 | ✅ 已具备:应用结构化日志(转码耗时/失败原因、业务异常、SlowRequestLogger 慢请求告警都在代码里)+ 容器级 healthcheck(/healthz) |
至少把"容器 unhealthy"接到人的手机上(可用 docker compose events + 简单脚本/飞书机器人) |
| 告警渠道 + 值班 + Runbook | ❌ 未定 | 定渠道(飞书/钉钉/邮件)、排值班表、把 DEPLOY.md§九「故障速查」扩成 Runbook |
结论:监控告警 ❌ 未满足,但按 specs §七 的既定节奏,第一阶段允许先用日志兜底 ——
前提是"告警能到达人"。上线前最低要求:容器 unhealthy / 冒烟失败能被发现(哪怕先是人工每天跑一次 tools/smoke.sh)。
七、密钥托管与轮换(对应 10-安全方案§五)
specs 原文:§五「密钥托管:生产密钥集中托管,最小权限」;12-上线检查清单§三「JWT/签名密钥走环境变量,未硬编码/入库」「生产密钥集中托管」。
| 要求 | 现状 | 上线前必须补 |
|---|---|---|
| 密钥走环境变量、未硬编码/入库 | ✅ 已满足:三个可运行件的密钥全部 ${ENV:...} 注入;.env 已 gitignore;.env.example 只有占位;镜像里不含密钥 |
继续保持;代码审查时禁止把密钥写回 yml |
| 缺失即启动失败 | ✅ 已满足:ProdSecretGuard 在 prod profile 下校验三个密钥 + 签名开关 + DB_URL + CORS,缺失/仍是 dev 默认值/不足 32 位 → 退出码 1 |
— |
| 集中托管 | ⚠️ 部分满足:现在是"目标机的 .env 文件"(文件权限 600),没有密钥管理系统 |
短期:.env 权限 600、只有运维账号可读、不进任何 git 仓库、单独备份(加密);中期:迁到 K8s Secret / 云 KMS / Vault(04-部署架构§五 生产路线也是 K8s Secret) |
| 最小权限 | ⚠️ 部分满足:DB 用单一 fruitshorts 账号(读写全库) |
拆账号:应用用 fruitshorts_app(DML 权限、无 DDL);备份用只读账号;DDL 只留给运维 |
| 轮换 | ❌ 未做(也没有流程) | 定义轮换周期(建议 90 天或按事件):先加新密钥 → 双密钥并行验证期 → 再下线旧密钥;JWT 轮换会导致存量 token 失效,需选低峰并公告(10-安全方案§一 token 有效期 120min,影响窗口可控) |
八、上线检查清单对照表(逐条映射 docs/12-上线检查清单.md)
三态:✅ 已满足 | ⚠️ 部分满足 / 有条件满足 | ❌ 未满足(上线前必补) 「责任方」列区分:Codex(我能做的)/ 用户或运维(需要账号、域名、外部资源)。
一、代码与门禁
| 检查项 | 状态 | 依据 / 缺口 | 责任方 |
|---|---|---|---|
| 三端门禁全绿 | ⚠️ | 后端 ✅:mvn test 83 条全过;前端(Flutter/Web)不在本工程范围,由另一同事的 AI 负责,需其提供门禁结果 |
用户/前端 |
接口契约 api-phase1.md 已同步 |
✅ | 本轮 B1-1/B1-2 的 verify / reconcile 改动都已同步进契约 | Codex |
| 作者标识齐全 | ✅ | 远端已做全量补齐(35be37c),本轮新增文件也都带 // Author: fruit.com.cn |
Codex |
| 代码规模红线、无关键路径 TODO | ⚠️ | 未做静态检查工具(后端无 checkstyle/pmd),存量未逐文件核对;无 TODO 扫描证据 | Codex(需立项) |
二、功能与测试
| 检查项 | 状态 | 依据 / 缺口 | 责任方 |
|---|---|---|---|
| 核心用例通过、P0 清零 | ⚠️ | 后端 83 条(含真实 ffmpeg smoke)全过;前端与端到端用例不在本工程 | Codex/用户 |
| 支付闭环端到端 | ⚠️ | 票据校验/幂等/退款回收/对账已实现并有单测;真实 Google Play 未联调(缺 packageName + service account JSON,属付费凭据) | 用户(凭据)+ Codex(联调) |
| 播放长稳 + 弱网测试 | ❌ | 未做(需真机 + 网络模拟) | 前端/用户 |
| 多端(iOS/Android)回归 | ❌ | 未做(Android 无可用模拟器,iOS 有真机) | 前端/用户 |
三、安全
| 检查项 | 状态 | 依据 / 缺口 | 责任方 |
|---|---|---|---|
播放签名 signature-required=true(生产必开) |
✅ | application-prod.yml 写死 true,ProdSecretGuard 再校验一次,缺了直接拒启 |
Codex |
| JWT/签名密钥走环境变量,未硬编码/入库 | ✅ | 三件全 ${ENV:...};.env gitignore;镜像不含密钥 |
Codex |
| 越权/注入/敏感数据专项测试 | ⚠️ | 越权:创作者中心有专项用例(B 批);注入/SQL 注入:全部走 MyBatis-Plus 参数绑定,无字符串拼接 SQL(人工核对),无自动化用例;敏感数据脱敏有实现(AppIdentifier.mask)但无专项测试 |
Codex(需立项) |
| 生产密钥集中托管 | ⚠️ | 见 §七:现为 .env 文件权限隔离,未接 KMS/Vault |
用户/运维 |
四、基础设施
| 检查项 | 状态 | 依据 / 缺口 | 责任方 |
|---|---|---|---|
| 数据库分区已生效 | ✅ | watch_history/playback_ticket/order_event 均为声明式月分区,partition-maintenance 启动时+每日补齐。实测证据:select tableoid::regclass, count(*) from playback_ticket group by 1 → playback_ticket_202610 | 1(落月分区,不是 _default);select count(*) from watch_history_default → 0 |
Codex |
| Redis/缓存(如接入)配置正确 | ⚠️ | compose 已备 Redis 容器,代码尚未接入(C2 待做);当前不依赖 Redis | Codex(C2) |
| 媒资已迁 OSS/S3 + CDN(生产) | ❌ | 仍是本地磁盘 ./data/uploads,与在线服务同机;MediaStorageService 已把存储收敛到一处,切换 OSS 只需改它 + 转码产物上传路径 |
用户(账号)+ Codex |
| 备份恢复已配置并演练 | ❌ | 见 §五,差距最大 | 用户/运维 + Codex(脚本) |
| 监控告警已接入、告警可达 | ❌ | 见 §六 | 用户/运维 |
五、商店与合规
| 检查项 | 状态 | 依据 / 缺口 | 责任方 |
|---|---|---|---|
| 应用名称/截图/文案/隐私标签一致 | ❌ | 未办(客户端上架材料) | 用户 |
| App Privacy / Data Safety / SDK 清单 | ❌ | 未办 | 用户 |
| 隐私政策、用户协议已上线 | ❌ | 未办(后端有 app_user_consent 落库能力,文案与页面需法务/前端) |
用户 |
| 版权/素材/商标授权台账 | ❌ | 未办 | 用户 |
| 商店账号/证书/包名有效 | ❌ | 未办;并且包名仍不一致(Android com.stormg.lumadrama / iOS com.stormg.lumadramv,见 C 端回执) |
用户(建议上架前统一) |
六、发布与回滚
| 检查项 | 状态 | 依据 / 缺口 | 责任方 |
|---|---|---|---|
版本号 + tag 冻结(v1.0.0) |
❌ | 尚未打 tag(规范见 §四) | 用户(合并 main 时打) |
| 回滚方案已演练 | ❌ | 方案已写(DEPLOY.md§七),未演练 |
用户/运维 |
| 值班表 + 告警 Runbook 就绪 | ⚠️ | DEPLOY.md§九「故障速查」可作为 Runbook 初稿;值班表未定 |
用户 |
| 灰度/放量计划明确 | ❌ | 单机 Compose 无灰度能力;生产上 K8s 后再做 | 用户 |
七、观察窗口(上线后)
| 检查项 | 状态 | 依据 / 缺口 | 责任方 |
|---|---|---|---|
| 核心链路监控 | ❌ | 监控未接;上线首日建议人工每 30 分钟跑一次 tools/smoke.sh + 看 docker compose logs 作为过渡 |
用户/运维 |
| 支付/订单对账数据回看 | ⚠️ | 对账能力已在(/admin/reconcile/run,storeAmountSum 无数据源时返回 null + notes),真实商店数据要等凭据 |
Codex/用户 |
| 崩溃率/错误率观察 | ❌ | 未接监控;容器日志可人工查 | 用户/运维 |
| 问题复盘归档 | ⚠️ | 本工程有 PROGRESS/回执留痕习惯,可沿用 | Codex/用户 |
九、风险 / 待确认(CODING_STANDARDS§7 要求:技术决策必须留痕)
| # | 风险 / 待确认 | 影响 | 建议与责任方 |
|---|---|---|---|
| R1 | 媒资仍在本机磁盘(./data/uploads),未迁 OSS/CDN |
单机磁盘满/机器损坏即媒资全丢;播放无法借 CDN 扛量 | 12-上线检查清单§四把"迁 OSS/CDN"列为上线项,属上线前必补;MediaStorageService 已是唯一替换点,切换工作量可控(Codex 可做,需 OSS 账号) |
| R2 | 单点无高可用:一台办公室主机跑全栈 | 机器/网络故障 = 服务全停;无灰度能力 | test 阶段可接受;生产必须按 04-部署架构§三 生产规格(应用 2+、DB 主备)+ §五 上 K8s |
| R3 | 备份未演练、无 WAL 归档、备份与库同机 | 真出事时可能既恢复不了也丢得多(RPO 远大于 5 分钟) | 上线前至少"每日全量 + 异机保存 + 一次恢复演练";两周内补 WAL 归档与加密(见 §五) |
| R4 | 监控与告警未接 | 故障靠人发现;上线首日风险最高的窗口无自动告警 | 短期用"人工冒烟 + 容器 healthcheck";随后按 07-监控告警方案部署(需先给服务加 actuator,属代码改动) |
| R5 | 商店合规未办(隐私政策/Data Safety/SDK 清单/版权台账/包名) | 无法上架;印尼还涉及 Kominfo PSE 注册(未注册可能被整体封锁,见 docs/08/PRD 合规节) |
全部为用户侧工作;其中"包名统一"建议在上架前完成(一旦上架不可改) |
| R6 | 真实 Google Play 联调未做(缺 packageName + service account JSON) | 支付闭环在真机/商店侧未验证;STORE_VERIFIER=disabled 时对外明确返回"尚未配置",不会产生假订单 |
用户提供凭据后,Codex 用沙盒测试购买联调(STORE_VERIFIER=google-play) |
| R7 | HTTPS/域名未就绪,当前 IP+HTTP | 不满足 04-部署架构§四与 10-安全方案§二;公网明文传输不可接受 |
上线前按 §二 配域名 + 证书 + nginx(用户/运维) |
| R8 | DB 账号未做最小权限(单账号读写全库) | 应用被攻破即拥有 DDL 能力 | 拆 fruitshorts_app(仅 DML)与备份只读账号(见 §七) |
| R9 | /swagger-ui/** 静态资源在 SWAGGER_ENABLED=false 时仍可访问 |
不泄露接口信息(spec 与 config 都已 404),但严格合规环境下应彻底关闭 | 可选加固:spring.web.resources 排除 webjar;需你点头再改(Codex) |
| R10 | 转码 worker 与在线服务同机(虽为独立容器) | 大批量转码会抢 CPU,影响播放稳定性 | 04-部署架构§三 的完整方案是 worker 独立 1 台;上线前如有第二台机器就拆开,否则给 worker 容器加 CPU 限额(Codex 可改 compose) |
十、上线前必补清单(按优先级)
| 优先级 | 事项 | 依赖 | 责任方 |
|---|---|---|---|
| P0 | HTTPS + 独立域名 + nginx 反代(§二) | 域名、证书 | 用户/运维 |
| P0 | 每日全量备份 + 异机保存 + 一次恢复演练(§五) | 目标机 + 异地存储 | 用户/运维(Codex 可提供脚本) |
| P0 | 媒资迁 OSS/CDN(R1) | 云账号 | 用户 + Codex |
| P1 | tag 规范落地 + 回滚演练(§四) | — | 用户(合并 main 时)/ Codex 配合 |
| P1 | 监控告警最低可用(§六:容器 unhealthy 能到人) | 通知渠道 | 用户/运维 |
| P1 | 真实 Google Play 联调(R6) | 付费凭据 | 用户 → Codex |
| P2 | DB 最小权限账号(R8)、密钥集中托管(§七) | 运维 | 用户/运维 |
| P2 | K8s 生产化(R2)、灰度能力、WAL 归档与加密 | 生产资源 | 后续阶段 |