## Context EmailBill 项目在早期开发了 V1 版本的日历、统计、预算三大核心功能模块。随着业务迭代,V2 版本已经重构并稳定运行,提供了更优的用户体验和代码架构。当前代码库中同时维护 V1 和 V2 两套实现,导致: 1. **代码冗余**: 前端包含 `CalendarView.vue`, `BudgetView.vue`, `statisticsV1/Index.vue` 等页面,后端包含多个仅服务于 V1 的 API 端点 2. **维护成本**: 任何共享组件或数据模型的变更需要同时考虑 V1 和 V2 的兼容性 3. **认知负担**: 新开发者需要理解两套架构,增加了上手难度 4. **测试负担**: 需要维护两套测试用例,且部分测试已失效 ### 当前状态 - V2 版本已完成功能对齐,用户已逐步迁移 - V1 相关 API 端点部分已标记 `[Obsolete]` (如 `TransactionRecordController.GetDailyStatisticsAsync`) - 路由守卫中包含 V1/V2 版本切换逻辑 ### 约束条件 - **不能影响 V2 功能**: 必须保证 V2 页面完全正常运行 - **共享组件不能删除**: `TransactionList`, `TransactionDetail`, `PopupContainer` 等组件被 V2 使用 - **Repository 层不能动**: V1 和 V2 共用相同的数据访问层 - **需要手动测试**: 删除后必须打开 V2 页面验证功能完整性 ### 利益相关者 - **开发团队**: 减少维护负担,简化架构 - **测试团队**: 减少测试用例数量 - **最终用户**: 无感知(已迁移到 V2) --- ## Goals / Non-Goals ### Goals 1. **完全移除 V1 代码**: 删除所有 V1 专用的页面、API、Service 方法 2. **保持 V2 功能完整**: 确保删除操作不影响 V2 版本的任何功能 3. **清理路由配置**: 移除 V1 路由和版本切换逻辑 4. **验证功能正常**: 通过手动测试验证 V2 页面能正常打开和使用 ### Non-Goals 1. **不修改 Repository 层**: V2 继续使用现有的 Repository,不进行任何修改 2. **不修改数据库**: 不涉及数据迁移或表结构变更 3. **不重构 V2 代码**: 仅删除 V1 代码,不对 V2 进行任何优化或重构 4. **不移除共享组件**: 即使组件原本为 V1 开发,只要 V2 在用就保留 5. **不更新文档**: API 文档和用户文档的更新不在本次变更范围内 --- ## Decisions ### Decision 1: 采用自底向上的删除顺序 (Backend → Frontend) **选择**: 先删除后端 Service/Application → 再删除 Controller → 最后删除前端页面和路由 **理由**: - **依赖方向**: 前端依赖后端 API,先删除底层可以避免悬挂引用 - **验证便利**: 删除后端接口后,前端调用会立即报 404,易于发现遗漏 - **回滚简单**: 如果出问题,可以快速恢复后端接口,前端暂时保留也不影响 **备选方案 (未选择)**: - **自顶向下 (Frontend → Backend)**: 先删除前端页面,可能导致后端接口成为"僵尸代码"难以发现 - **同步删除**: 一次性删除所有层,风险较高且难以定位问题 --- ### Decision 2: 通过代码搜索确认 V1 专用性 **选择**: 对每个待删除的方法/接口进行全局搜索,确认仅被 V1 页面调用 **搜索关键字**: - 前端页面: `CalendarView.vue`, `BudgetView.vue`, `statisticsV1/Index.vue` - API 方法: `GetDailyStatistics`, `GetUncoveredCategories`, `GetArchiveSummary`, `GetBalanceStatistics` - 路由: `/calendar`, `/budget`, `name: 'statistics'` **验证标准**: - 如果搜索结果仅出现在以上三个页面中 → 可以安全删除 - 如果出现在其他文件中 → 标记为"需保留"或"需进一步分析" **理由**: - **准确性**: 避免误删 V2 依赖的代码 - **可追溯**: 搜索结果可作为删除依据留存 --- ### Decision 3: 保留共享组件,即使其仅在 V1 中被直接使用 **选择**: 保留 `TransactionList`, `TransactionDetail`, `PopupContainer`, `SmartClassifyButton` 等组件 **判断依据**: - 通过搜索确认这些组件在 V2 页面中有引用 - 即使组件内部包含 V1 特定逻辑(如全局事件监听),也不在本次变更中修改 **理由**: - **最小化风险**: 删除共享组件可能导致 V2 功能异常 - **职责分离**: 组件优化应作为独立的重构任务,不在本次删除范围内 --- ### Decision 4: 移除全局事件监听 (条件性) **选择**: 如果全局事件 (`transaction-deleted`, `transactions-changed`) **仅在 V1 页面中监听**,则移除事件触发代码 **验证流程**: 1. 搜索 `window.addEventListener('transaction-deleted')` 2. 确认监听器仅在 `CalendarView.vue` 和 `statisticsV1/Index.vue` 中注册 3. 搜索 `window.dispatchEvent(new Event('transaction-deleted'))` 4. 如果触发位置在共享组件中(如 `TransactionDetail.vue`),检查该组件是否被 V2 使用 - 如果被 V2 使用 → 保留事件触发代码(即使 V1 删除后无人监听) - 如果仅 V1 使用 → 删除事件触发代码 **理由**: - **保守策略**: 优先保证 V2 功能不受影响 - **技术债务**: 遗留的无用事件触发代码可作为后续清理任务 --- ### Decision 5: 采用手动测试验证 V2 功能 **选择**: 删除完成后,手动打开以下 V2 页面并验证核心功能 **测试清单**: 1. **统计 V2** (`/statistics-v2`): - 月度统计数据正常加载 - 分类统计饼图正常渲染 - 日度统计折线图正常渲染 - 交易列表正常展示和滚动加载 2. **预算 V2** (`/budget-v2`): - 预算列表正常加载 - 分类统计(月度+年度)正常显示 - 预算创建/编辑/删除功能正常 - 存款预算导航和显示正常 3. **日历 V2** (`/calendar-v2`): - 日历视图正常渲染 - 日期选择和统计数据加载正常 - 交易详情查看和编辑正常 **理由**: - **V2 无单元测试覆盖**: 当前项目主要测试集中在后端,前端缺少自动化测试 - **快速反馈**: 手动测试可以在 10 分钟内完成所有关键路径验证 - **用户体验保证**: 确保最终用户不会遇到功能异常 **备选方案 (未选择)**: - **仅依赖编译检查**: 无法发现运行时错误(如路由配置错误) - **编写自动化测试**: 时间成本过高,且本次变更不涉及逻辑修改 --- ## Risks / Trade-offs ### Risk 1: 误删 V2 依赖的代码 **表现**: 删除后端接口或前端方法,导致 V2 页面调用失败 **缓解措施**: - 采用 Decision 2 的搜索验证流程,确保每个删除操作都经过确认 - 先删除后端 Service 层,观察前端是否有新的 404 错误 - 使用 Git 进行版本控制,支持快速回滚 **残留影响**: - 如果 V2 通过动态路由或字符串拼接调用接口,静态搜索可能遗漏 --- ### Risk 2: 共享组件包含 V1 特定逻辑但未被清理 **表现**: 保留的组件中包含 V1 特定的条件判断或事件监听,成为"死代码" **缓解措施**: - 标记为 Non-Goal,不在本次清理范围内 - 在任务清单中添加"后续优化"任务,记录需要清理的组件列表 **残留影响**: - 代码库中保留少量无用代码,但不影响功能正确性 --- ### Risk 3: 路由守卫中遗留 V1 相关逻辑 **表现**: 删除 V1 路由后,`router/index.js` 或 `useVersionStore` 中仍有版本切换逻辑 **缓解措施**: - 在任务清单中明确包含"清理路由守卫"任务 - 搜索 `isV2()`, `useVersionStore`, `router.push` 等关键字,逐一检查 **残留影响**: - 可能导致用户访问不存在的路由时出现 404 错误 --- ### Risk 4: V2 页面功能异常但手动测试未覆盖 **表现**: 删除操作影响了 V2 的边缘功能(如智能分类、批量操作),但未在测试清单中 **缓解措施**: - 优先测试 V2 的核心流程(查看、创建、编辑、删除) - 如果发现问题,立即回滚对应的删除操作 - 记录测试结果,作为归档的一部分 **残留影响**: - 边缘功能可能在生产环境中被用户发现,需要后续修复 --- ### Trade-off 1: 保留共享组件 vs 彻底清理 **权衡**: 为了保证 V2 功能稳定,选择保留所有共享组件,即使部分组件包含 V1 特定逻辑 **代价**: - 代码库中保留部分冗余代码 - 后续维护时可能需要额外的上下文理解 **收益**: - 大幅降低误删风险 - 缩短变更周期,快速上线 --- ### Trade-off 2: 自动化测试 vs 手动测试 **权衡**: 采用手动测试而非编写自动化测试用例 **代价**: - 无法在 CI/CD 中自动验证 V2 功能 - 未来的变更可能再次破坏 V2 功能 **收益**: - 节省测试编写时间(预计 2-3 小时) - 适用于一次性删除任务,性价比高 --- ## Migration Plan ### 阶段 1: 准备工作 (Pre-deletion) 1. 创建 feature 分支 `feature/remove-v1-modules` 2. 运行所有现有测试,确认当前状态正常 3. 备份 V1 相关文件列表(用于回滚) ### 阶段 2: 后端删除 (Backend Removal) 1. **Service 层删除**: - 删除 `BudgetService.GetUncoveredCategoriesAsync` - 删除 `BudgetService.GetArchiveSummaryAsync` - 删除 `TransactionStatisticsService.GetBalanceStatisticsAsync` - 编译验证,确认无编译错误 2. **Application 层删除**: - 删除 `BudgetApplication.GetUncoveredCategoriesAsync` - 删除 `BudgetApplication.GetArchiveSummaryAsync` - 删除 `TransactionStatisticsApplication.GetBalanceStatisticsAsync` - 编译验证 3. **Controller 层删除**: - 删除 `TransactionRecordController.GetDailyStatisticsAsync` - 删除 `BudgetController.GetUncoveredCategoriesAsync` - 删除 `BudgetController.GetArchiveSummaryAsync` - 删除 `TransactionStatisticsController.GetBalanceStatisticsAsync` - 编译验证 4. **运行后端测试**: ```bash dotnet test WebApi.Test/WebApi.Test.csproj ``` - 移除失败的 V1 相关测试用例 - 确保其他测试通过 ### 阶段 3: 前端删除 (Frontend Removal) 1. **API 客户端清理**: - 清理 `Web/src/api/transactionRecord.js` 中的 `GetDailyStatistics` 调用 - 清理 `Web/src/api/budget.js` 中的 `GetUncoveredCategories`, `GetArchiveSummary` - 清理 `Web/src/api/statistics.js` 中的 `GetBalanceStatistics` 2. **页面文件删除**: - 删除 `Web/src/views/CalendarView.vue` - 删除 `Web/src/views/BudgetView.vue` - 删除 `Web/src/views/statisticsV1/Index.vue` - 删除 `Web/src/views/statisticsV1/` 目录 3. **路由配置清理**: - 删除 `Web/src/router/index.js` 中的 V1 路由定义: - `/calendar` - `/budget` - `/` (statisticsV1) - 简化 `useVersionStore` 中的版本切换逻辑 - 移除路由守卫中的 V1 相关判断 4. **编译验证**: ```bash cd Web && pnpm build ``` ### 阶段 4: 手动测试验证 (Manual Testing) 按照 Decision 5 的测试清单,逐项验证 V2 功能: 1. 启动开发服务器: `pnpm dev` 2. 打开浏览器,访问 V2 页面 3. 验证核心功能(数据加载、交互、导航) 4. 记录测试结果 ### 阶段 5: 代码审查和合并 (Code Review & Merge) 1. 提交变更到远程分支 2. 创建 Pull Request 3. 代码审查关注点: - 确认删除的代码不在 V2 中被引用 - 检查是否有遗漏的 V1 特定逻辑 4. 合并到主分支 ### 回滚策略 如果发现 V2 功能异常: 1. **立即回滚**: `git revert ` 2. **定位问题**: 使用 `git diff` 找到引起问题的删除操作 3. **部分恢复**: 仅恢复必要的文件或方法 4. **重新测试**: 确认恢复后 V2 功能正常 --- ## Open Questions ### Q1: 是否需要保留 `[Obsolete]` 标记的接口一段时间? **当前决策**: 直接删除,因为 V2 已稳定运行 **待确认**: 是否有外部系统或移动端 APP 仍在调用这些接口?如果有,需要先通知相关方并提供迁移时间 --- ### Q2: 全局事件监听 (`transaction-deleted`) 在 V2 中是否还需要? **当前决策**: 保留事件触发代码,即使 V1 删除后无人监听 **待确认**: V2 是否使用其他机制(如 Pinia store)来实现组件间通信?如果是,可以在后续任务中移除全局事件 --- ### Q3: 是否需要更新 API 文档 (Swagger/Scalar)? **当前决策**: 标记为 Non-Goal,不在本次范围内 **待确认**: API 文档是否自动生成?如果是手动维护,需要添加任务来移除已删除接口的文档 --- ### Q4: V2 页面是否有完整的功能对齐? **当前假设**: V2 已完全替代 V1 功能 **待确认**: 是否有用户或内部团队仍在使用 V1 特有的功能(如 `GetUncoveredCategories`)?如果有,需要先在 V2 中实现对应功能 --- **设计文档完成**。本文档为实施团队提供了清晰的技术决策依据和操作步骤,确保删除操作安全可控。