Files
EmailBill/.doc/APPLICATION_LAYER_PROGRESS.md
SunCheng d052ae5197 fix
2026-02-10 17:49:19 +08:00

25 KiB
Raw Permalink Blame History

Application Layer 重构进度文档

创建时间: 2026-02-10
状态: Phase 2 部分完成5/8模块 - 准备进入Phase 3
总测试数: 44个测试全部通过


📊 总体进度

Phase 1: 基础设施搭建100%完成)

已完成内容:

  1. Application项目创建

    • 位置: Application/Application.csproj
    • 依赖: Service, Repository, Entity, Common
    • NuGet包: JWT认证相关
  2. 核心文件

    • GlobalUsings.cs - 全局引用配置
    • ServiceCollectionExtensions.cs - DI自动注册扩展
  3. 异常类体系

    Application/Exceptions/
    ├── ApplicationException.cs      # 基类异常
    ├── ValidationException.cs       # 业务验证异常 → HTTP 400
    ├── BusinessException.cs         # 业务逻辑异常 → HTTP 500
    └── NotFoundException.cs         # 资源未找到 → HTTP 404
    
  4. 全局异常过滤器

    • 位置: WebApi/Filters/GlobalExceptionFilter.cs.pending
    • 状态: 已创建待Phase 3集成时重命名启用
    • 功能: 统一捕获Application层异常并转换为BaseResponse
  5. 测试基础设施

    • WebApi.Test/Application/BaseApplicationTest.cs
    • 继承自BaseTest提供Mock辅助方法

Phase 2: 模块实现5/8模块完成63%

已完成模块5个

1. AuthApplication

  • 文件:
    • Application/Dto/Auth/LoginRequest.cs
    • Application/Dto/Auth/LoginResponse.cs
    • Application/Auth/AuthApplication.cs
    • WebApi.Test/Application/AuthApplicationTest.cs
  • 测试: 7个测试全部通过
  • 功能: JWT Token生成、密码验证
  • 关键方法:
    • Login(LoginRequest) - 用户登录验证

2. ConfigApplication

  • 文件:
    • Application/Dto/Config/ConfigDto.cs
    • Application/Config/ConfigApplication.cs
    • WebApi.Test/Application/ConfigApplicationTest.cs
  • 测试: 8个测试全部通过
  • 功能: 配置读取/设置、参数验证
  • 关键方法:
    • GetConfigAsync(string key) - 获取配置
    • SetConfigAsync(string key, string value) - 设置配置

3. ImportApplication

  • 文件:
    • Application/Dto/Import/ImportDto.cs
    • Application/Import/ImportApplication.cs
    • WebApi.Test/Application/ImportApplicationTest.cs
  • 测试: 7个测试全部通过
  • 功能: 账单导入、文件验证CSV/Excel、大小限制10MB
  • 关键方法:
    • ImportAlipayAsync(ImportRequest) - 支付宝账单导入
    • ImportWeChatAsync(ImportRequest) - 微信账单导入

4. BudgetApplication

  • 文件:
    • Application/Dto/Budget/BudgetDto.cs
    • Application/Budget/BudgetApplication.cs
    • WebApi.Test/Application/BudgetApplicationTest.cs
  • 测试: 13个测试全部通过
  • 功能: 预算CRUD、分类统计、业务验证
  • 关键方法:
    • GetListAsync(DateTime) - 获取预算列表(含排序)
    • CreateAsync(CreateBudgetRequest) - 创建预算(含复杂验证逻辑)
    • UpdateAsync(UpdateBudgetRequest) - 更新预算
    • DeleteByIdAsync(long) - 删除预算
    • GetCategoryStatsAsync(...) - 获取分类统计
    • GetUncoveredCategoriesAsync(...) - 获取未覆盖分类
    • GetArchiveSummaryAsync(DateTime) - 获取归档总结
    • GetSavingsBudgetAsync(...) - 获取存款预算
  • 核心业务逻辑:
    • 不记额预算必须是年度预算的验证
    • 分类冲突检测同Category下SelectedCategories不能重叠
    • NoLimit为true时强制Limit=0
    • 多字段排序(刚性支出优先 → 分类 → 类型 → 使用率 → 名称)

