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:
WorkBuddy
2026-09-21 20:34:30 +08:00
parent 60c591fc68
commit c195133680
8 changed files with 730 additions and 15 deletions
@@ -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()`