Some checks failed
Build and Push Docker / build (push) Failing after 2m33s
- Add CLEANDDD-WORKFLOW.md - CleanDDD development workflow guide - Keep GATEWAY_ADMIN_README.md and DATABASE_SCHEMA_FIX.md - Remove all .planning/ GSD workflow documents - Remove old EF migrations (using EnsureCreated for test env)
5.8 KiB
5.8 KiB
CleanDDD 开发工作流
本文档描述 Fengling 微服务项目的标准开发流程,基于 Clean Architecture 和 Domain-Driven Design 原则。
开发技能栈
| 技能 | 用途 | 位置 |
|---|---|---|
cleanddd-requirements-analysis |
需求澄清与拆解 | ~/.agents/skills/ |
cleanddd-modeling |
领域模型设计(聚合/命令/事件/查询) | ~/.agents/skills/ |
cleanddd-dotnet-coding |
代码实现(实体/命令/端点/事件) | ~/.agents/skills/ |
cleanddd-dotnet-init |
新项目初始化 | ~/.agents/skills/ |
标准开发流程
阶段 1:需求分析
业务需求描述
↓
cleanddd-requirements-analysis
↓
结构化需求文档(标注业务实体、干系人)
阶段 2:领域建模
结构化需求
↓
cleanddd-modeling
↓
领域蓝图:
- 聚合根定义(含强类型ID)
- 领域事件列表
- 命令与查询分离
- API 端点设计
- 仓储接口
阶段 3:代码实现
领域蓝图
↓
cleanddd-dotnet-coding
↓
项目结构:
├── Domain/
│ ├── AggregatesModel/{Aggregate}/
│ │ ├── {Aggregate}.cs # 聚合根
│ │ ├── {Aggregate}Id.cs # 强类型ID
│ │ └── Events/ # 领域事件
│ └── DomainEvents/
├── Infrastructure/
│ ├── EntityConfigurations/ # EF 配置
│ └── Repositories/ # 仓储实现
└── Web/
├── Application/
│ ├── Commands/ # CQRS 命令
│ ├── Queries/ # CQRS 查询
│ └── DomainEventHandlers/ # 领域事件处理器
└── Endpoints/ # API 端点
项目结构规范
CleanDDD 标准结构
{ServiceName}/
├── src/
│ ├── {ServiceName}.Domain/ # 领域层(无依赖)
│ │ ├── AggregatesModel/
│ │ │ └── {Aggregate}/
│ │ │ ├── {Aggregate}.cs
│ │ │ ├── {Aggregate}Id.cs
│ │ │ └── Events/
│ │ └── DomainEvents/
│ │
│ ├── {ServiceName}.Infrastructure/ # 基础设施层
│ │ ├── EntityConfigurations/
│ │ ├── Repositories/
│ │ └── {ServiceName}DbContext.cs
│ │
│ └── {ServiceName}.Web/ # 表现层
│ ├── Application/
│ │ ├── Commands/
│ │ │ └── {Feature}/
│ │ │ ├── {Command}.cs
│ │ │ └── {Command}Handler.cs
│ │ ├── Queries/
│ │ └── DomainEventHandlers/
│ └── Endpoints/
│ └── {Feature}Endpoints.cs
│
└── tests/ # 测试项目
├── {ServiceName}.Domain.UnitTests/
├── {ServiceName}.Infrastructure.UnitTests/
└── {ServiceName}.Web.UnitTests/
命名约定
| 类型 | 命名格式 | 示例 |
|---|---|---|
| 聚合根 | {名词} |
Campaign, Order |
| 强类型ID | {名词}Id |
CampaignId, OrderId |
| 领域事件 | {名词}{动词}edEvent |
CampaignCreatedEvent |
| 命令 | {动词}{名词}Command |
CreateCampaignCommand |
| 查询 | Get{名词}Query |
GetCampaignQuery |
| 端点 | {名词}Endpoints |
CampaignEndpoints |
| 仓储 | I{名词}Repository |
ICampaignRepository |
代码规范
必须遵守
- 强类型 ID:所有实体使用
IInt64StronglyTypedId或IGuidStronglyTypedId - 聚合根:继承
Entity<TId>,实现IAggregateRoot - 领域事件:在状态变更时发布
this.AddDomainEvent() - 仓储:使用异步方法(
GetAsync,AddAsync),禁止在 Handler 中调用SaveChanges - 命令验证:每个命令必须有对应的
AbstractValidator<T> - 端点配置:使用属性配置
[HttpPost],[Tags],不使用Configure()方法
禁止事项
- ❌ 手动赋值实体 ID(使用 EF 值生成器)
- ❌ 在领域层引用基础设施层
- ❌ 在非聚合/实体中发布领域事件
- ❌ 仓储同步方法
- ❌ 命令 Handler 中调用
SaveChanges
网关架构说明
配置流向
K8s Service (app-router-* label)
↓
Console (K8sServiceWatchService)
↓
PendingConfigCache (内存缓存)
↓
PendingConfigController (用户确认)
↓
PostgreSQL (GwRoutes, ServiceInstances)
↓
PostgreSQL NOTIFY (gateway_config_changed)
↓
Gateway (PgSqlConfigChangeListener)
↓
YARP DynamicProxyConfigProvider
↓
TenantRoutingTransform (按 TenantCode 路由)
↓
后端服务
多租户路由
| 路由类型 | URL 模式 | 说明 |
|---|---|---|
| 全局路由 | /{ServicePrefix}/{Version}/{Resource} |
所有租户共享 |
| 租户路由 | /tenant/{tenantCode}/{ServicePrefix}/{Version}/{Resource} |
租户专属目标 |
关键实体
- GwRoute:全局路由配置(Path → Cluster)
- GwCluster:服务集群(含 Destinations 列表)
- GwDestination:目标端点(含 TenantCode 用于租户路由)
故障排除
| 问题 | 原因 | 解决 |
|---|---|---|
bigint = character varying |
表结构过时 | 见 DATABASE_SCHEMA_FIX.md |
libgssapi_krb5.so.2 警告 |
Alpine 缺少 Kerberos 库 | 可忽略,或设 Logging__LogLevel__Npgsql=Error |
| Watch 连接断开不恢复 | HTTP/2 连接超时 | 已修复:onClosed 回调触发重连 |
| Config 未生效 | NOTIFY 未触发 | 检查 LISTEN config_changes; |
相关文档
DATABASE_SCHEMA_FIX.md- 数据库表结构修复步骤GATEWAY_ADMIN_README.md- Gateway Admin UI 开发指南../../AGENTS.md- 项目级架构概览