building-with-medusa by medusajs/medusa-agent-skills
npx skills add https://github.com/medusajs/medusa-agent-skills --skill building-with-medusa适用于 Medusa 应用程序的全面后端开发指南。包含 6 个类别的模式,涵盖架构、类型安全、业务逻辑放置和常见陷阱。
执行任何后端开发任务时都应加载此技能,包括:
在以下情况也应加载此技能:
下面的快速参考不足以用于实现。 在为某个组件编写代码之前,必须加载相关的参考文件。
根据你要实现的内容加载这些参考:
reference/custom-modules.mdreference/workflows.md广告位招租
在这里展示您的产品或服务
触达数万 AI 开发者,精准高效
reference/api-routes.mdreference/module-links.mdreference/querying-data.mdreference/authentication.md最低要求: 在实现之前,至少加载 1-2 个与你的具体任务相关的参考文件。
始终遵循此流程 - 切勿绕过层级:
Module (数据模型 + CRUD 操作)
↓ 被...使用
Workflow (业务逻辑 + 带回滚的变更操作)
↓ 由...执行
API Route (HTTP 接口,验证中间件)
↓ 被...调用
Frontend (通过 SDK 的管理面板/商店前端)
关键约定:
query.graph() 进行跨模块数据检索query.index()(索引模块)对通过链接关联的独立模块进行过滤| 优先级 | 类别 | 影响 | 前缀 |
|---|---|---|---|
| 1 | 架构违规 | 关键 | arch- |
| 2 | 类型安全 | 关键 | type- |
| 3 | 业务逻辑放置 | 高 | logic- |
| 4 | 导入与代码组织 | 高 | import- |
| 5 | 数据访问模式 | 中(包含关键的价格规则) | data- |
| 6 | 文件组织 | 中 | file- |
arch-workflow-required - 所有变更操作都使用工作流,切勿从路由直接调用模块服务arch-layer-bypass - 切勿绕过层级(路由 → 服务而不经过工作流)arch-http-methods - 仅使用 GET、POST、DELETE(切勿使用 PUT/PATCH)arch-module-isolation - 使用模块链接,而非直接的跨模块服务调用arch-query-config-fields - 使用 req.queryConfig 时,不要显式设置 fieldstype-request-schema - 使用 req.validatedBody 时,将 Zod 推断的类型传递给 MedusaRequest<T>type-authenticated-request - 对于受保护的路由,使用 AuthenticatedMedusaRequest(而非 MedusaRequest)type-export-schema - 从中间件导出 Zod 模式和推断的类型type-linkable-auto - 切勿向数据模型添加 .linkable()(会自动添加)type-module-name-camelcase - 模块名称必须是 camelCase,切勿使用短横线(会导致运行时错误)logic-workflow-validation - 将业务验证放在工作流步骤中,而非 API 路由中logic-ownership-checks - 在工作流中验证所有权/权限,而非在路由中logic-module-service - 保持模块简单(仅 CRUD),将逻辑放在工作流中import-top-level - 在文件顶部导入工作流/模块,切勿在路由主体中使用 await import()import-static-only - 对所有依赖项使用静态导入import-no-dynamic-routes - 动态导入会增加开销并破坏类型检查data-price-format - 关键:价格在 Medusa 中按原样存储(49.99 存储为 49.99,不是以分为单位)。保存时切勿乘以 100,显示时切勿除以 100data-query-method - 使用 query.graph() 检索数据;使用 query.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_contextfile-workflow-steps - 推荐:在 src/workflows/steps/[name].ts 中创建步骤file-workflow-composition - 在 src/workflows/[name].ts 中编写组合函数file-middleware-exports - 从中间件文件导出模式和类型file-links-directory - 在 src/links/[name].ts 中定义模块链接工作流函数有严格的约束:
// ✅ 正确
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)
}
)
约束:
function)when())transform())transform()).config({ name: "unique-name" }) 以避免冲突在实现之前,请确认你没有做以下事情:
架构:
req.queryConfig 时显式设置 fields类型安全:
MedusaRequest<SchemaType> 类型参数MedusaRequest 而非 AuthenticatedMedusaRequest.linkable()业务逻辑:
req.auth_context?.actor_id导入:
await import()数据访问:
query.graph() 按链接模块字段过滤(应使用 query.index() 或从另一端查询).filter()(应使用 query.index() 或直接查询链接实体)query.graph() 进行跨模块数据检索query.graph()(应使用 query.index())关键:完成实现后,始终运行构建命令以捕获类型错误和运行时问题。
检测包管理器并运行相应的命令:
npm run build # 或 pnpm build / yarn build
如果构建失败:
常见的构建错误:
MedusaRequest<T> 类型参数)成功实现功能后,始终向用户提供以下后续步骤:
如果服务器尚未运行,请启动它:
npm run dev # 或 pnpm dev / yarn dev
打开浏览器并导航到:
使用你的管理员凭据登录,以测试任何与管理相关的功能。
如果你实现了自定义 API 路由,请列出它们供用户测试:
管理端路由(需要身份验证):
POST http://localhost:9000/admin/[你的路由] - 描述其功能GET http://localhost:9000/admin/[你的路由] - 描述其功能商店端路由(公开或需要客户身份验证):
POST http://localhost:9000/store/[你的路由] - 描述其功能GET http://localhost:9000/store/[你的路由] - 描述其功能使用 cURL 测试示例:
# 管理端路由(需要身份验证)
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"
# 商店端路由
curl -X POST http://localhost:9000/store/reviews \
-H "Content-Type: application/json" \
-d '{"product_id": "prod_123", "rating": 5, "comment": "Great product!"}'
根据实现的内容,提及:
在实现后,始终以清晰、可操作的格式呈现后续步骤:
## 实现完成
[功能名称] 已成功实现。以下是测试方法:
### 启动开发服务器
[基于包管理器的服务器启动命令]
### 访问管理面板
在浏览器中打开 http://localhost:9000/app
### 测试 API 路由
我已添加以下路由:
**管理端路由:**
- POST /admin/[路由] - [描述]
- GET /admin/[路由] - [描述]
**商店端路由:**
- POST /store/[路由] - [描述]
### 测试内容
1. [具体测试用例 1]
2. [具体测试用例 2]
3. [具体测试用例 3]
有关详细模式和示例,请加载参考文件:
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 - Cron 任务和周期性任务
reference/subscribers-and-events.md - 事件处理
reference/troubleshooting.md - 常见错误和解决方案
每个参考文件包含:
⚠️ 关键:规划和实现时应首先参考此技能。
将此技能用于(主要来源):
将 MedusaDocs MCP 服务器用于(次要来源):
为何技能优先:
⚠️ 关键:前端应用程序必须使用 Medusa JS SDK 进行所有 API 请求
当构建跨越后端和前端的特性时:
对于管理面板:
building-admin-dashboard-customizations 技能sdk.admin.product.list())sdk.client.fetch("/admin/my-route")对于商店前端:
building-storefronts 技能sdk.store.product.list())sdk.client.fetch("/store/my-route")为何需要 SDK:
x-publishable-api-key 请求头Authorization 和会话请求头有关完整的集成模式,请参阅各自的前端技能。
每周安装数
946
代码仓库
GitHub 星标数
114
首次出现
2026年1月26日
安全审计
安装于
codex826
github-copilot823
opencode817
gemini-cli817
amp773
kimi-cli772
Comprehensive backend development guide for Medusa applications. Contains patterns across 6 categories covering architecture, type safety, business logic placement, and common pitfalls.
Load this skill for ANY backend development task, including:
Also load these skills when:
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:
reference/custom-modules.md firstreference/workflows.md firstreference/api-routes.md firstreference/module-links.md firstreference/querying-data.md firstreference/authentication.md firstMinimum requirement: Load at least 1-2 reference files relevant to your specific task before implementing.
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:
query.graph() for cross-module data retrievalquery.index() (Index Module) for filtering across separate modules with links| Priority | Category | Impact | Prefix |
|---|---|---|---|
| 1 | Architecture Violations | CRITICAL | arch- |
| 2 | Type Safety | CRITICAL | type- |
| 3 | Business Logic Placement | HIGH | logic- |
| 4 | Import & Code Organization | HIGH | import- |
| 5 | Data Access Patterns |
arch-workflow-required - Use workflows for ALL mutations, never call module services from routesarch-layer-bypass - Never bypass layers (route → service without workflow)arch-http-methods - Use only GET, POST, DELETE (never PUT/PATCH)arch-module-isolation - Use module links, not direct cross-module service callsarch-query-config-fields - Don't set explicit fields when using req.queryConfigtype-request-schema - Pass Zod inferred type to MedusaRequest<T> when using req.validatedBodytype-authenticated-request - Use AuthenticatedMedusaRequest for protected routes (not MedusaRequest)type-export-schema - Export both Zod schema AND inferred type from middlewarestype-linkable-auto - Never add .linkable() to data models (automatically added)type-module-name-camelcase - Module names MUST be camelCase, never use dashes (causes runtime errors)logic-workflow-validation - Put business validation in workflow steps, not API routeslogic-ownership-checks - Validate ownership/permissions in workflows, not routeslogic-module-service - Keep modules simple (CRUD only), put logic in workflowsimport-top-level - Import workflows/modules at file top, never use await import() in route bodyimport-static-only - Use static imports for all dependenciesimport-no-dynamic-routes - Dynamic imports add overhead and break type checkingdata-price-format - 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 displayingdata-query-method - Use query.graph() for retrieving data; use query.index() (Index Module) for filtering across linked modulesdata-query-graph - Use query.graph() for cross-module queries with dot notation (without cross-module filtering)data-query-index - Use query.index() when filtering by properties of linked data models in separate modulesdata-list-and-count - Use for single-module paginated queriesfile-workflow-steps - Recommended: Create steps in src/workflows/steps/[name].tsfile-workflow-composition - Composition functions in src/workflows/[name].tsfile-middleware-exports - Export schemas and types from middleware filesfile-links-directory - Define module links in src/links/[name].tsThe workflow function has critical constraints:
// ✅ 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:
function)when())transform())transform()).config({ name: "unique-name" }) to avoid conflictsBefore implementing, verify you're NOT doing these:
Architecture:
fields explicitly with req.queryConfigType Safety:
MedusaRequest<SchemaType> type argumentMedusaRequest instead of AuthenticatedMedusaRequest for protected routes.linkable() to data modelsBusiness Logic:
req.auth_context?.actor_id when middleware already appliedImports:
await import() in route handler bodiesData Access:
query.graph() (use query.index() or query from other side instead).filter() on linked data (use query.index() or query the linked entity directly)query.graph() for cross-module data retrievalquery.graph() when you need to filter across separate modules (use query.index() instead)CRITICAL: Always run the build command after completing implementation to catch type errors and runtime issues.
Detect the package manager and run the appropriate command:
npm run build # or pnpm build / yarn build
If the build fails:
Common build errors:
MedusaRequest<T> type argument)After successfully implementing a feature, always provide these next steps to the user:
If the server isn't already running, start it:
npm run dev # or pnpm dev / yarn dev
Open your browser and navigate to:
Log in with your admin credentials to test any admin-related features.
If you implemented custom API routes, list them for the user to test:
Admin Routes (require authentication):
POST http://localhost:9000/admin/[your-route] - Description of what it doesGET http://localhost:9000/admin/[your-route] - Description of what it doesStore Routes (public or customer-authenticated):
POST http://localhost:9000/store/[your-route] - Description of what it doesGET http://localhost:9000/store/[your-route] - Description of what it doesTesting with cURL example:
# 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!"}'
Depending on what was implemented, mention:
Always present next steps in a clear, actionable format after implementation:
## 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]
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 solutions
Each reference file contains:
⚠️ CRITICAL: This skill should be consulted FIRST for planning and implementation.
Use this skill for (PRIMARY SOURCE):
Use MedusaDocs MCP server for (SECONDARY SOURCE):
Why skills come first:
⚠️ CRITICAL: Frontend applications MUST use the Medusa JS SDK for ALL API requests
When building features that span backend and frontend:
For Admin Dashboard:
building-admin-dashboard-customizations skillsdk.admin.product.list())sdk.client.fetch("/admin/my-route")For Storefronts:
building-storefronts skillsdk.store.product.list())sdk.client.fetch("/store/my-route")Why the SDK is required:
x-publishable-api-key headerAuthorization and session headersSee respective frontend skills for complete integration patterns.
Weekly Installs
946
Repository
GitHub Stars
114
First Seen
Jan 26, 2026
Security Audits
Gen Agent Trust HubPassSocketPassSnykPass
Installed on
codex826
github-copilot823
opencode817
gemini-cli817
amp773
kimi-cli772
React 组合模式指南:Vercel 组件架构最佳实践,提升代码可维护性
102,200 周安装
Grimoire CLI 使用指南:区块链法术编写、验证与执行全流程
940 周安装
Grimoire Uniswap 技能:查询 Uniswap 元数据与生成代币/资金池快照的 CLI 工具
940 周安装
Grimoire Aave 技能:查询 Aave V3 元数据和储备快照的 CLI 工具
941 周安装
Railway CLI 部署指南:使用 railway up 命令快速部署代码到 Railway 平台
942 周安装
n8n Python 代码节点使用指南:在自动化工作流中编写 Python 脚本
943 周安装
Flutter Platform Views 实现指南:Android/iOS/macOS原生视图与Web嵌入教程
943 周安装
| MEDIUM (includes CRITICAL price rule) |
data- |
| 6 | File Organization | MEDIUM | file- |
listAndCountdata-linked-filtering - query.graph() can't filter by linked module fields - use query.index() or query from that entity directlydata-no-js-filter - Don't use JavaScript .filter() on linked data - use database filters (query.index() or query the entity)data-same-module-ok - Can filter by same-module relations with query.graph() (e.g., product.variants)data-auth-middleware - Trust authenticate middleware, don't manually check req.auth_context