Files
danyang-match/docs/P0阻断项修复报告_2026-09-15.md
Codex eaf8fdf195 refactor(backend): P0 阻断修复 + 按最新修改时间收敛重复模块与契约
## P0 阻断修复
- 编译:修复实体类与服务类同名导致 Lombok 注解轮次中止的问题
  (MatchmakerService/CounselingService -> *Record),196 个编译错误归零
- 权限矩阵:platform_admin 按设计文档收紧为拒绝 5 项高危权限(不改测试阈值)
- 启动:修复 8 组 MyBatis-Plus 同名 bean 冲突(ConflictingBeanDefinition)
  与 URL 路由歧义(Ambiguous mapping),应用可正常启动

## 模块收敛(裁决规则:以文件修改时间为准)
- messaging 包整体删除,能力迁移至 chat 包
  * 会话列表/详情/未读端点、ConversationDTO、CursorPage
  * 消息游标分页统一为 { items, nextCursor }
- relationship 的 Match/UserRelation entity 与 mapper 合并进 match 包
- MatchmakerUserController 合并进 MatchmakerController,删除冗余 Controller
- 补齐 INV-004:chat sendText 增加双向 Block 校验,拉黑后禁止发送

## 契约对齐
- 红娘服务提交请求兼容前端 { requirement } 字段
- 消息与会话分页契约前后端统一

## 测试
- 迁移 6 个风控用例至 ChatSafetyServiceTest
- 清理 messaging 测试包遗留:6 个真实常量断言归位 chat 包,
  移除 2 个 assertTrue(true) 占位假测试(Block 真实行为已由
  P0FixVerificationTest / RelationshipBlockPriorityPhase08Test 覆盖)
- schema-h2.sql 对齐 PostgreSQL 真实表结构(matches 补列、
  conversation_members 改复合主键)

结果:290 tests, 0 failures, 0 errors, 3 skipped, BUILD SUCCESS
2026-09-15 22:29:26 +08:00

