fengling-platform/.planning/codebase/CONVENTIONS.md
movingsam 1b8c937aa4
Some checks failed
Build and Push Docker / build (push) Failing after 23s
Publish NuGet Packages / build (push) Failing after 8s
feat: 添加 Gateway 路由实体到 Platform
- 新增 GatewayAggregate 领域实体 (GwTenant, GwTenantRoute, GwServiceInstance)
- 新增 IRouteStore, RouteStore, IInstanceStore, InstanceStore
- 新增 IRouteManager, RouteManager
- 合并 GatewayDbContext 到 PlatformDbContext
- 统一 Extensions.AddPlatformCore 注册所有服务
2026-02-28 23:53:00 +08:00

216 lines
6.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 代码约定
**分析日期:** 2026-02-28
## 命名模式
### 文件
- **类/记录:** PascalCase`ApplicationUser.cs`、`TenantManager.cs`、`TenantInfo.cs`
- **枚举:** PascalCase`TenantStatus`,定义在 `Tenant.cs` 中)
- **接口:** PascalCase + "I" 前缀(如 `ITenantStore.cs`、`ITenantManager.cs`
- **配置:** PascalCase + "Configuration" 后缀(如 `TenantConfiguration.cs`
### 目录
- **聚合文件夹:** PascalCase`UserAggregate/`、`TenantAggregate/`、`RoleAggregate/`
- **用途文件夹:** PascalCase`Configurations/`、`Migrations/`
### 命名空间
- **模式:** `Fengling.Platform.{层级}.{聚合}.{组件}`
- **示例:**
- `Fengling.Platform.Domain.AggregatesModel.TenantAggregate`
- `Fengling.Platform.Domain.AggregatesModel.UserAggregate`
- `Fengling.Platform.Infrastructure`
### 类型
| 类型 | 模式 | 示例 |
|------|------|------|
| 类 | PascalCase | `TenantManager`, `PlatformDbContext` |
| 接口 | I + PascalCase | `ITenantManager`, `ITenantStore` |
| 记录 | PascalCase | `TenantInfo` |
| 枚举 | PascalCase | `TenantStatus` |
| 枚举值 | PascalCase | `Active`, `Inactive`, `Frozen` |
| 属性 | PascalCase | `TenantCode`, `CreatedAt`, `IsDeleted` |
| 方法 | PascalCase | `FindByIdAsync`, `GetAllAsync` |
| 参数 | camelCase | `tenantId`, `tenantCode`, `cancellationToken` |
| 私有字段 | camelCase | `_context`, `_tenants` |
## 代码风格
### 项目配置
- **目标框架:** .NET 10.0
- **隐式 using:** 启用
- **可空:** 启用
- **文档生成:** 启用(`<GenerateDocumentationFile>true</GenerateDocumentationFile>`
- **集中包管理:** 启用(`<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>`
### 格式化
- **大括号:** K&R 风格(开括号在同一行)
- **缩进:** 标准 Visual Studio 默认4 空格)
- **行尾:** 平台默认Unix LFWindows CRLF
### 全局 Using
Domain 项目 (`Fengling.Platform.Domain/GlobalUsings.cs`):
```csharp
global using NetCorePal.Extensions.Domain;
global using NetCorePal.Extensions.Primitives;
global using System.ComponentModel.DataAnnotations;
```
Infrastructure 项目 (`Fengling.Platform.Infrastructure/GlobalUsings.cs`):
```csharp
global using NetCorePal.Extensions.Domain;
global using NetCorePal.Extensions.Primitives;
global using NetCorePal.Extensions.Repository;
global using NetCorePal.Extensions.Repository.EntityFrameworkCore;
global using MediatR;
global using Microsoft.EntityFrameworkCore;
global using Microsoft.EntityFrameworkCore.Metadata.Builders;
```
## 导入组织
### 顺序
1. 系统命名空间(通过 ImplicitUsings 隐式)
2. 外部包MediatR、EF Core
3. 领域命名空间(本地项目)
4. 基础设施命名空间(本地项目)
### 完全限定
- 需要时使用 `Microsoft.AspNetCore.Identity` 的完全限定(如 `ITenantStore.cs` 中的 `Microsoft.AspNetCore.Identity.IdentityResult`
## 错误处理
### 空检查
**模式:** 显式参数空检查并抛出异常
```csharp
if (modelBuilder is null)
{
throw new ArgumentNullException(nameof(modelBuilder));
}
```
- 位置: `PlatformDbContext.cs` 第 20-23 行
### 空返回
**模式:** 对可空结果返回 `Task.FromResult<T?>(null)`
```csharp
if (tenantId == null) return Task.FromResult<Tenant?>(null);
```
- 位置: `TenantStore.cs` 第 23 行
### 验证
- 查询中使用 `string.IsNullOrEmpty()` 进行字符串验证
- 对引用类型使用可空注解 `?` 后缀
## 记录类型
### 值对象
**模式:** 带参数的主构造函数记录
```csharp
public record TenantInfo(long? TenantId, string? TenantCode, string? TenantName)
{
public TenantInfo(Tenant? tenant)
: this(tenant?.Id, tenant?.TenantCode, tenant?.Name)
{
}
public static TenantInfo Admin => new TenantInfo(null, null, null);
}
```
- 位置: `TenantInfo.cs`
## 实体设计
### 贫血领域模型
- **Tenant:** 贫血模型(带公共 setter 的数据容器)
- **ApplicationUser:** 富模型,带到 `TenantInfo` 的导航属性
- **ID 类型:** 所有实体标识使用 `long`
### 属性模式
```csharp
public long Id { get; set; }
public string TenantCode { get; set; } = string.Empty;
public string Name { get; set; } = string.Empty;
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
public DateTime? UpdatedAt { get; set; }
public bool IsDeleted { get; set; }
```
## 类设计
### 主构造函数
**模式:** 用于依赖注入的主构造函数
```csharp
public sealed class TenantManager(ITenantStore store) : ITenantManager
{
// 构造函数参数自动成为私有 readonly 字段
}
```
- 位置: `TenantManager.cs` 第 21 行
### 泛型约束
```csharp
public class TenantStore<TContext> : ITenantStore
where TContext : PlatformDbContext
```
### 方法返回类型
- 异步方法: 返回 `Task<T>``Task`
- 集合查询: 返回 `IList<T>``IQueryable<T>`
- 单个实体: 返回 `T?`
## 注释
### 何时注释
- **中文注释:** 用于领域概念和解释
```csharp
/// <summary>
/// 租户信息
/// </summary>
public record TenantInfo(...)
```
- **XML 文档:** 用于公共 API
- **最少行内注释:** 仅用于复杂业务逻辑
### JSDoc/TSDoc
- 对公共 API 使用 `/// <summary>``/// <param name="...">`
- 位置: `TenantInfo.cs` 第 3-8 行、11-13 行
## 函数设计
### 异步方法
- 始终接受 `CancellationToken cancellationToken = default` 作为最后一个参数
- 一致使用 `async`/`await`
- 对有返回值操作返回 `Task<T>`
### 查询方法
- **分页:** 接受 `page``pageSize` 参数
- **过滤:** 接受可选过滤参数(`name`、`tenantCode`、`status`
- **排序:** 按创建日期应用 `OrderByDescending`
### IdentityResult 模式
业务操作返回 `IdentityResult`:
```csharp
Task<IdentityResult> CreateAsync(Tenant tenant, CancellationToken cancellationToken = default);
Task<IdentityResult> UpdateAsync(Tenant tenant, CancellationToken cancellationToken = default);
Task<IdentityResult> DeleteAsync(Tenant tenant, CancellationToken cancellationToken = default);
```
## DbContext 设计
### 配置
- **模式:** `OnModelCreating` 中的流式 API
- **实体配置:** 使用 `modelBuilder.Entity<T>(entity => {...})`
- **索引配置:** 使用 `entity.HasIndex(e => e.Property)`
- **拥有类型:** 使用 `entity.OwnsOne(e => e.TenantInfo, navigationBuilder => {...})`
### 配置发现
```csharp
modelBuilder.ApplyConfigurationsFromAssembly(typeof(PlatformDbContext).Assembly);
```
---
*约定分析: 2026-02-28*