Bỏ qua

Multi-environment Deployment

Environment Strategy

Staging → Production Flow

┌─────────────────────────────────────────────────────────────┐
│                  DEPLOYMENT FLOW                             │
├─────────────────────────────────────────────────────────────┤
│                                                              │
│  Developer                                                   │
│     │                                                        │
│     ▼                                                        │
│  Feature Branch ──▶ PR ──▶ Code Review                      │
│                              │                               │
│                              ▼                               │
│                         Merge to staging                     │
│                              │                               │
│                              ▼                               │
│  ┌───────────────────────────────────────────────────┐      │
│  │              STAGING ENVIRONMENT                   │      │
│  │  - staging.myapp.com                              │      │
│  │  - Supabase staging project                       │      │
│  │  - Cloudflare staging worker                      │      │
│  │  - Test with real data (sanitized)               │      │
│  └───────────────────────────────────────────────────┘      │
│                              │                               │
│                         Manual approval                      │
│                              │                               │
│                              ▼                               │
│  ┌───────────────────────────────────────────────────┐      │
│  │            PRODUCTION ENVIRONMENT                  │      │
│  │  - myapp.com                                      │      │
│  │  - Supabase production project                    │      │
│  │  - Cloudflare production worker                   │      │
│  └───────────────────────────────────────────────────┘      │
│                                                              │
└─────────────────────────────────────────────────────────────┘

Branch Strategy

Git Flow cho Light Stack

main (production)
  ├── staging (staging env)
  │     │
  │     ├── feature/add-user-auth
  │     ├── feature/task-list
  │     └── fix/login-bug
  └── Hotfix branches (direct to main)

Branch Rules

main:
- Protected branch
- Requires PR + approval
- Auto-deploy to production
- No direct pushes

staging:
- Auto-deploy to staging
- Merge features here first
- Integration testing

