# ColaFlow API ColaFlow 后端 API 服务 - 基于 .NET 9 的 **Modular Monolith + Clean Architecture + DDD + CQRS** 实现。 ## 架构亮点 - **Modular Monolith Architecture** - 模块化单体架构,清晰的模块边界 - **Clean Architecture** - 四层架构设计(Domain → Application → Infrastructure → API) - **Domain-Driven Design (DDD)** - 领域驱动设计(战术模式) - **CQRS** - 命令查询职责分离(MediatR) - **Event Sourcing** - 事件溯源(用于审计日志) - **Architecture Testing** - 自动化架构测试(NetArchTest) ## 技术栈 - **.NET 9** - 最新的 .NET 平台 - **Entity Framework Core 9** - ORM - **PostgreSQL 16+** - 主数据库 - **Redis 7+** - 缓存和会话管理 - **MediatR** - 中介者模式(CQRS 和模块间通信) - **xUnit** - 单元测试框架 - **NetArchTest.Rules** - 架构测试 - **Testcontainers** - 集成测试 ## 项目结构(模块化单体) ``` colaflow-api/ ├── src/ │ ├── ColaFlow.API/ # API 层(统一入口) │ │ └── Program.cs # 模块注册和启动 │ │ │ ├── Modules/ # 业务模块 │ │ ├── ProjectManagement/ # 项目管理模块 │ │ │ ├── ColaFlow.Modules.PM.Domain/ │ │ │ │ ├── Aggregates/ # Project, Epic, Story, Task │ │ │ │ ├── ValueObjects/ # ProjectId, ProjectKey, etc. │ │ │ │ ├── Events/ # Domain Events │ │ │ │ └── Exceptions/ # Domain Exceptions │ │ │ ├── ColaFlow.Modules.PM.Application/ │ │ │ │ ├── Commands/ # CQRS Commands │ │ │ │ ├── Queries/ # CQRS Queries │ │ │ │ └── DTOs/ # Data Transfer Objects │ │ │ ├── ColaFlow.Modules.PM.Infrastructure/ │ │ │ │ ├── Persistence/ # EF Core Configurations │ │ │ │ └── Repositories/ # Repository Implementations │ │ │ └── ColaFlow.Modules.PM.Contracts/ │ │ │ └── Events/ # Integration Events │ │ │ │ │ ├── Workflow/ # 工作流模块(待实现) │ │ ├── UserManagement/ # 用户管理模块(待实现) │ │ ├── Notifications/ # 通知模块(待实现) │ │ ├── Audit/ # 审计模块(待实现) │ │ └── AI/ # AI 模块(待实现) │ │ │ ├── Shared/ # 共享内核 │ │ └── ColaFlow.Shared.Kernel/ │ │ ├── Common/ # Entity, ValueObject, AggregateRoot │ │ ├── Events/ # DomainEvent │ │ └── Modules/ # IModule 接口 │ │ │ └── [Legacy - To be removed] # 旧的单体结构(迁移中) │ ├── ColaFlow.Domain/ │ ├── ColaFlow.Application/ │ └── ColaFlow.Infrastructure/ │ ├── tests/ │ ├── ColaFlow.ArchitectureTests/ # 架构测试(模块边界) │ ├── ColaFlow.Domain.Tests/ # 领域层单元测试 │ ├── ColaFlow.Application.Tests/ # 应用层单元测试 │ └── ColaFlow.IntegrationTests/ # 集成测试 └── ColaFlow.sln ``` ## Modular Monolith 架构 ### 模块边界规则 ``` ┌────────────────────────────────────────────────────┐ │ ColaFlow.API (Entry Point) │ └─────────────────┬──────────────────────────────────┘ │ ┌─────────────┴─────────────┐ │ │ ▼ ▼ ┌─────────────┐ ┌─────────────┐ │ PM │ │ Workflow │ ... (其他模块) │ Module │◄─────────►│ Module │ └─────────────┘ └─────────────┘ │ │ ▼ ▼ ┌─────────────────────────────────────┐ │ Shared.Kernel (Common Base) │ └─────────────────────────────────────┘ ``` ### 模块通信规则 1. **禁止直接引用其他模块的 Domain 实体** 2. **允许通过 MediatR 查询其他模块**(Application Service Integration) 3. **允许通过 Domain Events 解耦通信**(Event-Driven) 4. **使用 Contracts 项目定义模块对外接口** ### 架构测试 项目包含自动化架构测试,确保模块边界被严格遵守: ```bash dotnet test tests/ColaFlow.ArchitectureTests ``` 测试内容: - Domain 层不依赖 Application 和 Infrastructure - Domain 层只依赖 Shared.Kernel - 模块间不直接引用其他模块的 Domain 实体 - AggregateRoot 正确继承 - ValueObject 是不可变的(sealed) ## Clean Architecture 层级依赖 每个模块内部仍然遵循 Clean Architecture: ``` Module Structure: API/Controllers ──┐ ├──> Application ──> Domain Infrastructure ───┘ ``` **依赖规则:** - **Domain 层**:仅依赖 Shared.Kernel(无其他依赖) - **Application 层**:依赖 Domain 和 Contracts - **Infrastructure 层**:依赖 Domain 和 Application - **API 层**:依赖所有层 ## 快速开始 ### 前置要求 - .NET 9 SDK - Docker Desktop(用于 PostgreSQL 和 Redis) - IDE:Visual Studio 2022 / JetBrains Rider / VS Code ### 1. 安装依赖 ```bash cd colaflow-api dotnet restore ``` ### 2. 启动数据库(使用 Docker) 从项目根目录启动: ```bash cd .. docker-compose up -d postgres redis ``` ### 3. 运行数据库迁移 ```bash # 创建迁移(Infrastructure 层完成后) dotnet ef migrations add InitialCreate --project src/ColaFlow.Infrastructure --startup-project src/ColaFlow.API # 应用迁移 dotnet ef database update --project src/ColaFlow.Infrastructure --startup-project src/ColaFlow.API ``` ### 4. 运行 API ```bash cd src/ColaFlow.API dotnet run ``` API 将运行在: - HTTP: `http://localhost:5000` - HTTPS: `https://localhost:5001` - Swagger/Scalar: `https://localhost:5001/scalar/v1` ### 5. 运行测试 ```bash # 运行所有测试 dotnet test # 运行单元测试 dotnet test --filter Category=Unit # 运行集成测试 dotnet test --filter Category=Integration # 生成覆盖率报告 dotnet test /p:CollectCoverage=true /p:CoverletOutputFormat=opencover ``` ## 开发指南 ### Domain Layer 开发 **聚合根示例:** ```csharp public class Project : AggregateRoot { public ProjectId Id { get; private set; } public string Name { get; private set; } // 工厂方法 public static Project Create(string name, string description, UserId ownerId) { var project = new Project { Id = ProjectId.Create(), Name = name, OwnerId = ownerId }; project.AddDomainEvent(new ProjectCreatedEvent(project.Id, project.Name)); return project; } // 业务方法 public void UpdateDetails(string name, string description) { Name = name; Description = description; AddDomainEvent(new ProjectUpdatedEvent(Id)); } } ``` ### Application Layer 开发(CQRS) **Command 示例:** ```csharp public sealed record CreateProjectCommand : IRequest { public string Name { get; init; } public string Description { get; init; } } public sealed class CreateProjectCommandHandler : IRequestHandler { public async Task Handle(CreateProjectCommand request, CancellationToken cancellationToken) { // 1. 创建聚合 var project = Project.Create(request.Name, request.Description, currentUserId); // 2. 保存 await _repository.AddAsync(project, cancellationToken); await _unitOfWork.SaveChangesAsync(cancellationToken); // 3. 返回 DTO return _mapper.Map(project); } } ``` **Query 示例:** ```csharp public sealed record GetProjectByIdQuery : IRequest { public Guid ProjectId { get; init; } } public sealed class GetProjectByIdQueryHandler : IQueryHandler { public async Task Handle(GetProjectByIdQuery request, CancellationToken cancellationToken) { var project = await _context.Projects .AsNoTracking() .FirstOrDefaultAsync(p => p.Id == request.ProjectId, cancellationToken); return _mapper.Map(project); } } ``` ### API Layer 开发 **Controller 示例:** ```csharp [ApiController] [Route("api/v1/[controller]")] public class ProjectsController : ControllerBase { private readonly IMediator _mediator; [HttpPost] [ProducesResponseType(typeof(ProjectDto), StatusCodes.Status201Created)] public async Task CreateProject([FromBody] CreateProjectCommand command) { var result = await _mediator.Send(command); return CreatedAtAction(nameof(GetProject), new { id = result.Id }, result); } [HttpGet("{id}")] [ProducesResponseType(typeof(ProjectDto), StatusCodes.Status200OK)] public async Task GetProject(Guid id) { var result = await _mediator.Send(new GetProjectByIdQuery { ProjectId = id }); return Ok(result); } } ``` ## 测试策略 ### 测试金字塔 - **70% 单元测试** - Domain 和 Application 层 - **20% 集成测试** - API 端点测试 - **10% E2E 测试** - 关键用户流程 ### 单元测试示例 ```csharp public class ProjectTests { [Fact] public void Create_WithValidData_ShouldCreateProject() { // Arrange var name = "Test Project"; var ownerId = UserId.Create(); // Act var project = Project.Create(name, "Description", ownerId); // Assert project.Should().NotBeNull(); project.Name.Should().Be(name); project.DomainEvents.Should().ContainSingle(e => e is ProjectCreatedEvent); } } ``` ### 集成测试示例 ```csharp public class ProjectsControllerTests : IntegrationTestBase { [Fact] public async Task CreateProject_WithValidData_ShouldReturn201() { // Arrange var command = new CreateProjectCommand { Name = "Test", Description = "Test" }; // Act var response = await _client.PostAsJsonAsync("/api/v1/projects", command); // Assert response.StatusCode.Should().Be(HttpStatusCode.Created); var project = await response.Content.ReadFromJsonAsync(); project.Should().NotBeNull(); } } ``` ## 代码质量 ### 覆盖率要求 - **最低要求:80%** - **目标:90%+** - **关键路径:100%** ### 代码规范 - 遵循 C# 编码规范 - 使用 private 构造函数 + 工厂方法 - 所有 public 方法必须有 XML 注释 - 所有业务逻辑必须有单元测试 ## NuGet 包版本 ### Domain Layer - 无外部依赖 ### Application Layer - MediatR 13.1.0 - FluentValidation 12.0.0 - AutoMapper 15.1.0 ### Infrastructure Layer - Microsoft.EntityFrameworkCore 9.0.10 - Npgsql.EntityFrameworkCore.PostgreSQL 9.0.4 - StackExchange.Redis 2.9.32 ### API Layer - Serilog.AspNetCore 9.0.0 - Scalar.AspNetCore 2.9.0 ### Test Projects - xUnit 2.9.2 - FluentAssertions 8.8.0 - Moq 4.20.72 - Testcontainers 4.x ## 环境变量 创建 `src/ColaFlow.API/appsettings.Development.json`: ```json { "ConnectionStrings": { "DefaultConnection": "Host=localhost;Port=5432;Database=colaflow;Username=colaflow;Password=colaflow_password", "Redis": "localhost:6379,password=colaflow_redis_password" }, "Logging": { "LogLevel": { "Default": "Information", "Microsoft.AspNetCore": "Warning" } } } ``` ## API 文档 启动应用后,访问: - **Scalar UI**: `https://localhost:5001/scalar/v1` - **OpenAPI JSON**: `https://localhost:5001/openapi/v1.json` ## 相关文档 - [完整架构设计](../docs/M1-Architecture-Design.md) - [项目计划](../product.md) - [Sprint 计划](../docs/Sprint-Plan.md) - [Docker 使用指南](../DOCKER-README.md) - [测试指南](tests/README.md) ## 下一步开发任务 ### Infrastructure Layer(进行中) - [ ] 配置 EF Core DbContext - [ ] 创建 Entity Configurations - [ ] 生成数据库 Migrations - [ ] 实现 Repository 和 Unit of Work ### Application Layer(待开发) - [ ] 实现 CQRS Commands - [ ] 实现 CQRS Queries - [ ] 配置 MediatR Pipeline Behaviors - [ ] 实现 FluentValidation Validators ### API Layer(待开发) - [ ] 实现 REST API Controllers - [ ] 配置 OpenAPI/Scalar - [ ] 实现异常处理中间件 - [ ] 配置 JWT 认证 ### 测试(待开发) - [ ] 编写 Domain 单元测试(≥80% 覆盖率) - [ ] 编写 Application 单元测试 - [ ] 编写 API 集成测试 ## License MIT License ## 团队 ColaFlow Development Team --- **当前状态**: 🟡 Domain Layer 完成,Infrastructure 和 Application 层开发中 **最后更新**: 2025-11-02