Files
danyang-match/docs/PROGRESS-ASSESSMENT-2026-09-21.md
WorkBuddy 8bd1ab804a fix(organization): 修复创建机构审计缺操作人;补全机构修复的验证并部署 Docker 测试环境
一、机构审计归属缺陷(本轮活栈验收中新发现)
- 现象:audit_logs 中 CREATE_ORGANIZATION 的 operator_id 7/7 为 NULL,
  而 DISABLE/ENABLE_ORGANIZATION 均正确记录操作人。审计不可归属 = 无效审计。
- 根因:OrganizationController.create 持有 @AuthenticationPrincipal OperatorPrincipal,
  却只把 params 传给 Service,未透传 principal.id() → saveAuditLog(null, ...)。
- 修复:createOrganization(params, operatorId) 签名透传;新增测试断言
  createOrganizationRecordsOperatorInAuditLog 长期守卫。
- 复验:新写入的 7 条 CREATE 审计全部带 operator_id,旧 14 条仍为 NULL(前后对照清晰)。

二、补全 rc.22 的验证缺口(此前记为「已修复待验证」)
- 全量回归 757 / 0 / 0 / 3,BUILD SUCCESS,108 个测试类,6:44(基线 741 + 新增 16)。
- 负向注入:ORG_STATUS_ACTIVE 改回 "normal" → 16 例变 3 失败 + 7 错误
  (守卫三条断言各自命中 + 服务侧 7 例被 H2 CHK_ORG_STATUS 拦下)。
  注入采用「仓库只读挂载 + 容器内副本改写」,工作区哈希前后一致,源码零污染。
- 活栈实测(Docker 全栈):创建/停用/启用均 2xx、非法输入 400、不存在 404、全程零 5xx(15/15)。
- 对已部署栈 pytest tests/e2e → 65 passed。

三、Docker 测试环境部署与工具链固化
- 测试镜像 danyang-match-backend-test 与命名卷 danyang-m2-cache 因 Docker Desktop 重装丢失,
  构建定义此前是临时产物 → 落盘为仓库资产 infrastructure/test-toolchain/Dockerfile。
- 本地栈统一使用 docker compose -p danyang(原项目名 infra 与另一项目撞名,
  其 --remove-orphans 会误删本项目容器;已确认邻项目数据无丢失,见 known-risks KR-09)。

四、UI 门禁脆弱性修复
- ui-document-baseline-contracts.mjs 解析 docker-compose.staging.yml 时报假红
  (「守卫自身失效」);真因是该文件为 CRLF 而守卫正则要求 \n 紧随 container_name 之后
  (prod.yml 是 LF 所以此前能过)。解析改为行尾无关,真实断言未削弱。门禁 18/18。

五、文档
- STATUS.md 新增 rc.23 并将 rc.22 由「待验证」订正为「已验证关闭」。
- 实施计划附 B.1、PROGRESS-ASSESSMENT-2026-09-21.md 同步订正。
- known-risks.md:KR-07 解除(Docker 已恢复)、KR-01/KR-06 按复测订正,
  新增 KR-08(Docker Hub 域名 DNS 被投毒,改用国内镜像源绕行)与 KR-09(compose 项目名撞名)。

验证状态:全量回归 757/0/0/3 全绿;UI 契约门禁 18/18;对已部署栈 E2E 65/65;
负向注入可变红;工作区哈希未被注入过程污染。
未验证:GitHub Actions 首次真绿(仍未推送,见 KR-06)。
2026-09-22 00:46:10 +08:00

14 KiB
Raw Permalink Blame History

项目进度评估报告 — 2026-09-21

评估方式:以 docs/STATUS.md(权威状态表)为索引,逐项回溯代码、迁移、测试与 CI 配置实测复核, 不采信文档中的历史「✅」声明。凡本文标注「实测」的结论均可按「核查证据」栏复现。

评估基线:main @ 60c591f(2026-09-21 11:13),工作区干净;最新 tag v101-dod-complete-2026-09-21。


一、总体结论

代码与测试面已具备进入 UAT 的条件;阻塞点是人工确认与环境补绿,外加一处此前登记但未修复的运营端写操作缺陷。

维度 结论
业务功能 Phase 0122 全部 KEEP-VERIFY 复验关闭;Phase 23 批 13 完成
质量门禁 后端 741 / 0 失败 / 0 错误 / 3 跳过;UI 契约门禁 18/18;E2E 本机活栈 65 通过
数据层 迁移 V001~V051(51 个文件,无缺号);H2 测试库表漂移盲区已在本轮前多轮补齐
停点 Phase 24(UAT)启动门前 —— 按项目规则须由用户确认,不得自动进入
风险等级 中 —— 无架构级问题,但存在 1 项 High 未修缺陷 + 2 项环境/流程阻塞

