Files
danyang-match/docs/V1.1_RECOVERY_DEVELOPMENT_PLAN_2026-09-09.md
T

302 lines
18 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 Recovery Implementation Plan
> **已被取代:** 本计划使用 R0~R8 恢复阶段,与客户 V1.1 增量基线不一致。当前唯一修复计划为 [善缘丹阳 V1.1 客户需求基线增量开发与修复计划.md](善缘丹阳%20V1.1%20客户需求基线增量开发与修复计划.md)。本文件仅保留为审计历史,不再作为执行依据。
> **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.1 恢复为满足业务不变量、可构建、可回归、可人工验收的发布候选版本。
**Architecture:** 保持 Java 21 + Spring Boot 模块化单体、PostgreSQL、Redis、私有对象存储、Vue 3 管理后台和微信原生小程序。按“安全底座 → 测试底座 → 业务纵切 → 前端闭环 → UAT → RC”恢复,不引入微服务和新基础设施。
**Tech Stack:** Java 21、Spring Boot 3.x、MyBatis-Plus、Flyway、PostgreSQL、Vue 3、TypeScript、Vite、微信小程序原生、Docker Compose。
**Spec:** `AGENTS.md`、`docs/善缘丹阳 V1.1 页面级功能清单与交互流程修订版.md`、`docs/善缘丹阳 V1.1 数据库与API增量设计.md`、`docs/superpowers/specs/2026-09-13-reference-driven-dual-client-ui-redesign-design.md`、`docs/善缘丹阳 V1.1 Codex-Jira 最终开发任务增量清单.md`。
## Global Constraints
- 用户永久免费,禁止 VIP、会员、金币和用户付费功能。
- Required 条件是 Hard Constraint,任何推荐路径不得自动放宽。
- Mutual Match 后才能聊天;Block 优先级最高。
- 活动互选必须经过双方分别确认后才创建或复用 Match/Conversation。
- Counselor 只能访问 Assigned Service;Content Editor 零用户婚恋数据权限。
- PostgreSQL 是 Source of Truth;前端 Store 和 Redis 不得覆盖数据库事实。
- 首页结构与 8 个核心入口顺序固定;Banner 仅允许内部目标类型。
- 默认简体中文、Asia/Shanghai、日期 `YYYY-MM-DD`、金额人民币元。
- 每个阶段结束必须产生真实测试输出和 Completion Report,并暂停等待审核。
---
## 执行策略
推荐采用“恢复式纵向切片”:先建立不可绕过的权限与测试门禁,再按首页、咨询/预约、活动互选、内容/服务站逐条打通后端—小程序—后台—测试。不要继续按原 Phase 编号批量补文件,也不要先重做视觉稿。
估算以 1 名全栈工程师持续投入为前提,仅用于排序:恢复到可进入正式 UAT 约需 20~30 个工程日;真实内容、第三方认证、微信审核和生产证书不计入。
### Phase R0:冻结错误基线并恢复可追溯性
**Files:**
- Modify: `docs/STATUS.md`
- Modify: `docs/JIRA_BACKLOG.md`
- Create: `docs/RECOVERY_ISSUE_TRACKER.md`
- Verify: `.git/` 或新的正式 Git 工作区
**Produces:** 单一版本号、真实状态矩阵、P0/P1 缺陷清单、可审计提交历史。
- [ ] 确认正式代码仓库位置;若当前目录是拷贝,迁回正式仓库后再修改源码。
- [ ] 对当前目录做不可变备份或建立恢复分支,记录当前 V027 数据库版本。
- [ ] 将 V1.1 状态改为 `RECOVERY`,撤销“100% 完成、可上线”的结论。
- [ ] 把旧 Completion Report 标为“历史记录,需按恢复门禁复验”。
- [ ] 统一 Backend、Admin、Miniapp、`VERSION` 和文档中的版本号为同一个 `1.1.0-recovery`。
- [ ] 建立缺陷编号:安全 P0、功能 P1、体验 P2;每项写清复现步骤、影响不变量、验收测试。
**Exit Gate:** `git status` 可用;版本唯一;状态文档不存在同一模块既完成又未完成的冲突。
### Phase R1:建立不可伪造的质量门禁
**Files:**
- Modify: `.github/workflows/ci.yml`
- Modify: `backend/Dockerfile`
- Modify: `admin-web/package.json`
- Modify: `miniapp/package.json`
- Modify: `miniapp/tsconfig.json`
- Create: `pytest.ini`
- Create: `tests/e2e/conftest.py`
- Replace: `tests/e2e/*_test.py` 中的空壳测试
**Produces:** 一条失败即阻断的 CI;后端、后台、小程序、迁移、E2E 均有真实门禁。
- [ ] 先写一个 CI 自检用例,证明空 `pass`、未知 pytest mark 和缺失 fixture 会使流水线失败。
- [ ] 为 E2E 建立隔离测试数据、用户令牌与操作员令牌 fixture,不再用管理员令牌代替用户。
- [ ] 把 `run_v11_tests.py` 拆成可独立运行、可清理数据、每个结果都有断言的测试。
- [ ] 将 INV-011~020 改为调用真实 Service/Controller/Database 的行为测试,删除“常量存在即不变量成立”的判定方式。
- [ ] 后端镜像构建执行 `mvn verify -B`,移除 `maven.test.skip=true`。
- [ ] Admin CI 顺序固定为 `npm ci`、`npm run type-check`、无修复模式 lint、`npm run build`。
- [ ] Miniapp CI 执行 `npm ci`、`npm run type-check`,并校验页面注册、WXML 事件处理器和目标路径存在。
- [ ] Migration Job 使用临时 PostgreSQL 真正执行 Flyway,不再只检查 SQL 文件非空。
**Exit Gate:** 全新环境可一次运行全部门禁;故意破坏任一不变量时相应测试会失败。
### Phase R2:修复认证、RBAC、DataScope 与敏感数据边界
**Files:**
- Modify: `backend/src/main/java/com/danyang/match/platform/shared/filter/JwtAuthFilter.java`
- Replace: `backend/src/main/java/com/danyang/match/platform/shared/filter/PermissionFilter.java`
- Modify: `backend/src/main/java/com/danyang/match/platform/shared/config/SecurityConfig.java`
- Modify: `backend/src/main/java/com/danyang/match/platform/counseling/controller/CounselingController.java`
- Modify: `backend/src/main/java/com/danyang/match/platform/counseling/service/CounselingServiceApp.java`
- Modify: `backend/src/main/java/com/danyang/match/platform/service_appointment/controller/ServiceAppointmentController.java`
- Modify: `backend/src/main/java/com/danyang/match/platform/service_appointment/service/ServiceAppointmentService.java`
- Test: `backend/src/test/java/com/danyang/match/platform/invariants/PermissionMatrixTest.java`
- Test: `tests/e2e/counseling_permission_test.py`
- Test: `tests/e2e/service_station_permission_test.py`
- Test: `tests/e2e/organization_isolation_test.py`
**Produces:** 用户主体与操作员主体分离;接口级 Permission + DataScope;敏感字段按角色裁剪。
- [ ] 写失败测试:用户令牌调用后台咨询接口返回 403。
- [ ] 写失败测试:服务站人员访问全局用户、咨询队列、全局统计返回 403。
- [ ] 写失败测试:Counselor A 访问 Counselor B 的咨询详情、跟进和状态变更返回 403。
- [ ] 写失败测试:Matchmaker 与普通管理员无法读取咨询正文和 followup 内容。
- [ ] 写失败测试:用户 A 读取用户 B 的预约详情返回 404 或 403,且不泄露记录存在性。
- [ ] 将 operator API 统一迁到 `/api/v1/operator/...`,为每组接口映射明确权限码。
- [ ] 控制器只从已验证 Principal 取主体,不再各自解析 Authorization Header。
- [ ] 只有具备代办权限的操作员可指定 `userId`,普通用户请求体中的 `userId` 被拒绝。
- [ ] 在 Service 层实现 Assigned Counselor、Service Station、Organization DataScope,避免只依赖路由过滤。
- [ ] 对咨询 DTO 做角色视图裁剪;日志仅记录咨询 ID、风险级别和脱敏标识。
**Exit Gate:** INV-011、012、013、018、019、020 行为测试全部通过;无低权限角色能通过直接 API 绕过前端菜单。
### Phase R3:首页聚合与 Capability 单一事实源
**Files:**
- Create: `backend/src/main/java/com/danyang/match/platform/capability/service/CapabilityService.java`
- Modify: `backend/src/main/java/com/danyang/match/platform/home/service/HomeApplicationService.java`
- Modify: `backend/src/main/java/com/danyang/match/platform/home/dto/HomeDTO.java`
- Modify: `backend/src/main/java/com/danyang/match/platform/banner/service/HomeBannerService.java`
- Test: `backend/src/test/java/com/danyang/match/platform/home/HomeApplicationServiceTest.java`
- Test: `tests/e2e/home_v11_test.py`
**Produces:** `GET /api/v1/home` 从真实模块聚合数据,入口顺序固定,所有入口由服务端能力控制。
- [ ] 写失败测试,精确断言 8 个入口 code、顺序、目标页面和 enabled 状态。
- [ ] 写失败测试,Banner 外链目标、过期 Banner、受众不匹配 Banner 均不会返回。
- [ ] 写失败测试,未实名、审核中、暂停寻找、成功牵手五类首页状态分别符合文档。
- [ ] CapabilityService 统一读取账户、实名、资料审核、本地资格、关系状态和 Feature Flag。
- [ ] 用真实身份记录替换 `verified=true`,用推荐服务替换空列表。
- [ ] 从 `service_locations`、`content_articles` 读取服务站和婚恋课堂内容,移除硬编码业务对象。
- [ ] 修正 8 个入口和全部 CTA 到真实、已注册的内部页面。
- [ ] 严格输出固定首页顺序:品牌/状态由前端壳展示,数据区依次为 Banner、8 入口、推荐、公益服务、活动、服务站、婚恋课堂、安全提醒。
**Exit Gate:** 首页 E2E 覆盖 5 种用户状态、Banner 规则、精确入口顺序和所有目标页面;返回数据无阶段占位值。
### Phase R4:活动互选二阶段确认闭环
**Files:**
- Modify: `backend/src/main/java/com/danyang/match/platform/activity_mutual/service/ActivityMutualConsentService.java`
- Modify: `backend/src/main/java/com/danyang/match/platform/activity_mutual/controller/ActivityMutualConsentController.java`
- Modify: `backend/src/main/java/com/danyang/match/platform/relationship/service/RelationshipService.java`
- Modify: `backend/src/main/resources/db/migration/V024__add_activity_mutual_connection_consents.sql` 的约束策略通过新增迁移实现,禁止改写已应用迁移
- Create: `backend/src/main/resources/db/migration/V028__harden_activity_mutual_consents.sql`
- Test: `tests/e2e/activity_mutual_consent_test.py`
- Test: `backend/src/test/java/com/danyang/match/platform/activity_mutual/ActivityMutualConsentServiceTest.java`
**Produces:** Mutual Interest → 双方分别确认 → 原子创建/复用 Match → 创建/复用 Conversation。
- [ ] 写失败测试:单向 Interest 对另一方不可见。
- [ ] 写失败测试:Mutual Interest 和单方 Confirm 都不会创建 Match/Conversation。
- [ ] 写失败测试:双方并发 Confirm 只生成一个结果。
- [ ] 写失败测试:已有 active Match 时复用;曾 Unmatch 时创建新 Match Episode。
- [ ] 在单事务内锁定 consent pair、重读双方状态、处理幂等键、创建或复用 Match/Conversation。
- [ ] 增加规范化 pair 唯一约束和重复请求冲突处理。
- [ ] 返回前端所需的 `bothConfirmed`、`matchId`、`conversationId`、`reusedExistingMatch`。
**Exit Gate:** INV-014、015 及“已有 Match 复用/曾 Unmatch 新建”全部在并发测试中通过。
### Phase R5:小程序改为单一 TypeScript 运行源并补齐页面闭环
**Files:**
- Modify: `project.config.json`
- Modify: `miniapp/project.config.json`
- Modify: `miniapp/tsconfig.json`
- Replace: `miniapp/pages/index/index.ts`
- Remove after verified migration: 与 13 个 TypeScript 页面重复且漂移的手写 `.js`
- Create/complete: `miniapp/pages/service-center/**`
- Create/complete: `miniapp/pages/service-station/**`
- Create/complete: `miniapp/pages/service-appointment/**`
- Create/complete: `miniapp/pages/my-appointments/**`
- Create/complete: `miniapp/pages/classroom/**`
- Create/complete: `miniapp/pages/article-detail/**`
- Create/complete: `miniapp/pages/anti-fraud/**`
- Create/complete: `miniapp/pages/service-program/**`
- Create/complete: `miniapp/pages/service-history/**`
- Modify: `miniapp/app.json`
**Produces:** 一套可编译的 TypeScript 源码;U49~U64 与活动互选页可真实导航和操作。
- [ ] 先建立页面注册、handler 存在、内部目标可达的静态失败测试。
- [ ] 明确 `.ts` 为唯一手写源;生成 `.js` 不纳入人工维护,CI 检测同名双轨漂移。
- [ ] 修复请求 Promise 类型、页面级模块作用域、全局类型和 `uploadBase` 定义。
- [ ] 重建首页,让 WXML、TS 和 `/home` DTO 字段完全一致,并补上婚恋课堂区块。
- [ ] 接通 8 个核心入口与 Banner 内部跳转,不再借用本地资格页承载无关业务。
- [ ] 补齐服务预约、我的预约、内容列表/详情、反诈、专项服务、服务记录页面。
- [ ] 活动互选页覆盖“结果、本人确认、等待对方、双方确认、已有聊天、拒绝/超时”状态。
- [ ] 所有提交、取消、拉黑、退出等重要操作提供进度、结果与二次确认。
**Exit Gate:** `npm run type-check` 无错误;微信开发者工具编译无错误;首页固定顺序和 U49~U64 核心流程完成真机/模拟器截图验收。
### Phase R6:管理后台按角色形成可运营工作台
**Files:**
- Modify: `admin-web/src/router/index.ts`
- Modify: `admin-web/src/layouts/MainLayout.vue`
- Replace: `admin-web/src/modules/counseling/CounselingView.vue`
- Complete: `admin-web/src/modules/banner/BannerManagementView.vue`
- Complete: `admin-web/src/modules/content/ContentManagementView.vue`
- Complete: `admin-web/src/modules/service-station/ServiceStationView.vue`
- Complete: `admin-web/src/modules/service-appointment/ServiceAppointmentView.vue`
- Complete: `admin-web/src/modules/service-program/ServiceProgramView.vue`
- Create: `admin-web/src/modules/counseling/CounselingDetailView.vue`
- Test: `admin-web/src/**/*.spec.ts`
**Produces:** Platform Admin、Counseling Manager、Counselor、Content Editor、Service Station Operator 各自只看到可执行任务。
- [ ] 先写路由与权限测试,证明菜单可见性、直接 URL 访问和 API 403 三层一致。
- [ ] 注册 `/counseling` 路由,修复语法和接口路径,拆分队列、我的咨询、详情/跟进职责。
- [ ] 将长侧栏按“用户与审核、婚恋服务、公益服务、内容运营、系统治理”分组。
- [ ] 工作台优先展示待办、超时、风险和今日服务,不以全零累计数字作为主视觉。
- [ ] Banner 编辑器校验内部目标类型、排期、受众和预览。
- [ ] 服务站人员只能处理本站预约;Content Editor 页面完全不请求用户婚恋数据。
- [ ] 为列表补齐加载、空状态、错误恢复、分页、筛选和操作结果反馈。
**Exit Gate:** type-check、lint、unit test、build 全通过;五种角色逐一完成登录—待办—详情—处理—审计留痕流程。
### Phase R7:业务纵切回归与隐私安全复验
**Files:**
- Modify: `tests/invariant_integration_test.py`
- Modify: `tests/uat/UAT-Test-Cases.md`
- Modify: `tests/README.md`
- Create: `docs/security/V1.1_SECURITY_RETEST.md`
- Create: `docs/Phase-R7-Completion-Report.md`
**Produces:** V1.0 核心不变量 + V1.1 新增不变量的完整回归证据。
- [ ] 回归 Auth、Profile、Review、Required、Match、Mutual、Block、Chat、RBAC。
- [ ] 执行 INV-001~020 的 API + DB 双层断言。
- [ ] 对本地资格佐证、咨询附件、聊天图片执行对象存储私有访问和过期 URL 测试。
- [ ] 执行 IDOR、水平越权、垂直越权、组织隔离、日志脱敏测试。
- [ ] 对注销流程验证预约取消、咨询生命周期、专项项目退出和本地资格失效。
- [ ] 生成覆盖实际命令、版本、通过数、失败数和已知限制的完成报告。
**Exit Gate:** 无 P0/P1 缺陷;20 条不变量全部有失败前例和通过证据;安全复验无发布阻断项。
### Phase R8:正式 UAT、内容验收与发布候选
**Files:**
- Modify: `docs/Go-NoGo-Checklist.md`
- Modify: `docs/STATUS.md`
- Modify: `docs/PENDING_DECISIONS.md`
- Create: `docs/Phase-R8-UAT-Completion-Report.md`
- Create: `releases/v1.1.0-RC.1/RELEASE_NOTES.md`
- Create: `releases/v1.1.0-RC.1/FILE_MANIFEST.md`
**Produces:** 有真实运营人员和测试用户签字的 RC,而不是 API 可返回 200 的演示版本。
- [ ] 使用独立 UAT 数据库和对象存储,禁止复用开发脏数据。
- [ ] 完成服务站扫码→预约→到场、咨询申请→完成、婚前辅导、活动互选→双方确认→聊天四条端到端场景。
- [ ] 按角色确认无需 Excel、个人微信和纸质临时台账即可留痕。
- [ ] 完成真实 Banner、服务站信息、咨询介绍、婚前辅导、反诈、课堂、关于与主办信息审核。
- [ ] 执行移动端、常见 Windows 浏览器、弱网、空数据、错误恢复和无障碍抽查。
- [ ] 生产 Smoke 覆盖首页、入口、服务站、咨询、内容、活动互选、Block 与权限矩阵。
- [ ] 只有 Go/No-Go 清单全部通过后,才将状态改为 `1.1.0-RC.1`。
**Exit Gate:** UAT 签字、真实内容审核、安全复验、备份恢复演练和生产 Smoke 全部有证据。
## 每阶段统一验收命令
```powershell
# Backend(本机需 JDK 21 + Maven)
Set-Location backend
mvn verify -B
# Admin Web
Set-Location ..\admin-web
npm ci
npm run type-check
npm run build
# Miniapp
Set-Location ..\miniapp
npm ci
npm run type-check
# E2E
Set-Location ..
python -m pytest -q tests/e2e
```
```bash
# Backend
cd backend && mvn verify -B
# Admin Web
cd ../admin-web && npm ci && npm run type-check && npm run build
# Miniapp
cd ../miniapp && npm ci && npm run type-check
# E2E
cd .. && python3 -m pytest -q tests/e2e
```
## 计划自检
- Spec coverage:覆盖首页、8 入口、本地资格、咨询、婚前辅导、多类型活动互选、服务站/预约、内容、专项服务、Analytics、账户生命周期、权限与发布。
- Placeholder scan:计划没有以空任务代替实现;每阶段均有明确文件、失败测试、实现动作和 Exit Gate。
- Type consistency:统一以服务端 Principal、Permission + DataScope、`CapabilityService` 和 `/api/v1/operator/**` 作为跨模块接口约束。
- Scope control:不引入微服务、Kubernetes、Kafka、新 CMS Server 或新咨询 Server。
## 执行顺序
严格执行 R0 → R1 → R2 → R3 → R4 → R5 → R6 → R7 → R8。R2 未通过前不得处理视觉美化;R7 未通过前不得进入正式 UAT;R8 未通过前不得恢复“可上线”表述。