119 lines
6.1 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 善缘丹阳 V1.1 — P0 阻断项修复报告
> 日期:2026-09-15 | 范围:backend | 验证方式:Docker 容器内 Maven 构建 + 全量测试
> **结论:293 tests / 0 failures / 0 errors / BUILD SUCCESS**(修复前:196 个编译错误 + 应用无法启动)
---
## 一、最终验证
```
[INFO] Tests run: 293, Failures: 0, Errors: 0, Skipped: 3
[INFO] BUILD SUCCESS
```
Spring 应用上下文成功启动 4 次,`Failed to load ApplicationContext` 归零。
共改动 **46 个文件**,**未提交**(保留在工作区待评审)。
---
## 二、修复链条(每修一层暴露下一层)
### P0-1 编译断裂:196 错误 → 0
| 根因 | 说明 | 处理 |
|---|---|---|
| **同名类冲突导致 Lombok 停摆** | `MatchmakerService`、`CounselingService` 既是实体又是 Service,javac 因重复定义中止注解处理轮次,Lombok 不生成 getter/setter,引发约 110 个"找不到符号" | 实体重命名为 `MatchmakerServiceRecord` / `CounselingServiceRecord`(均有显式 `@TableName`,不影响 DB 映射) |
| 契约缺失 | `ApiResponse` 缺 `unauthorized()/forbidden()/notFound()`(35 处调用) | 补齐 3 个工厂方法 |
| 命名约定分裂 | `NotificationService` 已有业务通知方法但命名不同(phase-11 与后续提交分裂) | 按调用方约定补 9 个 `sendXxx` 别名,内部复用既有隐私安全模板 |
| 其他 | 多个 mapper 缺方法、`ChatService` Optional 未解包、`ChatSafetyService` redis expire 类型错误、缺 import | 逐个补齐 |
> 顺带修正一处语义 bug:Service 文件里 `new MatchmakerService()`、返回类型 `List<MatchmakerService>` 本意是实体,因同名实际解析成了 Service 类自己。
### P0-2 权限矩阵测试:失败 → 12/12 通过
失败断言:`platform_admin 应有至少5个被拒绝的权限`(实际只拒 1 项)。
**采用收紧权限的方式修复,未放宽测试。** 依据 `运营管理后台与组织权限体系详细设计.md`:
| 权限 | 依据 |
|---|---|
| `user.sensitive.view` → 拒绝 | 第十二章:完整身份证查看"仍应单独授权" |
| `risk.user.ban` → 拒绝 | 第六十九章:永久封禁属严重高风险,"至少由高权限角色操作" |
| `organization.manage` → 拒绝 | 第十一章:组织管理属 super_admin |
| `permission.manage` → 拒绝 | 第十一章:权限管理属 super_admin |
| `data.export` → 拒绝 | 第一百零三章:导出须单独授权,"不要能看列表就能导出" |
### 迁移基线
`MigrationValidationTest.LATEST_MIGRATION` 33 → 35(实际 V001–V035,35 个脚本)。该测试是"基线守卫",新增迁移时本就应同步递增。
### P0-0(新发现,比原三项更严重)应用无法启动 → 修复
**8 组 Spring bean 重名** —— 全部是并行模块重复所致:
| 重复 bean 名 | 位置 |
|---|---|
| MessageController、MessageMapper、ConversationMapper、ConversationMemberMapper、ChatWebSocketHandler、WebSocketConfig | `chat` vs `messaging` |
| MatchMapper、UserRelationMapper | `match` vs `relationship` |
处理:`messaging` 三个 mapper 加 `Legacy` 前缀、`relationship` 两个 mapper 加 `Relationship` 前缀、遗留 Controller 与 WebSocket 类显式指定 bean 名。**未删除任何模块**(保留可逆性)。
**路由歧义**:`GET/POST /matchmaker/services` 在 `MatchmakerController` 与 `MatchmakerUserController` 重复映射。删除后者的重复方法,保留其独有的 `/services/{id}`(小程序依赖)。
---
## 三、重要更正:昨天的 P0-3 判断有误
昨日评估称"V1.1 四个新角色零实现、硬规则 #22–#25 未落地"——**此结论错误**。
`V015__add_v11_roles_and_permissions.sql` 已完整实现四角色,且权限设计相当克制:
- `service_station_operator`:仅服务站查看 + 预约确认/完成 → 符合硬规则 #24
- `counselor`:仅 `counseling.service.view/process` + `note.create`(**无 note.view**)→ 符合 INV-012
- `counseling_manager`:带 `note.view` → INV-013 分层正确
- `content_editor`:仅 `content.*` → 符合硬规则 #23
**缺的是 admin-web 前端 UI,不是后端。** 教训:此前只 grep 了前端,未检查数据库迁移脚本。
---
## 四、新发现(未修,需要决策)
### 1. 两套并行聊天实现(架构级)
`chat`(V1.1) 与 `messaging`(V1.0) 都映射 `conversations` 表。
- `chat`:`ConversationController.list()` 是**桩**(`TODO` + 返回空列表),缺 `/conversations/{id}`、`/unread`
- `messaging`:功能完整(图片消息/历史/未读数),但端点前缀 `/messages`,前端不调
当前两者并存可启动,但长期是数据一致性隐患。**需决定合并方向。**
### 2. role_permissions 种子数据残缺(运行时权限实际是坏的)
- `platform_admin`:只有 V1.1 权限,**V1.0 那 18 个一条没有**(无法查看用户、审核、活动)
- `super_admin`:只有 V1.0 权限,**V1.1 的 30 多个全缺**
- `reviewer` / `matchmaker` / `activity_manager` / `risk_operator` / `volunteer` / `data_viewer`:**从未被授予任何权限**
### 3. 前后端契约不一致
小程序 `applyService` 发送 `{ requirement }`,后端 `SubmitRequest` 接收 `{ serviceType, description }`。
### 4. 缺失端点
小程序调用的 `/conversations/{id}/unread`,两个包都没有实现。
---
## 五、环境备忘(本机无 JDK,务必按此执行)
```bash
MSYS_NO_PATHCONV=1 docker run --rm \
-v "E:/develop/公益婚恋服务平台:/proj" \
-v danyang-m2-cache:/root/.m2/repository \
-w /proj danyang-match-backend-test:latest \
mvn -B -f backend/pom.xml test
```
三个坑:
1. **必须挂载项目根目录**(不是 backend),否则按 `backend/src/...` 取路径的测试会误报 NoSuchFileException(本次误报 16 个)
2. **不要用 `-o`**:缺 `surefire-junit-platform`,且容器 `--rm` 不留存下载 → 用命名卷持久化 `/root/.m2/repository`
3. **`mvn clean` 离线会失败**(clean 插件未缓存)→ 手动 `rm -rf backend/target/classes`
另:本机 `find` 在中文路径下对所有目录返回 0,统计文件请用 `grep -rl ... | wc -l` 或 Glob 工具。