二、进度快照

2.1 Phase 矩阵

Phase 区间 状态 证据
01~06 基线 / Auth / RBAC / Profile / 审核 / Match Engine ✅ 关闭 各 Phase Completion Report
07 V1.1 首页 + 找对象 ✅ 关闭 2026-09-16 用户验收(基本达标);11 页 UI 验收通过
08~13A Like/Match/Block · Chat · 图片安全 · 通知 · 关系扩展 · 红娘转介 · 咨询辅导 ✅ 关闭 2026-09-16/17 KEEP-VERIFY,共修复 40+ 真实缺陷
14~20 多类型活动 · 报名签到 · 互选双确认 · 举报风控 · 申诉 · 运营后台 · Analytics ✅ 关闭 2026-09-17 复验,修复 60+ 缺陷(含 4 处必崩级)
21 账户生命周期 ✅ 关闭 2026-09-18;注销三处 TODO 桩已实现;数据保留流程 V049 落地
22 Feature Flag ✅ 关闭 死配置已移除;PUT /feature-flags 真持久化(V048)
23 可信系统测试重建 ⚠️ 部分关闭 假覆盖归零、E2E 场景真实实现;仅余 CI 上首次跑绿
23B E2E 基建 + 横向加固(HTTP 语义 / 身份收敛 / 幂等键) ✅ 关闭 幂等键 30 端点、105 处真实状态码
V1.0.1 配置与规则纠偏 ✅ 关闭 rc.21(2026-09-21);governance 六表 + 并发强校验 + canonical key
24 UAT ⏳ 待启动 用例 46 条(9 角色 × 7 路径)已编写;需用户确认
25 RC 内容 / 26 生产 Smoke ⏳ 待运营 真实素材未提供;13 项 smoke 待执行

2.2 量化指标

指标 实测值 核查方式
后端测试 741 / 0 failures / 0 errors / 3 skipped docs/STATUS.md rc.21 行(离线容器 mvn -o test,命令见计划附 B-9)
测试类文件 108 个 backend/src/test/**/*.java 计数
UI 契约门禁 18/18(UI_GUARDS_MIN 下限守卫防删除报绿) ui-tests/ 18 个 .mjs;执行器 scripts/run-ui-contracts.mjs
E2E 用例 65 通过(本机真栈真库) tests/e2e/ 14 个测试文件
数据库迁移 V001~V051,51 个,无缺号重复 backend/src/main/resources/db/migration
CI job 7 个:backend / admin-web / miniapp / migration / test-shell-guard / ui-contracts / e2e .github/workflows/ci.yml
待产品决策 13 项 + 第三方开放遗留 7 项 docs/PENDING_DECISIONS.md、docs/governance/open-questions.md

三、关键发现:一处 High 缺陷登记后未修复

3.1 机构创建 / 停用 / 启用三个写操作必然失败(High,2026-09-22 已验证关闭)

处置完成(2026-09-22 复核):本项已按第五节 P0-1 执行完毕 —— Constants 新增 ORG_STATUS_ACTIVE/INACTIVE、三处状态值修正、type 白名单前置校验、 测试库 schema-h2.sql 补两条 CHECK 及 NOT NULL/DEFAULT、 新增 OrganizationConstraintParityTest 与 OrganizationServiceTest。

2026-09-22 完成全部补跑验证(此前记为「已修复待验证」的缺口已补齐):

  1. 全量回归 757 / 0 / 0 / 3,BUILD SUCCESS(108 个测试类,6:44;基线 741 + 新增 16 = 757);
  2. 负向注入可红:把 Constants.ORG_STATUS_ACTIVE 改回 "normal" 后,16 个用例变 3 失败 + 7 错误 —— 守卫 backendWhitelistsMatchProductionDdl / orgStatusConstantsCoverProductionWhitelist / orgStatusMustNotReuseAccountStatusValues 三条断言各自命中该误用,服务侧 7 例被 H2 CHK_ORG_STATUS 拦下。注入采用 仓库只读挂载 + 容器内副本改写,工作区哈希前后一致(28aaaedb…),源码零污染;
  3. 活栈实测(Docker 全栈):创建 / 停用 / 启用全部 2xx 且落库为 active/inactive, 非法 type 与缺字段 400 VALIDATION_ERROR,不存在机构 404 NOT_FOUND, 全流程零 5xx(15/15 通过);
  4. 对已部署栈跑 pytest tests/e2e:65 passed。

本项状态:已验证关闭。 另:活栈验收中新发现同族缺陷「创建机构审计缺操作人」——CREATE_ORGANIZATION 审计行 operator_id 7/7 为 NULL(停用/启用却正确记录),已一并修复并复验,见 docs/STATUS.md rc.23。

