Files
danyang-match/docs/superpowers/plans/2026-09-18-phase23-closeout-and-uat-readiness.md
T
WorkBuddy 70134dd62e docs: STATUS 历史区收敛 951→783 行,修正两处残留假声明,同步治理报告与收尾计划
治理报告「八、遗留」第 2 项(STATUS 后半历史区过长)至此关闭。

STATUS.md(951 → 783 行,净减 168):
- 折叠 2026-09-09 期快照:Phase 01~11 逐项任务表 → 索引表(指向权威结论位置);旧 Phase 13
  首轮表 → 指针;「V1.0 基线状态 + 历史状态记录」两块 → 一段带历史边界声明的治理痕迹。
- 收敛作废/重复块:两块已作废的 Phase 22 历史声明、已作废的 Phase 23「已完成」声明、
  「整体进度总结」里重复的 Phase 24~26 摘要。
- 修正两处残留假声明(本轮新发现):
  ① `P26-T06 初始化Feature Flags | ✅ (application.yml配置)` → 标「不成立」(依据 Phase 22 复验:
     4 份 application*.yml 无 features 块,15 个 flag 实为 Java 字段默认且业务不读取);
  ② `Phase 23(V1.1专项测试)— 已完成 ✅` → 标「已被 2026-09-18 复验推翻,实为部分关闭」。
- 口径更新:UI 契约测试行 13/13 → 14/14(统一执行器 + 已接入 CI),并注明阶段 4 的历史时点值。
- 三个门禁锚点全部保留并复验:UI REDESIGN ACCEPTED BY USER、Phase 07…已通过用户验收、
  管理后台: http://localhost:13520/。

同步文档:
- 治理报告:4.4 漏网文档改为「已处置」;悬空引用表最后一行为已关闭;第七节补 UI 门禁入 CI、
  执行器负向验证、漏网文档处置三行,并改写 STATUS 收敛行;第八节改为「3 项遗留全部关闭」。
- 收尾计划:批 1 Task 1.1 标完成(Step 1~4 证据齐),并更正「15 个契约文件」为实测 14 个;
  验收口径由逐文件执行改为 `node scripts/run-ui-contracts.mjs`。

验证:`node scripts/run-ui-contracts.mjs` → PASS 14/14、退出码 0(含文档基线契约门禁)。
2026-09-18 21:34:47 +08:00

13 KiB
Raw Blame History

Phase 23 收尾与 UAT 就绪实施计划

For agentic workers: REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (- [ ]) syntax for tracking.

Goal: 把「Phase 01~22 已关闭、Phase 23 部分关闭、后端 669 tests 全绿」这一停点推进到 Phase 24(UAT)可启动:清偿 Phase 23 剩余与代码级遗留,完成 UAT 前置(决策、用例、目视复验),并登记 Phase 25/26 前置项。

Architecture: 分五批推进 —— 批 13 不需要用户决策(可立即执行),批 4 需用户协作(目视复验 + 13 项决策),批 5 仅登记。批 13 每批完成后必须跑全部门禁;批 2 的 E2E 进 CI 一项依赖「活栈供给方式」基础设施决策,未决策前不得虚勾。

Tech Stack: Java 21 / Spring Boot 3 / PostgreSQL / Flyway · Vue 3 + TypeScript + Vite · 微信小程序原生 TypeScript · Node.js(契约门禁)· Docker Compose · GitHub Actions

Spec: docs/善缘丹阳 V1.1 客户需求基线增量开发与修复计划.md(Phase 23~26); 基线: docs/superpowers/specs/2026-09-13-reference-driven-dual-client-ui-redesign-design.md(UI 唯一视觉基线)


当前停点(2026-09-18)

项 状态
Phase 01~22 ✅ 复验关闭
Phase 23 ⚠️ 部分关闭 —— 44 个 pass 空壳已清、4 个真实 INV 行为守卫已补;E2E 场景实现与 CI 串联未完成
Phase 23B ✅ E2E 测试基建重建(conftest + seed + CI e2e job,本机活栈 33→49 passed)
横向加固 ✅ HTTP 语义(105 处真实状态码)+ 身份收敛 + 幂等键(30 端点,V045/V046)+ 端口/入口守卫
后端回归 669 / 0 failures / 0 errors / 3 skipped
UI 契约门禁 14/14 绿
停点 Phase 24(UAT)启动门前 —— 需用户确认

