关于 building-with-medusa
building-with-medusa 是为 Medusa 后端开发者提供的技能,涵盖架构、类型安全、业务逻辑和数据访问,并按任务指向参考文件及实现检查步骤。
主要功能
- 01涵盖六类后端开发规范
- 02说明架构与分层约定
- 03提供类型安全和数据访问规则
- 04按任务指引相关参考文件
- 05列出构建与 lint 验证步骤
适用场景
- 01创建 Medusa 自定义模块
- 02实现变更工作流或 API 路由
- 03查询跨模块关联数据
- 04检查后端代码中的常见问题
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ medusajs/ medusa-agent-skills --skill building-with-medusa安装后在 Claude Code 中输入/building-with-medusa确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
reference/api-routes.mdauthentication.mdcustom-modules.mddata-models.mderror-handling.mdfrontend-integration.mdmodule-links.mdquerying-data.mdscheduled-jobs.mdsubscribers-and-events.mdtroubleshooting.mdworkflow-hooks.mdworkflows.md详细介绍
Medusa 后端开发
Medusa 应用的完整后端开发指南。涵盖 6 个类别中的常见模式,包括架构、类型安全、业务逻辑放置位置和常见陷阱。
适用场景
任何后端开发任务都要加载此技能,包括:
- 创建或修改自定义模块和数据模型
- 为变更实现工作流
- 构建 API 路由(商店或管理后台)
- 定义实体间的模块链接
- 编写业务逻辑或验证
- 跨模块查询数据
- 实现身份验证/授权
以下情况也要加载这些技能:
- building-admin-dashboard-customizations: 构建管理后台 UI(小组件、页面、表单)
- building-storefronts: 从店面调用后端 API 路由(SDK 集成)
重要:按需加载参考文件
以下快速参考不足以用于实现。 编写相关组件的代码前,必须加载相应的参考文件。
根据要实现的内容加载参考文件:
- 创建模块? → 必须先加载
reference/custom-modules.md - 创建工作流? → 必须先加载
reference/workflows.md - 创建 API 路由? → 必须先加载
reference/api-routes.md - 创建模块链接? → 必须先加载
reference/module-links.md - 查询数据? → 必须先加载
reference/querying-data.md - 添加身份验证? → 必须先加载
reference/authentication.md
最低要求: 实现前,至少加载 1-2 个与具体任务相关的参考文件。
核心架构模式
始终遵循此流程,绝不绕过任何层:
Module (data models + CRUD operations)
↓ used by
Workflow (business logic + mutations with rollback)
↓ executed by
API Route (HTTP interface, validation middleware)
↓ called by
Frontend (admin dashboard/storefront via SDK)
关键约定:
- 仅使用 GET、POST、DELETE 方法(绝不使用 PUT/PATCH)
- 所有变更都必须使用工作流
- 业务逻辑应放在工作流步骤中,而非路由中
- 使用
query.graph()跨模块检索数据 - 使用
query.index()(Index Module)通过链接筛选不同模块中的数据 - 模块链接用于保持模块间隔离
按优先级划分的规则类别
| 优先级 | 类别 | 影响 | 前缀 |
|---|---|---|---|
| 1 | 架构违规 | 严重 | arch- |
| 2 | 类型安全 | 严重 | type- |
| 3 | 业务逻辑放置位置 | 高 | logic- |
| 4 | 导入与代码组织 | 高 | import- |
| 5 | 数据访问模式 | 中(包含严重的价格规则) | data- |
| 6 | 文件组织 | 中 | file- |
快速参考
1. 架构违规(严重)
arch-workflow-required- 所有变更都使用工作流,绝不从路由调用模块服务arch-layer-bypass- 绝不绕过任何层(路由 → 服务,未经过工作流)arch-http-methods- 仅使用 GET、POST、DELETE(绝不使用 PUT/PATCH)arch-module-isolation- 使用模块链接,切勿直接跨模块调用服务arch-query-config-fields- 使用req.queryConfig时不要设置显式的fields
2. 类型安全(严重)
type-request-schema- 使用req.validatedBody时,将 Zod 推导类型传给MedusaRequest<T>type-authenticated-request- 受保护的路由使用AuthenticatedMedusaRequest(而非MedusaRequest)type-export-schema- 从中间件导出 Zod schema 和推导类型type-linkable-auto- 绝不要在数据模型中添加.linkable()(会自动添加)type-module-name-camelcase- 模块名称必须使用 camelCase,绝不使用连字符(会导致运行时错误)
3. 业务逻辑放置位置(高)
logic-workflow-validation- 将业务验证放在工作流步骤中,而非 API 路由中logic-ownership-checks- 在工作流中验证所有权/权限,而非路由中logic-module-service- 保持模块简单(仅执行 CRUD),将逻辑放在工作流中
4. 导入与代码组织(高)
import-top-level- 在文件顶部导入工作流/模块,绝不要在路由主体中使用await import()import-static-only- 所有依赖都使用静态导入import-no-dynamic-routes- 动态导入会增加开销并破坏类型检查import-zod-framework- 从@medusajs/framework/zod导入 Zod,绝不要直接从zod导入。Medusa 使用 Zod v4(自 v2.14.0 起):使用z.email()/z.url()/z.uuid(),而不是z.string().email()等;使用.extend(other.shape),而不是.merge(other);使用z.strictObject()/z.looseObject(),而不是.strict()/.passthrough();使用z.enum(MyEnum),而不是z.nativeEnum();使用z.record(z.string(), value),而不是z.record(value)
5. 数据访问模式(中)
data-price-format- 关键:Medusa 中的价格按原样存储(49.99 存储为 49.99,而不是以分为单位)。保存时绝不要乘以 100,显示时也绝不要除以 100data-query-method- 使用query.graph()检索数据;使用query.index()(Index 模块)筛选关联模块中的数据data-query-graph- 使用query.graph()通过点号表示法进行跨模块查询(不进行跨模块筛选)data-query-index- 按独立模块中关联数据模型的属性筛选时,使用query.index()data-list-and-count- 单模块分页查询使用listAndCountdata-linked-filtering-query.graph()无法按关联模块的字段筛选;请使用query.index(),或直接从该实体查询data-no-js-filter- 不要对关联数据使用 JavaScript.filter();请使用数据库筛选器(query.index()或直接查询该实体)data-same-module-ok- 可以使用query.graph()按同一模块中的关联关系筛选(例如 product.variants)data-auth-middleware- 信任authenticate中间件,不要手动检查req.auth_context
6. 文件组织(中)
file-workflow-steps- 建议:在src/workflows/steps/[name].ts中创建步骤file-workflow-composition- 在src/workflows/[name].ts中编写组合函数file-middleware-exports- 从中间件文件导出架构和类型file-links-directory- 在src/links/[name].ts中定义模块链接
工作流组合规则
工作流函数有严格限制:
// ✅ CORRECT
const myWorkflow = createWorkflow(
"name",
function (input) { // Regular function, not async, not arrow
const result = myStep(input) // No await
return new WorkflowResponse(result)
}
)
// ❌ WRONG
const myWorkflow = createWorkflow(
"name",
async (input) => { // ❌ No async, no arrow functions
const result = await myStep(input) // ❌ No await
if (input.condition) { /* ... */ } // ❌ No conditionals
return new WorkflowResponse(result)
}
)
限制:
- 不要使用 async/await(在加载时运行)
- 不要使用箭头函数(请使用
function) - 不要使用条件语句/三元表达式(请使用
when()) - 不要操作变量(请使用
transform()) - 不要创建日期(请使用
transform()) - 多次调用步骤时需要使用
.config({ name: "unique-name" })以避免冲突
常见错误检查清单
在实现之前,请确认你没有犯以下错误:
架构:
- 在 API 路由中直接调用模块服务
- 使用 PUT 或 PATCH 方法
- 绕过工作流执行变更
- 使用
req.queryConfig显式设置fields - 创建模块链接后跳过迁移
类型安全:
- 忘记提供
MedusaRequest<SchemaType>类型参数 - 对受保护路由使用
MedusaRequest,而不是AuthenticatedMedusaRequest - 未从中间件导出 Zod 推断类型
- 向数据模型添加
.linkable() - 在模块名称中使用连字符(必须使用 camelCase)
业务逻辑:
- 在 API 路由中验证业务规则
- 在路由中检查所有权,而不是在工作流中检查
- 中间件已生效时,仍手动检查
req.auth_context?.actor_id
导入:
- 在路由处理函数体中使用
await import() - 对工作流或模块使用动态导入
数据访问:
- **重要:**保存价格时乘以 100,或显示价格时除以 100(价格按原值存储:$49.99 = 49.99)
- 使用
query.graph()按关联模块字段筛选(应改用query.index(),或从另一侧查询) - 对关联数据使用 JavaScript
.filter()(应改用query.index(),或直接查询关联实体) - 未使用
query.graph()检索跨模块数据 - 需要跨独立模块筛选时使用
query.graph()(应改用query.index())
验证实现
重要:完成实现后,务必运行构建命令,以发现类型错误和运行时问题。
何时验证
- 实现任何新功能后
- 修改模块、工作流或 API 路由后
- 将任务标记为完成之前
- 主动验证,不要等用户要求
如何运行构建
检测包管理器并运行相应命令:
npm run build # or pnpm build / yarn build
处理构建错误
如果构建失败:
- 仔细阅读错误消息
- 修复类型错误、导入问题和语法错误
- 再次运行构建以确认修复
- 构建成功之前,不要将实现标记为完成
常见构建错误:
- 缺少导入或导出
- 类型不匹配(例如,缺少
MedusaRequest<T>类型参数) - 工作流组合不正确(异步函数、条件判断)
代码检查
从 Medusa v2.16.0 起,项目可以安装 @medusajs/eslint-plugin。它可以检查 Medusa 约定相关问题(API 路由、订阅者、计划任务、管理端自定义项、模块模式),这些问题无法通过类型检查发现。
- 如果项目有包含
@medusajs/eslint-plugin的eslint.config.*,medusa build和medusa develop默认会运行代码检查,并在检查出错时失败。请修复代码检查错误,而不是传入--no-lint。 - 使用
npx medusa lint显式运行代码检查(支持--fix和--quiet)。实现功能后,请与构建一并运行代码检查。 - 如果项目没有 ESLint 配置,建议添加配置(将
@medusajs/eslint-plugin、eslint和jiti作为开发依赖,然后添加一个导出defineConfig([...medusa.configs.recommended])的eslint.config.ts)——但不要擅自添加。
后续步骤 - 测试实现
成功实现功能后,务必向用户提供以下后续步骤:
1. 启动开发服务器
如果服务器尚未运行,请启动它:
npm run dev # or pnpm dev / yarn dev
2. 访问管理控制面板
打开浏览器并访问:
- 管理控制面板: http://localhost:9000/app
使用管理员凭据登录,测试与管理功能相关的特性。
3. 测试 API 路由
如果你实现了自定义 API 路由,请列出供用户测试:
管理路由(需要身份验证):
POST http://localhost:9000/admin/[your-route]- 说明其功能GET http://localhost:9000/admin/[your-route]- 说明其功能
商店路由(公开或需要客户身份验证):
POST http://localhost:9000/store/[your-route]- 说明其功能GET http://localhost:9000/store/[your-route]- 说明其功能
使用 cURL 测试的示例:
# Admin route (requires authentication)
curl -X POST http://localhost:9000/admin/reviews/123/approve \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_TOKEN" \
--cookie "connect.sid=YOUR_SESSION_COOKIE"
# Store route
curl -X POST http://localhost:9000/store/reviews \
-H "Content-Type: application/json" \
-d '{"product_id": "prod_123", "rating": 5, "comment": "Great product!"}'
4. 其他测试步骤
根据实现内容,说明:
- 工作流: 测试变更操作,并验证出错时是否回滚
- 订阅者: 触发事件,并检查日志以确认订阅者是否执行
- 定时任务: 等待任务执行,或检查日志中的 cron 输出
后续步骤的呈现格式
实现完成后,始终以清晰、可执行的格式呈现后续步骤:
## Implementation Complete
The [feature name] has been successfully implemented. Here's how to test it:
### Start the Development Server
[server start command based on package manager]
### Access the Admin Dashboard
Open http://localhost:9000/app in your browser
### Test the API Routes
I've added the following routes:
**Admin Routes:**
- POST /admin/[route] - [description]
- GET /admin/[route] - [description]
**Store Routes:**
- POST /store/[route] - [description]
### What to Test
1. [Specific test case 1]
2. [Specific test case 2]
3. [Specific test case 3]
如何使用
如需查看详细模式和示例,请加载参考文件:
reference/custom-modules.md - Creating modules with data models
reference/workflows.md - Workflow creation and step patterns
reference/api-routes.md - API route structure and validation
reference/module-links.md - Linking entities across modules
reference/querying-data.md - Query patterns and filtering rules
reference/authentication.md - Protecting routes and accessing users
reference/error-handling.md - MedusaError types and patterns
reference/scheduled-jobs.md - Cron jobs and periodic tasks
reference/subscribers-and-events.md - Event handling
reference/troubleshooting.md - Common errors and solutions
每个参考文件都包含:
- 分步实施清单
- 正确与错误的代码示例
- TypeScript 模式和类型安全
- 常见陷阱及解决方案
何时使用此 Skill,何时使用 MedusaDocs MCP Server
⚠️ 重要:规划和实施时应首先查阅此 Skill。
在以下场景使用此 Skill(主要来源):
- 规划 - 了解如何构建 Medusa 后端功能
- 架构 - Module → Workflow → API Route 模式
- 最佳实践 - 正确与错误的代码模式
- 关键规则 - 不应采取的做法(常见错误和反模式)
- 实施模式 - 附带清单的分步指南
在以下场景使用 MedusaDocs MCP server(次要来源):
- 确定要使用的方法后,查询特定的方法签名
- 内置模块的配置选项
- 官方类型定义
- 框架级配置详情
技能优先的原因:
- Skill 包含 MCP 不具备的指导原则和反模式
- Skill 展示规划所需的架构模式
- MCP 是参考资料;Skill 提供规范性指导
与前端应用集成
⚠️ 重要:前端应用必须使用 Medusa JS SDK 发送所有 API 请求
构建涉及后端和前端的功能时:
对于管理后台:
- 后端(此 Skill): Module → Workflow → API Route
- 前端: 加载
building-admin-dashboard-customizationsSkill - 连接方式:
- 内置端点:使用现有 SDK 方法(
sdk.admin.product.list()) - 自定义 API 路由:使用
sdk.client.fetch("/admin/my-route") - 切勿使用普通的 fetch()——缺少身份验证标头会导致错误
- 内置端点:使用现有 SDK 方法(
对于商店前台:
- 后端(此 Skill): Module → Workflow → API Route
- 前端: 加载
building-storefrontsSkill - 连接方式:
- 内置端点:使用现有 SDK 方法(
sdk.store.product.list()) - 自定义 API 路由:使用
sdk.client.fetch("/store/my-route") - 切勿使用普通的 fetch()——缺少可发布 API 密钥会导致错误
- 内置端点:使用现有 SDK 方法(
必须使用 SDK 的原因:
- 商店路由需要
x-publishable-api-key标头 - 管理路由需要
Authorization和会话标头 - SDK 会自动处理所有必需的标头
- 不带标头的普通 fetch() → 身份验证/授权错误
完整的集成模式请参阅相应的前端 Skill。