该问题于 2026-09-19 已在实施计划「附 B.1」中登记并实测复现,但截至本次评估(2026-09-21)代码未改动。

缺陷本体(实测复核,2026-09-21):

位置 写入值 生产约束 结果
OrganizationService.java:43 createOrganization ACCOUNT_STATUS_NORMAL = "normal" V001:45 chk_org_status CHECK (status IN ('active','inactive')) 违约 → 500
OrganizationService.java:63 disableOrganization ACCOUNT_STATUS_SUSPENDED = "suspended" 同上 违约 → 500
OrganizationService.java:73 enableOrganization ACCOUNT_STATUS_NORMAL = "normal" 同上 违约 → 500

根因:organizations.status 复用了语义上属于 users 表的常量 Constants.ACCOUNT_STATUS_*。 Constants 中不存在机构状态常量(ORG_STATUS_ACTIVE/INACTIVE 均无)—— 典型的「跨表常量误用」, 与项目此前多轮修复的「实体↔迁移漂移」「CHECK 白名单未对齐」同族。

二阶影响(决定优先级): activities.organizer_org_id 为 NOT NULL → 无机构则无法创建活动。 即运营端「新建机构 → 新建活动 → 用户报名 → 互选」这条链路的第一环是断的。 而 UAT 用例覆盖活动互选、报名、签到等场景,因此该缺陷可能阻塞 UAT 执行。

为什么门禁全绿却没发现:

  1. 108 个测试类中没有任何一个引用 OrganizationService / createOrganization(实测:0 命中);
  2. tests/e2e/sql/seed_e2e_activity.sql 是直接写库插入机构与活动,绕过了 Service 层 —— E2E 全绿掩盖了 API 路径的失败;
  3. H2 测试库此前长期缺约束复刻,即便有测试也可能静默通过。

这正好复现项目已总结过两次的模式:「测试环境用数据为空 / 直连绕过,掩盖代码必崩」。

附带问题(同文件,Low):

  • createOrganization 与 updateOrganization 均未校验 type 白名单 (chk_org_type 仅允许 women_federation / trade_union / charity_center / volunteer_team / civil_affairs_partner / other);
  • 私有 saveAuditLog 未填 ip / userAgent(Phase 17 只增强了 AuditLogService.recordSensitiveAccess)。

建议修法:新增 Constants.ORG_STATUS_ACTIVE/INACTIVE,三处改为 active / inactive; 补 type 白名单校验;新增 OrganizationServiceTest(走真实 DB,覆盖创建/停用/启用/type 非法), 另加一条解析 V001 DDL 取最终白名单的常量守卫(参照 MatchmakerReferralPhase13Test 的写法, 不要硬编码白名单副本 —— 那条教训已记录在 Phase 13 报告中)。修复后需 git tag 打点并回读验证。

3.2 其余已登记未处置项

项 级别 说明
用户侧取消预约不校验状态 Medium ServiceAppointmentService.cancelAppointment 只校验归属,已确认/已完成也能被本人取消;运营侧明确拒绝 completed。两侧口径不一致,需产品裁定(计划附 B.3)
Phase 22 Deployment/Ops 5 项未复验 Medium 删除镜像跳过测试的发布路径、生产关 Mock/Seed/Swagger、端口依赖检测、备份加密 + 真实恢复演练、Rollback 目标(REMAINING_WORK.md B 组)
多实例下 flag 内存值不自动刷新 Low 已知边界,需各自重启(Phase 22 报告)

四、环境与流程风险

4.1 Git 在当前执行环境不可用(阻塞提交纪律)

实测:git 报 fatal: detected dubious ownership in repository。 仓库目录属主为 S-1-5-21-881075190-…,当前用户为 CLIMBER/13070,二者不匹配。

影响:AGENTS.md 的版本控制约定(每批独立 commit + 单段名 tag + git bundle 自保 + 回读验证) 是项目防御「常驻进程删 refs 导致 HEAD 悬空」的核心手段,该链路当前无法执行。 本次评估为只读目的,以 GIT_CONFIG_COUNT/KEY/VALUE 环境变量临时注入 safe.directory 绕过, 未修改任何全局配置。

建议:由用户决定是否执行 git config --global --add safe.directory 'E:/develop/公益婚恋服务平台'。 在修复前,任何需要提交的工作都应先确认该前提,否则改动无法被打点保护。 (另:feat-ui-v11 已被 main 完全包含(落后 71 个提交、领先 0),仅为冗余锚点, 可考虑清理,但 AGENTS.md 目前要求保留 —— 属文档与事实的轻微不一致。)

4.2 CI 回归防线从未在真实 CI 上验证过