feature/*:
- Development work
- PR to staging
- CI checks must pass

GitHub Environments

Setup Environments

Repository Settings → Environments

1. Create "staging" environment
   - No protection rules (auto-deploy)
   - Secrets: SUPABASE_URL, etc.

2. Create "production" environment
   - Required reviewers: 1+
   - Wait timer: Optional
   - Deployment branches: main only
   - Secrets: Production values

Environment Secrets

staging:
├── SUPABASE_URL=https://staging-xxx.supabase.co
├── SUPABASE_ANON_KEY=eyJ...staging
├── SUPABASE_SERVICE_KEY=eyJ...staging
├── CLOUDFLARE_ACCOUNT_ID=xxx
└── CLOUDFLARE_API_TOKEN=xxx

production:
├── SUPABASE_URL=https://xxx.supabase.co
├── SUPABASE_ANON_KEY=eyJ...production
├── SUPABASE_SERVICE_KEY=eyJ...production
├── CLOUDFLARE_ACCOUNT_ID=xxx
└── CLOUDFLARE_API_TOKEN=xxx

Complete Workflow

Multi-environment Deploy

# .github/workflows/deploy.yml
name: Deploy

on:
  push:
    branches: [staging, main]
  pull_request:
    branches: [staging, main]

env:
  NODE_VERSION: '20'

jobs:
  # ========================================
  # Build and Test (all branches)
  # ========================================
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: ${{ env.NODE_VERSION }}
          cache: 'npm'

      - name: Install dependencies
        run: npm ci

      - name: Lint
        run: npm run lint

      - name: Type check
        run: npm run type-check

      - name: Test
        run: npm run test

      - name: Build
        run: npm run build

      - name: Upload build artifacts
        uses: actions/upload-artifact@v4
        with:
          name: build
          path: .open-next/
          retention-days: 1

  # ========================================
  # Deploy to Staging
  # ========================================
  deploy-staging:
    needs: build
    if: github.ref == 'refs/heads/staging'
    runs-on: ubuntu-latest
    environment: staging
    steps:
      - uses: actions/checkout@v4

      - name: Download build artifacts
        uses: actions/download-artifact@v4
        with:
          name: build
          path: .open-next/

      - name: Setup Supabase CLI
        uses: supabase/setup-cli@v1

      - name: Run Supabase Migrations
        run: |
          supabase link --project-ref ${{ vars.SUPABASE_PROJECT_REF }}
          supabase db push
        env:
          SUPABASE_ACCESS_TOKEN: ${{ secrets.SUPABASE_ACCESS_TOKEN }}

      - name: Deploy to Cloudflare
        uses: cloudflare/wrangler-action@v3
        with:
          apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
          accountId: ${{ vars.CLOUDFLARE_ACCOUNT_ID }}
          command: deploy --env staging

  # ========================================
  # Deploy to Production
  # ========================================
  deploy-production:
    needs: build
    if: github.ref == 'refs/heads/main'
    runs-on: ubuntu-latest
    environment: production
    steps:
      - uses: actions/checkout@v4

      - name: Download build artifacts
        uses: actions/download-artifact@v4
        with:
          name: build
          path: .open-next/

      - name: Setup Supabase CLI
        uses: supabase/setup-cli@v1

      - name: Run Supabase Migrations
        run: |
          supabase link --project-ref ${{ vars.SUPABASE_PROJECT_REF }}
          supabase db push
        env:
          SUPABASE_ACCESS_TOKEN: ${{ secrets.SUPABASE_ACCESS_TOKEN }}

      - name: Deploy to Cloudflare
        uses: cloudflare/wrangler-action@v3
        with:
          apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
          accountId: ${{ vars.CLOUDFLARE_ACCOUNT_ID }}
          command: deploy --env production

Cloudflare Environments

wrangler.toml

name = "my-app"
main = "src/index.ts"
compatibility_date = "2024-01-15"

# Default (production) environment
[vars]
ENVIRONMENT = "production"
NEXT_PUBLIC_SUPABASE_URL = "https://xxx.supabase.co"

# Staging environment
[env.staging]
name = "my-app-staging"
[env.staging.vars]
ENVIRONMENT = "staging"
NEXT_PUBLIC_SUPABASE_URL = "https://staging-xxx.supabase.co"

# KV bindings per environment
[[kv_namespaces]]
binding = "MY_KV"
id = "production-kv-id"

[[env.staging.kv_namespaces]]
binding = "MY_KV"
id = "staging-kv-id"

Supabase Multi-project

Project per Environment

Supabase Dashboard
├── my-app-staging (staging project)
│   └── Project ref: staging-xxx
└── my-app (production project)
    └── Project ref: xxx

Migrations for Both

# Link to staging
supabase link --project-ref staging-xxx
supabase db push

# Link to production
supabase link --project-ref xxx
supabase db push

Environment Variables

Next.js Environment Files

# .env.local (local development)
NEXT_PUBLIC_SUPABASE_URL=http://localhost:54321
NEXT_PUBLIC_SUPABASE_ANON_KEY=local-key

# .env.staging (staging - not committed)
NEXT_PUBLIC_SUPABASE_URL=https://staging-xxx.supabase.co
NEXT_PUBLIC_SUPABASE_ANON_KEY=staging-key

# .env.production (production - not committed)
NEXT_PUBLIC_SUPABASE_URL=https://xxx.supabase.co
NEXT_PUBLIC_SUPABASE_ANON_KEY=production-key

Build-time Variables

# In GitHub Actions
- name: Build for staging
  run: npm run build
  env:
    NEXT_PUBLIC_SUPABASE_URL: ${{ vars.SUPABASE_URL }}
    NEXT_PUBLIC_SUPABASE_ANON_KEY: ${{ secrets.SUPABASE_ANON_KEY }}

Tổng kết

Environment Setup Checklist

  • [ ] Create staging Supabase project
  • [ ] Create production Supabase project
  • [ ] Configure wrangler.toml environments
  • [ ] Setup GitHub environments
  • [ ] Add secrets per environment
  • [ ] Configure branch protection
  • [ ] Setup deployment workflow

Key Points

✅ Separate Supabase projects per environment
✅ GitHub environments for secrets isolation
✅ wrangler.toml [env.staging] for Cloudflare
✅ Automatic deploy on push to branch
✅ Manual approval for production

Q&A

  1. Có cần staging environment không?
  2. Approval process cho production?
  3. Rollback strategy?