Skip to content

Deployment ​

瑞成 PMS 以單一 Next.js 服務(next-app/)部署。主要目標是 Zeabur; GCP Cloud Run + Cloud SQL 為備援路線。deploy-config skill 兩條路都有說明。

三個環境(dev → stg → prd) ​

每個環境各有一個 git 分支與一個 Zeabur 專案,各自擁有獨立的 PostgreSQL(資料庫從不跨環境共用):

環境分支網址資料
devdevhttps://dev-pms.rei-chen.comdb:seed 完整示範資料;ENABLE_DEMO_LOGIN=true
stgstghttps://stg-pms.rei-chen.comdb:seed-admin + db:seed-baseline,無示範資料
prdprdhttps://pms.rei-chen.com同 stg;只在使用者明確下指令後才部署,且先 pg_dump 備份

晉升順序固定 dev → stg → prd,不跳級。三個環境的專案/服務/環境 ID 與連結見 docs/deployment/zeabur-environments.md。目前三個環境都在同一台 2C4G 伺服器上(6 個服務),執行期餘裕很小。

發版與晉升的實際指令(v1.3.0 起腳本化) ​

在乾淨的 origin/main checkout(不要在有未提交變更的工作樹)執行,順序固定:

bash
# 1. 資料庫:先驗證過的備份(pg_dump → ~/pms-backups/),再 migrate;暫時開的對外連接埠一定會關掉
scripts/deploy/zeabur-db.sh <dev|stg|prd> backup
scripts/deploy/zeabur-db.sh <dev|stg|prd> migrate        # HEAD 必須等於 origin/main,否則拒絕;prd 另需 CONFIRM_PRD=yes
scripts/deploy/zeabur-db.sh <dev|stg|prd> sql scripts/checks/frozen-date-scan.sql   # 唯讀稽核掃描

# 2. 應用:一定從 next-app/ 上傳(不是 repo 根目錄,否則會建出 404 的 app)
cd next-app && zeabur deploy --project-id <PID> --service-id <SID> --environment-id <EID> -i=false

# 3. 驗證:真的登入 + 核心頁 + 執行期 log + 側欄版本,不是只看 200
scripts/deploy/verify-env.sh <env> --version <x.y.z>

# 4. 紀錄:把 dev/stg/prd 分支併到與 main 同一棵樹(純 merge,不 force)
scripts/deploy/sync-env-branches.sh dev stg prd
  • migration 不會在啟動時自動執行。 next-app 的 start 就是 next start,執行期映像是 Next.js standalone(沒有 pnpm、沒有 drizzle-kit),所以必須由 zeabur-db.sh migrate 從本機對資料庫開暫時連接埠執行。先 migrate、再部署程式;migration 設計為純新增,舊版程式在新 schema 上仍可運作,回滾才安全。
  • zeabur-db.sh 與 rotate-pg-password.sh 不會把密碼印出來。輪替資料庫密碼用 scripts/deploy/rotate-pg-password.sh <dev|stg>:新密碼只存在 ~/pms-secrets/<env>-postgres-password.txt(權限 600,請移進密碼管理員後刪檔)。
  • 要把使用者名冊 CSV 匯入 stg/prd(不必先登入 App、同樣的稽核軌跡):scripts/deploy/import-roster.sh <env> <csv> [--dry-run|--verify] [--expect-badges],流程與 prd 規則見 docs/deployment/roster-import.md。
  • *.zeabur.app 網域仍可用,但文件與連結一律用 *.rei-chen.com。
  • 使用者手冊(user-docs/)的 Cloudflare Pages 部署目前因 GitHub Actions 帳務問題無法由 CI 執行,需手動 npx wrangler@4 pages deploy;修好前,每次手冊變更都要手動發佈。

Zeabur Deployment ​

Environment Variables (set in Zeabur before build) ​

env
# Required (runtime)
DATABASE_URL=postgresql://user:pass@host:5432/db
AUTH_SECRET=<openssl rand -base64 32>
AUTH_URL=https://your-app.zeabur.app
AUTH_TRUST_HOST=true

# Optional — build-time (baked into the bundle)
NEXT_PUBLIC_APP_URL=https://your-app.zeabur.app
NEXT_PUBLIC_SENTRY_DSN=https://...@sentry.io/...

瑞成 PMS 以工牌編號 + 密碼(Credentials)登入,不使用 OAuth;也沒有金流 (Stripe / ECPay 等 billing 功能已從產品移除)。因此無需設定 OAuth 或 payment provider 環境變數。

執行期開關(皆為執行期環境變數,切換不需重新建置):ENABLE_DEMO_LOGIN(只開在 dev)、 ENABLE_API_DOCS(prd 不開)、ENABLE_LOGIN_LOCKOUT(預設開)、NOTIFICATION_SCAN_CRON(覆寫預設的每小時整點燈號掃描,時區 Asia/Taipei)。

NEXT_PUBLIC_* are baked at build time — set them in the Zeabur dashboard before the build runs. AUTH_SECRET, DATABASE_URL, and other secrets are read at runtime; keep them out of NEXT_PUBLIC_*.

Deploy Steps ​

  1. Push your repo to GitHub.
  2. Create a Zeabur project → Add Service → point at next-app/.
  3. Zeabur auto-detects Next.js via next-app/zbpack.json.
  4. Set environment variables in the Zeabur dashboard.
  5. Trigger a deploy from next-app/(zeabur deploy;Zeabur 會忽略 .gitignore,靠 next-app/.zeaburignore 排除 node_modules/、.next/,否則上傳超過方案的 250 MB 上限)。Health check: https://your-app.zeabur.app/api/health。
  6. 字型已自架(@fontsource-variable/*),建置不再需要連到 Google Fonts(舊版曾因此在 Zeabur 建置失敗)。

Migrations 不會在啟動時自動執行(start 就是 next start)——請用上方的 scripts/deploy/zeabur-db.sh <env> migrate。

GCP Cloud Run + Cloud SQL ​

Build from next-app/Dockerfile, push to Artifact Registry, deploy to Cloud Run, and attach Cloud SQL (Postgres) via the Cloud SQL connector. lib/db.ts lazy-inits the connection so the build succeeds without DATABASE_URL — the runtime reads it from the Cloud Run env. See the deploy-config skill (Road 2) for the CLI walkthrough.

Cloudflare Pages (dev-docs) ​

The dev-docs/ VitePress site deploys to Cloudflare Pages via the gh-cf-deploy skill.

Build settings:

  • Build command: pnpm build
  • Build output directory: .vitepress/dist
  • Root directory: dev-docs
  • Environment variables: VITEPRESS_API_BASE(將 API playground 指向你部署後的 Next.js app)

Docker ​

A root docker-compose.yml runs the whole stack (Postgres, Mailpit, Next.js app) locally:

bash
docker compose up --build -d   # app on http://localhost:3000, Mailpit on http://localhost:8025
docker compose down            # stop (add -v to drop the db volume)

For production Docker, build next-app/Dockerfile directly.

Released under the MIT License.