Skip to content

Deployment

ระบบ deploy แบบ 3-tier serverless-friendly — frontend บน Cloudflare Pages, backend บน Render.com, database บน Supabase, object storage บน Cloudflare R2

Architecture

                ┌──────────────────────────────────────────────┐
                │              GitHub (master branch)          │
                └────────┬─────────────────────────┬───────────┘
                         │                         │
                         │ webhook                 │ wrangler CLI
                         │ (auto)                  │ (manual / GH Action)
                         ▼                         ▼
                ┌────────────────┐        ┌──────────────────┐
                │ Render.com     │        │ Cloudflare Pages │
                │ NestJS API     │        │ - wms-dev        │
                │ Singapore      │        │ - wms-admin      │
                │ Free tier      │        │ - wms-docs       │
                └────────┬───────┘        └────────┬─────────┘
                         │                         │
                         │  HTTPS (CORS)           │  Static assets
                         │                         │
                         ▼                         ▼
                ┌────────────────────────────────────────┐
                │           End users / browsers         │
                └────────────────────────────────────────┘

                         │ Prisma (pooled)

                ┌────────────────────────────────────────┐
                │  Supabase (PostgreSQL 16, PgBouncer)   │
                └────────────────────────────────────────┘

Frontend → Cloudflare Pages

3 separate Pages projects:

ProjectSourceBuild commandOutput dir
wms-devapps/web/pnpm --filter @wms/web buildapps/web/dist/
wms-adminapps/admin/pnpm --filter @wms/admin buildapps/admin/dist/
wms-docsapps/docs/pnpm --filter @wms/docs buildapps/docs/.vitepress/dist/

Branch = environment

  • main (หรือ master) → production deployment ที่ *.pages.dev
  • branch อื่น ๆ → preview deployment (URL auto-generated)

Deploy commands (CLI)

bash
# install wrangler ถ้ายังไม่มี
npm install -g wrangler

# manual deploy (จาก root)
pnpm --filter @wms/web build
wrangler pages deploy apps/web/dist --project-name=wms-dev --branch=main

pnpm --filter @wms/admin build
wrangler pages deploy apps/admin/dist --project-name=wms-admin --branch=main

pnpm --filter @wms/docs build
wrangler pages deploy apps/docs/.vitepress/dist --project-name=wms-docs --branch=main

Env vars สำหรับ frontend (apps/{web,admin}/.env.production)

bash
VITE_API_URL=https://wms-api-dev-2w6s.onrender.com

(prefix VITE_ จำเป็นเพื่อให้ Vite expose สู่ client bundle)

Backend → Render.com

render.yaml (infra-as-code):

yaml
services:
  - type: web
    name: wms-api-dev
    runtime: node
    region: singapore
    plan: free
    rootDir: .
    buildCommand: |
      npm install -g pnpm &&
      pnpm install &&
      cd apps/api &&
      npx prisma generate &&
      pnpm build
    startCommand: cd apps/api && node dist/main
    envVars:
      - key: NODE_ENV
        value: development
      - key: DATABASE_URL
        sync: false
      - key: DIRECT_URL
        sync: false
      - key: JWT_SECRET
        sync: false
      - key: CORS_ORIGIN
        sync: false

Free tier behavior

  • Auto-sleep หลัง 15 นาทีไม่มี traffic → request แรกหลังหลับจะรอ ~30 วินาที (cold start)
  • ดูวิธีจัดการ: Cold Start Troubleshooting
  • เพื่อหลีกเลี่ยง → upgrade เป็น Starter plan

Auto-deploy

Render listen GitHub webhook — push to master → auto build + redeploy

Required env vars

จาก app.module.ts (Joi validation):

Env varRequiredDefaultคำอธิบาย
DATABASE_URLSupabase pooled (port 6543)
DIRECT_URLSupabase direct (port 5432) — สำหรับ migrations
JWT_SECRET≥ 16 ตัว — app refuse to start ถ้าไม่ตั้ง
JWT_ACCESS_TTL900access token TTL (วินาที)
JWT_REFRESH_TTL604800refresh token TTL
APP_PORT3000(Render override ผ่าน PORT)
APP_TIERSS/M/L — กำหนด feature gating
NODE_ENVdevelopmentdevelopment/uat/production/test
CORS_ORIGINhttp://localhost:5173comma-separated
R2_ENDPOINT''Cloudflare R2 endpoint
R2_ACCESS_KEY_ID''R2 access key
R2_SECRET_ACCESS_KEY''R2 secret
R2_BUCKET_NAMEwms-filesbucket

port binding

Render inject PORT env var ตอนรัน — main.ts ใช้ก่อน fallback APP_PORT:

typescript
const port = config.get<number>('PORT') || config.get<number>('APP_PORT', 3000);

Database → Supabase

  • PostgreSQL 16 managed
  • Region: aws-1-ap-northeast-2 (Seoul) — ใกล้ Singapore ที่สุดในแถว free tier
  • 2 URLs:
    • DATABASE_URL — pooled (PgBouncer port 6543) — ใช้ runtime
    • DIRECT_URL — direct (port 5432) — ใช้ Prisma migrate/introspect
  • 3 separate Supabase projects แนะนำ (dev / uat / prod) — เพื่อแยก data

Schema management

bash
# apply schema ตรงๆ ไม่สร้าง migration file (สำหรับ Supabase)
pnpm db:push                # = prisma db push

# สร้าง migration file (local dev เท่านั้น)
pnpm db:migrate             # = prisma migrate dev

# regen Prisma Client หลัง schema เปลี่ยน
pnpm db:generate            # = prisma generate

ระบบใช้ db push workflow ใน Supabase (ไม่ commit migration files) — เหมาะกับทีมเล็กที่ schema เปลี่ยนบ่อย

CI/CD Flow

   Developer

       │  git push origin master

┌──────────────┐
│   GitHub     │
└──────┬───────┘

       ├─── webhook ───────► ┌──────────────┐
       │                     │ Render       │  ──► backend redeploy
       │                     │ (auto)       │      (~5 min build + deploy)
       │                     └──────────────┘

       └─── manual ──────► wrangler pages deploy ──► ┌──────────────────┐
                                                     │ Cloudflare Pages │
                                                     │ wms-dev          │
                                                     │ wms-admin        │
                                                     │ wms-docs         │
                                                     └──────────────────┘

ฝั่ง Cloudflare Pages สามารถผูก GitHub repo + auto-build ได้เหมือนกัน — แต่ปัจจุบันใช้ manual wrangler เพื่อให้ control timing ของ deploy

Local Development Stack (Optional)

ถ้าไม่อยากใช้ Supabase ตอน dev — ใช้ docker-compose.yml:

bash
docker compose up -d        # start postgres + redis + api

ดู Local Development สำหรับรายละเอียด

Health Check

bash
curl https://wms-api-dev-2w6s.onrender.com/api/v1/health/live
# {"status":"ok"}

curl https://wms-api-dev-2w6s.onrender.com/api/v1/health/ready
# {"status":"ok","db":"connected"}

curl https://wms-api-dev-2w6s.onrender.com/api/v1/health/stats
# { uptime, memory, dbResponseTime, ... }

Render ตั้ง health check path → /api/v1/health/live ก็พอ

เผยแพร่ภายใต้ Digital Outsourcing