Files
danyang-match/docs/善缘丹阳 V1.1 客户需求基线增量开发与修复计划.md
T
WorkBuddy 5b3bad326e fix(matchmaker,referral): close Phase 13 KEEP-VERIFY/EXTEND — 7 real defects
KEEP-VERIFY/EXTEND 复验(历史 ✅ 不可信;测试覆盖函数 ≠ 覆盖运行时路径)。
逐条核对运行时路径与生产约束后修复 7 处缺陷,其中 3 处「只在真实 PostgreSQL 上炸」。

D1 (Critical, 生产故障)
  matchmaker_recommendations.status 代码写 liked/passed/confirmed_mutual,
  而 V009 chk_rec_status 只允许 pending_view/viewed/responded 且从未扩展
  → 真实 PG 上用户接受/跳过推荐必崩。测试库未复刻该 CHECK,故长期静默。

D2 (Critical, 生产故障)
  控制器缺省 serviceType="recommendation" 不在 chk_matchmaker_service_type
  白名单 → 提交红娘服务必崩。
  D1+D2 同修于新增 V038__align_matchmaker_status_constraints.sql
  (沿用 V018/V020/V025 的 DROP CONSTRAINT IF EXISTS + 重加白名单惯例)。

D3 (High, 越权写)
  MatchmakerServiceService.recommendPartner 无 assignedOperatorId 归属校验,
  且可把用户推荐给自己 → 补校验 + 禁止自我推荐。

D4 (High, 越权读)
  getServiceDetail 无归属校验且返回完整用户资料(userId/description/
  userProfile/followups)→ 签名加 requesterId,按调用者返回完整/脱敏视图。

D5 (High, 越权写)
  ReferralService 的 userId 取自请求体且零授权校验 → 新增
  assertMatchmakerServesUser,在 referToServiceStation/referToActivity 入口
  强制校验存在进行中的服务关系。

D6 (High, 生产故障)
  MatchmakerFollowupMapper.findByServiceId 只有声明无 @Select
  → Invalid bound statement (not found),getServiceDetail 必崩。
  该缺陷由本轮新增测试首次暴露(历史测试从未调用该路径)→ 补 @Select。

D7 (Medium, 契约缺口)
  admin-web 5 处 API 缺口(4 条 404 + C 端端点被运营端误用)+ 小程序缺转介服务层
  → 后端补 GET /operator/matchmaker/recommendations 与
  GET /referrals/operator/history 两个运营端端点;前端改路径、
  assign 改 POST + body operatorId;新增 miniapp/services/referralService.js。

测试保真度
  - 测试库补 matchmaker_services/recommendations/followups 三表(此前该模块零真实覆盖),
    约束与 V038 对齐;EntityMigrationParityTest 三表移入 REQUIRED_IN_TEST_SCHEMA;
    MigrationValidationTest LATEST_MIGRATION 37 → 38。
  - 新增 MatchmakerReferralPhase13Test(17 用例,@SpringBootTest 走真实方法路径 + 真实落库)。
  - 重写 MatchmakerServiceTest(6 用例):直接解析 db/migration/V*.sql,按文件名顺序应用
    DROP CONSTRAINT IF EXISTS + ADD CONSTRAINT 取"最终有效"白名单,并内置解析器自检。
    【关键】首版守卫硬编码白名单副本,注入 D1 后仍全绿(对漂移零反应)→ 必须解析真实 DDL。
  - 删除 3 处假测试占位(MatchmakerServiceTest.testMatchmakerCannotLike 的 assertTrue(true);
    CoreInvariantsTest INV-007 断言的是状态常量、INV-010 亦为 assertTrue(true)),
    已如实改名并注明行为验证位置。

负向验证(两轮)
  注入 D1(回退 chk_rec_status 白名单)→ 行为守卫 DataIntegrityViolation
  + 常量守卫 Multiple Failures (3 failures) → Tests run: 23, Failures: 1, Errors: 2
  / BUILD FAILURE,守卫有效性得证。缺陷已还原。

全量回归(离线容器,实测)
  [WARNING] Tests run: 391, Failures: 0, Errors: 0, Skipped: 3
  [INFO] BUILD SUCCESS / Total time: 04:59 min
  Phase 12 基线 371 → 391(净 +20)。

报告:docs/Phase-13-V11-Recovery-Completion-Report-2026-09-16.md
Phase 13A 未自动进入,等待用户确认。
2026-09-17 00:01:53 +08:00

