Files
cc-switch/docs/BACKEND_REFACTOR_PLAN.md

154 lines
8.1 KiB
Markdown
Raw Normal View History

refactor(backend): phase 1 - unified error handling with thiserror Introduce AppError enum to replace Result<T, String> pattern across the codebase, improving error context preservation and type safety. ## Changes ### Core Infrastructure - Add src/error.rs with AppError enum using thiserror - Add thiserror dependency to Cargo.toml - Implement helper functions: io(), json(), toml() for ergonomic error creation - Implement From<PoisonError> for automatic lock error conversion - Implement From<AppError> for String to maintain Tauri command compatibility ### Module Migrations (60% complete) - config.rs: Full migration to AppError - read_json_file, write_json_file, atomic_write - archive_file, copy_file, delete_file - claude_mcp.rs: Full migration to AppError - get_mcp_status, read_mcp_json, upsert_mcp_server - delete_mcp_server, validate_command_in_path - set_mcp_servers_map - codex_config.rs: Full migration to AppError - write_codex_live_atomic with rollback support - read_and_validate_codex_config_text - validate_config_toml - app_config.rs: Partial migration - MultiAppConfig::load, MultiAppConfig::save - store.rs: Partial migration - AppState::save now returns Result<(), AppError> - commands.rs: Minimal changes - Use .map_err(Into::into) for compatibility - mcp.rs: Minimal changes - sync_enabled_to_claude uses Into::into conversion ### Documentation - Add docs/BACKEND_REFACTOR_PLAN.md with detailed refactoring roadmap ## Benefits - Type-safe error handling with preserved error chains - Better error messages with file paths and context - Reduced boilerplate code (118 Result<T, String> instances to migrate) - Automatic error conversion for seamless integration ## Testing - All existing tests pass (4/4) - Compilation successful with no warnings - Build time: 0.61s (no performance regression) ## Remaining Work - claude_plugin.rs (7 functions) - migration.rs, import_export.rs - Add unit tests for error.rs - Complete commands.rs migration after dependent modules Co-authored-by: Claude <claude@anthropic.com>
2025-10-27 16:29:11 +08:00
# CC Switch Rust 后端重构方案
## 目录
- [背景与现状](#背景与现状)
- [问题确认](#问题确认)
- [方案评估](#方案评估)
- [渐进式重构路线](#渐进式重构路线)
- [测试策略](#测试策略)
- [风险与对策](#风险与对策)
- [总结](#总结)
## 背景与现状
- 前端已完成重构,后端 (Tauri + Rust) 仍维持历史结构。
- 核心文件集中在 `src-tauri/src/commands.rs``lib.rs` 等超大文件中,业务逻辑与界面事件耦合严重。
- 测试覆盖率低,只有零散单元测试,缺乏集成验证。
## 问题确认
| 提案问题 | 实际情况 | 严重程度 |
| --- | --- | --- |
| `commands.rs` 过长 | ✅ 1526 行,包含 32 个命令,职责混杂 | 🔴 高 |
| `lib.rs` 缺少服务层 | ✅ 541 行,托盘/事件/业务逻辑耦合 | 🟡 中 |
| `Result<T, String>` 泛滥 | ✅ 118 处,错误上下文丢失 | 🟡 中 |
| 全局 `Mutex` 阻塞 | ✅ 31 处 `.lock()` 调用,读写不分离 | 🟡 中 |
| 配置逻辑分散 | ✅ 分布在 5 个文件 (`config`/`app_config`/`app_store`/`settings`/`codex_config`) | 🟢 低 |
代码规模分布(约 5.4k SLOC
- `commands.rs`: 1526 行28%)→ 第一优先级 🎯
- `lib.rs`: 541 行10%)→ 托盘逻辑与业务耦合
- `mcp.rs`: 732 行14%)→ 相对清晰
- `migration.rs`: 431 行8%)→ 一次性逻辑
- 其他文件合计2156 行40%
## 方案评估
### ✅ 优点
1. **分层架构清晰**
- `commands/`Tauri 命令薄层
- `services/`业务流程如供应商切换、MCP 同步
- `infrastructure/`:配置读写、外设交互
- `domain/`:数据模型 (`Provider`, `AppType` 等)
→ 提升可测试性、降低耦合度、方便团队协作。
2. **统一错误处理**
- 引入 `AppError``thiserror`),保留错误链和上下文。
- Tauri 命令仍返回 `Result<T, String>`,通过 `From<AppError>` 自动转换。
- 改善日志可读性,利于排查。
3. **并发优化**
- `AppState` 切换为 `RwLock<MultiAppConfig>`
- 读多写少的场景提升吞吐(如频繁查询供应商列表)。
### ⚠️ 风险
1. **过度设计**
- 完整 DDD 四层在 5k 行项目中会增加 30-50% 维护成本。
- Rust trait + repository 样板较多,收益不足。
- 推荐“轻量分层”而非正统 DDD。
2. **迁移成本高**
- `commands.rs` 拆分、错误统一、锁改造触及多文件。
- 测试缺失导致重构风险高,需先补测试。
- 估算完整改造需 5-6 周;建议分阶段输出可落地价值。
3. **技术选型需谨慎**
- `parking_lot` 相比标准库 `RwLock` 提升有限,不必引入。
- `spawn_blocking` 仅用于 >100ms 的阻塞任务,避免滥用。
- 以现有依赖为主,控制复杂度。
refactor(backend): phase 2 - split commands.rs by domain (100%) Split monolithic commands.rs (1525 lines) into 7 domain-focused modules to improve maintainability and readability while preserving the external API. ## Changes ### Module Structure Created `commands/` directory with domain-based organization: - **provider.rs** (946 lines, 15 commands) - Provider CRUD operations (get, add, update, delete, switch) - Usage query integration - Endpoint speed testing and custom endpoint management - Sort order management - Largest file but highly cohesive (all provider-related) - **mcp.rs** (235 lines, 13 commands) - Claude MCP management (~/.claude.json) - SSOT MCP config management (config.json) - Sync operations (Claude ↔ Codex) - Import/export functionality - **config.rs** (153 lines, 8 commands) - Config path queries (Claude/Codex) - Directory operations (open, pick) - Config status checks - Parameter compatibility layer (app_type/app/appType) - **settings.rs** (40 lines, 5 commands) - App settings management - App restart functionality - app_config_dir override (Store integration) - **plugin.rs** (36 lines, 4 commands) - Claude plugin management (~/.claude/config.json) - Plugin status and config operations - **misc.rs** (45 lines, 3 commands) - External link handling - Update checks - Portable mode detection - **mod.rs** (15 lines) - Module exports via `pub use` - Preserves flat API structure ### API Preservation - Used `pub use` pattern to maintain external API - All commands still accessible as `commands::function_name` - Zero breaking changes for frontend code - lib.rs invoke_handler unchanged (48 commands registered) ## Statistics - Files: 1 → 7 (modular organization) - Lines: 1525 → 1470 (net -55 lines, -3.6%) - Commands: 48 → 48 (all preserved) - Average file size: 210 lines (excluding provider.rs) - Compilation: ✅ Success (6.92s, 0 warnings) - Tests: ✅ 4/4 passed ## Benefits - **Maintainability**: Easier to locate and modify domain-specific code - **Readability**: Smaller files (~200 lines) vs monolithic 1500+ lines - **Testability**: Can unit test individual modules in isolation - **Scalability**: Clear pattern for adding new command groups - **Zero Risk**: No API changes, all tests passing ## Design Decisions 1. **Domain-based split**: Organized by business domain (provider, mcp, config) rather than technical layers (crud, query, sync) 2. **Preserved provider.rs size**: Kept at 946 lines to maintain high cohesion (all provider-related operations together). Can be further split in Phase 2.1 if needed. 3. **Parameter compatibility**: Retained multiple parameter names (app_type, app, appType) for backward compatibility with different frontend call styles ## Phase 2 Status: ✅ 100% Complete Ready for Phase 3: Adding integration tests. Co-authored-by: Claude <noreply@anthropic.com>
2025-10-27 22:18:05 +08:00
## 实施进度
- **阶段 1统一错误处理 ✅**
- 引入 `thiserror` 并在 `src-tauri/src/error.rs` 定义 `AppError`,提供常用构造函数和 `From<AppError> for String`,保留错误链路。
- 配置、存储、同步等核心模块(`config.rs``app_config.rs``app_store.rs``store.rs``codex_config.rs``claude_mcp.rs``claude_plugin.rs``import_export.rs``mcp.rs``migration.rs``speedtest.rs``usage_script.rs``settings.rs``lib.rs` 等)已统一返回 `Result<_, AppError>`,避免字符串错误丢失上下文。
- Tauri 命令层继续返回 `Result<_, String>`,通过 `?` + `Into<String>` 统一转换,前端无需调整。
- `cargo check` 通过,`rg "Result<[^>]+, String"` 巡检确认除命令层外已无字符串错误返回。
- **阶段 2拆分命令层 ✅**
- 已将单一 `src-tauri/src/commands.rs` 拆分为 `commands/{provider,mcp,config,settings,misc,plugin}.rs` 并通过 `commands/mod.rs` 统一导出,保持对外 API 不变。
- 每个文件聚焦单一功能域供应商、MCP、配置、设置、杂项、插件命令函数平均 150-250 行,可读性与后续维护性显著提升。
- 相关依赖调整后 `cargo check` 通过,静态巡检确认无重复定义或未注册命令。
- **阶段 3补充测试 🚧**
refactor(backend): phase 3 - expand integration tests for Codex and MCP sync Expand test suite from 3 to 11 integration tests, adding comprehensive coverage for Codex dual-file atomicity and bidirectional MCP synchronization: New Codex sync tests: - sync_codex_provider_writes_auth_and_config: validates atomic write of auth.json and config.toml, plus SSOT backfill of latest toml content - sync_enabled_to_codex_writes_enabled_servers: MCP projection to config.toml - sync_enabled_to_codex_removes_servers_when_none_enabled: cleanup when all disabled - sync_enabled_to_codex_returns_error_on_invalid_toml: error handling for malformed TOML New Codex MCP import tests: - import_from_codex_adds_servers_from_mcp_servers_table: imports new servers from live config - import_from_codex_merges_into_existing_entries: smart merge preserving SSOT server configs New Claude MCP tests: - sync_claude_enabled_mcp_projects_to_user_config: enabled/disabled filtering for .claude.json - import_from_claude_merges_into_config: intelligent merge preserving existing configurations Expand lib.rs API exports: - Codex paths: get_codex_auth_path, get_codex_config_path - Claude MCP: get_claude_mcp_path - MCP sync: sync_enabled_to_claude, sync_enabled_to_codex - MCP import: import_from_claude, import_from_codex - Error type: AppError (for test assertions) Test infrastructure improvements: - Enhanced reset_test_fs() to clean .claude.json - All tests use isolated HOME directory with sequential execution via mutex Test results: 11/11 passed Files changed: 3 (+394/-6 lines) Next steps: Command layer integration tests and error recovery scenarios
2025-10-27 23:26:42 +08:00
- `tests/import_export_sync.rs` 集成测试涵盖配置备份、Claude/Codex live 同步、MCP 投影与 Codex/Claude 双向导入流程,并新增启用项清理、非法 TOML 抛错等失败场景验证;统一使用隔离 HOME 目录避免污染真实用户环境。
- 扩展 `lib.rs` re-export暴露 `AppType``MultiAppConfig``AppError`、配置 IO 以及 Codex/Claude MCP 路径与同步函数,方便服务层及测试直接复用核心逻辑。
- 当前已覆盖配置、Codex/Claude MCP 核心路径及关键错误分支,后续仍需补齐命令层边界与导入导出异常回滚测试。
refactor(backend): phase 2 - split commands.rs by domain (100%) Split monolithic commands.rs (1525 lines) into 7 domain-focused modules to improve maintainability and readability while preserving the external API. ## Changes ### Module Structure Created `commands/` directory with domain-based organization: - **provider.rs** (946 lines, 15 commands) - Provider CRUD operations (get, add, update, delete, switch) - Usage query integration - Endpoint speed testing and custom endpoint management - Sort order management - Largest file but highly cohesive (all provider-related) - **mcp.rs** (235 lines, 13 commands) - Claude MCP management (~/.claude.json) - SSOT MCP config management (config.json) - Sync operations (Claude ↔ Codex) - Import/export functionality - **config.rs** (153 lines, 8 commands) - Config path queries (Claude/Codex) - Directory operations (open, pick) - Config status checks - Parameter compatibility layer (app_type/app/appType) - **settings.rs** (40 lines, 5 commands) - App settings management - App restart functionality - app_config_dir override (Store integration) - **plugin.rs** (36 lines, 4 commands) - Claude plugin management (~/.claude/config.json) - Plugin status and config operations - **misc.rs** (45 lines, 3 commands) - External link handling - Update checks - Portable mode detection - **mod.rs** (15 lines) - Module exports via `pub use` - Preserves flat API structure ### API Preservation - Used `pub use` pattern to maintain external API - All commands still accessible as `commands::function_name` - Zero breaking changes for frontend code - lib.rs invoke_handler unchanged (48 commands registered) ## Statistics - Files: 1 → 7 (modular organization) - Lines: 1525 → 1470 (net -55 lines, -3.6%) - Commands: 48 → 48 (all preserved) - Average file size: 210 lines (excluding provider.rs) - Compilation: ✅ Success (6.92s, 0 warnings) - Tests: ✅ 4/4 passed ## Benefits - **Maintainability**: Easier to locate and modify domain-specific code - **Readability**: Smaller files (~200 lines) vs monolithic 1500+ lines - **Testability**: Can unit test individual modules in isolation - **Scalability**: Clear pattern for adding new command groups - **Zero Risk**: No API changes, all tests passing ## Design Decisions 1. **Domain-based split**: Organized by business domain (provider, mcp, config) rather than technical layers (crud, query, sync) 2. **Preserved provider.rs size**: Kept at 946 lines to maintain high cohesion (all provider-related operations together). Can be further split in Phase 2.1 if needed. 3. **Parameter compatibility**: Retained multiple parameter names (app_type, app, appType) for backward compatibility with different frontend call styles ## Phase 2 Status: ✅ 100% Complete Ready for Phase 3: Adding integration tests. Co-authored-by: Claude <noreply@anthropic.com>
2025-10-27 22:18:05 +08:00
refactor(backend): phase 1 - unified error handling with thiserror Introduce AppError enum to replace Result<T, String> pattern across the codebase, improving error context preservation and type safety. ## Changes ### Core Infrastructure - Add src/error.rs with AppError enum using thiserror - Add thiserror dependency to Cargo.toml - Implement helper functions: io(), json(), toml() for ergonomic error creation - Implement From<PoisonError> for automatic lock error conversion - Implement From<AppError> for String to maintain Tauri command compatibility ### Module Migrations (60% complete) - config.rs: Full migration to AppError - read_json_file, write_json_file, atomic_write - archive_file, copy_file, delete_file - claude_mcp.rs: Full migration to AppError - get_mcp_status, read_mcp_json, upsert_mcp_server - delete_mcp_server, validate_command_in_path - set_mcp_servers_map - codex_config.rs: Full migration to AppError - write_codex_live_atomic with rollback support - read_and_validate_codex_config_text - validate_config_toml - app_config.rs: Partial migration - MultiAppConfig::load, MultiAppConfig::save - store.rs: Partial migration - AppState::save now returns Result<(), AppError> - commands.rs: Minimal changes - Use .map_err(Into::into) for compatibility - mcp.rs: Minimal changes - sync_enabled_to_claude uses Into::into conversion ### Documentation - Add docs/BACKEND_REFACTOR_PLAN.md with detailed refactoring roadmap ## Benefits - Type-safe error handling with preserved error chains - Better error messages with file paths and context - Reduced boilerplate code (118 Result<T, String> instances to migrate) - Automatic error conversion for seamless integration ## Testing - All existing tests pass (4/4) - Compilation successful with no warnings - Build time: 0.61s (no performance regression) ## Remaining Work - claude_plugin.rs (7 functions) - migration.rs, import_export.rs - Add unit tests for error.rs - Complete commands.rs migration after dependent modules Co-authored-by: Claude <claude@anthropic.com>
2025-10-27 16:29:11 +08:00
## 渐进式重构路线
### 阶段 1统一错误处理高收益 / 低风险)
- 新增 `src-tauri/src/error.rs`,定义 `AppError`
- 底层文件 IO、配置解析等函数返回 `Result<T, AppError>`
- 命令层通过 `?` 自动传播,最终 `.map_err(Into::into)`
- 预估 3-5 天,立即启动。
### 阶段 2拆分 `commands.rs`(高收益 / 中风险)
- 按业务拆分为 `commands/provider.rs``commands/mcp.rs``commands/config.rs``commands/settings.rs``commands/misc.rs`
- `commands/mod.rs` 统一导出和注册。
- 文件行数降低到 200-300 行/文件,职责单一。
- 预估 5-7 天,可并行进行部分重构。
### 阶段 3补充测试中收益 / 中风险)
- 引入 `tests/``src-tauri/tests/` 集成测试覆盖供应商切换、MCP 同步、配置迁移。
- 使用 `tempfile`/`tempdir` 隔离文件系统,组合少量回归脚本。
- 预估 5-7 天,为后续重构提供安全网。
### 阶段 4提取轻量服务层中收益 / 中风险)
- 新增 `services/provider_service.rs``services/mcp_service.rs`
- 不强制使用 trait直接以自由函数/结构体实现业务流程。
```rust
pub struct ProviderService;
impl ProviderService {
pub fn switch(config: &mut MultiAppConfig, app: AppType, id: &str) -> Result<(), AppError> {
// 业务流程:验证、回填、落盘、更新 current、触发事件
}
}
```
- 命令层负责参数解析,服务层处理业务逻辑,托盘逻辑重用同一接口。
- 预估 7-10 天,可在测试补齐后执行。
### 阶段 5锁与阻塞优化低收益 / 低风险)
- `AppState``Mutex` 改为 `RwLock`
- 读写操作分别使用 `read()`/`write()`,减少不必要的互斥。
- 长耗时任务(如归档、批量迁移)用 `spawn_blocking` 包裹,其余直接同步调用。
- 预估 3-5 天,可在主流程稳定后安排。
## 测试策略
- **优先覆盖场景**
- 供应商切换:状态更新 + live 配置同步
- MCP 同步enabled 服务器快照与落盘
- 配置迁移:归档、备份与版本升级
- **推荐结构**
```rust
#[cfg(test)]
mod integration {
use super::*;
#[test]
fn switch_provider_updates_live_config() { /* ... */ }
#[test]
fn sync_mcp_to_codex_updates_claude_config() { /* ... */ }
#[test]
fn migration_preserves_backup() { /* ... */ }
}
```
- 目标覆盖率:关键路径 >80%,文件 IO/迁移 >70%。
## 风险与对策
- **测试不足** → 阶段 3 强制补齐,建立基础集成测试。
- **重构跨度大** → 按阶段在独立分支推进(如 `refactor/backend-step1` 等)。
- **回滚困难** → 每阶段结束打 tag`v3.6.0-backend-step1`),保留回滚点。
- **功能回归** → 重构后执行手动冒烟流程供应商切换、托盘操作、MCP 同步、配置导入导出。
## 总结
- 当前规模下不建议整体引入完整 DDD/四层架构,避免过度设计。
- 建议遵循“错误统一 → 命令拆分 → 补测试 → 服务层抽象 → 锁优化”的渐进式策略。
- 完成阶段 1-3 后即可显著提升可维护性与可靠性;阶段 4-5 可根据资源灵活安排。
- 重构过程中同步维护文档与测试,确保团队成员对架构演进保持一致认知。