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

302 lines
18 KiB
Markdown
Raw Normal View History

2026-09-09 22:05:00 +08:00
# 善缘丹阳 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/善缘丹阳 V1.1 前端 UI-UX 高保真原型修订说明.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 未通过前不得恢复“可上线”表述。