474 lines
34 KiB
Markdown
Raw 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 客户需求基线增量开发与修复 Implementation Plan
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
**Goal:** 在保留已经验证正确的 V1.0 婚恋核心和 V1.1 数据资产的前提下,依据客户最新修订文档修复当前伪完成、权限越界、前端不可用和业务闭环缺失问题,交付可测试、可运营、可回滚的善缘丹阳 V1.1。
**Architecture:** 继续使用 Java 21 + Spring Boot 模块化单体、PostgreSQL、Redis、私有对象存储、Vue 3 统一运营后台和微信原生 TypeScript 小程序。V1.1 是 V1.0 的增量升级,不新建第二套系统;正确模块 KEEP,缺少能力 EXTEND/ADD,错误首页和活动互选逻辑 REPLACE/REFACTOR。
**Tech Stack:** Java 21、Spring Boot 3.x、Spring Security、MyBatis-Plus、Flyway、PostgreSQL、Redis、WebSocket、S3-Compatible Private Object Storage、Vue 3、TypeScript、Vite、Pinia、Element Plus、微信原生小程序、Docker Compose、Nginx。
**Spec:** `docs/善缘丹阳 V1.1 WorkBuddy最终主启动提示词(整合版).md`、`docs/superpowers/specs/2026-09-13-reference-driven-dual-client-ui-redesign-design.md`、`docs/善缘丹阳 V1.1 数据库与API增量设计.md`、`docs/善缘丹阳 V1.1 页面级功能清单与交互流程修订版.md`、`docs/善缘丹阳 V1.1 WorkBuddy 开发执行计划修订版.md`、`docs/善缘丹阳 V1.1 WorkBuddy-Jira 最终开发任务增量清单.md`。
## Global Constraints
- 这六份客户修订文档共同构成 V1.1 需求基线,不能以其中一份覆盖其余文档的专业域要求。
- 主启动提示词负责执行纪律和不变量;页面清单负责功能与交互;2026-09-13 参考图重设计规格是唯一视觉和状态基线;数据库/API 文档负责数据契约;执行计划和 Jira 增量清单负责 Phase、任务与依赖。
- 文档中的“✅、已完成、已部署、MVP完成”属于历史进度声明,不属于客户需求;必须由当前代码、自动化测试和人工流程重新证明。
- V1.0 正确核心按 KEEP 处理,不重新开发;但每个受影响 Phase 必须执行回归门禁。
- V001~V027 已应用迁移不得改写;数据结构修复只能新增向前迁移。
- 用户基础婚恋服务永久免费;不增加支付、会员、金币、礼物、付费曝光或商业广告。
- Required 不自动放宽;普通婚恋 Mutual 后才能聊天;Block 优先级最高;红娘不得替用户 Like 或确认。
- 活动互选必须经过双方分别确认开启沟通,再复用或创建 Match Episode 和 Conversation。
- 本地资格独立于实名认证;咨询独立于红娘;所有新业务复用统一 User、Operator、RBAC、DataScope、Audit、Notification、Risk 和 Object Storage。
- 首页结构、8 个核心入口及其顺序固定;底部导航固定为首页、找对象、消息、活动、我的。
- 用户端采用 `#E96B6B` 品牌 Token、`#FAFAF8` 暖白背景、16px 水平边距、44×44px 最小点击区;禁止页面散落硬编码颜色。
- 所有未确认参数配置化;Feature Flag 仅用于灰度和故障关闭,不能把已确认的 V1.1 正式范围降为“以后再做”。
- 单智能体执行时按 Phase 01、02、03……13、13A、14……26 顺序;每个 Phase 输出 Completion Report 后停止。
---
## 一、对上一版计划的纠正
上一版计划的主要错误不是发现的问题失实,而是处理策略失实:
1. 错误地把主启动提示词当成单一产品规格;正确做法是六份客户修订文档共同约束。
2. 错误地把 V1.0 Phase 01~26 当成全部需要重建;客户文档明确要求“保留主结构、增量修订、不重建全部 Backlog”。
3. 错误地把“未重新验证”统一判成“未完成”;正确做法是 KEEP 项快速回归,只有失败项才进入修复。
4. 错误地声称 U49~U64 全部缺失;实际 U55~U59、U62~U63 已有页面文件,但类型检查和运行链路尚未通过;明确缺失的是 U49~U54、U60、U61、U64。
5. 没有充分区分“数据库已建表”“后端有骨架”“前端可操作”“业务闭环可验收”四种进度。
6. 没有把 Jira/STATUS/PENDING_DECISIONS 中未经验证的 ✅ 当作待清理的项目治理问题。
本计划因此采用:**增量恢复 + 纵向闭环 + 证据驱动状态**,而不是全项目推倒重来。
## 二、当前真实进度基线
### 2.1 已有资产
- V001~V027 迁移文件及对应的 V1.1 表、字段、角色和种子数据已经存在。
- Backend 已有 home、local_eligibility、service_appointment、counseling、content、service_program、activity_mutual 等模块骨架。
- Miniapp 已有 U55~U59、U62~U63 及活动互选结果/等待页面文件。
- Admin Web 已有 Banner、Content、Service Station、Appointment、Program、Counseling、Referral 等 Vue 文件。
- V1.0 Auth、Profile、Review、Match、Like/Block、Messaging、Relationship、Matchmaker、Activity、Risk、Appeal 模块可作为 KEEP 候选。
### 2.2 不能算作完成的证据
- Admin Web `npm run type-check` 当前失败:`CounselingView.vue` 存在语法错误;路由文件未注册 counseling 页面。
- Miniapp TypeScript 当前有 20 余个错误,且 `.ts`/`.js` 双轨并存,不能证明运行的是客户修订版本。
- U49 公益服务中心、U50 服务站、U51 预约、U52 我的预约、U53 课堂、U54 内容详情、U60 反诈、U61 专项服务、U64 服务记录没有注册为可访问页面。
- `/api/v1/operator/**` 当前只统一检查 `operator_login`,不能满足 Permission + DataScope + Sensitive Permission。
- 用户预约创建仍可从请求体接受 `userId`,存在替他人创建/越权风险。
- Counseling 的 operator 接口位于 `/counseling/services/operator/**`,不受现有 `/operator/**` 过滤规则覆盖。
- Activity Mutual 代码只检测 active Match,没有形成“双方确认后复用/新建 Match Episode + Conversation”的完整事务。
- E2E 文件大量使用 `pass`,不能证明功能通过;Jira 中相应 ✅ 必须回退为待验证。
- `docs/PENDING_DECISIONS.md` 同时存在“待确认”与“已部署”矛盾,且包含测试默认账号和密码描述,需清理。
### 2.3 分层进度估算
| 层级 | 当前估算 | 说明 |
|---|---:|---|
| V1.0 核心资产 | 70%~85% | 代码较完整,但需受影响回归 |
| V1.1 数据模型/迁移 | 80%~90% | 迁移齐全,仍需约束、权限和回滚验证 |
| V1.1 后端业务闭环 | 35%~50% | 多数有骨架,主体、权限、事务和真实聚合不足 |
| V1.1 小程序页面闭环 | 25%~35% | 部分页面存在,缺页、未注册、TS/JS 漂移明显 |
| V1.1 运营后台闭环 | 20%~30% | 文件存在但类型检查失败、路由/权限/交互不完整 |
| 自动化测试可信度 | 10%~20% | 大量空壳、fixture 缺失,无法支撑完成声明 |
| 发布就绪度 | 10%~15% | 无可信系统测试、UAT、备份恢复和回滚证据 |
综合开发资产约 45%~55%,可验收业务闭环约 30%~35%。后续进度只按“验收项通过数”计算,不再按文件数量计算。
## 三、修复策略与执行门禁
### 3.1 Phase 状态定义
- `KEEP-VERIFY`:不改业务设计,只跑回归;通过即可关闭。
- `EXTEND`:保留现有实现,补客户新增能力和测试。
- `REFACTOR`:保留数据资产,替换错误业务流程或权限边界。
- `REPLACE`:删除旧运行入口,只保留客户定稿实现。
- `ADD`:补齐不存在的页面、接口或运营闭环。
### 3.2 每 Phase 的统一完成证据
- 关联 Jira 任务状态与实际代码一致,禁止仅凭文件存在勾选 ✅。
- Backend 单元/集成测试通过;Admin type-check/build 通过;涉及 Miniapp 时 TypeScript 检查和开发者工具构建通过。
- 新增/修改 POST 的身份主体、幂等、并发和状态机测试通过。
- Permission、DataScope、Sensitive Access 负向用例返回 401/403/404,不能返回脱敏后的 200 冒充拒绝。
- 受影响业务至少完成一条真实 happy path 和一条失败路径人工验证。
- 更新 STATUS、JIRA_BACKLOG、API/数据库/UI 文档以及对应 Completion Report。
- 输出报告并停止,不自动进入下一 Phase。
## 四、按客户正式 Phase 的增量开发与修复计划
### Phase 01:项目治理与可重复构建基线 — EXTEND
**Files:** `AGENTS.md`、`docs/STATUS.md`、`docs/PENDING_DECISIONS.md`、`docs/JIRA_BACKLOG.md`、`docs/V1_0_TO_V1_1_GAP_ANALYSIS.md`、`docs/ARCHITECTURE_BASELINE_V1.1.md`、`README.md`、`backend/pom.xml`、`admin-web/package.json`、`miniapp/project.config.json`。
- [x] 将六份客户修订文档登记为共同需求基线,并按专业域定义冲突裁决规则。
- [x] 把未经验证的“已完成/已部署”改为 `待验证`、`部分完成` 或 `失败`;保留历史说明,不伪造完成记录。
- [x] 清除文档中的默认账号密码;测试账号改由本地 seed/环境变量生成且不进入交付文档。
- [x] 建立 Windows PowerShell 与 Bash 两套一键检查入口,覆盖 backend test、admin type-check/build、miniapp type-check、E2E。
- [x] 修复或重新初始化 Git 元数据问题;若无法恢复,记录仓库来源、当前文件清单和后续提交策略,不擅自覆盖用户文件。(当前无法恢复,已记录并等待用户决定)
- [x] 生成 Phase 01 Completion Report 后停止。
**Gate:** 三端检查命令可重复启动并给出真实成功/失败;项目状态文件不再互相矛盾。
### Phase 02:统一认证、RBAC、DataScope 与敏感访问 — REFACTOR
**Files:** `backend/src/main/java/com/danyang/match/platform/shared/filter/PermissionFilter.java`、`permission/**`、`security/**`、`audit/**`、V015 后续新迁移、`admin-web/src/stores/auth.ts`、`admin-web/src/router/index.ts`。
- [x] 先写角色×资源×动作×数据范围矩阵测试,覆盖 counselor、counseling_manager、content_editor、service_station_operator。
- [x] 用明确的用户 Principal 和 Operator Principal 替代各 Controller 自行解析 token/userId。
- [x] 移除 `/operator/** → operator_login` 粗粒度授权,改为接口 Permission + Service DataScope 双重校验。
- [x] 把当前不在 `/operator/**` 下的运营接口统一迁移或施加同等级方法权限。
- [x] 验证 ContentEditor 无用户婚恋数据权限、Counselor 仅 Assigned、ServiceStationOperator 仅站点/任务范围、Organization 关系不继承权限。
**Gate:** 权限正向用例通过,四类越权负向用例全部被服务端拒绝并写审计;前端菜单隐藏仅作为体验,不作为安全控制。
### Phase 03:实名认证增量预留 — EXTEND
**Files:** verification 模块、`miniapp/pages/verification/**`、FeatureFlag 配置。
- [x] 验证 V1.0 实名、年龄、加密/hash 和状态流转回归。
- [x] 保留 liveness/provider/verification_level 预留;人脸首发未确认前不实现自研识别、不保存 face embedding。
- [x] 删除任何“官方婚姻状态认证、100%真实”的前端文案。
**Gate:** 实名状态来自数据库而非首页硬编码;人脸 Flag 关闭时流程可正常完成。
### Phase 04:Profile、Preference 与本地资格 — EXTEND
**Files:** `local_eligibility/**`、profile/status/capability 服务、`miniapp/pages/local-eligibility/**`、`miniapp/pages/local-eligibility-supplement/**`。
- [x] 保留 V1.0 Profile/Preference,补齐本地资格声明、按需补证、提交、状态查询和 `/me/status`。
- [x] 用户 API 的 userId 只能来自认证主体;佐证文件进入私有存储,先鉴权再签名。
- [x] 将本地资格佐证触发规则、数量、大小、类型和保留期限全部配置化。
- [x] 把 U62/U63 接入首次准入与“我的”,并覆盖未提交、声明完成、待补充、审核中、已核验、未通过状态。
**Gate:** 本地资格与身份表独立;非本人和无特殊权限人员不能读取佐证。
### Phase 05:统一审核扩展 — EXTEND(2026-09-12 已完成)
**Files:** review 模块、local eligibility service、`admin-web/src/modules/review/ReviewView.vue`。
- [x] 复用现有 ReviewTask,增加 local_eligibility 类型,不建第二套审核引擎。
- [x] 验证 Claim 原子性、Need Evidence、Approve、Reject 与本地资格状态联动。
- [x] 每次查看敏感佐证记录 purpose、operator、target、timestamp、result。
**Gate:** 两名审核员不能同时 claim;审核通过/拒绝与前台状态一致。
### Phase 06:Match Eligibility 增量 — KEEP/EXTEND(2026-09-12 已完成)
**Files:** `match/service/MatchEligibilityService.java`、`RecommendationEngineService.java`、对应测试。
- [x] 先跑 V1.0 双向 Required、Block、Paused、Successful 和隐私回归,不重写正确算法。
- [x] 仅在配置要求时把本地资格接入 eligibility;不得自动放宽 Required。
- [x] 确认首页推荐仍调用正式 Match Engine,推荐数量、阈值、冷却均配置化。
**Gate:** 双方任一 Required 不满足时永不入选;前台不显示数字匹配率。
### Phase 07:V1.1 首页唯一实现 + 找对象 — 业务证据保留,UI REOPENED(2026-09-13)
> 后端聚合、Capability、8 入口及推荐规则的专项证据保留;旧页面视觉已被用户否决。当前 UI 实施入口仅为 `docs/superpowers/plans/2026-09-13-reference-driven-dual-client-ui-redesign.md`,不得按本节历史完成标记恢复旧设计。
**Files:** `home/**`、banner 读取服务、`miniapp/pages/index/**`、`miniapp/pages/discover/**`、首页组件、`miniapp/app.json`、Design Token。
- [x] 为 HomeApplicationService 写聚合契约测试,确保它调用正式 status、match、activity、location、content、capability 服务,不复制规则。
- [x] 修复硬编码 verified、空 recommendations/articles、固定服务站和错误入口路由。
- [x] 固定首页顺序:品牌、状态、Banner、8 入口、推荐、公益服务、活动、服务站、课堂、安全提醒。
- [x] 固定 8 入口顺序并分别路由到真实页面;未开放时展示服务端 Capability 返回的 Disabled 原因。
- [x] 统一 TypeScript 为唯一源,配置小程序 TypeScript 编译;移除同页手写 `.ts`/`.js` 逻辑漂移。
- [x] 落实未登录、未实名、审核中、Searching、Paused、Successful、空数据、网络错误、Skeleton 状态矩阵。
- [x] 迁移完成后删除旧首页运行逻辑,不保留 `/home-old`。
**Gate:** 首页 5 秒识别品牌和主要入口;Banner 仅内部目标;首页真实聚合数据可用;小程序 TS 检查和开发者工具构建通过。
### Phase 08:Like / Match / Block — KEEP-VERIFY/EXTEND(2026-09-16 已完成)
> 复验中发现并修复 3 处真实缺陷:搜索完全绕过 Block(INV-004「搜索不可见」整体失效)、
> 详情页对双向拉黑者仍可见、`matches.source` 取值越界(实测 Mapper 传 `"liked"`,违反 `V003` 的 `chk_match_source`,
> 仅在 H2 测试库无该约束时才静默通过)。详见 `docs/Phase-08-V11-Recovery-Completion-Report-2026-09-16.md`。
**Files:** relationship 模块、discover/relationship 页面和对应测试。
- [x] 验证 Like、Pass、普通 Mutual、Unmatch、Block 全链路。
- [x] 增加 Activity Match Episode 兼容,不改变普通 Match 的双向 Like 规则。
- [x] 验证 Block 后推荐排除、搜索不可见、聊天停止且无法由缓存绕过。
**Gate:** V1.0 核心回归通过;活动来源兼容不会创建第二套 Match 逻辑。
### Phase 09:Text Chat — KEEP-VERIFY/EXTEND(2026-09-16 已完成)
> 复验中发现并修复 4 处真实缺陷:① WebSocket 下行整条链路是死代码(无握手鉴权、无 userId 写入、
> `sendToUser` 零调用点);② Unmatch 只改 Match 不联动会话,且发消息只校验会话状态 → 解除匹配后仍可发消息;
> ③ `RelationService.block` 调用静态 `MatchService.unmatch`(只改内存态)→ Block 后 Match 未落库;
> ④ 聊天四个读/写接口无会话成员校验 → 任意登录用户可读他人私聊(IDOR)。
> 详见 `docs/Phase-09-V11-Recovery-Completion-Report-2026-09-16.md`。
**Files:** `messaging/**`、WebSocket 配置、Miniapp messages/chat 页面。
- [x] 验证 REST send + WebSocket receive、消息幂等、重连和未读计数。
- [x] 验证非 active Match 禁聊,Unmatch/Block 后即时禁聊。
- [x] 让活动双确认产生的 Conversation 复用同一消息体系。
**Gate:** 未 Mutual 或活动未双确认时不能发消息;正常会话不重复投递。
### Phase 10:Image & Chat Safety — KEEP-VERIFY
**Files:** photo 模块、message safety、对象存储配置和聊天页面。
- [x] 验证图片私有访问、类型/大小校验、审核和水印。
- [x] 验证风险识别、举报入口和违规内容处理。
- [x] 检查日志不记录聊天正文、身份证、手机号或签名 URL。
**Gate:** 越权图片访问被拒绝,敏感内容不进入普通日志。
(2026-09-16 复验通过:修复 D1 图片上传魔数校验死代码——本地资格佐证上传曾 100% 失败;D2 高风险词写入普通日志。水印未实现,登记 gap。)
### Phase 11:Notification — EXTEND
**Files:** `notification/**`、预约/咨询/资格/活动服务及通知页面。
- [x] 新增预约、咨询、辅导、本地资格和活动双确认通知。
- [x] 统一在业务事务提交后发送,发送失败不回滚核心事实。
- [x] 锁屏和通知摘要使用隐私安全文案,不泄露咨询主题或单向意向。
**Gate:** 回滚事务不发通知;已提交事务通知失败可重试且不产生重复业务记录。
(2026-09-16 复验:修复 D3——10 种通知 type 违反生产 CHECK 约束致全部落库失败;D1——补通知幂等唯一索引
V036;D2——接线婚前辅导及管理端排期通知。`sendExternal` 在事务内执行的缺口已登记,接入真实微信 API 前须
改为提交后发送。真机文案 INV-010 达标。)
### Phase 12:Relationship Progress — KEEP-VERIFY/EXTEND
**Files:** relationship 状态服务、Match Episode、relationship-status 页面。
- [x] 验证成功关系双确认、恢复/退出、历史 Episode 和并发确认。
- [x] 补充 getting_to_know 阶段的婚前辅导入口引导。
- [x] 验证工作人员不能替用户确认成功关系。
**Gate:** 单方确认不改变最终关系;历史 Episode 可追踪但不会恢复旧聊天权限。
(2026-09-16 复验:修复 D1——实体与生产迁移系统性漂移,23 表 50 列缺失,其中 `matches.episode`
等 11 张表属"INSERT 必崩"级生产故障,真实 PG 上 Match 创建 / 偏好保存 / 权限写入等全部失败;
D2——`RelationshipService.createMatch` 不写 episode/lastActivityAt,与 `MatchService` 双路径字段不一致,
且 `episode` 为 null 时 `getEpisode() + 1` 自动拆箱 NPE;D3——测试库缺 `user_identities` 等 7 张表,
致 `GET /home` 在测试环境直接 BadSqlGrammar,首页零回归覆盖;D4——Phase 12 计划项 2 实际未实现
(getting_to_know 只给 counseling,无婚前辅导入口)。新增 `EntityMigrationParityTest` 把
「实体字段 ⊆ 生产迁移列」「测试库覆盖关键表」固化为自动守卫,并经负向验证证明会变红。
真机行为:双确认/并发确认/历史 Episode 不恢复旧聊天/非成员不可代确认 —— 14 项全绿。)
### Phase 13:公益红娘转介 — EXTEND
**Files:** `matchmaker/**`、`referral/**`、Miniapp 红娘页面、Admin referral 页面。
- [x] 保留红娘服务和人工推荐;验证任何工作人员不能替用户 Like。
- [x] 补齐转介咨询、活动、服务站的用户同意、来源追踪和状态记录。
- [x] 红娘只能看转介状态和必要摘要,不能读取 counseling followup 正文。
**Gate:** 转介形成可追踪记录但不越权;用户决定权测试通过。
> **2026-09-16 复验结论(KEEP-VERIFY/EXTEND)**:历史 ✅ 不可信。全仓库唯一的"INV-005 红娘不可代用户操作"
> 证据是 `MatchmakerServiceTest#testMatchmakerCannotLike` 的 `assertTrue(true)` 占位,以及
> `CoreInvariantsTest#testMatchmakerCannotLike`(断言的是 `MATCHMAKER_STATUS_*` **状态常量字符串**,
> 与 Like 无关)—— 两者均为**名不副实的假测试**;且测试库 `schema-h2.sql` **完全缺失** `matchmaker_*` 三表,
> 该模块**零真实行为覆盖**。逐条核对运行时路径后修复 7 处缺陷:
> - **D1(Critical,生产故障)** `matchmaker_recommendations.status`:代码写
> `liked`/`passed`/`confirmed_mutual`,而 `V009 chk_rec_status` 只允许
> `pending_view/viewed/responded`,且**从未被后续迁移扩展** → 真实 PostgreSQL 上
> 用户"接受/跳过"红娘推荐**必然 500**,P13 主流程不可用。
> - **D2(Critical,生产故障)** `MatchmakerController.submit` 在请求未带 `serviceType` 时兜底写
> `"recommendation"`,而 `V009 chk_matchmaker_service_type` 白名单只含 `recommend_partner` 等 7 个值
> → 真实 PG 上提交红娘服务**必然 500**。(`MatchmakerService` 注释声明的
> `referral_counseling`/`referral_activity`/`referral_station` 同样越界。)
> - **D3(High)** `MatchmakerServiceService.recommendPartner` 缺 `assigned_operator_id` 归属校验
> → 任何持 `matchmaker.service` 权限的 operator 可对**任意** serviceId 创建推荐(越权)。
> - **D4(High)** `getServiceDetail` 无任何归属校验,任何 `matchmaker.view` 持有者可读**任意**服务的
> 完整用户资料(displayName/gender/age/region/education/occupation/maritalStatus)→ 越权读。
> - **D5(High)** `ReferralService.referToActivity` / `referToServiceStation` 的 `userId` 直接取自
> 请求体且**无任何授权校验**(连 `MatchmakerServiceMapper` 都没注入)→ 任意红娘可把**任意用户**
> 转介到任意活动/服务站,并顺带为该用户创建报名/预约(越权代操作)。
> - **D6(High,生产故障)** `MatchmakerFollowupMapper.findByServiceId` **只有方法声明、没有 `@Select`**
> → MyBatis 运行时抛 `Invalid bound statement (not found)`,`getServiceDetail` 必然 500,
> 红娘工作台"查看服务详情"完全不可用。此前不可见:测试库缺 `matchmaker_followups` 表。
> - **D7(Medium)** Admin referral 页面契约缺口:`/referrals/my-history`(C 端 UserPrincipal 端点)
> 被运营端调用;`/matchmaker/services/operator/queue`、`/matchmaker/recommendations/operator`、
> `PUT /matchmaker/services/{id}/assign`、`POST /matchmaker/services/{id}/recommendation`
> 四条路径在后端**均不存在**(404)。
> 修复:新增 `V038__align_matchmaker_status_constraints.sql`(沿用 V018/V020/V025 的
> `DROP CONSTRAINT IF EXISTS` + 重加白名单惯例);测试库补 `matchmaker_*` 三表(约束对齐 V038);
> D3/D4/D5 补归属校验与转介授权;D6 补 `@Select`;D7 补两个运营端端点并修正前端调用。
> **新增守卫** `MatchmakerReferralPhase13Test`(17 用例,走真实服务方法 + 真实落库)替换假测试;
> `MatchmakerServiceTest` 重写为**直接解析迁移 SQL** 的口径守卫(第一轮负向验证暴露"抄副本"守卫
> 对漂移无反应,已修正);`CoreInvariantsTest` 的 INV-007/INV-010 假断言已如实改名并指向真实验证。
> **两轮负向验证**:注入 D1(回退 `chk_rec_status` 白名单)→ 行为守卫抛 `DataIntegrityViolation`、
> 常量守卫报 3 处 failure,守卫有效性得证。
>
> **全量回归实测**:`[WARNING] Tests run: 391, Failures: 0, Errors: 0, Skipped: 3` / `BUILD SUCCESS`(4 分 59 秒)。
> Phase 12 基线 371 → 391(净 +20)。**Phase 13 已关闭。Phase 13A 未自动进入,等待用户确认。**
> 报告:`docs/Phase-13-V11-Recovery-Completion-Report-2026-09-16.md`
### Phase 13A:婚恋咨询与婚前辅导 — REFACTOR/EXTEND
**Files:** `counseling/**`、`miniapp/pages/counseling-*`、`miniapp/pages/my-counseling/**`、`miniapp/pages/premarital-*`、`admin-web/src/modules/counseling/CounselingView.vue`、router。
- [ ] 修复 Admin Vue 语法错误并注册 `/counseling` 路由,先使 type-check 失败转为通过。
- [ ] 用户申请接口从认证主体取 userId;补幂等、取消、详情 owner 校验和合法状态迁移。
- [ ] 分配操作使用条件更新/版本号解决并发;Counselor 只能读取和操作 Assigned Service。
- [ ] Counseling Manager 可分配和查看必要摘要;普通管理员、红娘、内容编辑不得读取咨询正文。
- [ ] 婚前辅导复用 counseling service type;邀请平台内伴侣必须由对方自主确认。
- [ ] U55~U59 修复类型错误、API 契约、Loading/Empty/Error/Permission 状态和非医疗化文案。
**Gate:** 申请→分配→预约→服务→完成→反馈真实闭环通过;所有隐私负向用例通过。
### Phase 14:多类型公益活动 — REFACTOR/EXTEND
**Files:** activity 模块、Miniapp activity 页面、Admin activity 页面。
- [ ] 保留活动基础,完成 ActivityType 分类、按类型报名策略、capacity groups 和多组织关系。
- [ ] 完成小程序分类 Tabs、类型化卡片、动态资格提示和后台动态表单。
- [ ] 验证主办组织关系不自动授予用户库访问权限。
**Gate:** matchmaking 与课堂/反诈类活动显示和资格策略不同;容量按配置正确扣减。
### Phase 15:活动报名、审核与签到 — KEEP-VERIFY/EXTEND
**Files:** activity registration、checkin 服务和 U29~U32 页面。
- [ ] 回归报名、审核、取消、签到码、重复签到和名额并发。
- [ ] 增加非 matchmaking 活动和 capacity group 场景测试。
- [ ] 服务站操作员只能操作指定活动或站点任务。
**Gate:** 重复请求和并发报名不超额;签到不可跨活动复用。
### Phase 16:活动互选与双方开启沟通确认 — REFACTOR
**Files:** activity_mutual、relationship、messaging 模块及 activity-mutual 页面。
- [ ] 以 activity_user_interests + activity_mutual_connection_consents 为唯一逻辑,废弃 mutual 直接建 Match/Chat 的所有入口。
- [ ] 双方确认事务中:已有 active Match 则复用已有会话;历史 Unmatch 则创建新 Episode;无历史则创建 Match 和 Conversation。
- [ ] 补 decline、timeout、重复确认幂等、并发确认和单向意向保密测试。
**Gate:** A 单选 B 时 B 无感知;Mutual 但未双确认时无新 Chat;双确认后 exactly-once 形成正确 Match/Conversation。
### Phase 17:举报与风控 — EXTEND
**Files:** risk、report、referral 模块和后台风险页面。
- [ ] 将 counseling、service_station、offline_activity 作为风险来源接入统一 RiskEvent。
- [ ] 后台显示必要来源上下文但不暴露无关咨询正文。
- [ ] 禁止公开黑名单;举报、处置、Block 与敏感访问继续审计。
**Gate:** 风险来源可追踪、正文最小可见,低权限人员不能扩大读取范围。
### Phase 18:申诉 — KEEP-VERIFY
**Files:** appeal 模块、Miniapp appeal 页面和后台 AppealCenter。
- [ ] 回归 ban/suspend 申诉、幂等处理、审批和解除动作。
- [ ] 验证申诉不能绕过仍有效的其他风险处置。
- [ ] 是否首发继续由已确认 Feature Flag 控制。
**Gate:** 申诉通过只解除目标处置;拒绝后原处置保持有效。
### Phase 19:统一运营后台 + 用户端公益服务页面 — ADD/REFACTOR
**Files:** Admin banner/content/service-station/service-appointment/service-program/counseling/referral 模块、MainLayout/router;Miniapp 新增 U49~U54、U60、U61、U64 页面;service API 文件。
- [ ] 先修复 Admin 全量 type-check 和角色路由,再实现“角色第一屏知道今天做什么”的待办型工作台。
- [ ] Banner 完成 CRUD、排期、排序、Audience、内部 target 校验和预览;禁止外链。
- [ ] Content 完成分类、文章编辑、发布/下架;用户端只做文章列表/详情,不做 Feed、评论和点赞。
- [ ] Service Station 完成万善公园站信息、开放时间、公告、服务项目和预约管理。
- [ ] 修复预约 IDOR:普通用户创建、详情、列表、取消只能操作本人;代登记使用独立 operator 接口和权限。
- [ ] Service Program 完成项目、申请、审批、退出和必要统计,禁止把项目成员身份变成用户价值标签。
- [ ] 新增并注册 U49 公益服务中心、U50 服务站、U51 预约、U52 我的预约、U53 课堂、U54 内容详情、U60 反诈、U61 专项服务、U64 公益服务记录。
- [ ] 重构 U37“我的”四组结构,接入上述新增页面;U64 只显示用户自己的服务时间线,不显示内部备注。
- [ ] 所有页面复用统一 Token 和组件,覆盖 Loading、Skeleton、Empty、Error、Permission、Disabled、Responsive。
**Gate:** 小程序 U01~U64 页面清单无缺页且路由可达;七类后台角色只看到自己的工作;后台 type-check/build 通过。
### Phase 20:公益服务 Analytics — EXTEND
**Files:** analytics 模块、统计查询/事实表后续迁移、Admin Analytics 页面、`docs/ANALYTICS_METRICS.md`。
- [ ] 为每个指标登记名称、定义、分子分母、去重键、时间字段、时区、版本和负责人。
- [ ] 分离服务用户数与服务人次、活动 mutual/confirmed/match/chat/success、Banner impression/click。
- [ ] 有效交友匹配在口径未确认前标为 provisional,不能当正式成功或对外宣传。
- [ ] 所有统计接口应用 `analytics.view` 和组织/站点 DataScope,低权限账号返回 403。
**Gate:** 用固定测试数据人工复算一致;相同用户多次服务不会污染去重人数。
### Phase 21:账户生命周期 — EXTEND
**Files:** `account/service/AccountLifecycleService.java`、预约/咨询/项目/资格服务、数据保留文档。
- [ ] 注销前检查进行中的预约、咨询、项目和本地资格审核。
- [ ] 注销事务关闭未来服务、退出项目、失效本地资格并匿名化允许保留的服务历史。
- [ ] 数据保留期限未确认的敏感材料采用配置和人工审核,不擅自永久保存或删除。
**Gate:** 注销后不能登录/推荐/聊天;统计留痕不反向暴露个人和咨询正文。
### Phase 22:Deployment / Ops — EXTEND
**Files:** Dockerfiles、`infrastructure/docker-compose*.yml`、Nginx、backup/restore/deploy/gray-release scripts、OPS/DEPENDENCIES 文档。
- [ ] 删除 Backend 镜像跳过测试的发布路径;CI 构建必须先测试再打包。
- [ ] 生产关闭 Mock WeChat、默认密码、Debug、Swagger 和演示 Seed;Secret 全部由环境变量/Secret 文件注入。
- [ ] 建立 `/api/v1`、WebSocket、私有对象、6688 端口检测及国内依赖镜像说明。
- [ ] 备份加密并存放独立位置,执行一次 PostgreSQL + 对象存储实际恢复演练。
- [ ] Rollback 明确回到哪个稳定镜像/版本;Flyway 只向前修复,不破坏 V001~V027。
**Gate:** staging 部署、健康检查、恢复演练和版本回滚都有命令、日志与结果证据。
### Phase 23:可信系统测试重建 — REFACTOR
**Files:** `backend/src/test/**`、`tests/e2e/**`、`tests/invariants/**`、测试 fixture/seed、CI scripts。
- [ ] 删除测试体中的空 `pass`,建立可隔离的用户、角色、组织、活动、咨询和预约 fixture。
- [ ] INV-001~020 必须测试真实服务行为,不能只断言常量字符串存在。
- [ ] E2E 覆盖首页聚合、Banner、资格、咨询、预约、内容、多类型活动、二阶段同意、组织隔离。
- [ ] 增加 appointment owner、Counselor Assigned、ContentEditor zero-user-data、station scope 等负向安全测试。
- [ ] CI 串联迁移、backend test、admin type-check/build、miniapp type-check 和 E2E,任何失败阻断发布。
**Gate:** 不允许 skip/pass 空壳;报告列出总数、通过、失败、跳过及原因,失败为零才进入 UAT。
### Phase 24:UAT — EXTEND
- [ ] 按用户、Reviewer、Matchmaker、Counselor、Counseling Manager、Service Station Operator、Content Editor、Activity Manager、Risk Operator 分角色验收。
- [ ] 验收线上主路径、线下扫码路径、咨询路径、辅导路径、服务站路径、活动二阶段确认和反诈举报路径。
- [ ] UI 按 375px 小程序基准和 1440px 后台基准检查,并覆盖弱网、空态、错误态、权限态。
**Gate:** 所有 P0/P1 客户场景有签字结果;阻断缺陷为零。
### Phase 25:RC — EXTEND
- [ ] 只使用客户确认的真实 Banner、站点、咨询、课堂、反诈、关于我们和组织信息;不 Seed 假用户/假 Match。
- [ ] 完成隐私政策、用户协议、敏感文案和“非官方婚姻状态核验”提示审核。
- [ ] 冻结 RC 镜像、数据库版本、配置清单、第三方依赖和回滚目标。
**Gate:** Go/No-Go 清单通过;所有未决事项有明确 Flag/配置行为和责任人。
### Phase 26:Production — EXTEND
- [ ] 上线前备份,执行 V027 及后续向前迁移,验证角色权限和真实基础内容。
- [ ] 依次执行 Home、Quick Entries、Service Station、Counseling、Content、Activity Mutual、Chat、Block smoke。
- [ ] 首日监控错误率、延迟、登录、推荐、消息、预约、咨询和权限拒绝;异常按已验证 Rollback 操作。
**Gate:** 生产 smoke 全部通过且无数据泄露/权限越界;否则立即 NO-GO 或回滚。
## 五、第一轮执行范围
收到“开始修复”后,只执行 Phase 01:
1. 纠正文档状态与共同基线;
2. 建立三端可重复检查命令;
3. 明确 Git/版本基线;
4. 输出 Phase 01 Completion Report;
5. 停止并等待用户确认 Phase 02。
不得借 Phase 01 提前修改首页、咨询、活动或后台业务代码。
## 六、计划自检
- 客户修订范围:品牌、首页、Banner、8 入口、本地资格、服务站、预约、咨询、辅导、课堂、反诈、多类型活动、二阶段同意、专项服务、多组织、来源和 Analytics 均已映射。
- 页面范围:U01~U48 KEEP;U49~U64 按“已有修复/缺失新增”分别处理。
- 数据范围:V001~V027 保留,后续只向前迁移;身份、资格、咨询、预约和活动边界独立。
- 权限范围:RBAC、DataScope、Sensitive Permission、Audit 和客户端 Capability 分层明确。
- 发布范围:测试、UAT、真实内容、Secret、备份恢复、Rollback、Production Smoke 均有 Gate。
- 禁止范围:未加入微服务、独立 CMS/咨询服务、社区 Feed、支付、AI 代聊或其他 V1.1 外功能。