7 个 job 均已配置,其中 ui-contracts(18 门禁)与 e2e(Compose 起全栈 + seed + pytest)配置完整, 但 E2E 作业从未在 GitHub Actions 上跑绿过一次(计划 Task 2.3 Step 3)。 本机已用同一序列模拟实测 65/65,但「本机绿」与「CI 绿」不是同一件事 —— 此前已发生过「本机有遗留 admin 账号所以本地一直绿、CI 全新库必然 401」的先例。

4.3 文档体量与自相矛盾

docs/ 91 个文件、STATUS.md 单文件 90KB,内含多处「历史声明块(已作废)」并列保留; PENDING_DECISIONS.md 与 docs/governance/* 三表职责交叉并依赖「矛盾以 governance 三表为准」的约定; REMAINING_WORK.md 被迫以「原编号索引」兼容历史引用。

这是治理的必要代价,但已产生实际成本:文档中出现过与实际严重不符的陈述 (如 CHANGELOG.md 3.3MB vs 实际 4.2KB、指向从未存在的报告文件)。 建议:不再新增并列的「状态类」文档;本评估报告即为一次性快照,结论应回写进 STATUS.md 而非另立体系。


五、下一步建议

优先级 P0 — 建议立即做(无需用户决策,纯技术清偿)

  1. 修复机构三个写操作 + 补测试与守卫(3.1)。✅ 已修复且已通过全部验收项(2026-09-22): 全量回归 757 / 0 / 0 / 3 全绿;负向注入 16 例变 3 失败 + 7 错误(守卫三条断言全中 + H2 CHK_ORG_STATUS 拦下 7 例); 活栈实测 POST /operator/organizations 与停用/启用均 2xx、非法输入 400、不存在 404、全程零 5xx(15/15); 对已部署栈 pytest tests/e2e 65 passed。本项关闭。 附带清偿同族缺陷「创建机构审计缺操作人」(见 rc.23)。
  2. 确认 Git 可用性(4.1)。决定是否加 safe.directory,否则先不要写代码 —— 写了也打不了点。

优先级 P1 — 需用户/环境配合

  1. 推送一次 CI,拿到 E2E 与 ui-contracts 的首次真绿(需有 Docker Hub 出口的 runner)。 完成后 Phase 23 可由「部分关闭」转为关闭。
  2. 管理端桌面端目视复验(1440px)(批 4 Task 4.1)。小程序 375px 增补页面同理。 这是当前唯一「代码已就绪但从未被真人看过」的验收项。
  3. 13 项产品决策 + 7 项第三方开放遗留(批 4 Task 4.2)。 建议分批:先决 OQ-MATCH-001(推荐阈值)、OQ-PROFILE-001(照片上限)、 OQ-IDENTITY-001(活体核验)三项 —— 它们已被配置化,决策后只需改配置值; Banner 最大活跃数(OQ-BANNER-001)是真缺口,需产品定值后需实现 active-count 校验。

优先级 P2 — UAT 启动后的并行工作

  1. Phase 24(UAT)启动确认 —— 按项目规则须用户明确同意,AI 不得自动进入。 启动前建议先完成 P0-1 与 P1-4。
  2. Phase 22 Deployment/Ops 5 项复验,其中「备份加密 + 真实恢复演练」是上线硬门槛。
  3. 用户侧取消预约口径统一(3.2)—— 一次性产品裁定即可关闭。

优先级 P3 — 运营侧长周期

  1. Phase 25 真实素材(Banner / 课堂 / 反诈 / 关于我们 / 组织信息),不得 Seed 假数据。
  2. Phase 26 上线前 13 项 smoke + RC 冻结(镜像 / DB 版本 / 配置清单 / Rollback 目标)。

六、本次评估的核查证据

结论 证据
代码与测试就绪 docs/STATUS.md 文首「当前有效结论」+ rc.19~rc.21 版本演进行
机构缺陷未修 backend/src/main/java/com/danyang/match/platform/organization/service/OrganizationService.java:43,63,73;Constants.java:11,14;V001__init_base_tables.sql:45(三处逐一读源确认)
机构零测试覆盖 backend/src/test/** 全量检索 OrganizationService / createOrganization → 0 命中(108 个测试类)
E2E 绕过 Service 层 tests/e2e/sql/seed_e2e_activity.sql 直插库
CI 配置完整但未验证 .github/workflows/ci.yml 全文;计划 Task 2.3 Step 3 仍为未勾选项
Git 不可用 git rev-parse HEAD 报 dubious ownership;属主 SID 与当前用户不一致
迁移基线 db/migration 计数 51,最新 V051__canonical_liveness_flag_key.sql
剩余项清单 REMAINING_WORK.md、docs/PENDING_DECISIONS.md、计划「批 4 / 批 5」

评估人:WorkBuddy · 创建:2026-09-21 性质:一次性快照。结论请回写 docs/STATUS.md,本文件不作为长期状态源。