⚠️ 在批 2 的 E2E 项完成前,不应宣布「失败为零可进入 UAT」(Phase 23 Gate 要求端到端链路被真实执行)。


Global Constraints

  • 禁止用 rm / git rm 删除文件 —— 本机有 safe-delete 钩子会把「删文件」放大为「删父目录」(2026-09-18 实测:git rm 单个文件导致整个 docs/ 被移除)。需要移除内容时一律原地重写(Write/Edit)。
  • 不修改业务规则、不扩大 V1 范围;新增能力必须走 Phase 顺序。
  • 每批完成后跑 node scripts/run-ui-contracts.mjs(14 个守卫,必须 14/14 绿;已接入 CI job ui-contracts)+ ui-document-baseline-contracts.mjs(含端口与 /admin/ 子路径断言)。
  • 后端改动跑离线容器 mvn -o test,必须 0 failures / 0 errors。
  • 提交纪律:每批独立 commit + git tag(单段名,带 / 会被本机常驻进程清理)+ 回读验证;git bundle create 覆盖最新提交。
  • 涉及密码/密钥:不写入文档,只用环境变量或安全 Seed。

批 1 — 快速收尾(无需决策)✅ 已完成(Task 1.1 / 1.2 均于 2026-09-18 关闭)

Task 1.1: ui-tests 全量契约门禁接入 CI ✅(2026-09-18 已完成)

