Medusa Commerce
Medusa Commerce Headless Open Source Node.js TypeScript API-first E-commerce Multi-currency Multi-region Plugin Remote Work Self-hosted Stripe PayPal Next.js
| Platform | Type | Self-hosted | ราคา | เหมาะกับ |
|---|---|---|---|---|
| Medusa | Headless OSS | ใช่ | ฟรี | Dev Team |
| Shopify | SaaS | ไม่ | $29+/mo | Non-tech |
| WooCommerce | WordPress Plugin | ใช่ | ฟรี | WordPress |
| Saleor | Headless OSS | ใช่ | ฟรี | GraphQL |
| Commerce.js | Headless SaaS | ไม่ | Free/Paid | JAMstack |
Medusa Setup
# === Medusa Installation ===
# Quick Start
# npx create-medusa-app@latest my-store
# cd my-store
# Backend Structure
# my-store/
# ├── backend/
# │ ├── src/
# │ │ ├── api/ # Custom API routes
# │ │ ├── services/ # Custom services
# │ │ ├── subscribers/ # Event handlers
# │ │ └── models/ # Custom models
# │ ├── medusa-config.js
# │ ├── package.json
# │ └── .env
# └── storefront/ # Next.js frontend
# .env Configuration
# DATABASE_URL=postgres://user:pass@localhost:5432/medusa
# REDIS_URL=redis://localhost:6379
# JWT_SECRET=your-super-secret-jwt
# COOKIE_SECRET=your-cookie-secret
# STRIPE_API_KEY=sk_test_xxx
# STORE_CORS=http://localhost:8000
# ADMIN_CORS=http://localhost:7001
# medusa-config.js
# module.exports = {
# projectConfig: {
# redis_url: process.env.REDIS_URL,
# database_url: process.env.DATABASE_URL,
# store_cors: process.env.STORE_CORS,
# admin_cors: process.env.ADMIN_CORS,
# },
# plugins: [
# `medusa-fulfillment-manual`,
# `medusa-payment-manual`,
# {
# resolve: `medusa-payment-stripe`,
# options: {
# api_key: process.env.STRIPE_API_KEY,
# },
# },
# {
# resolve: `medusa-file-s3`,
# options: {
# s3_url: process.env.S3_URL,
# bucket: process.env.S3_BUCKET,
# region: process.env.S3_REGION,
# access_key_id: process.env.S3_ACCESS_KEY,
# secret_access_key: process.env.S3_SECRET_KEY,
# },
# },
# ],
# };
# Run Development
# cd backend && medusa develop
# cd storefront && npm run dev
from dataclasses import dataclass
@dataclass
class MedusaFeature:
feature: str
description: str
plugin: str
status: str
features = [
MedusaFeature("Products", "จัดการสินค้า Variants Options", "Built-in", "GA"),
MedusaFeature("Orders", "สั่งซื้อ Fulfillment Returns", "Built-in", "GA"),
MedusaFeature("Payments", "Stripe PayPal Manual", "medusa-payment-stripe", "GA"),
MedusaFeature("Shipping", "Flat Rate Manual Custom", "medusa-fulfillment-manual", "GA"),
MedusaFeature("Multi-currency", "หลายสกุลเงิน THB USD EUR", "Built-in", "GA"),
MedusaFeature("Multi-region", "หลายภูมิภาค Tax ต่างกัน", "Built-in", "GA"),
MedusaFeature("File Storage", "S3 MinIO Local", "medusa-file-s3", "GA"),
MedusaFeature("Search", "MeiliSearch Algolia", "medusa-plugin-meilisearch", "GA"),
]
print("=== Medusa Features ===")
for f in features:
print(f" [{f.status}] {f.feature}")
print(f" {f.description} | Plugin: {f.plugin}")
API และ Storefront
# === Medusa API & Next.js Storefront ===
# REST API Examples
# GET /store/products — List products
# GET /store/products/:id — Get product
# POST /store/carts — Create cart
# POST /store/carts/:id/line-items — Add item
# POST /store/carts/:id/payment-sessions — Init payment
# POST /store/carts/:id/complete — Complete order
# Next.js Storefront — Product Page
# // pages/products/[handle].tsx
# import { medusaClient } from "@lib/medusa"
#
# export async function getStaticProps({ params }) {
# const { product } = await medusaClient.products.retrieve(
# params.handle
# )
# return { props: { product }, revalidate: 60 }
# }
#
# export default function ProductPage({ product }) {
# return (
#
#
# {product.description}
# Price: {product.variants[0].prices[0].amount / 100} THB
#
#
# )
# }
# Custom API Route
# // src/api/routes/store/custom/index.ts
# import { Router } from "express"
# const router = Router()
#
# router.get("/store/custom/bestsellers", async (req, res) => {
# const productService = req.scope.resolve("productService")
# const products = await productService.list(
# { status: "published" },
# { order: { sold_count: "DESC" }, take: 10 }
# )
# res.json({ products })
# })
@dataclass
class APIEndpoint:
method: str
path: str
description: str
auth: str
rate_limit: str
endpoints = [
APIEndpoint("GET", "/store/products", "รายการสินค้า", "ไม่ต้อง", "100/min"),
APIEndpoint("POST", "/store/carts", "สร้างตะกร้า", "ไม่ต้อง", "50/min"),
APIEndpoint("POST", "/store/customers", "สมัครสมาชิก", "ไม่ต้อง", "10/min"),
APIEndpoint("GET", "/admin/orders", "รายการออเดอร์", "JWT Admin", "100/min"),
APIEndpoint("POST", "/admin/products", "เพิ่มสินค้า", "JWT Admin", "50/min"),
APIEndpoint("POST", "/hooks/payment", "Payment Webhook", "Signature", "Unlimited"),
]
print("\n=== API Endpoints ===")
for e in endpoints:
print(f" [{e.method}] {e.path}")
print(f" {e.description} | Auth: {e.auth} | Limit: {e.rate_limit}")
Remote Work Deployment
# === Production Deployment ===
# Docker Compose — Production
# services:
# backend:
# build: ./backend
# environment:
# - DATABASE_URL=postgres://medusa:secret@db:5432/medusa
# - REDIS_URL=redis://redis:6379
# ports:
# - "9000:9000"
# depends_on: [db, redis]
#
# storefront:
# build: ./storefront
# environment:
# - NEXT_PUBLIC_MEDUSA_BACKEND_URL=https://api.mystore.com
# ports:
# - "8000:8000"
#
# db:
# image: postgres:15-alpine
# environment:
# - POSTGRES_USER=medusa
# - POSTGRES_PASSWORD=secret
# - POSTGRES_DB=medusa
# volumes:
# - pgdata:/var/lib/postgresql/data
#
# redis:
# image: redis:7-alpine
# Railway / Fly.io Deployment
# fly launch --name mystore-api
# fly secrets set DATABASE_URL=postgres://...
# fly secrets set STRIPE_API_KEY=sk_live_...
# fly deploy
# CI/CD — GitHub Actions
# name: Deploy
# on:
# push:
# branches: [main]
# jobs:
# deploy:
# runs-on: ubuntu-latest
# steps:
# - uses: actions/checkout@v4
# - uses: superfly/flyctl-actions/setup-flyctl@master
# - run: flyctl deploy --remote-only
remote_workflow = {
"Development": "Local Docker Compose ทุกู้คืนรันเหมือนกัน",
"Staging": "Auto-deploy จาก develop branch ทดสอบก่อน",
"Production": "Deploy จาก main branch หลัง PR Approved",
"Admin Dashboard": "https://admin.mystore.com ทุกู้คืนเข้าได้",
"API Docs": "Swagger UI ที่ /api-docs สำหรับ Frontend Team",
"Monitoring": "Sentry สำหรับ Error Tracking ทุก Environment",
"Communication": "Slack Channel #store-dev สำหรับทีม",
}
print("Remote Work Workflow:")
for stage, desc in remote_workflow.items():
print(f" [{stage}]: {desc}")
team_setup = [
"Backend Dev: พัฒนา API Plugin Custom Service",
"Frontend Dev: พัฒนา Storefront Next.js Components",
"Mobile Dev: ใช้ REST API สร้าง iOS Android App",
"Designer: ออกแบบ UI/UX ใน Figma Collaborate",
"QA: ทดสอบบน Staging Environment",
"DevOps: จัดการ Infrastructure CI/CD Monitoring",
"PM: จัดการ Sprint ใน Jira Linear",
]
print(f"\n\nTeam Roles:")
for i, t in enumerate(team_setup, 1):
print(f" {i}. {t}")
เคล็ดลับ
- Docker: ใช้ Docker Compose ให้ทุกู้คืนรัน Environment เดียวกัน
- Staging: ตั้ง Staging Environment ทดสอบก่อน Production
- Plugin: ใช้ Plugin System ขยาย Feature ไม่ต้องแก้ Core
- API-first: ออกแบบ API ก่อน ให้ทุก Team ใช้ได้
- Seed: สร้าง Seed Data สำหรับ Development ทุกู้คืน
Medusa Commerce คืออะไร
Open Source Headless Commerce Node.js TypeScript REST API Admin Multi-currency Multi-region Plugin Stripe PayPal Self-hosted แทน Shopify
Headless Commerce คืออะไร
แยก Backend Frontend สื่อสาร API Next.js Gatsby Nuxt Mobile ไม่ถูกล็อก Template Backend Product Order Payment Frontend UI UX อิสระ
ตั้งค่า Medusa อย่างไร
npx create-medusa-app PostgreSQL Redis Next.js Starter medusa develop Port 9000 7001 8000 .env Database JWT Stripe S3
ใช้ Medusa กับทีม Remote อย่างไร
Deploy Cloud Admin Dashboard Git CI/CD Staging Plugin API-first Mobile Web แยก Documentation Notion Confluence Slack
สรุป
Medusa Commerce Headless Open Source Node.js TypeScript API-first Plugin Multi-currency Remote Work Docker CI/CD Staging Production Next.js Stripe E-commerce
