fix(notification): Phase 11 复验 —— 修复通知类型违反生产 CHECK 约束(生产故障)/ 幂等无库兜底 / 婚前辅导通知未接线
复验模式:KEEP-VERIFY/EXTEND(不轻信历史 ✅,逐条核对运行时路径与生产约束)。 == D3(Critical · 生产故障)通知 type 全量违反生产 CHECK 约束 == NotificationService 的 10 个业务模板传入复合 type (appointment_submitted / counseling_assigned / le_verified / referral_created 等), 而生产 V020__extend_notification_types.sql 的 chk_notification_type 白名单只允许 12 个短名。 真实 PostgreSQL 下这些通知全部落库失败;测试库 schema-h2.sql 未复刻该约束,故历史 334 测试全绿 → 假绿。 修复: - type 归一为白名单短名,业务细分交由 businessType/title 承担: appointment_submitted|_confirmed|_changed -> appointment counseling_assigned|_scheduled|_completed -> counseling premarital_scheduled -> premarital le_need_evidence|le_verified|le_rejected -> local_eligibility referral_created -> matchmaker - 重写 buildPrivacySafeCopy:原以复合 type 为 key 的 Map.ofEntries 归一后产生重复 key 会抛 IllegalArgumentException(运行期崩溃),改为按短名 switch。 - schema-h2.sql 补齐生产 CHECK 约束(测试保真度下沉)。 == D1(High)通知幂等仅 SELECT-then-INSERT,无 DB 兜底 == NotificationMapper.findExisting 为查后插,并发下可重复落库。 修复:新增 V036__add_notification_idempotency_index.sql,建 partial unique index uk_notification_business(user_id, type, business_type, business_id, content) WHERE business_id IS NOT NULL(先按 created_at ASC 去重存量数据)。 schema-h2.sql 同步唯一索引(H2 无 partial index,标准 UNIQUE 对 NULL 多行共存语义等价)。 == D2(Medium)婚前辅导通知未接线 == premaritalScheduled 零调用;CounselingServiceApp.scheduleCounseling(P13A-T22 管理端路径)完全不发通知。 修复:CounselingService.schedule 与 CounselingServiceApp.scheduleCounseling 均按 service_type 分流, premarital 走 premaritalScheduled,其余走 counselingScheduled; 管理端路径包 try/catch —— 通知失败不回滚排期事实。 == 测试(基线 334 → 346,+12) == - NotificationPhase11IntegrationTest(5):回滚不发通知(Gate 前半)、提交后可见、 顺序重试幂等、绕过 findExisting 由唯一索引兜底抛异常且最终仅 1 条、business_id IS NULL 多行共存。 - NotificationPrivacyCopyTest(5):反射校验 4 类隐私文案,咨询类不含「咨询」且标题为「服务通知」, 不泄露姓名/时间/证件类型;未知 type 安全回退;ALLOWED_TYPES 守卫。 - NotificationTemplateTypeGuardTest(2):关键 —— 调用模板方法本身(而非直接传字面量 send), 断言 10 个模板全部以白名单短名落库。 - MigrationValidationTest:LATEST_MIGRATION 35 -> 36,DDL 校验补 CREATE UNIQUE INDEX 识别。 == 负向验证(两轮,含第一轮失效教训) == 第一轮:注入复合 type 后 NotificationPhase11IntegrationTest 仍全绿 —— 因该测试直接 send(..., "appointment", ...) 传字面量,不经过模板方法,属无效守卫。 第二轮:改为 NotificationTemplateTypeGuardTest 调用模板本身,注入后精准抛 DataIntegrityViolation,守卫有效性得证。教训已写入报告:守卫必须经负向验证证明会变红。 == 证据 == 全量回归 346 tests / 0 failures / 0 errors / 3 skipped / BUILD SUCCESS (离线 Docker:danyang-match-backend-test:latest + 卷 danyang-m2-cache) 迁移校验 12/12;定向 19/19。 == Gate 判定 == 回滚事务不发通知 ✅ | 通知失败不回滚核心事实 ✅ | 隐私安全文案 INV-010 ✅ 已提交事务通知失败可重试且不产生重复业务记录 ✅(修复后成立) == 遗留 gap(登记不自动实现) == sendExternal 在事务内同步执行外部副作用,当前为占位实现;接入真实微信推送前必须改为 @TransactionalEventListener(AFTER_COMMIT) / REQUIRES_NEW —— 全仓当前无任何 afterCommit 机制。
This commit is contained in:
@@ -5,6 +5,15 @@
|
||||
|
||||
> **2026-09-16 状态校正:** Phase 07 UI 已按 2026-09-13 规格重新实现,**首批 11 页于 2026-09-16 通过用户验收(结论:基本达标)**,本文件此前"视觉否决/REOPENED"口径随之关闭。
|
||||
>
|
||||
> **2026-09-16 Phase 11 复验关闭:** EPIC-P11-V11 已完成。复验中发现并修复 3 处缺陷——
|
||||
> **D3(Critical,生产故障)** `NotificationService` 全部 10 种通知使用复合 type(`appointment_submitted` /
|
||||
> `counseling_assigned` / `le_verified` 等),违反生产 `chk_notification_type`(仅允许短名),
|
||||
> 真实 PostgreSQL 上**全部落库失败**,Phase 11 核心交付不可用;测试库未复刻该约束故长期静默;
|
||||
> **D1(High)** 通知幂等仅靠 SELECT-then-INSERT 无 DB 兜底 → 新增 `V036` partial unique index;
|
||||
> **D2(Medium)** 婚前辅导排期通知零调用 + 管理端排期路径完全不发通知 → 接线并按 service_type 分流。
|
||||
> 新增测试 12 用例(含真实调用模板方法的 type 守卫)。后端全量 **346 tests / 0 failures / 0 errors**。
|
||||
> 证据:`docs/Phase-11-V11-Recovery-Completion-Report-2026-09-16.md`。**Phase 12 需用户确认后启动。**
|
||||
>
|
||||
> **2026-09-16 Phase 10 复验关闭:** EPIC-P10-V11 已完成。复验中发现并修复 2 处缺陷——
|
||||
> **D1(Critical,生产故障)** `PhotoService.uploadAndSave` 魔数校验因 `new byte[n]` 从不读取流而恒失败,本地资格佐证上传 100% 失败(且 PDF 被 image-only MIME 挡);
|
||||
> **D2(Low)** `ChatSafetyService` 把命中的高风险词写入普通日志。
|
||||
@@ -34,6 +43,7 @@
|
||||
| Phase 08 Like / Match / Block 复验 | 已完成(2026-09-16) | 见 `Phase-08-V11-Recovery-Completion-Report-2026-09-16.md`;修复 3 处真实缺陷(搜索绕过 Block、详情无 Block 检查、`matches.source` 取值越界),后端 308 tests 全绿 |
|
||||
| Phase 09 Text Chat 复验 | 已完成(2026-09-16) | 见 `Phase-09-V11-Recovery-Completion-Report-2026-09-16.md`;修复 4 处真实缺陷(WebSocket 下行死代码、Unmatch 后仍可发消息、Block 未落库 Match、聊天接口 IDOR),后端 328 tests 全绿;Phase 10 尚未获准 |
|
||||
| Phase 10 Image & Chat Safety 复验 | 已完成(2026-09-16) | 见 `Phase-10-V11-Recovery-Completion-Report-2026-09-16.md`;修复 2 处缺陷(图片上传魔数校验死代码致本地资格佐证上传 100% 失败、高风险词写入日志),推翻旧报告 2 项安全声明,后端 334 tests 全绿;Phase 11 尚未获准 |
|
||||
| Phase 11 Notification 复验 | 已完成(2026-09-16) | 见 `Phase-11-V11-Recovery-Completion-Report-2026-09-16.md`;修复 3 处缺陷(10 种通知 type 违反生产 CHECK 约束致全部落库失败、幂等无 DB 兜底、婚前辅导通知未接线),后端 346 tests 全绿;Phase 12 尚未获准 |
|
||||
| UI-CLEANUP-20260913 | 已完成 | 废弃 UI 代码、冲突规范、旧计划和无效验收证据已清理;`ui-document-baseline-contracts` 锁定唯一视觉入口 |
|
||||
| UI-ADMIN-20260913 | 已完成(待桌面端目视复验) | 管理端全局框架与工作台已按规格交付;18 modules + 22 routes,vue-tsc 与 vite build 全绿 |
|
||||
| UI-MINIAPP-20260913 | 已完成 | 小程序 11 个核心页面已重构;11/11 页 TS-only,2026-09-16 通过用户验收 |
|
||||
|
||||
Reference in New Issue
Block a user