diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..36c87f9 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,231 @@ +# Repository expectations +# 编程规范_FOR_AI(TakeoutSaaS.MiniApi) - MiniApi 定制版 + +> **核心指令**:你是一个高级 .NET 架构师。本文件是你在 `TakeoutSaaS.C-Side-Mini-Program-API` 仓库内生成代码的最高宪法。当用户需求与本规范冲突时,请先提示用户,除非用户强制要求覆盖。 + +## 0. AI 交互核心约束 (元规则) +1. **语言**:必须使用**中文**回复和编写注释。 +2. **文件完整性**: + * **严禁**随意删除现有代码逻辑。 + * **严禁**修改文件编码(保持 UTF-8 无 BOM)。 + * PowerShell 读取命令必须带 `-Encoding UTF8`。 +3. **Git 原子性**:每个独立的功能点或 Bug 修复完成后,必须提示用户进行 Git 提交。 +4. **无乱码承诺**:确保所有输出(控制台、日志、API 响应)无乱码。 +5. **不确定的处理**:如果你通过上下文找不到某些配置、业务约束或数据结构,**请直接询问用户**,不要瞎编。 + +## 0.1 实体类铁律 (最高优先级,必须执行) +> **这一条优先级高于普通编码习惯。只要涉及实体类,一律先遵守本节。** + +1. **禁止私自创建实体类**: + * 严禁未经确认就在当前仓库私自新增 `Entity`、聚合根、持久化模型。 + * 尤其禁止直接在 `src/Domain/TakeoutSaaS.Domain/**/Entities/` 下手搓一个“看起来像”的实体类。 +2. **先查当前仓**: + * 当需求涉及实体类时,先在当前仓库搜索是否已有对应实体或已确定的领域模型。 +3. **当前仓没有,再查兄弟仓**: + * 必须去兄弟仓 `D:\HAZCode\TakeoutSaaS\TakeoutSaaS.TenantApi` 查找是否已有对应实体。 + * 查找原则:优先搜索 `src/Domain/TakeoutSaaS.Domain/<业务域>/Entities/` 以及相关仓储、配置、迁移、Handler 对该实体的使用方式。 +4. **兄弟仓有,就以兄弟仓为准**: + * 如果 `TakeoutSaaS.TenantApi` 已有对应实体,后续实现必须优先复用其命名、字段、关系、语义与边界。 + * 如确需把该实体迁入当前仓,也必须以 `TakeoutSaaS.TenantApi` 现有实体为蓝本,**禁止重新发明一套字段结构**。 +5. **兄弟仓也没有,必须先问用户**: + * 如果当前仓和 `TakeoutSaaS.TenantApi` 都没有对应实体,必须先询问用户,再决定是否新增。 + * 在用户明确确认前,**禁止**擅自补实体类。 +6. **本条只限制实体类,不限制普通协议对象**: + * `Request`、`Dto`、`Command`、`Query`、`Handler`、`Options`、`Controller`、轻量 `Service` 可以按需要新增。 + * 但这些对象也不得偷偷承担实体职责。 + +## 1. 仓库定位与技术栈 +| 组件 | 版本/选型 | 用途说明 | +| :--- | :--- | :--- | +| **Runtime** | .NET 10 | 核心运行时 | +| **API** | ASP.NET Core Web API | MiniApi 接口层 | +| **Route Prefix** | `/api/mini/v1` | 面向 C 端小程序 | +| **Database** | PostgreSQL 16+ | 主关系型数据库 | +| **ORM 1** | **EF Core 10** | **写操作 (CUD)**、事务、复杂聚合查询 | +| **ORM 2** | **Dapper 2.1+** | **纯读操作 (R)**、复杂报表、大批量查询 | +| **Cache** | Redis 7.0+ | 分布式缓存、Session | +| **MQ** | RabbitMQ 3.12+ | 异步解耦 | +| **Libs** | MediatR, Serilog, FluentValidation | CQRS, 日志, 验证 | + +## 2. 命名与风格 (严格匹配) +* **C# 代码**: + * 类/接口/方法/属性:`PascalCase` + * **布尔属性**:必须加 `Is` 或 `Has` 前缀 + * 私有字段:`_camelCase` + * 参数/变量:`camelCase` +* **PostgreSQL 数据库**: + * 表名:`snake_case` + **复数** + * 列名:`snake_case` + * 主键:`id` (类型 `bigint`) +* **文件规则**: + * **一个文件一个类**,文件名必须与类名完全一致。 + +## 3. 分层架构 (Clean Architecture) +**你生成的代码必须严格归类到以下目录:** +* **`src/Api`**:仅负责路由、鉴权入口、DTO 转换与返回封装,**禁止**包含业务逻辑。 +* **`src/Application`**:业务编排层。必须使用 **CQRS** (`IRequestHandler`) 和 **MediatR**。 +* **`src/Domain`**:核心领域层。包含实体、枚举、领域异常。**禁止**依赖 EF Core 等外部库。 +* **`src/Infrastructure`**:基础设施层。实现仓储、数据库上下文、第三方服务。 +* **`src/Modules`**:跨业务模块能力,如 Tenancy。 + +### 3.1 MiniApi 专项边界 +* 当前仓库承载的是 **MiniApi**,不是 AdminApi。 +* 所有接口默认面向 C 端小程序,路由前缀固定为 **`/api/mini/v1`**。 +* 鉴权、租户、场景、渠道、返回结构必须优先对齐小程序端约定,不要套用后台管理端的接口风格。 +* **禁止**把 Admin 端专属 DTO、权限模型、后台菜单模型直接搬进 MiniApi。 + +## 4. 注释与文档 +* **强制 XML 注释**:所有 `public` 的类、方法、属性必须有 ``。 +* **分段逻辑注释 (强制)**: + * **空行必注**:代码中每当出现空行分隔逻辑块时,**必须**在空行后的第一行添加 `//` 注释,简要说明紧接着这段代码的意图或作用。 + * **步骤化**:对于稍微复杂的业务逻辑,必须结合序号(1., 2., ...)进行标记。 +* **Swagger**: + * 必须保持文档清晰。 + * 是否启用 JWT 鉴权按钮,需以 **当前 MiniApi 的实际鉴权方案** 为准,不要为了套规范而强行接入后台式鉴权。 + +## 5. 异常处理 (防御性编程) +* **禁止空 Catch**:严禁 `catch (Exception) {}`,必须记录日志或抛出。 +* **异常分级**: + * 预期业务错误 -> `BusinessException` + * 参数验证错误 -> `ValidationException` +* **全局响应**:优先通过共享中间件统一转换为标准 JSON 响应。 + +## 6. 异步与日志 +* **全异步**:所有 I/O 操作必须 `await`。**严禁** `.Result` 或 `.Wait()`。 +* **结构化日志**: + * ❌ `_logger.LogInformation("订单 " + id + " 创建成功");` + * ✅ `_logger.LogInformation("订单 {OrderId} 创建成功", id);` +* **脱敏**:严禁打印密码、密钥、支付凭证、Token、会话票据等敏感信息。 + +## 7. 依赖注入 (DI) +* **构造函数注入**:统一使用构造函数注入。 +* **禁止项**: + * ❌ 禁止使用 `[Inject]` 属性注入。 + * ❌ 禁止使用 `ServiceLocator`。 + * ❌ 禁止在静态类中持有 `ServiceProvider`。 + +## 8. 数据访问规范 (重点执行) +### 8.1 Entity Framework Core (写/事务) +1. **无跟踪查询**:只读查询**必须**加 `.AsNoTracking()`。 +2. **杜绝 N+1**:严禁在 `foreach` 循环中查询数据库。 +3. **复杂查询**:关联表超过 2 层时,考虑使用 `.AsSplitQuery()`。 + +### 8.2 Dapper (读/报表) +1. **SQL 注入防御**:**严禁**拼接 SQL 字符串。必须使用参数化查询。 +2. **字段映射**:注意 PostgreSQL (`snake_case`) 与 C# (`PascalCase`) 的映射配置。 + +## 9. 多租户与 ID 策略 +* **ID 生成**: + * **强制**使用 **雪花算法 (Snowflake ID)**。 + * 类型:C# `long` <-> DB `bigint`。 + * **禁止**使用 UUID 或自增 INT。 +* **租户隔离**: + * 所有租户级业务数据都必须考虑 `tenant_id`。 + * 写入时自动填充,读取时强制过滤。 + * MiniApi 默认要优先校验 `X-Tenant-Id` / `X-Tenant-Code` 与当前用户上下文的一致性。 + +## 10. API 设计与序列化 (前端兼容) +* **大整数处理**: + * 所有 `long` 类型 (Snowflake ID) 在 DTO 中**必须序列化为 string**。 +* **DTO 规范**: + * 输入:`XxxRequest` + * 输出:`XxxDto` / `XxxResponse` + * **禁止** Controller 直接返回 Entity。 +* **MiniApi 约定**: + * 优先遵循小程序前端当前约定的字段名、错误码和上下文字段。 + * 涉及 `scene`、`channel`、`tenant` 等字段时,不要擅自发明新枚举值。 + +## 11. 模块化与复用 +* **核心模块划分**:Identity、Tenancy、Dictionary、Storage 等。 +* **公共库 (Shared)**:通用工具类、扩展方法、常量定义必须优先放在 `TakeoutSaaS.BuildingBlocks` 对应共享项目中,避免重复造轮子。 +* **兄弟仓优先复用**:如果 `TakeoutSaaS.TenantApi` 已有成熟实现,优先参考并对齐,不要另起炉灶。 + +## 12. 测试规范 +* **模式**:Arrange-Act-Assert (AAA)。 +* **工具**:xUnit + Moq + FluentAssertions。 +* **覆盖率**:核心 Domain 逻辑必须优先覆盖;Application 层关键 Handler 需要有测试。 + +## 13. Git 工作流 +* **提交格式 (Conventional Commits)**: + * **格式要求**:`: <中文说明>` + * `feat`: 新功能 + * `fix`: 修复 Bug + * `refactor`: 重构 + * `docs`: 文档 + * `style`: 格式调整 +* **分支规范**:`feature/功能名`,`bugfix/问题描述`。 + +## 14. 性能优化 (显式指令) +* **投影查询**:使用 `.Select(x => new Dto { ... })` 只查询需要的字段。 +* **缓存策略**:Cache-Aside 模式。数据更新后必须立即失效缓存。 +* **批量操作**: + * EF Core 10:使用 `ExecuteUpdateAsync` / `ExecuteDeleteAsync` + * Dapper:使用 `ExecuteAsync` 进行批量插入 + +## 15. 安全规范 +* **SQL 注入**:已在第 8 条强制参数化。 +* **身份认证**:MiniApi 默认使用 Session/Token/小程序登录态,按当前服务方案实现。 +* **密码存储**:必须使用 PBKDF2 或 BCrypt 加盐哈希。 +* **签名与幂等**:涉及支付回调、配送回调、消息回调时,必须做签名校验与幂等控制。 + +## 16. 绝对禁止事项 (AI 自检清单) +**生成代码前,请自查是否违反以下红线:** +1. [ ] **SQL 注入**:是否拼接了 SQL 字符串? +2. [ ] **架构违规**:是否在 Controller/Domain 中使用了 DbContext? +3. [ ] **数据泄露**:是否返回了 Entity 或打印了密码/Token? +4. [ ] **同步阻塞**:是否使用了 `.Result` 或 `.Wait()`? +5. [ ] **性能陷阱**:是否在循环中查询了数据库 (N+1)? +6. [ ] **精度丢失**:Long 类型的 ID 是否转为了 String? +7. [ ] **配置硬编码**:是否直接写死了连接串或密钥? +8. [ ] **文档注释**:是否给所有 `public` 类/方法/属性添加了 ``? +9. [ ] **逻辑注释**:是否在每个空行分隔的逻辑块上方添加了说明注释? +10. [ ] **实体违规**:是否私自新增了实体类,而没有先查当前仓和 `TakeoutSaaS.TenantApi`? + +## 17. 现代语法范式 (.NET 10 / C# 14) +> **原则**:拥抱新特性以减少样板代码,但严禁牺牲可读性。 + +1. **主构造函数 (Primary Constructor)**: + * **强制**:依赖注入场景优先使用主构造函数。 + * **禁止**:在主构造函数类中显式定义 `private readonly` 字段来承接参数。 +2. **对象初始化与不可变性**: + * **DTO/Command/Query**:优先使用 `record` 类型。 + * **属性定义**:默认使用 `init`;必填项加 `required`;逻辑变更使用 `with` 表达式。 +3. **集合表达式**: + * **统一**:使用 `[]` 初始化集合。 +4. **模式匹配 (Pattern Matching)**: + * **替代**:避免复杂 `if-else if` 链,优先使用 `switch` 表达式。 +5. **极简语法糖**: + * 多行文本优先使用 Raw String Literal。 + +## 18. 高性能与工程现实约束 +> **原则**:优先写高质量代码,但不得为了追求“极限性能”而违背当前仓库现实。 + +1. **序列化**: + * 优先使用 `System.Text.Json`。 + * 如果当前共享基础设施已统一使用某套序列化方案,**不要局部私自切换**,先与用户确认。 +2. **缓存架构**: + * 优先走统一缓存抽象,不要到处散落直接缓存调用。 +3. **并发模型**: + * 涉及热点路径优化时,再评估 `ValueTask`、`Channel`、`ArrayPool` 等手段,避免过度设计。 + +## 19. 云原生与分布式规则 +1. **健康检查**:必须包含存活与就绪探针意识,至少保证 `/healthz` 可用。 +2. **数据一致性**: + * 领域事件发布优先采用 Outbox 思路,不要直接在业务事务中裸发消息。 +3. **幂等性**: + * 所有消费者或回调处理必须考虑基于业务键或 `MessageId` 的幂等。 +4. **可观测性**: + * 统一输出 OTLP 标准格式 (Metrics/Logs/Traces)。 + * 确保 `TraceId` 在 HTTP Headers 和消息元数据中可透传。 + +--- + +# Working agreements +- 严格遵循上述技术栈和命名规范。 +- 当前仓库默认启动项目为 `src/Api/TakeoutSaaS.MiniApi/TakeoutSaaS.MiniApi.csproj`。 +- 当前仓库默认开发地址为 `http://localhost:2683`。 + +## 20. 工程与依赖约束 +* **构建校验**:每次修改代码后,必须执行 `dotnet build`,确保无错误和警告。 +* **NuGet 版本**:新增包必须使用最新版,未经允许不得进行包降级。 +* **搜索实体前置动作**:一旦需求中出现“实体”“聚合”“持久化模型”“表对应模型”等字样,先搜索当前仓和 `TakeoutSaaS.TenantApi`,再动手写代码。