# Moai Feature

> Orchestrate a full-stack feature in the MoAI project (backend CQRS module + frontend page + i18n + verification). Use when the user asks to add a feature module, API endpoint, or management page, or says "做XX功能/新增接口/加个管理页". 仅限 MoAI 项目。Use only for the MoAI project.

- Skill: `whuanle/moai-feature` (Agent Skill)
- Install (CLI): `npx skillmds@latest add whuanle/moai-feature`
- Raw SKILL.md: https://api.skillmd.com/api/skills/whuanle/moai-feature/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Web & Frontend
- Author: whuanle (https://skillmd.com/u/whuanle)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/whuanle/moai-feature

---


# MoAI 全栈新功能编排（L1）

## PROJECT SCOPE

只服务 MoAI 项目（`/Users/wen/project/maomi/moai`）。本 skill 是**调度入口**，不承载代码细则——细则在 L2 两个分层 skill，铁律审查在 L3。

## WHEN

- "做 XX 功能"、"前后端一起做 XX"、"新增一个接口 + 页面"
- "给管理后台加个 XX 模块"

## WHAT

把一个功能需求拆成 后端 → API 同步 → 前端 → 验证 四步，调度对应分层 skill 执行，最终交付全绿。

## HOW

1. **澄清需求**：资源名、字段、谁有权操作（admin/root/所有人）、是否需要管理页。
2. **后端** → 按 `L2-code-standards/moai-cqrs-backend` 执行（Shared/Core/Api 三层）。
3. **API 同步**：先起后端，再生成客户端。**必须带 `CODEBUDDY_SAFE_DELETE_ENABLED=0`**——`npm run syncapi` 会 `rmSync(ui/src/api/client)` 重建，否则被 safe-delete 拦截而中止：
   ```bash
   cd src/MoAI && ASPNETCORE_ENVIRONMENT=Development ASPNETCORE_URLS=http://localhost:5000 \
     dotnet run --project MoAI.csproj --no-build --no-restore   # openapi: /openapi/v1.json
   cd ui && CODEBUDDY_SAFE_DELETE_ENABLED=0 npm run syncapi
   ```
   用 `dotnet run --project ...`，别用 `dotnet MoAI.dll`（dll 在 `bin/Debug/net10.0/`，且 content root 不对会读不到 `appsettings.Development.json`）。
   端口不同则给 syncapi 显式传参；后端实在起不来可用 `src/MoAI/MoAI.json` 离线生成。细节见 `docs/api_interface.md`。
4. **前端** → 按 `L2-code-standards/moai-frontend-ui` 执行（api 封装 + 页面 + i18n + 测试）。
5. **验证**（全绿才算完成）：
   ```bash
   dotnet build src/MoAI/MoAI.csproj --no-restore    # 0 error
   cd ui && npm run typecheck && npm run lint && npm run test
   # e2e 按模块选：node local-dev/app-e2e.mjs 等（需后端运行中）
   ```
   ⚠️ **NuGet 还原失败时不要急着放弃**：本机若报 `NuGet ... Value cannot be null. (Parameter 'path1')`
   （根因 NuGet `ConfigurationDefaults` 静态构造取不到系统目录），`dotnet restore` 与不带 `--no-restore` 的 build 会挂，
   但 **`dotnet build <proj> --no-restore` 在已还原过的项目上可用**：2026-09 实测 `src/MoAI` 宿主、`src/app`、`src/database`
   都能 0 error 编译并 `dotnet run` 起服务（能起才能跑 syncapi 与 E2E）。
   所以顺序是「先按 `--no-restore` + `dotnet run` 试」→ 真编不过才如实标注「后端 build / E2E 待系统终端复验」并把命令清单交给用户。
   不要伪造 `obj/project.assets.json`。另注意：对**未改动**项目 `--no-restore` 会**增量跳过**而显示 0 error，别当成编译通过。
   ⚠️ 也别用 `-t:Rebuild` 兜底：它会先 `Clean` 掉 `obj/project.assets.cache`，逼 `ResolvePackageAssets` 重跑 → NuGet 必挂。
   取真实编译证据的可行做法（2026-09-11 实测）：`dotnet build <proj> --no-restore -p:GenerateDependencyFile=false`
   会连带把依赖项目一起过 Csc，既拿 0 error 也能看到真实告警；改过的文件先 `touch` 再编，避免被增量跳过。
   ⚠️ `-t:CoreCompile` **单独执行不可信**——不解析引用，会误报成片 `CS0400/CS0246`（连 `System`/`Maomi` 都「找不到」），
   别按它的输出判断有没有改坏。<br>
   ⚠️ 另：`obj/**` 下的中间产物别删（如 `obj/Debug/net10.0/<X>.dll`），会毁掉 obj 状态并让后续编译出现假错误。
6. **功能依赖外部 HTTP 服务时的验证**（自带「桩服务」跑真实后端，无需真实 Key / 不消耗额度）：
   1) 先让上游地址可配置（如博查 `MoAI:BoCha:Endpoint`，默认官方地址），否则 `BaseAddress` 硬编码、无法指向桩；
   2) 写一个 node 脚本自起桩服务回放厂商文档样例报文，再 `spawn('dotnet', ['run','--project','src/MoAI/MoAI.csproj','--no-build','--no-restore'])`
      拉起独立后端（env 传 `MoAI__Port` 换端口、`MoAI__BoCha__Endpoint` 指向桩），`taskkill /pid <pid> /T /F` 收尾；
   3) 断言要覆盖「参数怎么下去 + 结果怎么解析上来」两侧。范例：`local-dev/bocha-search-e2e.mjs`（22 断言）。
   注意沙箱**禁止用编译器直接编译任意 C# 代码**，临时「桩客户端单测」走不通，只能用这种方式。
   另注意本机 shell 的 `http_proxy/https_proxy`：`curl` 探活要加 `--noproxy '*'`；.NET 请求行会变 absolute-form，
   桩服务必须 `new URL(req.url, 'http://x').pathname` 再匹配路径。
7. **审查**：改动多时按 `L3-fix-standards/moai-cqrs-review` 清单过一遍。
8. **回填**：踩到新坑 → 登记 Obsidian `99-问题台账`；沉淀新流程 → 按 `skills/README.md` 新增规则落新 skill。

## REFERENCE

正例：user-management 全链路（后端 34 e2e 场景 + 前端 /users 页 + 3 组件测试）。

## LIMITS

- 不承载代码细则——后端看 `L2-code-standards/moai-cqrs-backend`，前端看 `L2-code-standards/moai-frontend-ui`。
- 纯 bug 修复/review 直接进 `L3-fix-standards/moai-cqrs-review`，不必走本编排。
- 不做数据库迁移、部署（超出当前分层体系范围时先问）。

