fix(organization): 机构三处写操作必崩 500 修复 + type 白名单 + 测试库约束补齐
缺陷本体(实施计划附 B.1,2026-09-19 登记并实测复现,本轮处置):
OrganizationService 的 createOrganization / disableOrganization / enableOrganization
分别写入 Constants.ACCOUNT_STATUS_NORMAL("normal") 与 ACCOUNT_STATUS_SUSPENDED("suspended")。
那是 users.account_status 的取值,而 organizations.status 的 CHECK 白名单
(V001 chk_org_status)只有 ('active','inactive') → 三个写操作全部违约,
生产必崩 PSQLException violates check constraint "chk_org_status" → HTTP 500。
二阶影响:activities.organizer_org_id NOT NULL ⇒ 无机构即无法新建活动,
运营端「建机构 → 建活动 → 报名 → 互选」链路的第一环是断的。
修复:
- Constants 新增 ORG_STATUS_ACTIVE / ORG_STATUS_INACTIVE(独立于 users.account_status,
附注释说明两者白名单不同,禁止互相复用)
- 三处状态值改为 ORG_STATUS_ACTIVE / ORG_STATUS_INACTIVE
- 新增 OrganizationService.ALLOWED_TYPES + type 白名单前置校验:
非法值返回 VALIDATION_ERROR(400),不再打到 PostgreSQL 才 500
- 「机构不存在」由裸 RuntimeException(→500 SERVER_ERROR) 改为 NOT_FOUND(404)
- 异常类型统一为 GlobalExceptionHandler.BusinessException —— 独立类
shared.exception.BusinessException 没有 @ExceptionHandler,抛它仍会退化成 500
根因第三重盲区(缺陷长期隐身的直接原因):
schema-h2.sql 的 organizations 表此前未复刻这两条 CHECK,H2 上写 'normal' 畅通无阻。
已补齐 chk_org_type / chk_org_status 及 NOT NULL / DEFAULT,与生产 DDL 逐值一致。
新增守卫:
- OrganizationConstraintParityTest:生产迁移 DDL ↔ 测试库 schema ↔ 后端白名单 ↔
Constants 四方比对 + 解析器自检(虚构约束名必须解析失败,防断言静默永真)。
其中 status DEFAULT 的解析必须先把范围切到 organizations 建表块 —— 全文件搜索会
误命中 users.account_status(本轮自检脚本实测踩到并修正该缺陷)。
- OrganizationServiceTest:走真实 DB 的 H2 集成测试,9 用例覆盖创建/停用/启用/
停启往返/六个合法 type/非法 type/名称空白/404 语义,断言落库值而非返回值。
⚠️ 未在本机运行测试:本轮探测确认本机无 Docker、无 JDK,wsl.exe 被安全策略阻止
(与 known-risks.md 的 WSL/Docker 故障一致),mvn -o test 与负向注入均无法执行。
已用等价正则的独立脚本验证守卫判别力与两处 DDL 一致性(PASS,脚本留痕
.workbuddy/_verify_org_guard.py)。
补跑全量回归 + 负向注入前,本项记为「待验证」,不得计入已验收。
This commit is contained in:
@@ -0,0 +1,206 @@
|
||||
# 项目进度评估报告 — 2026-09-21
|
||||
|
||||
> 评估方式:以 `docs/STATUS.md`(权威状态表)为索引,**逐项回溯代码、迁移、测试与 CI 配置实测复核**,
|
||||
> 不采信文档中的历史「✅」声明。凡本文标注「实测」的结论均可按「核查证据」栏复现。
|
||||
>
|
||||
> 评估基线:`main` @ `60c591f`(2026-09-21 11:13),工作区干净;最新 tag `v101-dod-complete-2026-09-21`。
|
||||
|
||||
---
|
||||
|
||||
## 一、总体结论
|
||||
|
||||
**代码与测试面已具备进入 UAT 的条件;阻塞点是人工确认与环境补绿,外加一处此前登记但未修复的运营端写操作缺陷。**
|
||||
|
||||
| 维度 | 结论 |
|
||||
|---|---|
|
||||
| 业务功能 | Phase 01~22 全部 KEEP-VERIFY 复验关闭;Phase 23 批 1~3 完成 |
|
||||
| 质量门禁 | 后端 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-21 已修复,待补跑回归验证**)
|
||||
|
||||
> **处置更新(2026-09-21 当天)**:本项已按第五节 P0-1 执行完毕 ——
|
||||
> `Constants` 新增 `ORG_STATUS_ACTIVE/INACTIVE`、三处状态值修正、`type` 白名单前置校验、
|
||||
> 测试库 `schema-h2.sql` 补两条 CHECK 及 NOT NULL/DEFAULT、
|
||||
> 新增 `OrganizationConstraintParityTest` 与 `OrganizationServiceTest`(9 用例)。
|
||||
> **但本机无 Docker / 无 JDK(`wsl.exe` 被安全策略阻止),`mvn -o test` 与负向注入未能执行**,
|
||||
> 故当前状态为「**已修复待验证**」而非「已验证」。
|
||||
> 详见 `docs/superpowers/plans/2026-09-18-phase23-closeout-and-uat-readiness.md` 附 B.1 的处置留痕
|
||||
> 与 `docs/STATUS.md` 版本行 rc.22。
|
||||
|
||||
该问题于 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-21)**;
|
||||
⚠️ 验收项中的「全量回归 + 负向注入 + 活栈实测」因本机无 Docker/JDK **未执行**,待在有该环境处补跑。
|
||||
原验收标准:`mvn -o test` 全绿 + 新增用例经负向注入可变红 + 活栈实测
|
||||
`POST /operator/organizations` 返回 2xx。
|
||||
2. **确认 Git 可用性**(4.1)。决定是否加 `safe.directory`,否则先不要写代码 —— 写了也打不了点。
|
||||
|
||||
### 优先级 P1 — 需用户/环境配合
|
||||
|
||||
3. **推送一次 CI,拿到 E2E 与 ui-contracts 的首次真绿**(需有 Docker Hub 出口的 runner)。
|
||||
完成后 Phase 23 可由「部分关闭」转为关闭。
|
||||
4. **管理端桌面端目视复验(1440px)**(批 4 Task 4.1)。小程序 375px 增补页面同理。
|
||||
这是当前唯一「代码已就绪但从未被真人看过」的验收项。
|
||||
5. **13 项产品决策 + 7 项第三方开放遗留**(批 4 Task 4.2)。
|
||||
建议分批:先决 `OQ-MATCH-001`(推荐阈值)、`OQ-PROFILE-001`(照片上限)、
|
||||
`OQ-IDENTITY-001`(活体核验)三项 —— 它们已被配置化,决策后只需改配置值;
|
||||
Banner 最大活跃数(`OQ-BANNER-001`)是真缺口,需产品定值后**需实现** active-count 校验。
|
||||
|
||||
### 优先级 P2 — UAT 启动后的并行工作
|
||||
|
||||
6. **Phase 24(UAT)启动确认** —— 按项目规则须用户明确同意,AI 不得自动进入。
|
||||
启动前建议先完成 P0-1 与 P1-4。
|
||||
7. **Phase 22 Deployment/Ops 5 项复验**,其中「备份加密 + 真实恢复演练」是上线硬门槛。
|
||||
8. **用户侧取消预约口径统一**(3.2)—— 一次性产品裁定即可关闭。
|
||||
|
||||
### 优先级 P3 — 运营侧长周期
|
||||
|
||||
9. Phase 25 真实素材(Banner / 课堂 / 反诈 / 关于我们 / 组织信息),**不得 Seed 假数据**。
|
||||
10. 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`,本文件不作为长期状态源。*
|
||||
@@ -63,6 +63,7 @@
|
||||
| 1.1.0-rc.19 | 2026-09-19 | 批 2/3 收尾完成:E2E 互选 8 + 预约 8 场景真实实现(本机活栈 **65 passed**,负向注入 2 轮)+ INV-011 显式守卫(9 用例);隐私设置接真实落库(V047)+ 5 死开关/2 死配置移除(产品裁定)+ `PUT /feature-flags` 真持久化(V048)+ 5 个无 SQL Mapper 方法补齐;**Task 3.3 四项 + 红娘服务拦截接线**(互选 `expires_at`、随访审计、随访风险检测、Onboarding 确认、注销 blocker 接线 + 竞态兜底);UI 契约门禁 **14→18**(WXML 结构 / WXSS 选择器 / api.js 行为 / miniapp 请求层,并修复小程序 P0 请求层崩溃);全量回归 **712 / 0 / 0 / 3** 全绿(B-9 命令实测) |
|
||||
| 1.1.0-rc.20 | 2026-09-20 | **数据保留流程落地**(产品 2026-09-19 确认:注销后数据保留不得低于 36 个月):V049 `users.closed_at` + `account.retention.purge` 权限(仅 super_admin)+ `AccountConfig.dataRetentionMonths`(36,配置化)+ `DataRetentionService`(人工审核:到期清单 + 幂等匿名化清除 + 审计;保留期内服务端拒绝)+ `DataRetentionGuardTest` 5 用例(负向注入摘掉下限判断恰 1 红);顺带清偿测试库缺 `user_photos` 表(照片软删路径 BadSqlGrammar 盲区,补表 + 移出 ParityTest 可选白名单)与 MyBatis-Plus `updateById` null 不进 SQL 陷阱(改 `LambdaUpdateWrapper.set(null)`);隐私政策 §3.3 / PIA §8 「30 天删除」修订为 36 个月;迁移基线 48→49。**全量回归 717 / 0 / 0 / 3 全绿**;**E2E 本机模拟 CI 序列 65/65 全绿**(宿主机 Python 3.11);UAT 用例 V1.1 版 46 用例(9 角色 × 7 路径)编写完成 |
|
||||
| 1.1.0-rc.21 | 2026-09-21 | **V1.0.1 配置与规则纠偏**(根治「技术默认值被误当产品规则 / 配置存在但未闭环 / 文档代码漂移」):① **照片上限配置化** `profile.photo.maxCount`(默认 6 未产品确认)+ `ProfilePolicy` + 服务器端并发强校验(新增 `PHOTO_LIMIT_EXCEEDED` 码,拒绝先于对象存储上传不留孤儿)+ 前端 `mergeAppConfig` 嵌套键修复(服务端值真正下发);② **活体开关闭环** `IdentityPolicy` + `GET /verification/liveness-status` 真实判定点(默认关不阻断实名主流程,开则 `enhancedVerified` 变化,消除假开关)+ 删死 seed `livenessVerification.enabled`;③ **推荐阈值纠偏**(60 为技术默认非产品确认)+ 规则版本化 **V050** `recommendation_records.threshold_snapshot` + 删死重复配置类 `MatchConfig`;④ 新增 `docs/governance/`(config-register / open-questions / decision-register / hardcoded-rule-audit / config-drift-audit / known-risks)并消解 PENDING 阈值/照片矛盾;⑤ 守卫 `PhotoLimitGuardTest` 8 + `IdentityLivenessGuardTest` 5 + `RecommendationThresholdSnapshotGuardTest` 4(均经负向注入可红);⑥ **canonical key 字面化**:`FeatureFlagConfig.KEY_ALIASES`(`identity.liveness.enabled` / 遗留 `livenessVerification.enabled` → 实现字段 `livenessEnabled` 读兼容)+ Controller PUT/DELETE 落库归一 canonical 键 + **V051** 清理遗留键并写入 canonical 行;⑦ **PHOTO-004 真实并发突破实测** `PhotoLimitConcurrencyGuardTest`(3 线程 H2 并发冲顶)——实测咬住「锁照片行+读时计数」在 H2 MVCC 下快照漏读、3/3 全成功突破上限的缺陷,并发控制改为**锁用户行(`UserMapper.lockUserRow` FOR UPDATE)+ 锁后新语句计数**(0 张照片亦有锁可加,补齐「首张并发」缺口),改后恰 1 成功;⑧ `AGENTS.md` 规则 27(配置与规则治理纪律:技术默认值≠产品确认规则 + canonical key 唯一 + 并发上限必须服务器强校验+并发突破测试)。**全量回归 741 / 0 / 0 / 3 全绿(基线 717 + 25 新增 − 1 删死测试);UI 契约门禁 18/18** |
|
||||
| 1.1.0-rc.22 | 2026-09-21 | **运营端机构管理三处写操作 500 修复**(清偿计划附 B.1 遗留,2026-09-19 登记、本轮处置):`OrganizationService` 创建/停用/启用分别写入 `ACCOUNT_STATUS_NORMAL`("normal") 与 `ACCOUNT_STATUS_SUSPENDED`("suspended") —— 那是 `users.account_status` 的取值,而 `organizations.status` 的 CHECK 白名单(V001 `chk_org_status`)只有 `('active','inactive')` → **三个写操作全部违约必崩**;二阶影响为 `activities.organizer_org_id` NOT NULL ⇒ 无机构即无法建活动(运营端链路级阻塞)。修复:`Constants` 新增 `ORG_STATUS_ACTIVE/INACTIVE`(独立于账号状态);三处改用 `active`/`inactive`;`OrganizationService.ALLOWED_TYPES` 补 `type` 白名单前置校验(非法值 400 取代撞 `chk_org_type` 的 500);「机构不存在」由裸 `RuntimeException`(→500)改为 `NOT_FOUND`(404);异常统一为实际被 `@ExceptionHandler` 捕获的 `GlobalExceptionHandler.BusinessException`(独立类 `shared.exception.BusinessException` **无 handler**,抛它仍会 500 —— 全仓仅 `AnalyticsService` 一处既存误用)。**根因第三重盲区同步补齐**:`schema-h2.sql` 的 `organizations` 此前**未复刻**这两条 CHECK,故 H2 上写 `'normal'` 畅通无阻 —— 已补 CHECK ×2 + NOT NULL + DEFAULT。新增守卫 `OrganizationConstraintParityTest`(生产 DDL ↔ 测试库 ↔ 后端白名单 ↔ Constants 四方比对 + 解析器自检)与 `OrganizationServiceTest`(真实 DB,9 用例)。**⚠️ 未在本机运行测试**:本轮探测确认本机**无 Docker、无 JDK**,`wsl.exe` 被安全策略阻止(同 `known-risks.md` 的 WSL/Docker 故障),`mvn -o test` 与负向注入均无法执行;已用等价正则的独立脚本验证守卫判别力与两处 DDL 一致性(PASS)。**补跑全量回归 + 负向注入前,本项记为「待验证」,不计入已验收。** |
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -506,6 +506,28 @@
|
||||
(`women_federation / trade_union / charity_center / volunteer_team /
|
||||
civil_affairs_partner / other`)。
|
||||
影响:运营端无法新建机构 → 无机构则**无法新建活动**(`activities.organizer_org_id` NOT NULL)。
|
||||
|
||||
> **✅ 2026-09-21 已修复(处置留痕)**
|
||||
>
|
||||
> - **状态取值**:`Constants` 新增 `ORG_STATUS_ACTIVE` / `ORG_STATUS_INACTIVE`
|
||||
> (独立于 `users.account_status` 的 `ACCOUNT_STATUS_*`);`createOrganization` /
|
||||
> `disableOrganization` / `enableOrganization` 三处改为 `active` / `inactive`。
|
||||
> - **type 校验**:新增 `OrganizationService.ALLOWED_TYPES` 前置校验,非法值返回
|
||||
> `VALIDATION_ERROR`(400),不再撞 `chk_org_type` 变 500。
|
||||
> - **附带修正**:「机构不存在」由裸 `RuntimeException`(→500 SERVER_ERROR)改为
|
||||
> `NOT_FOUND`(404);异常类型统一为项目实际处理的 `GlobalExceptionHandler.BusinessException`
|
||||
> (独立类 `shared.exception.BusinessException` 无 handler,抛它仍会 500)。
|
||||
> - **测试库盲区已补(缺陷长期隐身的第三重原因)**:`schema-h2.sql` 的 `organizations`
|
||||
> 此前**没有复刻** `chk_org_type` / `chk_org_status` —— 已补齐两条 CHECK 及
|
||||
> NOT NULL / DEFAULT,H2 上写 `'normal'` 现在会真的失败。
|
||||
> - **新增守卫**:`OrganizationConstraintParityTest`(生产 DDL ↔ 测试库 ↔ 后端白名单 ↔
|
||||
> Constants 四方比对 + 解析器自检)、`OrganizationServiceTest`(走真实 DB,
|
||||
> 9 个用例覆盖创建/停用/启用/往返/type 合法与非法/名称空白/404 语义)。
|
||||
> - ⚠️ **未在本机运行测试**:2026-09-21 探测确认本机**无 Docker、无 JDK**,
|
||||
> `wsl.exe` 被安全策略阻止(与 `known-risks.md` 的 WSL/Docker 故障一致),
|
||||
> 故 `mvn -o test` 与负向注入**均未能执行**。已用等价正则的独立脚本验证
|
||||
> 守卫机制判别力与两处 DDL 一致性(PASS,脚本留痕于 `.workbuddy/_verify_org_guard.py`)。
|
||||
> **补跑全量回归 + 负向注入前,本项不得计入「已验证」。**
|
||||
2. **互选记录永不过期**(Medium,即批 3 Task 3.3 的 P16-T13)
|
||||
`createMutualConsent` 从不写 `expires_at`(列无默认值),而
|
||||
`confirmSideIfPending` 的过期闸门 `expires_at IS NULL OR expires_at > NOW()`
|
||||
|
||||
Reference in New Issue
Block a user