Files
danyang-match/docs/善缘丹阳 V1.1 客户需求基线增量开发与修复计划.md
T
WorkBuddy 72b4e9b846 fix(ops-backend/service-station): close Phase 19 KEEP-VERIFY — 25 defects (unreachable announcements + station write privilege escalation; banner 500 + soft-delete leak; content publish dead-end; program approval dead-end/draft leak/zero counts/missing withdraw; zero-coverage test schema) ; add V042 announcement chain + 34 guard tests; full regression 602 green
Backend
- Service Station: expose the 「临时公告」 chain end-to-end (V042 table/service existed
  but had ZERO endpoints -> both admin and miniapp could never reach it): 5 operator
  endpoints (list/create/update/publish/archive) + 1 user-facing read endpoint.
- Fix privilege escalation: create/update were guarded only by the class-level
  service_location.view, making V015's service_location.manage a never-used dead
  permission -> read-only roles could edit stations. Permissions moved to method level.
- Add ServiceLocationOperatorController to OperatorEndpointPermissionCoverageTest
  (it was NOT scanned, which is why the escalation stayed invisible).
- Add create/update validation (address NOT NULL + status CHECK only blew up on PG).
- Banner: validation failures threw bare RuntimeException -> 500; now VALIDATION_ERROR
  -> 400. Add deleted_at IS NULL to both home queries (soft-deleted banners stayed live).
- Content: operator list/detail split (admin «publish» was a dead end because it reused
  the published-only public API); category deactivate/reactivate; article body on edit.
- Service Program: operator member list now includes pending (approval reachable);
  active-only public visibility (draft leak); memberCount/pendingCount aggregation;
  withdraw/removeMember; reuse row on re-apply (UNIQUE(program_id,user_id) crash).
- MeController: add the missing GET /me/service-history route.

Schema / guards
- schema-h2.sql: add service_location_announcements (+ chk_announcement_status) and
  content_categories (+ uk_content_category_code, chk_category_status); move both into
  REQUIRED_IN_TEST_SCHEMA. MigrationValidationTest baseline 41 -> 42.
- V11PermissionMatrixContractTest now scans ALL migrations instead of hardcoding V015+V029.
- New: ServiceLocationAnnouncementPhase19IntegrationTest (24),
  ServiceLocationControllerPermissionContractTest (5),
  ServiceLocationAnnouncementConstraintParityTest (5, prod DDL <-> test schema <->
  backend whitelist <-> admin labels).

Frontend
- admin-web: ServiceStationView gains announcement management (statuses, create/edit,
  publish/archive with confirm, expiry); write buttons gated by service_location.manage.
- miniapp: U50 renders the 临时公告 block via new serviceStationService; page no longer
  talks to utils/api directly; announcement failure degrades to [] instead of erroring.
- ui-tests: U37 four-group + U50 announcement contracts; /home assertion retargeted to
  the service layer.

Verification
- Negative verification: 3 injected defects (drop soft-delete filter / drop test-schema
  CHECK / downgrade write endpoint to view) -> 4 named tests fail precisely, no
  collateral failures; restored, NEG-VAL residue = 0.
- Backend full regression: 602 tests, 0 failures, 0 errors, 3 skipped (baseline 420).
- admin-web: vue-tsc --noEmit EXIT=0, vite build EXIT=0. Miniapp: tsc --noEmit EXIT=0.
- ui-tests 14/14 PASS.
2026-09-17 22:21:31 +08:00

