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
최근 소스 활동
2026년 9월 11일 03:51
감지된 SKILL.md 언어
중국어
스타
11
포크
3

설치 방법

기본적으로 소스를 먼저 확인하는 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에서 보기