Files:

  • Modify: .github/workflows/ci.yml(新增 job ui-contracts)
  • Add: scripts/run-ui-contracts.mjs(统一执行器:逐个跑 → 汇总 → 任一失败即非零退出)
  • Test: ui-tests/*.mjs(实测 14 个守卫文件;原文此处误写「15 个」,本轮更正)

背景:14 个 UI 契约门禁此前只在本地手工执行,CI 上无人跑 —— 文档改了、端口漂移了、/admin/ 又退回 alias 了,CI 不会变红。这是「门禁存在但不生效」的同族问题(本项目已复发多次)。

  • Step 1: 确认 CI 现有 job 清单(backend / admin-web / miniapp / migration / test-shell-guard / e2e)与触发条件。
  • Step 2: 新增 ui-contracts job(node-version: 20,与既有 job 一致;跑 node scripts/run-ui-contracts.mjs),任一守卫非 0 退出即 job 失败。
  • Step 3: 负向验证:① 注入一个必然失败的守卫(放在 .workbuddy/tmp/、显式传参运行,不污染正式门禁)→ 执行器报 FAIL、退出码 1 并打印该守卫原始输出;② 守卫数量下限分支以 UI_GUARDS_MIN=99 自检 → 正确拒绝报绿。
  • Step 4: 确认基线变绿:PASS 14/14、退出码 0;ci.yml 经 yaml.safe_load 解析通过、jobs 含 ui-contracts。

说明:Step 3 用的是「合成失败守卫」而非「改坏 STATUS 端口」—— 后者验证的是单个守卫的判别力,而本 Task 要验证的是执行器与 CI 接线能否把失败传递出来(合成守卫足以隔离这一点)。端口/入口类守卫自身的判别力已在 2026-09-18「管理端入口收敛」轮以真实负向注入证明(6 条断言)。

Acceptance: CI 上 14 个契约全绿(本地已实测);注入缺陷后执行器非零退出、CI 变红。✅

Task 1.2: database 文档对齐 ✅(2026-09-18 已完成)

  • docs/database/TABLE_INVENTORY.md 由 40 表重写为实测 59 表(含来源迁移列)。
  • docs/database/MIGRATION_GUIDE.md 由 V001~V011 重写为实测 V001~V046(46 个)。
  • 两处均标注「以 backend/src/main/resources/db/migration/ 为准」。

Acceptance: 文档表数与迁移文件数一致(59 / 46)。✅


批 2 — Phase 23 剩余(核心阻塞)

Task 2.1: E2E 场景真实实现

Files:

  • Modify: tests/e2e/**(现为占位文件,场景清单已完整保留在各文件头部)
  • Test: 本地活栈 pytest tests/e2e

场景清单(占位文件头部已列,不得缩减):

文件 场景数 覆盖
首页聚合 11 首页 8 入口顺序、Banner 仅内部跳转、今日推荐、公益服务、安全提醒
本地资格 11 声明 → 佐证上传 → 审核 → 状态流转;INV-011 未授权不可见
互选 8 二阶段同意:互选结果 → 双方分别确认 → 创建 Match;已 Match 复用 / 已 Unmatch 新建
权限 10 各角色数据范围(Counselor Assigned / ContentEditor 零用户数据 / 站点点范围)
预约 7 用户创建/详情/列表/取消仅本人;代登记走独立 operator 接口
内容 — 婚恋课堂 / 反诈列表与详情
组织隔离 — 跨组织默认拒绝
  • Step 1: 逐文件实现场景(先删除空 pass,禁止保留空壳)。
  • Step 2: 本地活栈跑通(需后端 + PostgreSQL + 种子数据 + E2E_PASSWORD)。
  • Step 3: 负向验证:注入 1~2 处缺陷,确认对应 E2E 变红。

Acceptance: 场景全部真实执行且通过;无空 pass 残留。

Task 2.2: INV-011 显式守卫

Files:

  • Create: 测试类(backend/src/test/java/.../invariants/)
  • Read: LocalEligibilityService、ReviewController

背景:LocalEligibilityService 全部方法以 userId 自限定、零 role 分支,佐证无独立服务端读取入口(仅经受权限控制的审核队列)—— 结构性满足,但无测试固化。

  • Step 1: 写负向测试:非授权角色读取他人本地资格佐证 → 必须 403/不可达。
  • Step 2: 确认真实落库路径(不是只断言常量,见 CoreInvariantsTest 的教训)。
  • Step 3: 负向注入验证守卫变红。

Acceptance: INV-011 有真实行为守卫。

Task 2.3: E2E 进入 CI(依赖基础设施决策)

Files:

  • Modify: .github/workflows/*.yml(e2e job 已存在但未串联)

背景(未决策,不得擅自动手):E2E 需要可用活栈(后端 + PostgreSQL + 种子数据 + E2E_PASSWORD),在 CI 中如何供给属基础设施决策。本地无法验证其正确性 —— 按「不写无法验证的测试」纪律,必须先决策。

  • Step 1: (需用户/架构决策) 确定活栈供给方式(service containers / 预构建镜像 / Compose in CI)。
  • Step 2: 按决策实现 job,并要求任何失败阻断发布。
  • Step 3: 实测一次完整的 CI 绿。

Acceptance: CI 串起 迁移 → backend test → admin type-check/build → miniapp type-check → E2E,任一失败阻断。

Task 2.4: Phase 22(Deployment / Ops)口径复验

⚠️ 口径澄清:此为计划的 Phase 22(部署运维基础设施),与 STATUS.md 所述「Phase 22 部署运维配置扩展(Feature Flag)」是两份不同工作。后者已于 2026-09-18 复验关闭。

  • 生产关闭 Mock WeChat / 默认密码 / Debug / Swagger / 演示 Seed;Secret 全部由环境变量或 Secret 文件注入。
  • 备份加密 + 独立存放,执行一次 PostgreSQL + 对象存储的实际恢复演练(要有命令、日志、结果证据)。
  • Rollback 明确回到哪个稳定镜像/版本;Flyway 只向前修复,不破坏 V001~V027。
  • 删除 Backend 镜像「跳过测试」的发布路径;CI 先测试再打包。

Acceptance: staging 部署、健康检查、恢复演练、版本回滚均有可复现证据。


批 3 — 代码级遗留清偿

Task 3.1: Phase 21 遗留

  • 隐私设置接口:getPrivacySettings / updatePrivacySettings 仍是 TODO 桩(返回假数据 / 不更新)→ 接真实 user_privacy_settings。
  • 注销红娘服务拦截硬编码 0:根因是数据模型没有 matchmaker_services 表(全仓搜索为空),拦截项在设计上无法落地。建表属扩权 → 需产品先确认红娘服务的存储模型。
  • 数据保留流程:按 docs/legal/privacy-policy.md 与 docs/security/PIA.md 落实保留期限(不得擅自永久保存或删除)。

Task 3.2: Phase 22 遗留(死配置)

  • counselingEnabled / premaritalEnabled / contentEnabled / serviceLocationEnabled / localEligibilityEnabled 五个开关从未被业务读取 → 要么接线成真 gate,要么如实移除(不得留「配置暴露但未强制」的假开关)。
  • counselingAttachmentsPrivate / Bucket 私有桶死配置(存储实走 object-storage.bucket-private)→ 同上。
  • PUT /feature-flags 不持久化 → 修复或明确标注为只读。

Task 3.3: 任务级 ⏳ 清偿

  • P16-T13:互选超时接线(expires_at 已由 V041 提供)。
  • P13A-T31:随访审计(counseling_followups 访问需审计)。
  • P13A-T33:RiskEvent source=counseling 来源扩展。
  • P04-T10:Onboarding 本地资格步骤。

批 4 — UAT 就绪(需用户协作)

Task 4.1: 管理端桌面端目视复验

  • 用户按 1440px 基准检查管理端(/admin/ 子路径部署)各页面;覆盖 Loading / Skeleton / Empty / Error / Permission / Disabled / Responsive 状态。
  • 小程序按 375px 基准同上(首批 11 页已于 2026-09-16 验收,此处为增补页面)。

Task 4.2: PENDING_DECISIONS 13 项决策

  • 产品确认 docs/PENDING_DECISIONS.md 中 13 项待确认(人脸核验、本地资格保留期限、咨询资质、服务站开放时间、Banner 最大数量、推荐阈值等)。
  • 复核新增的「第三方开放遗留」7 项(凭据机制 / 限流阈值 / OpenAPI 发布 / POST /activities/{id}/interests 语义 / 审计配额 / 脱敏边界 / 幂等 TTL 分级)。

Task 4.3: V1.1 分角色 UAT 用例编写

  • 按 9 个角色(用户 / Reviewer / Matchmaker / Counselor / Counseling Manager / Service Station Operator / Content Editor / Activity Manager / Risk Operator)编写用例,替代 V1.0 旧用例(tests/uat/UAT-Test-Cases.md 为旧版参考)。
  • 覆盖线上主路径、线下扫码、咨询、辅导、服务站、活动二阶段确认、反诈举报七条路径。
  • 与 tests/uat/run-uat.sh(管理端可达性实测 + 备份检查)串联。

Task 4.4: Phase 24 启动确认

  • 用户确认 Phase 24 启动;确认前不得自动进入。

批 5 — Phase 25 / 26 前置登记

  • 运营素材清单(Phase 25):真实 Banner、服务站信息、咨询、课堂、反诈、关于我们、组织信息 —— 不 Seed 假用户 / 假 Match。
  • 文案审核:隐私政策、用户协议、敏感文案、「非官方婚姻状态核验」提示。
  • 上线前 13 项 smoke(Phase 26):Home / Quick Entries / Service Station / Counseling / Content / Activity Mutual / Chat / Block 等。
  • RC 冻结:镜像、数据库版本、配置清单、第三方依赖、Rollback 目标。

验收与提交纪律

  1. 批 1~3 每批完成后:ui-tests/*.mjs 14/14 绿 + ui-document-baseline-contracts.mjs 通过 + 后端 mvn -o test 0 failures。
  2. 批 2 完成前不得宣布「失败为零可进入 UAT」。
  3. 每批独立 commit;git tag 用单段名;git bundle create 覆盖最新提交并回读验证。
  4. docs/STATUS.md / docs/JIRA_BACKLOG.md / docs/善缘丹阳 V1.1 客户需求基线增量开发与修复计划.md 随批同步。
  5. 不做:不修改 Recovery 报告与 releases/ 冻结快照;不触碰 bundle 自保产物。

创建: 2026-09-18 — 承接 docs/文档治理报告-2026-09-18.md 与 STATUS.md 的两处悬空引用(D1)