593 lines
48 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。
- [x] 修复 Admin Vue 语法错误并注册 `/counseling` 路由,先使 type-check 失败转为通过。
- [x] 用户申请接口从认证主体取 userId;补幂等、取消、详情 owner 校验和合法状态迁移。
- [x] 分配操作使用条件更新/版本号解决并发;Counselor 只能读取和操作 Assigned Service。
- [x] Counseling Manager 可分配和查看必要摘要;普通管理员、红娘、内容编辑不得读取咨询正文。
- [x] 婚前辅导复用 counseling service type;邀请平台内伴侣必须由对方自主确认。
- [x] U55~U59 修复类型错误、API 契约、Loading/Empty/Error/Permission 状态和非医疗化文案。
**Gate:** 申请→分配→预约→服务→完成→反馈真实闭环通过;所有隐私负向用例通过。
> **复验完成(2026-09-17)** — Tag:`phase13a-recovery-2026-09-17`
>
> 复验发现 counseling 模块存在**双实现**:线上权威 `CounselingService`(167 行)
> **零测试**,唯一被测的 `CounselingServiceApp`(280 行)是**孤儿类**
> (无注入点、无端点可达,生产永不执行)。已合并并删除孤儿类。
>
> **9 处缺陷(D1~D9)**:
> - D1 **Critical 生产故障 / INV-013 泄露**:咨询正文原文被写入 WARN 日志(同 Phase 10 D2 一族)。
> - D2 High 越权:申请 userId 取自请求体而非认证主体。
> - D3 High 并发:分配「先读后写」→ 并发**静默覆盖**;改 `assignIfPending` 条件更新。
> - D4 High 越权读:manager 经 `getDetail` 可读 followups 正文(INV-013 绕过通道)。
> - D5 Medium:无状态机 → 「已完成」可被再取消。
> - D6 Medium 生产故障:`GET /services/intro` 后端不存在,小程序 intro 页 100% 无数据
> (且被 `/services/{id}` 吞掉)→ 已补端点并置于变量路径之前。
> - D7 Medium:Admin 调用 5 条不存在的运营端端点(404)+ 缺四态。
> - D8 Medium:小程序字段名不匹配 + 无幂等 + 未检查 `success`(403 静默空列表)+ 跳转不存在的页。
> - D9 Medium 测试保真度:测试库 counseling 两表**零 CHECK 约束**,`counseling_services` 零覆盖。
>
> **另修 4 处测试基建缺陷(T1~T4)**:守卫因 surefire `workingDirectory` 指向仓库根而
> **找不到 DDL**(恒真假绿);全限定 `@TableField(exist=false)` 漏解析(假警报);
> 权限守卫扫到私有辅助方法(假阳性);两处测试自身逻辑缺陷。
>
> **负向验证两轮**:① DDL 常量守卫 —— 从 V039 移除 `scheduled` → 守卫精准变红
> (证明解析的是**真实 DDL** 而非副本);② 行为守卫 —— 注入并发/INV-013/状态机
> 三个缺陷 → 三个用例精准变红。均已还原。
>
> **全量回归实测**:`[WARNING] Tests run: 420, Failures: 0, Errors: 0, Skipped: 3` /
> `BUILD SUCCESS`(4 分 49 秒)。Phase 13 基线 391 → 420(净 +29)。
> **Phase 13A 已关闭。Phase 14 未自动进入,等待用户确认。**
> 报告:`docs/Phase-13A-V11-Recovery-Completion-Report-2026-09-17.md`
### Phase 14:多类型公益活动 — REFACTOR/EXTEND
**Files:** activity 模块、Miniapp activity 页面、Admin activity 页面。
- [x] 保留活动基础,完成 ActivityType 分类、按类型报名策略、capacity groups 和多组织关系。
- [x] 完成小程序分类 Tabs、类型化卡片、动态资格提示和后台动态表单。
- [x] 验证主办组织关系不自动授予用户库访问权限。
**Gate:** matchmaking 与课堂/反诈类活动显示和资格策略不同;容量按配置正确扣减。
> **复验完成(2026-09-17)** — Tag:`phase14-recovery-2026-09-17`
>
> **11 处后端缺陷(D1~D11)**:
> - D1 **Critical 生产故障**:`ActivityMapper.countRemainingCapacity` 无 `@Select` 无 XML
> → 活动详情/报名/审核三条路径必抛 `Invalid bound statement`。
> - D2 **Critical 并发**:报名与审核均为「先读后写」→ 并发超卖;改
> `insertIfCapacityAvailable` / `approveIfCapacityAvailable` 单条原子 SQL。
> - D3 High 生产故障:`activityType` / `orgRole` 未校验生产 `chk_activity_type` /
> `chk_org_role` 白名单("只在 PG 上炸")。
> - D4 High 契约:`ActivityListItemDTO` 无 `activityType` → 小程序分类 Tabs 恒无数据。
> - D5 Medium:男女人数为 `approvedCount/2` 编造 → 改按 `user_profiles.gender` 真实统计。
> - D6 Medium:年龄门槛为 TODO 空壳,完全不生效。
> - D7 Medium:`registration_policy` 只写不读,按类型资格策略为空(Gate 未落地)。
> - D8 Medium:`POST /operator/activities` 丢弃类型/多组织/容量分组,且把
> `organizer_org_id` 错设为操作者 userId → 后台动态表单无法创建带类型活动。
> - D9 Medium:三个运营写入端点错挂在**用户端** `ActivityController`(双实现、零调用方)。
> - D10 Medium NPE:软删活动致 `getMyActivities` NPE;后台漏填字段致创建活动 500。
> - D11 Medium 契约:DTO 缺 `registeredCount`/`status`/`coverFileId`/`description`
> → 卡片报名人数恒 0、按钮恒"查看详情"、封面与摘要恒不显示。
>
> **3 处前端契约缺陷(F1~F3)**:小程序分类 code `classroom` 不在生产白名单
> (应为 `relationship_education`)且缺三类入口;卡片读取 7 个后端根本不存在的字段;
> admin-web 完全没有活动管理页(已新增 `ActivityManagementView.vue` 类型驱动动态表单)。
>
> **2 处测试保真度缺陷(T1~T2)**:`testNoOverbooking` /
> `testNoDuplicateRegistration` 为 `assertTrue(true)` 占位假绿(已删除);
> 测试库缺 V023 列与三张表,且 activity 五表在 `EntityMigrationParityTest`
> 只属"可选白名单"(零覆盖)→ 已补齐并移入必选集合。
>
> **负向验证两轮**:① 后端 —— 从 V023 删 `anti_fraud` + 报名退化为无容量检查
> → 3 条用例精准变红;② 前端契约 —— 分类 code 改回 `classroom` + 卡片加回
> `activity.suitableFor` → 3 条守卫精准变红。均已还原。
>
> **全量回归实测**:`[WARNING] Tests run: 450, Failures: 0, Errors: 0, Skipped: 3` /
> `BUILD SUCCESS`(4 分 52 秒)。Phase 13A 基线 420 → 450(净 +30)。
> admin-web `vue-tsc --noEmit` 0 error、`vite build` 通过。
> **Phase 14 已关闭。Phase 15 未自动进入,等待用户确认。**
> 报告:`docs/Phase-14-V11-Recovery-Completion-Report-2026-09-17.md`
### Phase 15:活动报名、审核与签到 — KEEP-VERIFY/EXTEND
**Files:** activity registration、checkin 服务和 U29~U32 页面。
- [x] 回归报名、审核、取消、签到码、重复签到和名额并发。
- [x] 增加非 matchmaking 活动和 capacity group 场景测试。
- [x] 服务站操作员只能操作指定活动或站点任务。
**Gate:** 重复请求和并发报名不超额;签到不可跨活动复用。
> **2026-09-17 复验关闭**:修复 16 处缺陷(8 处签到 + 5 处报名/审核/取消 + 1 处容量分组 + 2 处前端契约)
> + 3 处测试保真度缺陷。两处必崩:**D1 签到码一生成即作废**(`generateCheckinToken` 写 `"used"`,
> 扫码 100% 失败)、**D9 取消后永远无法再报名**(撞生产 `UNIQUE(activity_id,user_id)`,
> 测试库缺该约束故零覆盖)。新增 V040 `activity_staff_assignments` 落实签到数据范围(INV-020)。
> 一轮负向验证:3 处注入 → 8 条用例精准变红并还原。全量回归 **474 tests 全绿**(基线 450)。
> 报告:`docs/Phase-15-V11-Recovery-Completion-Report-2026-09-17.md`
> **Phase 16 未自动进入,等待用户确认。**
### Phase 16:活动互选与双方开启沟通确认 — REFACTOR ✅ 已完成(2026-09-17 KEEP-VERIFY/EXTEND 复验关闭)
**Files:** activity_mutual、relationship、messaging 模块及 activity-mutual 页面。
- [x] 以 activity_mutual_connection_consents 为唯一逻辑,双实现统一到 `RelationshipService.confirmActivityInterest`。
- [x] 双方确认事务中:已有 active Match 则复用已有会话;历史 Unmatch 则复用同一行(episode 递增 + reopen);无历史则创建 Match 和 Conversation。
- [x] 补 decline、expires_at 超时、重复确认幂等、并发确认(exactly-once)和单向意向保密(INV-006)测试。
**Gate:** A 单选 B 时 B 无感知;Mutual 但未双确认时无新 Chat;双确认后 exactly-once 形成正确 Match/Conversation。
> **2026-09-17 复验结论(KEEP-VERIFY/EXTEND):** 历史 ✅ 不可信,逐条核对运行时路径后发现**活动互选核心 Gate 缺陷**——
> 新路径 `ActivityMutualConsentController.confirmConnection` 双确认后**根本不建 Match/会话**(违反 INV-014/015),而旧路径
> `ActivityInterest.confirmInterest`→`confirmActivityInterest` 建 Match 却**缺会话**;两条路径分裂。已统一到
> `RelationshipService.confirmActivityInterest` 单实现。修复 **7 处缺陷 + 1 处隐藏编译缺陷 + 1 处测试保真度缺陷**:
> - **D1(Critical,Gate 缺陷 · INV-014/015)** 双确认后不建 Match/会话 → 重写为 `confirmConnection` 走
> `confirmActivityInterest`,由原子 `confirmSideIfPending` 保证 exactly-once(`both_confirmed_at` NULL→非NULL 仅一方赢家建 Match+会话并 `bindMatch` 溯源);单方确认不建 Match。
> - **D2(High,双实现分裂)** 旧/新路径各自为政 → 统一到 `RelationshipService.confirmActivityInterest`(返回 `matchId` + `priorUnmatch`)。
> - **D3(High,隐藏编译缺陷 · 必崩级)** Phase 15 提交态引用 `matchMapper.reopenEpisode` 但该方法**从未定义** → 整个
> activity_mutual / relationship 模块**根本不编译**,**"474 绿"基线从未真实存在**。修复:在 `MatchMapper` 补 `@Update reopenEpisode`
> (`WHERE status='unmatched' AND deleted_at IS NULL`)。**这是本轮最严重发现:Phase 15 的提交态从未通过编译。**
> - **D4(High,INV-006 泄露)** `getMyConsentStatus` 本侧未确认即回显对方确认状态 → 改为
> `partnerAccepted = myAccepted && partnerSideAccepted`(本侧未确认则对方确认态不回显)。
> - **D5(Medium,缺会话)** 复用/新建 Match 后未显式开启会话 → `confirmActivityInterest` 现在**显式**调用
> `chatService.getOrCreateConversation` 并返回 `conversationAutoCreated=true`。
> - **D6(Medium,测试库零覆盖)** `schema-h2.sql` 缺 `activity_mutual_connection_consents` 表 → 补表
> (含 `deleted_at`/`expires_at`/`match_id` 与 `chk_consent_status` CHECK、UNIQUE(activity_id,user_a_id,user_b_id)),与 V024+V037+V041 对齐;
> `EntityMigrationParityTest` 将其从 `TEST_SCHEMA_OPTIONAL_TABLES` 移入 `REQUIRED_IN_TEST_SCHEMA`;`MigrationValidationTest` 基线 40 → 41。
> - **D7(Medium,无互选测试)** 新建 `ActivityMutualConsentServiceTest`(7 用例:双确认建 Match+会话+溯源、INV-006 单向不暴露、
> decline 阻止、幂等重确认不重复建、expires_at 超时拒绝、软删过滤、复用 active Match),`@SpringBootTest` 走真实方法路径。
> - **D8(Medium,断言与 #20 冲突)** `ChatPhase09IntegrationTest:344` 假设"每次活动互选新建独立会话",与 AGENTS.md #20
> "同对用户 Unmatch 后重连复用同一 Match 行、会话随之复用"冲突 → 改为 `assertEquals`(认可复用),保留 sendText/WebSocket/未读主断言以验证"复用同一消息管线"。
> - **负向验证**:临时注释 `createMatchAndConversation(consent)` 调用 → `ActivityMutualConsentServiceTest` 中 doubleConfirm + idempotent
> 两条依赖 Match 的用例**精准变红**(`Tests run: 7, Failures: 2`)→ 证明守卫有牙 → 已还原(`grep -c "NEG-VAL"` = 0)。
> - 新增迁移 `V041__extend_mutual_consent_expiry.sql`(`expires_at` + `match_id` + 索引)。
> - 全量回归 **481 tests / 0 failures / 0 errors / 3 skipped / BUILD SUCCESS**(约 5 分)。基线 474 → 481(净 +7)。
> - 报告:`docs/Phase-16-V11-Recovery-Completion-Report-2026-09-17.md`。**Phase 17 需用户确认后启动。**
### Phase 17:举报与风控 — EXTEND ✅ 已完成(2026-09-17 KEEP-VERIFY/EXTEND 复验通过)
**Files:** risk、report、referral 模块和后台风险页面。
- [x] 将 counseling、service_station、offline_activity 作为风险来源接入统一 RiskEvent(运行时已真实调用,本轮确认非假绿)。
- [x] 后台显示必要来源上下文但不暴露无关咨询正文(INV-006 同族最小可见约束延续)。
- [x] 禁止公开黑名单;举报、处置、Block 与敏感访问继续审计(补 D2 人工标记审计、D3 敏感访问审计、D4 审计 ip/ua)。
**Gate:** 风险来源可追踪 ✅、正文最小可见 ✅、低权限人员不能扩大读取范围 ✅。
**复验结论:** 修复 6 处真实缺陷(D1 测试库缺三表必崩级盲区、D2 人工标记无审计、D3 敏感访问无审计、D4 审计缺 ip/ua、D5 findByUserId 未过滤软删、D6 jakarta 编译缺陷+risk_events 漏 updated_at);新增集成测试 7 例;全量回归 488 全绿。
**报告:** `docs/Phase-17-V11-Recovery-Completion-Report-2026-09-17.md`。**Phase 18 需用户确认后启动。**
### Phase 18:申诉 — KEEP-VERIFY ✅ 已完成(2026-09-17 KEEP-VERIFY 复验通过)
**Files:** appeal 模块、Miniapp appeal 页面和后台 AppealCenter。
- [x] 回归 ban/suspend 申诉、幂等处理、审批和解除动作。
- [x] 验证申诉不能绕过仍有效的其他风险处置(负向验证已证守卫有牙)。
- [x] 是否首发继续由已确认 Feature Flag 控制(`features.appeal-enabled`,dev/docker 均 false)。
**Gate:** 申诉通过只解除目标处置 ✅;拒绝后原处置保持有效 ✅。
**复验结论:** 修复 8 处真实缺陷(D1 测试库缺 `appeals` 表 + `AppealServiceTest` 6 处假绿 → 零覆盖;**D2 escalate 向 operator 发用户通知撞 `notifications.user_id→users(id)` FK,PG 上升级 100% 失败**;**D3 appealType 未校验生产 `chk_appeal_type` 白名单**;D4 escalated 死胡同;D5 processAppeal 先读后写并发竞态;D6 三处查询漏软删过滤;D7 硬编码 resolved;D8 证据字段契约 evidenceFileIds);新增 `AppealPhase18IntegrationTest`(15 例),删除假绿 `AppealServiceTest`(9 例);全量回归 494 全绿。
**报告:** `docs/Phase-18-V11-Recovery-Completion-Report-2026-09-17.md`。**Phase 19 需用户确认后启动。**
### 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 文件。
- [x] 先修复 Admin 全量 type-check 和角色路由,再实现“角色第一屏知道今天做什么”的待办型工作台。
- [x] Banner 完成 CRUD、排期、排序、Audience、内部 target 校验和预览;禁止外链。
- [x] Content 完成分类、文章编辑、发布/下架;用户端只做文章列表/详情,不做 Feed、评论和点赞。
- [x] Service Station 完成万善公园站信息、开放时间、公告、服务项目和预约管理。
- [x] 修复预约 IDOR:普通用户创建、详情、列表、取消只能操作本人;代登记使用独立 operator 接口和权限。
- [x] Service Program 完成项目、申请、审批、退出和必要统计,禁止把项目成员身份变成用户价值标签。
- [x] 新增并注册 U49 公益服务中心、U50 服务站、U51 预约、U52 我的预约、U53 课堂、U54 内容详情、U60 反诈、U61 专项服务、U64 公益服务记录。
- [x] 重构 U37“我的”四组结构,接入上述新增页面;U64 只显示用户自己的服务时间线,不显示内部备注。
- [x] 所有页面复用统一 Token 和组件,覆盖 Loading、Skeleton、Empty、Error、Permission、Disabled、Responsive。
**Gate:** 小程序 U01~U64 页面清单无缺页且路由可达 ✅(`ui-tests/ui-contracts.mjs`:`app.json` 63 页);七类后台角色只看到自己的工作 ✅(`admin-role-navigation-contracts` + `V11PermissionMatrixContractTest` 扫全部迁移 + `OperatorEndpointPermissionCoverageTest`);后台 type-check/build 通过 ✅(`vue-tsc --noEmit` EXIT=0、`vite build` EXIT=0)。
**复验结论:** 修复 **25 处真实缺陷**。高价值项:**Service Station 公告能力整条不可达**(Service 与 V042 表都已存在但全仓零端点,后台与小程序都拿不到)→ 补运营端五端点 + 用户端只读端点 + 后台公告 UI + 小程序 U50 公告区块;
**服务站 `create/update` 越权写**(类级 `service_location.view` 兜底,V015 的 `service_location.manage` 是从未被使用的死权限)→ 权限下沉方法级,并把该控制器纳入权限覆盖守卫(此前未纳入,正是缺陷长期隐形的原因);
**Banner 校验失败落 500**(裸 `RuntimeException`)→ 统一 `VALIDATION_ERROR`,并补软删过滤(软删 Banner 曾仍上首页);
**Content「发布」是死路**(后台复用只返回 `published` 的公开接口,草稿永不出现)→ 运营端接口分离;**Service Program 审批死路 / 草稿项目泄露 / 成员数恒 0 / 「退出」未实现 / 重复申请撞唯一键**;
**测试库缺 `content_categories` 与 `service_location_announcements`** → 对应路径零覆盖(约束漂移盲区),已补表并移入必选集合。
新增守卫:`ServiceLocationAnnouncementPhase19IntegrationTest`(24) / `ServiceLocationControllerPermissionContractTest`(5) / `ServiceLocationAnnouncementConstraintParityTest`(5,**生产 DDL ↔ 测试库 ↔ 后端白名单 ↔ 后台标签** 四方一致);`V11PermissionMatrixContractTest` 由硬编码 V015+V029 改为扫描全部迁移,消除「后续迁移权限变更隐形」。
负向验证:注入 3 处缺陷(移除软删过滤 / 移除测试库 CHECK / 写端点降级为 `view`)→ **4 个用例精准变红且无无关失败**,还原后 `NEG-VAL` 残留 0。
全量回归 **602 tests 全绿**(起点 420);admin-web `vue-tsc` EXIT=0 + `vite build` EXIT=0;小程序 `tsc --noEmit` EXIT=0;ui-tests 14/14。
**报告:** `docs/Phase-19-V11-Recovery-Completion-Report-2026-09-17.md`。**Phase 20 需用户确认后启动。**
### 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 外功能。