medusa
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseMedusa E-Commerce Skill
Medusa 电商开发技能
Load with: base.md + typescript.md
For building headless e-commerce with Medusa - open-source, Node.js native, fully customizable.
加载依赖:base.md + typescript.md
使用Medusa构建无头电商——开源、原生支持Node.js、完全可定制。
Why Medusa
为什么选择Medusa
| Feature | Benefit |
|---|---|
| Open Source | Self-host, no vendor lock-in, MIT license |
| Node.js Native | TypeScript, familiar stack, easy to customize |
| Headless | Any frontend (Next.js, Remix, mobile) |
| Modular | Use only what you need, extend anything |
| Built-in Admin | Dashboard included, customizable |
| 特性 | 优势 |
|---|---|
| 开源 | 可自托管,无供应商锁定,MIT许可证 |
| 原生支持Node.js | 基于TypeScript,技术栈熟悉,易于定制 |
| 无头架构 | 适配任意前端(Next.js、Remix、移动端) |
| 模块化设计 | 按需选用功能,可扩展任意模块 |
| 内置管理后台 | 自带仪表盘,支持定制 |
Quick Start
快速开始
Prerequisites
前置要求
bash
undefinedbash
undefinedRequired
必需项
node --version # v20+ LTS
git --version
node --version # v20+ LTS版本
git --version
PostgreSQL running locally or remote
本地或远程运行的PostgreSQL
undefinedundefinedCreate New Project
创建新项目
bash
undefinedbash
undefinedScaffold new Medusa application
搭建新的Medusa应用
npx create-medusa-app@latest my-store
npx create-medusa-app@latest my-store
This creates:
此命令将创建:
- Medusa backend
- Medusa后端
- PostgreSQL database (auto-configured)
- PostgreSQL数据库(自动配置)
- Admin dashboard
- 管理仪表盘
- Optional: Next.js storefront
- 可选:Next.js店铺前端
cd my-store
npm run dev
undefinedcd my-store
npm run dev
undefinedAccess Points
访问地址
| URL | Purpose |
|---|---|
| Backend API |
| Admin dashboard |
| Storefront (if installed) |
| URL | 用途 |
|---|---|
| 后端API |
| 管理仪表盘 |
| 店铺前端(若已安装) |
Create Admin User
创建管理员用户
bash
npx medusa user -e admin@example.com -p supersecretbash
npx medusa user -e admin@example.com -p supersecretProject Structure
项目结构
medusa-store/
├── src/
│ ├── admin/ # Admin UI customizations
│ │ ├── widgets/ # Dashboard widgets
│ │ └── routes/ # Custom admin pages
│ ├── api/ # Custom API routes
│ │ ├── store/ # Public storefront APIs
│ │ │ └── custom/
│ │ │ └── route.ts
│ │ └── admin/ # Admin APIs
│ │ └── custom/
│ │ └── route.ts
│ ├── jobs/ # Scheduled tasks
│ ├── modules/ # Custom business logic
│ ├── workflows/ # Multi-step processes
│ ├── subscribers/ # Event listeners
│ └── links/ # Module relationships
├── .medusa/ # Auto-generated (don't edit)
├── medusa-config.ts # Configuration
├── package.json
└── tsconfig.jsonmedusa-store/
├── src/
│ ├── admin/ # 管理UI自定义
│ │ ├── widgets/ # 仪表盘小部件
│ │ └── routes/ # 自定义管理页面
│ ├── api/ # 自定义API路由
│ │ ├── store/ # 公开店铺API
│ │ │ └── custom/
│ │ │ └── route.ts
│ │ └── admin/ # 管理API
│ │ └── custom/
│ │ └── route.ts
│ ├── jobs/ # 定时任务
│ ├── modules/ # 自定义业务逻辑
│ ├── workflows/ # 多步骤流程
│ ├── subscribers/ # 事件监听器
│ └── links/ # 模块关联关系
├── .medusa/ # 自动生成(请勿编辑)
├── medusa-config.ts # 配置文件
├── package.json
└── tsconfig.jsonConfiguration
配置
medusa-config.ts
medusa-config.ts
typescript
import { defineConfig, loadEnv } from "@medusajs/framework/utils";
loadEnv(process.env.NODE_ENV || "development", process.cwd());
export default defineConfig({
projectConfig: {
databaseUrl: process.env.DATABASE_URL,
http: {
storeCors: process.env.STORE_CORS || "http://localhost:8000",
adminCors: process.env.ADMIN_CORS || "http://localhost:9000",
authCors: process.env.AUTH_CORS || "http://localhost:9000",
},
redisUrl: process.env.REDIS_URL,
},
admin: {
disable: false,
backendUrl: process.env.MEDUSA_BACKEND_URL || "http://localhost:9000",
},
modules: [
// Add custom modules here
],
});typescript
import { defineConfig, loadEnv } from "@medusajs/framework/utils";
loadEnv(process.env.NODE_ENV || "development", process.cwd());
export default defineConfig({
projectConfig: {
databaseUrl: process.env.DATABASE_URL,
http: {
storeCors: process.env.STORE_CORS || "http://localhost:8000",
adminCors: process.env.ADMIN_CORS || "http://localhost:9000",
authCors: process.env.AUTH_CORS || "http://localhost:9000",
},
redisUrl: process.env.REDIS_URL,
},
admin: {
disable: false,
backendUrl: process.env.MEDUSA_BACKEND_URL || "http://localhost:9000",
},
modules: [
// 在此添加自定义模块
],
});Environment Variables
环境变量
bash
undefinedbash
undefined.env
.env
DATABASE_URL=postgresql://user:pass@localhost:5432/medusa
REDIS_URL=redis://localhost:6379
DATABASE_URL=postgresql://user:pass@localhost:5432/medusa
REDIS_URL=redis://localhost:6379
CORS (comma-separated for multiple origins)
CORS(多源地址用逗号分隔)
STORE_CORS=http://localhost:8000
ADMIN_CORS=http://localhost:9000
STORE_CORS=http://localhost:8000
ADMIN_CORS=http://localhost:9000
Backend URL
后端地址
MEDUSA_BACKEND_URL=http://localhost:9000
MEDUSA_BACKEND_URL=http://localhost:9000
JWT Secrets
JWT密钥
JWT_SECRET=your-super-secret-jwt-key
COOKIE_SECRET=your-super-secret-cookie-key
---JWT_SECRET=your-super-secret-jwt-key
COOKIE_SECRET=your-super-secret-cookie-key
---Custom API Routes
自定义API路由
Store API (Public)
店铺API(公开)
typescript
// src/api/store/hello/route.ts
import type { MedusaRequest, MedusaResponse } from "@medusajs/framework/http";
export async function GET(
req: MedusaRequest,
res: MedusaResponse
) {
res.json({
message: "Hello from custom store API!",
});
}
// Accessible at: GET /store/hellotypescript
// src/api/store/hello/route.ts
import type { MedusaRequest, MedusaResponse } from "@medusajs/framework/http";
export async function GET(
req: MedusaRequest,
res: MedusaResponse
) {
res.json({
message: "来自自定义店铺API的问候!",
});
}Admin API (Protected)
访问地址:GET /store/hello
typescript
// src/api/admin/analytics/route.ts
import type { MedusaRequest, MedusaResponse } from "@medusajs/framework/http";
import { Modules } from "@medusajs/framework/utils";
export async function GET(
req: MedusaRequest,
res: MedusaResponse
) {
const orderService = req.scope.resolve(Modules.ORDER);
const orders = await orderService.listOrders({
created_at: {
$gte: new Date(Date.now() - 30 * 24 * 60 * 60 * 1000), // Last 30 days
},
});
const totalRevenue = orders.reduce(
(sum, order) => sum + (order.total || 0),
0
);
res.json({
orderCount: orders.length,
totalRevenue,
});
}
// Accessible at: GET /admin/analytics (requires auth)undefinedRoute with Parameters
管理API(受保护)
typescript
// src/api/store/products/[id]/reviews/route.ts
import type { MedusaRequest, MedusaResponse } from "@medusajs/framework/http";
export async function GET(
req: MedusaRequest,
res: MedusaResponse
) {
const { id } = req.params;
// Fetch reviews for product
const reviews = await getReviewsForProduct(id);
res.json({ reviews });
}
export async function POST(
req: MedusaRequest,
res: MedusaResponse
) {
const { id } = req.params;
const { rating, comment, customerId } = req.body;
const review = await createReview({
productId: id,
rating,
comment,
customerId,
});
res.status(201).json({ review });
}
// Accessible at:
// GET /store/products/:id/reviews
// POST /store/products/:id/reviewstypescript
// src/api/admin/analytics/route.ts
import type { MedusaRequest, MedusaResponse } from "@medusajs/framework/http";
import { Modules } from "@medusajs/framework/utils";
export async function GET(
req: MedusaRequest,
res: MedusaResponse
) {
const orderService = req.scope.resolve(Modules.ORDER);
const orders = await orderService.listOrders({
created_at: {
$gte: new Date(Date.now() - 30 * 24 * 60 * 60 * 1000), // 最近30天
},
});
const totalRevenue = orders.reduce(
(sum, order) => sum + (order.total || 0),
0
);
res.json({
orderCount: orders.length,
totalRevenue,
});
}Middleware
访问地址:GET /admin/analytics(需要认证)
typescript
// src/api/middlewares.ts
import { defineMiddlewares } from "@medusajs/framework/http";
import { authenticate } from "@medusajs/framework/http";
export default defineMiddlewares({
routes: [
{
matcher: "/store/protected/*",
middlewares: [authenticate("customer", ["session", "bearer"])],
},
{
matcher: "/admin/*",
middlewares: [authenticate("user", ["session", "bearer"])],
},
],
});undefinedModules (Custom Business Logic)
带参数的路由
Create Custom Module
—
typescript
// src/modules/reviews/index.ts
import { Module } from "@medusajs/framework/utils";
import ReviewModuleService from "./service";
export const REVIEW_MODULE = "reviewModuleService";
export default Module(REVIEW_MODULE, {
service: ReviewModuleService,
});typescript
// src/modules/reviews/service.ts
import { MedusaService } from "@medusajs/framework/utils";
class ReviewModuleService extends MedusaService({}) {
async createReview(data: CreateReviewInput) {
// Implementation
}
async getProductReviews(productId: string) {
// Implementation
}
async getAverageRating(productId: string) {
// Implementation
}
}
export default ReviewModuleService;typescript
// src/api/store/products/[id]/reviews/route.ts
import type { MedusaRequest, MedusaResponse } from "@medusajs/framework/http";
export async function GET(
req: MedusaRequest,
res: MedusaResponse
) {
const { id } = req.params;
// 获取商品评论
const reviews = await getReviewsForProduct(id);
res.json({ reviews });
}
export async function POST(
req: MedusaRequest,
res: MedusaResponse
) {
const { id } = req.params;
const { rating, comment, customerId } = req.body;
const review = await createReview({
productId: id,
rating,
comment,
customerId,
});
res.status(201).json({ review });
}Register Module
访问地址:
—
GET /store/products/:id/reviews
—
POST /store/products/:id/reviews
typescript
// medusa-config.ts
import { REVIEW_MODULE } from "./src/modules/reviews";
export default defineConfig({
// ...
modules: [
{
resolve: "./src/modules/reviews",
options: {},
},
],
});undefinedUse Module in API
中间件
typescript
// src/api/store/products/[id]/reviews/route.ts
import { REVIEW_MODULE } from "../../../modules/reviews";
export async function GET(req: MedusaRequest, res: MedusaResponse) {
const { id } = req.params;
const reviewService = req.scope.resolve(REVIEW_MODULE);
const reviews = await reviewService.getProductReviews(id);
const averageRating = await reviewService.getAverageRating(id);
res.json({ reviews, averageRating });
}typescript
// src/api/middlewares.ts
import { defineMiddlewares } from "@medusajs/framework/http";
import { authenticate } from "@medusajs/framework/http";
export default defineMiddlewares({
routes: [
{
matcher: "/store/protected/*",
middlewares: [authenticate("customer", ["session", "bearer"])],
},
{
matcher: "/admin/*",
middlewares: [authenticate("user", ["session", "bearer"])],
},
],
});Workflows
模块(自定义业务逻辑)
Define Workflow
创建自定义模块
typescript
// src/workflows/create-order-with-notification/index.ts
import {
createWorkflow,
createStep,
StepResponse,
} from "@medusajs/framework/workflows-sdk";
import { Modules } from "@medusajs/framework/utils";
const createOrderStep = createStep(
"create-order",
async (input: CreateOrderInput, { container }) => {
const orderService = container.resolve(Modules.ORDER);
const order = await orderService.createOrders(input);
return new StepResponse(order, order.id);
},
// Compensation (rollback) function
async (orderId, { container }) => {
const orderService = container.resolve(Modules.ORDER);
await orderService.deleteOrders([orderId]);
}
);
const sendNotificationStep = createStep(
"send-notification",
async (order: Order, { container }) => {
const notificationService = container.resolve("notificationService");
await notificationService.send({
to: order.email,
template: "order-confirmation",
data: { order },
});
return new StepResponse({ sent: true });
}
);
export const createOrderWithNotificationWorkflow = createWorkflow(
"create-order-with-notification",
(input: CreateOrderInput) => {
const order = createOrderStep(input);
const notification = sendNotificationStep(order);
return { order, notification };
}
);typescript
// src/modules/reviews/index.ts
import { Module } from "@medusajs/framework/utils";
import ReviewModuleService from "./service";
export const REVIEW_MODULE = "reviewModuleService";
export default Module(REVIEW_MODULE, {
service: ReviewModuleService,
});typescript
// src/modules/reviews/service.ts
import { MedusaService } from "@medusajs/framework/utils";
class ReviewModuleService extends MedusaService({}) {
async createReview(data: CreateReviewInput) {
// 实现逻辑
}
async getProductReviews(productId: string) {
// 实现逻辑
}
async getAverageRating(productId: string) {
// 实现逻辑
}
}
export default ReviewModuleService;Execute Workflow
注册模块
typescript
// In an API route
import { createOrderWithNotificationWorkflow } from "../../../workflows/create-order-with-notification";
export async function POST(req: MedusaRequest, res: MedusaResponse) {
const { result } = await createOrderWithNotificationWorkflow(req.scope).run({
input: req.body,
});
res.json(result);
}typescript
// medusa-config.ts
import { REVIEW_MODULE } from "./src/modules/reviews";
export default defineConfig({
// ...
modules: [
{
resolve: "./src/modules/reviews",
options: {},
},
],
});Subscribers (Event Listeners)
在API中使用模块
Create Subscriber
—
typescript
// src/subscribers/order-placed.ts
import type { SubscriberArgs, SubscriberConfig } from "@medusajs/framework";
export default async function orderPlacedHandler({
event,
container,
}: SubscriberArgs<{ id: string }>) {
const orderId = event.data.id;
console.log(`Order placed: ${orderId}`);
// Send notification, update analytics, etc.
const notificationService = container.resolve("notificationService");
await notificationService.sendOrderConfirmation(orderId);
}
export const config: SubscriberConfig = {
event: "order.placed",
};typescript
// src/api/store/products/[id]/reviews/route.ts
import { REVIEW_MODULE } from "../../../modules/reviews";
export async function GET(req: MedusaRequest, res: MedusaResponse) {
const { id } = req.params;
const reviewService = req.scope.resolve(REVIEW_MODULE);
const reviews = await reviewService.getProductReviews(id);
const averageRating = await reviewService.getAverageRating(id);
res.json({ reviews, averageRating });
}Common Events
工作流
—
定义工作流
| Event | Trigger |
|---|---|
| New order created |
| Order modified |
| Order cancelled |
| Order fulfilled |
| New customer registered |
| New product added |
| Product modified |
| Stock changed |
typescript
// src/workflows/create-order-with-notification/index.ts
import {
createWorkflow,
createStep,
StepResponse,
} from "@medusajs/framework/workflows-sdk";
import { Modules } from "@medusajs/framework/utils";
const createOrderStep = createStep(
"create-order",
async (input: CreateOrderInput, { container }) => {
const orderService = container.resolve(Modules.ORDER);
const order = await orderService.createOrders(input);
return new StepResponse(order, order.id);
},
// 补偿(回滚)函数
async (orderId, { container }) => {
const orderService = container.resolve(Modules.ORDER);
await orderService.deleteOrders([orderId]);
}
);
const sendNotificationStep = createStep(
"send-notification",
async (order: Order, { container }) => {
const notificationService = container.resolve("notificationService");
await notificationService.send({
to: order.email,
template: "order-confirmation",
data: { order },
});
return new StepResponse({ sent: true });
}
);
export const createOrderWithNotificationWorkflow = createWorkflow(
"create-order-with-notification",
(input: CreateOrderInput) => {
const order = createOrderStep(input);
const notification = sendNotificationStep(order);
return { order, notification };
}
);Scheduled Jobs
执行工作流
typescript
// src/jobs/sync-inventory.ts
import type { MedusaContainer } from "@medusajs/framework";
export default async function syncInventoryJob(container: MedusaContainer) {
const inventoryService = container.resolve("inventoryService");
console.log("Running inventory sync...");
await inventoryService.syncFromExternalSource();
console.log("Inventory sync complete");
}
export const config = {
name: "sync-inventory",
schedule: "0 */6 * * *", // Every 6 hours
};typescript
// 在API路由中
import { createOrderWithNotificationWorkflow } from "../../../workflows/create-order-with-notification";
export async function POST(req: MedusaRequest, res: MedusaResponse) {
const { result } = await createOrderWithNotificationWorkflow(req.scope).run({
input: req.body,
});
res.json(result);
}Admin UI Customization
订阅者(事件监听器)
Custom Widget
创建订阅者
tsx
// src/admin/widgets/sales-overview.tsx
import { defineWidgetConfig } from "@medusajs/admin-sdk";
import { Container, Heading, Text } from "@medusajs/ui";
const SalesOverviewWidget = () => {
return (
<Container>
<Heading level="h2">Sales Overview</Heading>
<Text>Your custom sales data here...</Text>
</Container>
);
};
export const config = defineWidgetConfig({
zone: "order.list.before", // Where to show the widget
});
export default SalesOverviewWidget;typescript
// src/subscribers/order-placed.ts
import type { SubscriberArgs, SubscriberConfig } from "@medusajs/framework";
export default async function orderPlacedHandler({
event,
container,
}: SubscriberArgs<{ id: string }>) {
const orderId = event.data.id;
console.log(`订单已下单:${orderId}`);
// 发送通知、更新分析数据等
const notificationService = container.resolve("notificationService");
await notificationService.sendOrderConfirmation(orderId);
}
export const config: SubscriberConfig = {
event: "order.placed",
};Widget Zones
常见事件
| Zone | Location |
|---|---|
| Before order list |
| After order details |
| Before product list |
| After product details |
| Before customer list |
| 事件 | 触发条件 |
|---|---|
| 新订单创建 |
| 订单修改 |
| 订单取消 |
| 订单完成 |
| 新客户注册 |
| 新商品添加 |
| 商品修改 |
| 库存变更 |
Custom Admin Route
定时任务
tsx
// src/admin/routes/analytics/page.tsx
import { defineRouteConfig } from "@medusajs/admin-sdk";
import { Container, Heading } from "@medusajs/ui";
import { ChartBar } from "@medusajs/icons";
const AnalyticsPage = () => {
return (
<Container>
<Heading level="h1">Analytics Dashboard</Heading>
{/* Your analytics charts */}
</Container>
);
};
export const config = defineRouteConfig({
label: "Analytics",
icon: ChartBar,
});
export default AnalyticsPage;typescript
// src/jobs/sync-inventory.ts
import type { MedusaContainer } from "@medusajs/framework";
export default async function syncInventoryJob(container: MedusaContainer) {
const inventoryService = container.resolve("inventoryService");
console.log("正在同步库存...");
await inventoryService.syncFromExternalSource();
console.log("库存同步完成");
}
export const config = {
name: "sync-inventory",
schedule: "0 */6 * * *", // 每6小时执行一次
};Store API (Built-in)
管理UI自定义
Products
自定义小部件
typescript
// Frontend: Fetch products
const response = await fetch("http://localhost:9000/store/products");
const { products } = await response.json();
// With filters
const response = await fetch(
"http://localhost:9000/store/products?" +
new URLSearchParams({
category_id: "cat_123",
limit: "20",
offset: "0",
})
);tsx
// src/admin/widgets/sales-overview.tsx
import { defineWidgetConfig } from "@medusajs/admin-sdk";
import { Container, Heading, Text } from "@medusajs/ui";
const SalesOverviewWidget = () => {
return (
<Container>
<Heading level="h2">销售概览</Heading>
<Text>自定义销售数据展示...</Text>
</Container>
);
};
export const config = defineWidgetConfig({
zone: "order.list.before", // 展示位置
});
export default SalesOverviewWidget;Cart
小部件区域
typescript
// Create cart
const { cart } = await fetch("http://localhost:9000/store/carts", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
region_id: "reg_123",
}),
}).then(r => r.json());
// Add item
await fetch(`http://localhost:9000/store/carts/${cart.id}/line-items`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
variant_id: "variant_123",
quantity: 1,
}),
});
// Complete cart (create order)
const { order } = await fetch(
`http://localhost:9000/store/carts/${cart.id}/complete`,
{ method: "POST" }
).then(r => r.json());| 区域 | 位置 |
|---|---|
| 订单列表上方 |
| 订单详情下方 |
| 商品列表上方 |
| 商品详情下方 |
| 客户列表上方 |
Customer Authentication
自定义管理页面
typescript
// Register
await fetch("http://localhost:9000/store/customers", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
email: "customer@example.com",
password: "password123",
first_name: "John",
last_name: "Doe",
}),
});
// Login
const { token } = await fetch("http://localhost:9000/store/auth/token", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
email: "customer@example.com",
password: "password123",
}),
}).then(r => r.json());
// Authenticated request
await fetch("http://localhost:9000/store/customers/me", {
headers: {
Authorization: `Bearer ${token}`,
},
});tsx
// src/admin/routes/analytics/page.tsx
import { defineRouteConfig } from "@medusajs/admin-sdk";
import { Container, Heading } from "@medusajs/ui";
import { ChartBar } from "@medusajs/icons";
const AnalyticsPage = () => {
return (
<Container>
<Heading level="h1">数据分析仪表盘</Heading>
{/* 自定义分析图表 */}
</Container>
);
};
export const config = defineRouteConfig({
label: "数据分析",
icon: ChartBar,
});
export default AnalyticsPage;Payment Integration
内置店铺API
Stripe Setup
商品
bash
npm install @medusajs/payment-stripetypescript
// medusa-config.ts
export default defineConfig({
modules: [
{
resolve: "@medusajs/payment-stripe",
options: {
apiKey: process.env.STRIPE_API_KEY,
},
},
],
});typescript
// 前端:获取商品
const response = await fetch("http://localhost:9000/store/products");
const { products } = await response.json();
// 带筛选条件
const response = await fetch(
"http://localhost:9000/store/products?" +
new URLSearchParams({
category_id: "cat_123",
limit: "20",
offset: "0",
})
);In Admin
购物车
- Go to Settings → Regions
- Add Stripe as payment provider
- Configure for each region
typescript
// 创建购物车
const { cart } = await fetch("http://localhost:9000/store/carts", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
region_id: "reg_123",
}),
}).then(r => r.json());
// 添加商品
await fetch(`http://localhost:9000/store/carts/${cart.id}/line-items`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
variant_id: "variant_123",
quantity: 1,
}),
});
// 完成购物车(创建订单)
const { order } = await fetch(
`http://localhost:9000/store/carts/${cart.id}/complete`,
{ method: "POST" }
).then(r => r.json());Deployment
客户认证
Railway
—
bash
undefinedtypescript
// 注册
await fetch("http://localhost:9000/store/customers", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
email: "customer@example.com",
password: "password123",
first_name: "John",
last_name: "Doe",
}),
});
// 登录
const { token } = await fetch("http://localhost:9000/store/auth/token", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
email: "customer@example.com",
password: "password123",
}),
}).then(r => r.json());
// 认证请求
await fetch("http://localhost:9000/store/customers/me", {
headers: {
Authorization: `Bearer ${token}`,
},
});Install Railway CLI
支付集成
—
Stripe设置
npm install -g @railway/cli
bash
npm install @medusajs/payment-stripetypescript
// medusa-config.ts
export default defineConfig({
modules: [
{
resolve: "@medusajs/payment-stripe",
options: {
apiKey: process.env.STRIPE_API_KEY,
},
},
],
});Login and deploy
管理后台配置
railway login
railway init
railway up
undefined- 进入 设置 → 区域
- 添加Stripe作为支付提供商
- 为每个区域配置Stripe
Render
部署
—
Railway平台
yaml
undefinedbash
undefinedrender.yaml
安装Railway CLI
services:
- type: web
name: medusa-backend
runtime: node
plan: starter
buildCommand: npm install && npm run build
startCommand: npm run start
envVars:
- key: NODE_ENV value: production
- key: DATABASE_URL fromDatabase: name: medusa-db property: connectionString
- key: JWT_SECRET generateValue: true
- key: COOKIE_SECRET generateValue: true
databases:
- name: medusa-db plan: starter
undefinednpm install -g @railway/cli
Docker
登录并部署
dockerfile
FROM node:20-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .
RUN npm run build
EXPOSE 9000
CMD ["npm", "run", "start"]railway login
railway init
railway up
undefinedCLI Commands
Render平台
bash
undefinedyaml
undefinedDevelopment
render.yaml
npm run dev # Start dev server
services:
- type: web
name: medusa-backend
runtime: node
plan: starter
buildCommand: npm install && npm run build
startCommand: npm run start
envVars:
- key: NODE_ENV value: production
- key: DATABASE_URL fromDatabase: name: medusa-db property: connectionString
- key: JWT_SECRET generateValue: true
- key: COOKIE_SECRET generateValue: true
databases:
- name: medusa-db plan: starter
undefinedDatabase
Docker部署
npx medusa db:migrate # Run migrations
npx medusa db:sync # Sync schema
dockerfile
FROM node:20-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .
RUN npm run build
EXPOSE 9000
CMD ["npm", "run", "start"]Users
CLI命令
npx medusa user -e email -p pass # Create admin user
bash
undefinedBuild
开发环境
npm run build # Build for production
npm run start # Start production server
---npm run dev # 启动开发服务器
Checklist
数据库操作
Setup
—
- PostgreSQL database configured
- Redis configured (optional but recommended)
- Admin user created
- CORS origins configured
- JWT/Cookie secrets set
npx medusa db:migrate # 运行数据库迁移
npx medusa db:sync # 同步数据库 schema
Customization
用户管理
- Custom modules for business logic
- Custom API routes for frontend
- Subscribers for event handling
- Workflows for complex operations
npx medusa user -e email -p pass # 创建管理员用户
Deployment
构建与启动
- Environment variables configured
- Database migrations run
- HTTPS enabled
- Admin URL secured
npm run build # 构建生产环境代码
npm run start # 启动生产服务器
---Anti-Patterns
检查清单
—
设置项
- Editing .medusa folder - Auto-generated, will be overwritten
- Direct database access - Use services and modules
- Skipping workflows for complex ops - Workflows provide rollback
- Hardcoding URLs - Use environment variables
- Ignoring TypeScript errors - Framework relies on types
- 已配置PostgreSQL数据库
- 已配置Redis(可选但推荐)
- 已创建管理员用户
- 已配置CORS源地址
- 已设置JWT/Cookie密钥
—
自定义项
—
- 已添加自定义业务逻辑模块
- 已创建自定义店铺API路由
- 已添加事件监听器订阅者
- 已为复杂操作配置工作流
—
部署项
—
- 已配置生产环境变量
- 已运行数据库迁移
- 已启用HTTPS
- 已保护管理后台地址
—
反模式
—
- 编辑.medusa文件夹 - 该文件夹为自动生成,内容会被覆盖
- 直接操作数据库 - 应使用框架提供的服务与模块
- 复杂操作跳过工作流 - 工作流提供回滚机制,保障数据一致性
- 硬编码URL - 应使用环境变量配置
- 忽略TypeScript错误 - 框架依赖类型检查,需确保代码符合类型规范