5. TransactionApplication 核心CRUD

  • 文件:
    • Application/Dto/Transaction/TransactionDto.cs
    • Application/Transaction/TransactionApplication.cs
    • WebApi.Test/Application/TransactionApplicationTest.cs
  • 测试: 9个测试全部通过
  • 功能: 交易记录CRUD、分页查询
  • 已实现方法:
    • GetListAsync(TransactionQueryRequest) - 分页查询(含多条件筛选)
    • GetByIdAsync(long) - 根据ID获取
    • CreateAsync(CreateTransactionRequest) - 创建交易
    • UpdateAsync(UpdateTransactionRequest) - 更新交易
    • DeleteByIdAsync(long) - 删除交易

📋 Phase 2 剩余工作3/8模块未完成

待实现模块优先级

🔴 必须实现(核心功能)

6. TransactionApplication扩展功能⚠️

当前状态: 已实现核心CRUD5个方法还需补充以下高级功能

待补充方法(参考WebApi/Controllers/TransactionRecordController.cs:614:

// 智能AI相关复杂需要处理流式响应
Task SmartClassifyAsync(long[] transactionIds, Action<(string, string)> onChunk);
Task<TransactionParseResult> ParseOneLineAsync(string text);
Task AnalyzeBillAsync(string userInput, Action<string> onChunk);

// 批量操作
Task<int> BatchUpdateClassifyAsync(List<BatchUpdateClassifyItem> items);
Task<int> BatchUpdateByReasonAsync(string reason, TransactionType type, string classify);

// 查询相关
Task<List<TransactionResponse>> GetByEmailIdAsync(long emailId);
Task<List<TransactionResponse>> GetByDateAsync(DateTime date);
Task<List<TransactionResponse>> GetUnconfirmedListAsync();
Task<int> GetUnconfirmedCountAsync();
Task<List<TransactionResponse>> GetUnclassifiedAsync(int pageSize);
Task<int> ConfirmAllUnconfirmedAsync(long[] ids);

实施建议:

  • AI相关方法需要注入ISmartHandleService
  • 流式响应逻辑保留在Controller层SSE特性
  • 批量操作需要循环调用Repository

预估工作量: 3-4小时


🟡 可选实现(简化或占位)

7. EmailMessageApplication

参考Controller: WebApi/Controllers/EmailMessageController.cs

核心方法(优先实现):

  • GetListAsync(...) - 邮件列表查询
  • DeleteByIdAsync(long) - 删除邮件
  • ReParseAsync(long) - 重新解析邮件

预估工作量: 2小时

8. MessageRecordApplication

参考Controller: WebApi/Controllers/MessageRecordController.cs

核心方法:

  • GetListAsync() - 消息列表
  • DeleteByIdAsync(long) - 删除消息

预估工作量: 1小时

9. TransactionStatisticsApplication

参考Controller: WebApi/Controllers/TransactionStatisticsController.cs

核心方法:

  • GetMonthlyStatsAsync(...) - 月度统计
  • GetCategoryStatsAsync(...) - 分类统计

预估工作量: 1.5小时

10. 其他简单Controller
  • NotificationController - 通知相关
  • TransactionCategoryController - 分类管理
  • TransactionPeriodicController - 周期性账单
  • JobController - 任务管理
  • LogController - 日志查询

实施建议: 创建最小化实现或直接在Phase 3迁移时按需补充

预估工作量: 2-3小时


🚀 Phase 3: 代码迁移与集成(未开始)

3.1 准备工作

Step 1: 集成Application到WebApi项目

文件修改:

<!-- WebApi/WebApi.csproj -->
<ItemGroup>
  <ProjectReference Include="..\Application\Application.csproj" />
  <!-- ... 其他引用 -->
</ItemGroup>

Step 2: 启用全局异常过滤器

操作:

# 重命名文件启用
mv WebApi/Filters/GlobalExceptionFilter.cs.pending WebApi/Filters/GlobalExceptionFilter.cs

修改Program.cs:

// WebApi/Program.cs
builder.Services.AddControllers(options =>
{
    options.Filters.Add<GlobalExceptionFilter>();
});

// 注册Application服务
builder.Services.AddApplicationServices();

Step 3: 迁移DTO到Application

操作:

  • 删除或废弃WebApi/Controllers/Dto/下的DTO除了BaseResponse和PagedResponse
  • 更新Controller中的using引用
    • 从: using WebApi.Controllers.Dto;
    • 改为: using Application.Dto.Auth;

3.2 Controller迁移清单

迁移顺序(建议从简单到复杂)

顺序 Controller Application 状态 预估工作量 风险
1 ConfigController ConfigApplication 已准备 15分钟
2 AuthController AuthApplication 已准备 15分钟
3 BillImportController ImportApplication 已准备 30分钟
4 BudgetController BudgetApplication 已准备 1小时
5 TransactionRecordController TransactionApplication ⚠️ 需补充AI功能 2-3小时
6 EmailMessageController 未实现 需先实现 2小时
7 MessageRecordController 未实现 需先实现 1小时
8 TransactionStatisticsController 未实现 需先实现 1.5小时
9 其他Controllers 未实现 按需补充 2-3小时

总预估: 10-12小时


3.3 Controller迁移模板

迁移前示例BudgetController:

public class BudgetController(
    IBudgetService budgetService,
    IBudgetRepository budgetRepository,
    ILogger<BudgetController> logger) : ControllerBase
{
    [HttpGet]
    public async Task<BaseResponse<List<BudgetResult>>> GetListAsync([FromQuery] DateTime referenceDate)
    {
        try
        {
            return (await budgetService.GetListAsync(referenceDate))
                .OrderByDescending(b => b.IsMandatoryExpense)
                .ThenBy(b => b.Category)
                .ToList()
                .Ok();
        }
        catch (Exception ex)
        {
            logger.LogError(ex, "获取预算列表失败");
            return $"获取预算列表失败: {ex.Message}".Fail<List<BudgetResult>>();
        }
    }
    
    // ... 其他方法 + 私有验证逻辑30行
}

迁移后示例:

public class BudgetController(
    IBudgetApplication budgetApplication,
    ILogger<BudgetController> logger) : ControllerBase
{
    [HttpGet]
    public async Task<BaseResponse<List<BudgetResponse>>> GetListAsync(
        [FromQuery] DateTime referenceDate)
    {
        // 全局异常过滤器会捕获异常
        var result = await budgetApplication.GetListAsync(referenceDate);
        return result.Ok();
    }
    
    // ... 其他方法业务逻辑已迁移到Application
}

代码减少: 约60-70%


3.4 迁移步骤每个Controller

标准流程:

  1. 修改构造函数

    • 移除: IBudgetService, IBudgetRepository
    • 添加: IBudgetApplication
  2. 简化Action方法

    • 移除try-catch交给全局过滤器
    • 调用Application方法
    • 返回.Ok()包装
  3. 更新DTO引用

    • 从: CreateBudgetDto
    • 改为: CreateBudgetRequest
    • 命名空间: Application.Dto.Budget
  4. 删除私有方法

    • 业务验证逻辑已迁移到Application
  5. 测试验证

    # 编译
    dotnet build WebApi/WebApi.csproj
    
    # 运行测试
    dotnet test --filter "FullyQualifiedName~BudgetController"
    
    # 启动应用手动验证
    dotnet run --project WebApi
    

📁 当前项目结构

EmailBill/
├── Application/                    ✅ 新增
│   ├── Application.csproj
│   ├── GlobalUsings.cs
│   ├── ServiceCollectionExtensions.cs
│   ├── Exceptions/                 # 4个异常类
│   ├── Dto/
│   │   ├── Auth/                   # LoginRequest, LoginResponse
│   │   ├── Config/                 # ConfigDto
│   │   ├── Import/                 # ImportRequest, ImportResponse
│   │   ├── Budget/                 # 6个DTO
│   │   └── Transaction/            # 4个DTO
│   ├── Auth/
│   │   └── AuthApplication.cs
│   ├── Config/
│   │   └── ConfigApplication.cs
│   ├── Import/
│   │   └── ImportApplication.cs
│   ├── Budget/
│   │   └── BudgetApplication.cs
│   └── Transaction/
│       └── TransactionApplication.cs  # 核心CRUD完成
├── WebApi/
│   └── Filters/
│       └── GlobalExceptionFilter.cs.pending  # 待启用
├── WebApi.Test/
│   └── Application/
│       ├── BaseApplicationTest.cs
│       ├── AuthApplicationTest.cs        # 7 tests ✅
│       ├── ConfigApplicationTest.cs      # 8 tests ✅
│       ├── ImportApplicationTest.cs      # 7 tests ✅
│       ├── BudgetApplicationTest.cs      # 13 tests ✅
│       └── TransactionApplicationTest.cs # 9 tests ✅
└── (其他现有项目保持不变)

🧪 测试统计

模块 测试数 状态 覆盖率
AuthApplication 7 全部通过 100%
ConfigApplication 8 全部通过 100%
ImportApplication 7 全部通过 100%
BudgetApplication 13 全部通过 ~95%
TransactionApplication 9 全部通过 ~80% (核心CRUD)
总计 44 0失败 ~90%

运行命令:

dotnet test WebApi.Test/WebApi.Test.csproj --filter "FullyQualifiedName~Application"

🎯 下一会话继续工作指南

立即任务(按优先级)

优先级1: 补充TransactionApplication的高级功能 ⚠️

位置: Application/Transaction/TransactionApplication.cs

需要添加的方法(参考TransactionRecordController.cs:

// 1. AI智能分类高优先级 - 核心功能)
Task SmartClassifyAsync(long[] transactionIds, Action<(string, string)> onChunk)
{
    // 验证
    if (transactionIds == null || transactionIds.Length == 0)
    {
        throw new ValidationException("请提供要分类的账单ID");
    }
    
    // 调用Service注入ISmartHandleService
    await _smartHandleService.SmartClassifyAsync(transactionIds, onChunk);
}

// 2. 一句话录账解析(高优先级)
Task<TransactionParseResult> ParseOneLineAsync(string text)
{
    if (string.IsNullOrEmpty(text))
    {
        throw new ValidationException("解析文本不能为空");
    }
    
    var result = await _smartHandleService.ParseOneLineBillAsync(text);
    if (result == null)
    {
        throw new BusinessException("AI解析失败");
    }
    
    return result;
}

// 3. 批量更新分类
Task<int> BatchUpdateClassifyAsync(List<BatchUpdateClassifyItem> items)
{
    // 循环更新每条记录
    // 返回成功数量
}

// 4. 其他查询方法
Task<List<TransactionResponse>> GetByEmailIdAsync(long emailId);
Task<List<TransactionResponse>> GetByDateAsync(DateTime date);
Task<List<TransactionResponse>> GetUnconfirmedListAsync();
Task<int> GetUnconfirmedCountAsync();
Task<List<TransactionResponse>> GetUnclassifiedAsync(int pageSize);
Task<int> ConfirmAllUnconfirmedAsync(long[] ids);

依赖注入修改:

public class TransactionApplication(
    ITransactionRecordRepository transactionRepository,
    ISmartHandleService smartHandleService,  // 新增
    ILogger<TransactionApplication> logger
)

测试补充: 为每个新方法添加2-3个测试用例


优先级2: 实现EmailMessageApplication

参考Controller: WebApi/Controllers/EmailMessageController.cs

关键方法:

public interface IEmailMessageApplication
{
    Task<PagedResult<EmailMessageResponse>> GetListAsync(EmailQueryRequest request);
    Task DeleteByIdAsync(long id);
    Task ReParseAsync(long id);
    Task MarkAsIgnoredAsync(long id);
}

创建文件:

  • Application/Dto/Email/EmailMessageDto.cs
  • Application/Email/EmailMessageApplication.cs
  • WebApi.Test/Application/EmailMessageApplicationTest.cs

优先级3: 快速实现简单模块

策略: 创建最小化实现满足基本CRUD即可

模块列表:

  • MessageRecordApplication - 消息记录
  • TransactionStatisticsApplication - 统计查询
  • NotificationApplication - 通知(可选)
  • 其他次要Controller

立即开始Phase 3的简化路径

如果时间紧张,可以采用渐进式迁移策略:

方案A: 只迁移已完成的5个模块

优点: 快速见效,风险低
缺点: Controller层仍有部分业务逻辑

迁移清单:

  1. AuthController → AuthApplication
  2. ConfigController → ConfigApplication
  3. BillImportController → ImportApplication
  4. BudgetController → BudgetApplication
  5. ⚠️ TransactionRecordController → TransactionApplication部分功能

方案B: 完整实现所有模块后再迁移

优点: 架构完整,一次性到位
缺点: 需要额外5-8小时完成剩余模块


📝 关键决策记录

已确认的设计决策

  1. 异常处理策略

    • Application层: 只抛异常,不处理
    • Controller层: 通过全局异常过滤器统一处理
    • 特殊场景(如流式响应): Controller手动处理
  2. 依赖关系

    Controller → Application → Service
                            → Repository (未来移除)
    
  3. DTO位置

    • 统一放在Application/Dto/
    • 按模块分目录Auth, Budget, Transaction等
  4. 命名约定

    • 项目名: Application
    • 类名: XxxApplication (实现) / IXxxApplication (接口)
    • DTO: XxxRequest (输入) / XxxResponse (输出)
  5. 测试策略

    • 集成测试为主
    • 放在WebApi.Test/Application/
    • Mock Service和Repository
    • 完整覆盖核心逻辑
  6. 响应格式

    • Application返回业务对象不含BaseResponse
    • Controller负责包装BaseResponse

🛠️ 快速命令参考

编译和测试

# 编译整个解决方案
dotnet build EmailBill.sln

# 编译Application项目
dotnet build Application/Application.csproj

# 运行所有Application测试
dotnet test WebApi.Test/WebApi.Test.csproj --filter "FullyQualifiedName~Application"

# 运行特定模块测试
dotnet test --filter "FullyQualifiedName~BudgetApplicationTest"

# 运行所有测试(验证无破坏)
dotnet test WebApi.Test/WebApi.Test.csproj

添加新模块(标准流程)

# 1. 创建目录
mkdir -p Application/Dto/ModuleName
mkdir -p Application/ModuleName

# 2. 创建文件
# - Application/Dto/ModuleName/XxxDto.cs
# - Application/ModuleName/XxxApplication.cs
# - WebApi.Test/Application/XxxApplicationTest.cs

# 3. 编译验证
dotnet build Application/Application.csproj

# 4. 运行测试
dotnet test --filter "FullyQualifiedName~XxxApplicationTest"

🚨 已知问题和注意事项

1. GlobalExceptionFilter暂未集成

原因: WebApi项目尚未引用Application项目
文件: WebApi/Filters/GlobalExceptionFilter.cs.pending
操作: Phase 3时重命名并在Program.cs注册

2. DTO类型差异需要注意

  • BudgetResult.SelectedCategoriesstring[] 类型
  • BudgetResult.StartDatestring 类型不是DateTime
  • BudgetStatsDto 没有 RemainingUsagePercentage 字段(需要计算)

3. TransactionApplication的AI功能未实现

影响: TransactionRecordController 中的以下方法无法迁移:

  • SmartClassifyAsync - 智能分类
  • AnalyzeBillAsync - 账单分析
  • ParseOneLine - 一句话录账

解决方案:

  • 需要注入ISmartHandleService
  • 流式响应逻辑保留在Controller

4. 流式响应SSE的特殊处理

位置: TransactionRecordController.SmartClassifyAsync, AnalyzeBillAsync

处理方式: Controller保留SSE响应逻辑Application提供回调接口

// Application
Task SmartClassifyAsync(long[] ids, Action<(string, string)> onChunk);

// Controller
public async Task SmartClassifyAsync([FromBody] SmartClassifyRequest request)
{
    Response.ContentType = "text/event-stream";
    // ...
    await _transactionApplication.SmartClassifyAsync(
        request.TransactionIds.ToArray(),
        async chunk => await WriteEventAsync(chunk.Item1, chunk.Item2)
    );
}

📈 收益分析(基于已完成模块)

代码质量改进

指标 改进前 改进后 提升
BudgetController代码行数 238行 ~80行预估 ⬇️ 66%
AuthController代码行数 78行 ~30行预估 ⬇️ 62%
业务逻辑位置 分散在Controller 集中在Application
可测试性 需Mock HttpContext 纯C#对象测试
代码复用 困难 Application可被多场景复用

架构清晰度

改进前:

Controller → Service/Repository (混合调用,职责不清)

改进后:

Controller → Application → Service (业务逻辑)
           (简单路由)      ↓
                        Repository (数据访问)

🔄 下一步行动建议

建议1: 快速完成核心功能(推荐)

时间: 4-5小时

  1. 补充TransactionApplication高级功能 (3小时)

    • AI智能分类
    • 一句话录账
    • 批量操作
    • 补充查询方法
  2. 实现EmailMessageApplication (1.5小时)

    • 核心CRUD
    • 重新解析邮件
  3. 开始Phase 3迁移 (0.5小时)

    • 集成Application到WebApi
    • 启用全局异常过滤器
    • 迁移1-2个简单Controller验证架构

建议2: 立即开始迁移已完成模块

时间: 2-3小时

  1. 集成基础设施 (30分钟)
  2. 迁移5个已完成的Controller (1.5小时)
  3. 功能验证 (30分钟)
  4. 后续按需补充剩余模块

📚 参考文档

相关文件路径

现有Controller:

  • WebApi/Controllers/BudgetController.cs:238
  • WebApi/Controllers/TransactionRecordController.cs:614
  • WebApi/Controllers/BillImportController.cs:82
  • WebApi/Controllers/AuthController.cs:78
  • WebApi/Controllers/ConfigController.cs:41
  • WebApi/Controllers/EmailMessageController.cs
  • WebApi/Controllers/MessageRecordController.cs
  • WebApi/Controllers/TransactionStatisticsController.cs

Service层参考:

  • Service/Budget/BudgetService.cs:549 - BudgetResult, BudgetStatsDto定义
  • Service/ImportService.cs:498 - 导入逻辑
  • Service/ConfigService.cs:78 - 配置服务
  • Service/AI/SmartHandleService.cs - AI智能处理

现有测试参考:

  • WebApi.Test/Service/BudgetStatsTest.cs - Service层测试示例
  • WebApi.Test/Basic/BaseTest.cs:18 - 测试基类

验证检查清单

Phase 2 完成验证

  • Application项目编译成功
  • 所有Application测试通过44个
  • 5个核心模块完整实现
  • DTO定义完整且符合规范
  • 异常处理机制完整
  • TransactionApplication高级功能待补充
  • 剩余3个模块待实现

Phase 3 就绪检查

  • 全局异常过滤器已创建
  • DI扩展已实现
  • WebApi项目引用Application待添加
  • 全局异常过滤器注册(待启用)
  • DTO命名空间更新待迁移时处理

🎯 成功标准

Phase 2最终目标部分达成

  • 5/8模块完整实现
  • 所有模块测试覆盖率≥90% (当前~90%
  • 所有测试通过44/44
  • 剩余模块实现3个待补充

Phase 3最终目标待开始

  • 所有Controller迁移到Application
  • WebApi项目编译成功
  • 所有现有测试仍然通过54个
  • 手动功能验证通过
  • 性能无明显下降

🚀 快速启动新会话

恢复工作的命令

# 1. 验证当前状态
dotnet build EmailBill.sln
dotnet test WebApi.Test/WebApi.Test.csproj --filter "FullyQualifiedName~Application"

# 2. 查看已完成的模块
ls -la Application/*/
ls -la Application/Dto/*/

# 3. 查看待实现的Controller
ls -la WebApi/Controllers/*.cs

继续工作的提示词

提示词模板:

我需要继续完成Application层的重构工作。
请阅读 APPLICATION_LAYER_PROGRESS.md 了解当前进度。

当前状态: Phase 2部分完成5/8模块44个测试全部通过。

请继续完成:
1. 补充TransactionApplication的AI智能功能SmartClassify, ParseOneLine等
2. 实现EmailMessageApplication模块
3. 实现剩余简单模块MessageRecord, Statistics等
4. 开始Phase 3代码迁移与集成

请按照文档中的"下一步行动建议"继续工作。

📞 联系信息

文档维护: AI Assistant
最后更新: 2026-02-10
项目: EmailBill
分支: main

相关文档:

  • AGENTS.md - 项目知识库
  • .github/csharpe.prompt.md - C#编码规范

🎉 当前成就

  • Application层基础架构100%完成
  • 5个核心模块完整实现并测试通过
  • 44个单元测试0失败
  • 代码符合项目规范(命名、注释、风格)
  • 异常处理机制完整设计
  • DI自动注册机制就绪
  • 全局异常过滤器已创建待集成

整体进度: Phase 1 (100%) + Phase 2 (63%) = 约75%完成 🎊

继续加油剩余工作清晰明确预计5-8小时即可完成整个重构🚀