Skip to main content

moai-cqrs-backend

Backend CQRS three-layer code standards for MoAI (.NET 9, Maomi modules, MediatR, EF Core). Use when adding/modifying Commands, Queries, Handlers, Controllers, validators, or business rules in src/*. 仅限 MoAI 项目。Use only for the MoAI project.

الانتقال إلى التثبيت

معلومات المصدر

المستودع
whuanle/moai
آخر نشاط في المصدر
١١ سبتمبر ٢٠٢٦ في ٠٣:٥١
لغة SKILL.md المكتشفة
الصينية
النجوم
١١
التفرعات
٣

خيارات التثبيت

يُحدَّد Prompt الذي يراجع المصدر أولًا بشكل افتراضي. يمكنك التبديل إلى أمر مباشر أو تنزيل نسخة محلية.

مراجعة ملفات المصدر

اقرأ SKILL.md وأي ملفات مرافقة يعرضها SkillsMP قبل أن تقرر التثبيت.

عرض SKILL.md

SKILL.md
تعليمات المصدر · معاينة للقراءة فقط
name
moai-cqrs-backend
description
Backend CQRS three-layer code standards for MoAI (.NET 9, Maomi modules, MediatR, EF Core). Use when adding/modifying Commands, Queries, Handlers, Controllers, validators, or business rules in src/*. 仅限 MoAI 项目。Use only for the MoAI project.
# MoAI 后端 CQRS 三层规范(L2) ## PROJECT SCOPE 只服务 MoAI 后端 `src/`。**REQUIRED REFERENCE:改代码前必读 [docs/cqrs-conventions.md](../../../docs/cqrs-conventions.md)(唯一真源,含完整代码模板与命名规范)。** 本 skill 只写执行要点与实踩坑。 ## WHEN - 新增/修改 Command、Query、Handler、Controller、校验 - 涉及 `src/<module>/MoAI.<Module>.{Shared,Core,Api}` 任一层的改动 ## WHAT 按三层依赖(`Api → Core → Shared`)产出合规范的 CQRS 代码,构建 0 错。 ## HOW ### 0. 先找范本 `rg` 找同域代码读真实实现。最佳完整范本:**user-management**(`src/account/` 的 UpdateUserIsAdminCommand 全链路)。 ### 1. 目录与命名(细则见真源 §目录结构/命名规范) | 项 | 规范 | |---|---| | Command | `{动作}{实体}Command.cs`,命名空间 `MoAI.{Domain}.Commands` | | Query | `Query{实体}{描述}Command.cs`,命名空间 `MoAI.{Domain}.Queries` | | Handler | `{Command/Query名}Handler.cs`;Command 在 `Handlers/`,Query 在 `Queries/` | | Response | `{Query名}Response.cs` / `{Query名}ResponseItem.cs`,在 `Queries/Responses/` | | 复杂模块 | 可按子领域建子目录(参照 `MoAI.Plugin.Shared/Classify/...`) | ### 2. Shared 层要点 - Command/Query 都继承 `IModelValidator<T>`(FluentValidation 静态 `Validate`),提前拦截无效请求 - ⚠️ **路由参数时序坑**:`{id}` 由 Controller 回填,自动验证发生在回填之前——Validate 里只能校验请求体字段,校验路由回填字段 = 接口恒 400(oauthconnect PUT 实踩) - 需要用户上下文的命令继承 `IUserIdContext`(`ContextUserId`/`ContextUserType`);用不到就别继承 - ⚠️ `IUserIdContext` 的两个属性**必须加 `[JsonIgnore]`**:否则会作为查询参数/请求体字段进入 OpenAPI,进而出现在 Kiota 生成的客户端里(查询型命令尤其明显)。仓库先例:`PagedParamter` 对内部属性同样加 `[JsonIgnore]`。Handler 侧读 `request.ContextUserId`,不要注入 `IUserContextProvider` - 分页继承 `PagedParamter`(上限 1000);写命令响应统一 `EmptyCommandResponse` - 公开成员全部中文 XML 注释(StyleCop 强制) ### 3. Core 层要点 - Handler 构造注入 `DatabaseContext` + 领域服务;**禁止注入 IUserContextProvider/UserContext**(用户信息只能经 Command 的 IUserIdContext 传入) - 实体审计属性(CreateUserId/CreateTime/UpdateUserId/UpdateTime/IsDeleted)框架自动注入,**不要手动赋值**;软删除字段 `IsDeleted` 类型是 **long**(0=未删),查询记得 `IsDeleted == 0`,勿写成 bool - 目标保护依赖 DB 事实:root 判定 = `setting` 表 `key="root"` 的 value - 业务异常:`throw new BusinessException("中文消息.") { StatusCode = 400/403/404/409 }`,禁止裸 500 - ⚠️ **写用户相关数据后必须 `RemoveUserStateAsync`** 失效 Redis 用户态(禁用/降权即时生效依赖此) ### 4. Api 层要点 - Controller 只做门禁 + 转发,无业务逻辑 - 角色门禁在 Controller(`EnsureAdminAsync`/`EnsureRootAsync` 私有方法,查 `GetUserStateAsync`,非 403 即抛);目标保护在 Handler - 路由参数显式回填 + `_userContextProvider.SetUserContext(cmd)` 后再 `_mediator.Send` - 用户上下文只经 `IUserContextProvider.GetUserContext()`,不直接注入 UserContext ### 5. 模块注册 三层各有 `{Domain}SharedModule`/`{Domain}CoreModule`/`{Domain}ApiModule`(`IModule`,Core 用 `[InjectModule<...>]` 声明依赖,模板见真源 §模块注册)。 ## REFERENCE 正例:`UpdateUserIsAdminCommand` 全链路(Shared 定义 → Handler 目标保护+缓存失效 → Controller EnsureRoot+回填)。 ## LIMITS - 不含前端规范(`L2-code-standards/moai-frontend-ui`);审查清单(`L3-fix-standards/moai-cqrs-review`) - 不做迁移/DDL、部署
عرض على GitHub