medusa

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Medusa 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

FeatureBenefit
Open SourceSelf-host, no vendor lock-in, MIT license
Node.js NativeTypeScript, familiar stack, easy to customize
HeadlessAny frontend (Next.js, Remix, mobile)
ModularUse only what you need, extend anything
Built-in AdminDashboard included, customizable

特性优势
开源可自托管,无供应商锁定,MIT许可证
原生支持Node.js基于TypeScript,技术栈熟悉,易于定制
无头架构适配任意前端(Next.js、Remix、移动端)
模块化设计按需选用功能,可扩展任意模块
内置管理后台自带仪表盘,支持定制

Quick Start

快速开始

Prerequisites

前置要求

bash
undefined
bash
undefined

Required

必需项

node --version # v20+ LTS git --version
node --version # v20+ LTS版本 git --version

PostgreSQL running locally or remote

本地或远程运行的PostgreSQL

undefined
undefined

Create New Project

创建新项目

bash
undefined
bash
undefined

Scaffold 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
undefined
cd my-store npm run dev
undefined

Access Points

访问地址

URLPurpose
http://localhost:9000
Backend API
http://localhost:9000/app
Admin dashboard
http://localhost:8000
Storefront (if installed)
URL用途
http://localhost:9000
后端API
http://localhost:9000/app
管理仪表盘
http://localhost:8000
店铺前端(若已安装)

Create Admin User

创建管理员用户

bash
npx medusa user -e admin@example.com -p supersecret

bash
npx medusa user -e admin@example.com -p supersecret

Project 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.json

medusa-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.json

Configuration

配置

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
undefined
bash
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(多源地址用逗号分隔)

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/hello
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: "来自自定义店铺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)
undefined

Route 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/reviews
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), // 最近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"])],
    },
  ],
});

undefined

Modules (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: {},
    },
  ],
});
undefined

Use 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

工作流

定义工作流

EventTrigger
order.placed
New order created
order.updated
Order modified
order.canceled
Order cancelled
order.completed
Order fulfilled
customer.created
New customer registered
product.created
New product added
product.updated
Product modified
inventory.updated
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

常见事件

ZoneLocation
order.list.before
Before order list
order.details.after
After order details
product.list.before
Before product list
product.details.after
After product details
customer.list.before
Before customer list
事件触发条件
order.placed
新订单创建
order.updated
订单修改
order.canceled
订单取消
order.completed
订单完成
customer.created
新客户注册
product.created
新商品添加
product.updated
商品修改
inventory.updated
库存变更

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());
区域位置
order.list.before
订单列表上方
order.details.after
订单详情下方
product.list.before
商品列表上方
product.details.after
商品详情下方
customer.list.before
客户列表上方

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-stripe
typescript
// 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

购物车

  1. Go to Settings → Regions
  2. Add Stripe as payment provider
  3. 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
undefined
typescript
// 注册
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-stripe
typescript
// 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
  1. 进入 设置 → 区域
  2. 添加Stripe作为支付提供商
  3. 为每个区域配置Stripe

Render

部署

Railway平台

yaml
undefined
bash
undefined

render.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
undefined
npm 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
undefined

CLI Commands

Render平台

bash
undefined
yaml
undefined

Development

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
undefined

Database

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
undefined

Build

开发环境

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错误 - 框架依赖类型检查,需确保代码符合类型规范