building-with-medusa
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseMedusa Backend Development
Medusa后端开发
Comprehensive backend development guide for Medusa applications. Contains patterns across 6 categories covering architecture, type safety, business logic placement, and common pitfalls.
这是一份针对Medusa应用的全面后端开发指南,包含6个类别的模式,涵盖架构、类型安全、业务逻辑放置和常见陷阱。
When to Apply
适用场景
Load this skill for ANY backend development task, including:
- Creating or modifying custom modules and data models
- Implementing workflows for mutations
- Building API routes (store or admin)
- Defining module links between entities
- Writing business logic or validation
- Querying data across modules
- Implementing authentication/authorization
Also load these skills when:
- building-admin-dashboard-customizations: Building admin UI (widgets, pages, forms)
- building-storefronts: Calling backend API routes from storefronts (SDK integration)
在进行任何后端开发任务时加载本技能,包括:
- 创建或修改自定义模块和数据模型
- 实现用于变更操作的工作流
- 构建API路由(店铺端或管理端)
- 定义实体之间的模块链接
- 编写业务逻辑或验证规则
- 跨模块查询数据
- 实现认证/授权功能
在以下场景中还需加载对应技能:
- building-admin-dashboard-customizations: 构建管理端UI(组件、页面、表单)
- building-storefronts: 从店铺端调用后端API路由(SDK集成)
CRITICAL: Load Reference Files When Needed
重要提示:按需加载参考文件
The quick reference below is NOT sufficient for implementation. You MUST load relevant reference files before writing code for that component.
Load these references based on what you're implementing:
- Creating a module? → MUST load first
reference/custom-modules.md - Creating workflows? → MUST load first
reference/workflows.md - Creating API routes? → MUST load first
reference/api-routes.md - Creating module links? → MUST load first
reference/module-links.md - Querying data? → MUST load first
reference/querying-data.md - Adding authentication? → MUST load first
reference/authentication.md
Minimum requirement: Load at least 1-2 reference files relevant to your specific task before implementing.
以下快速参考内容不足以支撑实际开发。 在编写对应组件的代码前,你必须加载相关参考文件。
根据开发内容加载对应参考文件:
- 创建模块? → 必须先加载
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个与你的具体任务相关的参考文件。
Critical Architecture Pattern
核心架构模式
ALWAYS follow this flow - never bypass layers:
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)Key conventions:
- Only GET, POST, DELETE methods (never PUT/PATCH)
- Workflows are required for ALL mutations
- Business logic belongs in workflow steps, NOT routes
- Query with for cross-module data retrieval
query.graph() - Query with (Index Module) for filtering across separate modules with links
query.index() - Module links maintain isolation between modules
始终遵循以下流程 - 绝不要跳过任何层级:
模块(数据模型 + CRUD操作)
↓ 被其调用
工作流(业务逻辑 + 支持回滚的变更操作)
↓ 由其执行
API路由(HTTP接口、验证中间件)
↓ 被其调用
前端(管理端后台/店铺端通过SDK调用)关键约定:
- 仅使用GET、POST、DELETE方法(绝不使用PUT/PATCH)
- 所有变更操作都必须使用工作流
- 业务逻辑应放在工作流步骤中,而非路由中
- 使用进行跨模块数据检索
query.graph() - 使用(索引模块)对带链接的独立模块进行过滤查询
query.index() - 模块链接维持模块之间的隔离性
Rule Categories by Priority
按优先级划分的规则类别
| Priority | Category | Impact | Prefix |
|---|---|---|---|
| 1 | Architecture Violations | CRITICAL | |
| 2 | Type Safety | CRITICAL | |
| 3 | Business Logic Placement | HIGH | |
| 4 | Import & Code Organization | HIGH | |
| 5 | Data Access Patterns | MEDIUM (includes CRITICAL price rule) | |
| 6 | File Organization | MEDIUM | |
| 优先级 | 类别 | 影响程度 | 前缀 |
|---|---|---|---|
| 1 | 架构违规 | 严重 | |
| 2 | 类型安全 | 严重 | |
| 3 | 业务逻辑放置 | 高 | |
| 4 | 导入与代码组织 | 高 | |
| 5 | 数据访问模式 | 中(包含1项严重的价格规则) | |
| 6 | 文件组织 | 中 | |
Quick Reference
快速参考
1. Architecture Violations (CRITICAL)
1. 架构违规(严重)
- - Use workflows for ALL mutations, never call module services from routes
arch-workflow-required - - Never bypass layers (route → service without workflow)
arch-layer-bypass - - Use only GET, POST, DELETE (never PUT/PATCH)
arch-http-methods - - Use module links, not direct cross-module service calls
arch-module-isolation - - Don't set explicit
arch-query-config-fieldswhen usingfieldsreq.queryConfig
- - 所有变更操作都使用工作流,绝不要从路由中直接调用模块服务
arch-workflow-required - - 绝不要跳过层级(路由 → 直接调用服务而不经过工作流)
arch-layer-bypass - - 仅使用GET、POST、DELETE(绝不使用PUT/PATCH)
arch-http-methods - - 使用模块链接,而非直接跨模块调用服务
arch-module-isolation - - 使用
arch-query-config-fields时不要显式设置req.queryConfigfields
2. Type Safety (CRITICAL)
2. 类型安全(严重)
- - Pass Zod inferred type to
type-request-schemawhen usingMedusaRequest<T>req.validatedBody - - Use
type-authenticated-requestfor protected routes (notAuthenticatedMedusaRequest)MedusaRequest - - Export both Zod schema AND inferred type from middlewares
type-export-schema - - Never add
type-linkable-autoto data models (automatically added).linkable() - - Module names MUST be camelCase, never use dashes (causes runtime errors)
type-module-name-camelcase
- - 使用
type-request-schema时,将Zod推断的类型传递给req.validatedBodyMedusaRequest<T> - - 受保护的路由使用
type-authenticated-request(而非AuthenticatedMedusaRequest)MedusaRequest - - 从中间件中导出Zod schema及其推断的类型
type-export-schema - - 绝不要给数据模型添加
type-linkable-auto(会自动添加).linkable() - - 模块名称必须为小驼峰式,绝不要使用短横线(会导致运行时错误)
type-module-name-camelcase
3. Business Logic Placement (HIGH)
3. 业务逻辑放置(高)
- - Put business validation in workflow steps, not API routes
logic-workflow-validation - - Validate ownership/permissions in workflows, not routes
logic-ownership-checks - - Keep modules simple (CRUD only), put logic in workflows
logic-module-service
- - 将业务验证放在工作流步骤中,而非API路由中
logic-workflow-validation - - 在工作流中验证所有权/权限,而非路由中
logic-ownership-checks - - 保持模块简洁(仅包含CRUD),将逻辑放在工作流中
logic-module-service
4. Import & Code Organization (HIGH)
4. 导入与代码组织(高)
- - Import workflows/modules at file top, never use
import-top-levelin route bodyawait import() - - Use static imports for all dependencies
import-static-only - - Dynamic imports add overhead and break type checking
import-no-dynamic-routes
- - 在文件顶部导入工作流/模块,绝不要在路由主体中使用
import-top-levelawait import() - - 对所有依赖项使用静态导入
import-static-only - - 动态导入会增加开销并破坏类型检查
import-no-dynamic-routes
5. Data Access Patterns (MEDIUM)
5. 数据访问模式(中)
- - CRITICAL: Prices are stored as-is in Medusa (49.99 stored as 49.99, NOT in cents). Never multiply by 100 when saving or divide by 100 when displaying
data-price-format - - Use
data-query-methodfor retrieving data; usequery.graph()(Index Module) for filtering across linked modulesquery.index() - - Use
data-query-graphfor cross-module queries with dot notation (without cross-module filtering)query.graph() - - Use
data-query-indexwhen filtering by properties of linked data models in separate modulesquery.index() - - Use
data-list-and-countfor single-module paginated querieslistAndCount - -
data-linked-filteringcan't filter by linked module fields - usequery.graph()or query from that entity directlyquery.index() - - Don't use JavaScript
data-no-js-filteron linked data - use database filters (.filter()or query the entity)query.index() - - Can filter by same-module relations with
data-same-module-ok(e.g., product.variants)query.graph() - - Trust
data-auth-middlewaremiddleware, don't manually checkauthenticatereq.auth_context
- - 严重: Medusa中的价格按原样存储(49.99就存储为49.99,而非以分为单位)。保存时绝不要乘以100,展示时绝不要除以100
data-price-format - - 使用
data-query-method检索数据;使用query.graph()(索引模块)对带链接的模块进行过滤查询query.index() - - 使用
data-query-graph通过点语法进行跨模块查询(不包含跨模块过滤)query.graph() - - 当需要按独立模块中关联数据模型的属性进行过滤时,使用
data-query-indexquery.index() - - 单模块分页查询使用
data-list-and-countlistAndCount - -
data-linked-filtering无法按关联模块字段过滤 - 使用query.graph()或直接从对应实体查询query.index() - - 不要对关联数据使用JavaScript的
data-no-js-filter- 使用数据库过滤(.filter()或查询对应实体)query.index() - - 可以使用
data-same-module-ok对同模块关联关系进行过滤(例如product.variants)query.graph() - - 信任
data-auth-middleware中间件,不要手动检查authenticatereq.auth_context
6. File Organization (MEDIUM)
6. 文件组织(中)
- - Recommended: Create steps in
file-workflow-stepssrc/workflows/steps/[name].ts - - Composition functions in
file-workflow-compositionsrc/workflows/[name].ts - - Export schemas and types from middleware files
file-middleware-exports - - Define module links in
file-links-directorysrc/links/[name].ts
- - 推荐:在
file-workflow-steps中创建步骤src/workflows/steps/[name].ts - - 组合函数放在
file-workflow-composition中src/workflows/[name].ts - - 从中间件文件中导出schema和类型
file-middleware-exports - - 在
file-links-directory中定义模块链接src/links/[name].ts
Workflow Composition Rules
工作流组合规则
The workflow function has critical constraints:
typescript
// ✅ 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)
}
)Constraints:
- No async/await (runs at load time)
- No arrow functions (use )
function - No conditionals/ternaries (use )
when() - No variable manipulation (use )
transform() - No date creation (use )
transform() - Multiple step calls need to avoid conflicts
.config({ name: "unique-name" })
工作流函数有严格约束:
typescript
// ✅ 正确示例
const myWorkflow = createWorkflow(
"name",
function (input) { // 普通函数,不要用异步函数或箭头函数
const result = myStep(input) // 不要用await
return new WorkflowResponse(result)
}
)
// ❌ 错误示例
const myWorkflow = createWorkflow(
"name",
async (input) => { // ❌ 不要用异步函数或箭头函数
const result = await myStep(input) // ❌ 不要用await
if (input.condition) { /* ... */ } // ❌ 不要用条件语句
return new WorkflowResponse(result)
}
)约束条件:
- 不要使用async/await(工作流在加载时运行)
- 不要使用箭头函数(使用)
function - 不要使用条件语句/三元表达式(使用)
when() - 不要操作变量(使用)
transform() - 不要创建日期(使用)
transform() - 多次调用步骤时需要添加以避免冲突
.config({ name: "unique-name" })
Common Mistakes Checklist
常见错误检查清单
Before implementing, verify you're NOT doing these:
Architecture:
- Calling module services directly from API routes
- Using PUT or PATCH methods
- Bypassing workflows for mutations
- Setting explicitly with
fieldsreq.queryConfig - Skipping migrations after creating module links
Type Safety:
- Forgetting type argument
MedusaRequest<SchemaType> - Using instead of
MedusaRequestfor protected routesAuthenticatedMedusaRequest - Not exporting Zod inferred type from middlewares
- Adding to data models
.linkable() - Using dashes in module names (must be camelCase)
Business Logic:
- Validating business rules in API routes
- Checking ownership in routes instead of workflows
- Manually checking when middleware already applied
req.auth_context?.actor_id
Imports:
- Using in route handler bodies
await import() - Dynamic imports for workflows or modules
Data Access:
- CRITICAL: Multiplying prices by 100 when saving or dividing by 100 when displaying (prices are stored as-is: $49.99 = 49.99)
- Filtering by linked module fields with (use
query.graph()or query from other side instead)query.index() - Using JavaScript on linked data (use
.filter()or query the linked entity directly)query.index() - Not using for cross-module data retrieval
query.graph() - Using when you need to filter across separate modules (use
query.graph()instead)query.index()
开始开发前,确认你没有犯以下错误:
架构方面:
- 从API路由中直接调用模块服务
- 使用PUT或PATCH方法
- 变更操作跳过工作流
- 使用时显式设置
req.queryConfigfields - 创建模块链接后跳过迁移
类型安全方面:
- 忘记添加类型参数
MedusaRequest<SchemaType> - 受保护路由使用而非
MedusaRequestAuthenticatedMedusaRequest - 没有从中间件中导出Zod推断的类型
- 给数据模型添加
.linkable() - 模块名称使用短横线(必须为小驼峰式)
业务逻辑方面:
- 在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()
Validating Implementation
验证实现
CRITICAL: Always run the build command after completing implementation to catch type errors and runtime issues.
完成开发后,务必运行构建命令以捕获类型错误和运行时问题。
When to Validate
验证时机
- After implementing any new feature
- After making changes to modules, workflows, or API routes
- Before marking tasks as complete
- Proactively, without waiting for the user to ask
- 实现任何新功能后
- 修改模块、工作流或API路由后
- 标记任务完成前
- 主动执行,无需等待用户要求
How to Run Build
如何运行构建
Detect the package manager and run the appropriate command:
bash
npm run build # or pnpm build / yarn build检测包管理器并运行对应命令:
bash
npm run build # 或 pnpm build / yarn buildHandling Build Errors
处理构建错误
If the build fails:
- Read the error messages carefully
- Fix type errors, import issues, and syntax errors
- Run the build again to verify the fix
- Do NOT mark implementation as complete until build succeeds
Common build errors:
- Missing imports or exports
- Type mismatches (e.g., missing type argument)
MedusaRequest<T> - Incorrect workflow composition (async functions, conditionals)
如果构建失败:
- 仔细阅读错误信息
- 修复类型错误、导入问题和语法错误
- 重新运行构建以验证修复
- 构建成功前不要标记开发完成
常见构建错误:
- 缺失的导入或导出
- 类型不匹配(例如缺少类型参数)
MedusaRequest<T> - 工作流组合错误(异步函数、条件语句)
Next Steps - Testing Your Implementation
下一步 - 测试你的实现
After successfully implementing a feature, always provide these next steps to the user:
成功实现功能后,务必向用户提供以下下一步操作指南:
1. Start the Development Server
1. 启动开发服务器
If the server isn't already running, start it:
bash
npm run dev # or pnpm dev / yarn dev如果服务器尚未运行,启动它:
bash
npm run dev # 或 pnpm dev / yarn dev2. Access the Admin Dashboard
2. 访问管理端后台
Open your browser and navigate to:
- Admin Dashboard: http://localhost:9000/app
Log in with your admin credentials to test any admin-related features.
3. Test API Routes
3. 测试API路由
If you implemented custom API routes, list them for the user to test:
Admin Routes (require authentication):
- - Description of what it does
POST http://localhost:9000/admin/[your-route] - - Description of what it does
GET http://localhost:9000/admin/[your-route]
Store Routes (public or customer-authenticated):
- - Description of what it does
POST http://localhost:9000/store/[your-route] - - Description of what it does
GET http://localhost:9000/store/[your-route]
Testing with cURL example:
bash
undefined如果你实现了自定义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测试示例:
bash
undefinedAdmin 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"
-H "Content-Type: application/json"
-H "Authorization: Bearer YOUR_TOKEN"
--cookie "connect.sid=YOUR_SESSION_COOKIE"
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"
-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!"}'
-H "Content-Type: application/json"
-d '{"product_id": "prod_123", "rating": 5, "comment": "Great product!"}'
undefinedcurl -X POST http://localhost:9000/store/reviews
-H "Content-Type: application/json"
-d '{"product_id": "prod_123", "rating": 5, "comment": "Great product!"}'
-H "Content-Type: application/json"
-d '{"product_id": "prod_123", "rating": 5, "comment": "Great product!"}'
undefined4. Additional Testing Steps
4. 额外测试步骤
Depending on what was implemented, mention:
- Workflows: Test mutation operations and verify rollback on errors
- Subscribers: Trigger events and check logs for subscriber execution
- Scheduled jobs: Wait for job execution or check logs for cron output
根据实现的功能,补充说明:
- 工作流: 测试变更操作并验证错误时的回滚功能
- 订阅器: 触发事件并检查日志中订阅器的执行情况
- 定时任务: 等待任务执行或检查日志中的定时任务输出
Format for Presenting Next Steps
下一步操作的展示格式
Always present next steps in a clear, actionable format after implementation:
markdown
undefined完成开发后,始终以清晰、可执行的格式展示下一步操作:
markdown
undefinedImplementation 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
在浏览器中打开 http://localhost:9000/app
Test the API Routes
测试API路由
I've added the following routes:
Admin Routes:
- POST /admin/[route] - [description]
- GET /admin/[route] - [description]
Store Routes:
- POST /store/[route] - [description]
我已添加以下路由:
管理端路由:
- POST /admin/[route] - [描述]
- GET /admin/[route] - [描述]
店铺端路由:
- POST /store/[route] - [描述]
What to Test
测试要点
- [Specific test case 1]
- [Specific test case 2]
- [Specific test case 3]
undefined- [具体测试用例1]
- [具体测试用例2]
- [具体测试用例3]
undefinedHow to Use
使用方法
For detailed patterns and examples, load reference files:
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 solutionsEach reference file contains:
- Step-by-step implementation checklists
- Correct vs incorrect code examples
- TypeScript patterns and type safety
- Common pitfalls and solutions
如需详细模式和示例,加载参考文件:
reference/custom-modules.md - 带数据模型的模块创建
reference/workflows.md - 工作流创建和步骤模式
reference/api-routes.md - API路由结构和验证
reference/module-links.md - 跨模块实体链接
reference/querying-data.md - 查询模式和过滤规则
reference/authentication.md - 路由保护和用户访问
reference/error-handling.md - MedusaError类型和模式
reference/scheduled-jobs.md - 定时任务和周期性任务
reference/subscribers-and-events.md - 事件处理
reference/troubleshooting.md - 常见错误和解决方案每个参考文件包含:
- 分步开发检查清单
- 正确/错误代码示例对比
- TypeScript模式和类型安全
- 常见陷阱和解决方案
When to Use This Skill vs MedusaDocs MCP Server
何时使用本技能 vs MedusaDocs MCP Server
⚠️ CRITICAL: This skill should be consulted FIRST for planning and implementation.
Use this skill for (PRIMARY SOURCE):
- Planning - Understanding how to structure Medusa backend features
- Architecture - Module → Workflow → API Route patterns
- Best practices - Correct vs incorrect code patterns
- Critical rules - What NOT to do (common mistakes and anti-patterns)
- Implementation patterns - Step-by-step guides with checklists
Use MedusaDocs MCP server for (SECONDARY SOURCE):
- Specific method signatures after you know which method to use
- Built-in module configuration options
- Official type definitions
- Framework-level configuration details
Why skills come first:
- Skills contain opinionated guidance and anti-patterns MCP doesn't have
- Skills show architectural patterns needed for planning
- MCP is reference material; skills are prescriptive guidance
⚠️ 重要:规划和开发时应首先参考本技能。
本技能适用场景(主要来源):
- 规划 - 了解如何构建Medusa后端功能的结构
- 架构 - 模块 → 工作流 → API路由的模式
- 最佳实践 - 正确/错误代码模式对比
- 关键规则 - 禁止操作(常见错误和反模式)
- 开发模式 - 带检查清单的分步指南
MedusaDocs MCP Server适用场景(次要来源):
- 确定使用哪个方法后,查询具体的方法签名
- 内置模块配置选项
- 官方类型定义
- 框架级配置细节
为什么优先使用技能:
- 技能包含MCP未提供的指导性建议和反模式
- 技能展示规划所需的架构模式
- MCP是参考资料;技能是规范性指南
Integration with Frontend Applications
与前端应用的集成
When building features that span backend and frontend:
For Admin Dashboard:
- Backend (this skill): Module → Workflow → API Route
- Frontend: Load skill
building-admin-dashboard-customizations - Connection: Admin widgets call custom API routes via
sdk.client.fetch()
For Storefronts:
- Backend (this skill): Module → Workflow → API Route
- Frontend: Load skill
building-storefronts - Connection: Storefront calls custom API routes via
sdk.client.fetch()
See respective frontend skills for complete integration patterns.
构建跨前后端的功能时:
管理端后台:
- 后端(本技能): 模块 → 工作流 → API路由
- 前端: 加载技能
building-admin-dashboard-customizations - 连接方式: 管理端组件通过调用自定义API路由
sdk.client.fetch()
店铺端:
- 后端(本技能): 模块 → 工作流 → API路由
- 前端: 加载技能
building-storefronts - 连接方式: 店铺端通过调用自定义API路由
sdk.client.fetch()
查看对应前端技能获取完整集成模式。