# ROBOTS ON PAYROLL / THE VAULT
# What this is: a GitHub Actions production deploy workflow: test, migrate the database, deploy to Vercel, alert on failure.
# How to use it: download this file and give it to your AI (Claude, ChatGPT,
# Cursor, Lovable chat) as a reference. Say: "Use this as my playbook for
# setting up my production deploy."
# Latest version + full guide: https://robotsonpayroll.com/resources/github-actions-runbooks
#
# deploy-with-migrations.yml
# Production deploy: test -> migrate DB -> deploy to Vercel -> alert on failure.
# Action versions current as of July 2026 (checkout v7, setup-node v6).
#
# SECRETS REQUIRED (Settings -> Secrets and variables -> Actions):
#   VERCEL_TOKEN        - Vercel access token (vercel.com/account/tokens, scope to one project if on a team)
#   VERCEL_ORG_ID       - from .vercel/project.json after running `vercel link` locally
#   VERCEL_PROJECT_ID   - same file
#   DATABASE_URL        - production Postgres connection string. Use the DIRECT
#                         (or session-mode) string, not the transaction pooler:
#                         prisma migrate fails through transaction pooling.
#   ALERT_WEBHOOK_URL   - Slack or Discord incoming webhook URL
#
# ONE-TIME SETUP:
#   1. Run `vercel link` locally, copy the two IDs from .vercel/project.json into secrets.
#   2. Disable Vercel's Git auto-deploy for this project (or set "git": { "deploymentEnabled": false }
#      in vercel.json). Otherwise Vercel and this workflow will both deploy every push and race.
#   3. Swap the migration command for your tool (prisma / drizzle / whatever you use).

name: Deploy to production

on:
  push:
    branches: [main]
  workflow_dispatch: {} # manual "Run workflow" button, useful for redeploys

# Deploys must never overlap. Same group name for every run of this workflow,
# cancel-in-progress: false means a second push QUEUES behind the running deploy
# instead of killing it mid-migration. GitHub keeps at most one run queued;
# older queued runs get superseded, which is what you want.
concurrency:
  group: production-deploy
  cancel-in-progress: false

env:
  VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }}
  VERCEL_PROJECT_ID: ${{ secrets.VERCEL_PROJECT_ID }}

jobs:
  deploy:
    runs-on: ubuntu-latest
    # Least privilege: this job only needs to read the repo.
    permissions:
      contents: read
    # Optional but recommended: create a "production" environment in
    # Settings -> Environments and move DATABASE_URL there. You can then add
    # required reviewers or a wait timer in front of prod deploys.
    environment:
      name: production
      url: ${{ steps.deploy.outputs.url }}

    steps:
      - name: Check out code
        uses: actions/checkout@v7

      - name: Set up Node
        uses: actions/setup-node@v6
        with:
          node-version: 22
          cache: npm # v6 only auto-caches npm; set 'pnpm' or 'yarn' explicitly if you use those

      - name: Install dependencies
        run: npm ci # ci, not install: exact lockfile versions, fails loudly on drift

      # Gate: broken code should never reach the migration step, let alone prod.
      - name: Run tests
        run: npm test

      # ---- DATABASE MIGRATION ----
      # Runs BEFORE the deploy so new code never talks to an old schema.
      # This ordering means migrations must be backward-compatible:
      # old code (still serving traffic) must survive the new schema for
      # the ~60s until the deploy finishes. Additive changes (new tables,
      # new nullable columns) are safe. Renames and drops are two-deploy jobs.
      - name: Run database migrations
        env:
          DATABASE_URL: ${{ secrets.DATABASE_URL }}
        run: npx prisma migrate deploy
        # drizzle:  npx drizzle-kit migrate
        # raw SQL:  psql "$DATABASE_URL" -f migrations/latest.sql
        # none yet: delete this step, add it back when you have a DB

      # ---- VERCEL DEPLOY (build here, ship prebuilt output) ----
      # vercel pull  = fetch project settings + prod env vars into .vercel/
      # vercel build = build locally on this runner using those settings
      # deploy --prebuilt = upload the finished build; Vercel never rebuilds
      - name: Install Vercel CLI
        run: npm install --global vercel@latest

      - name: Pull Vercel production settings
        run: vercel pull --yes --environment=production --token=${{ secrets.VERCEL_TOKEN }}

      - name: Build
        run: vercel build --prod --token=${{ secrets.VERCEL_TOKEN }}

      - name: Deploy to production
        id: deploy
        run: |
          url=$(vercel deploy --prebuilt --prod --token=${{ secrets.VERCEL_TOKEN }})
          echo "url=$url" >> "$GITHUB_OUTPUT"
          echo "Deployed: $url"

      # ---- FAILURE ALERT ----
      # if: failure() makes this run ONLY when an earlier step failed.
      # Works with Slack and Discord; both accept a JSON body on their
      # incoming webhook URL (Discord wants "content", Slack wants "text",
      # sending both keys works for either).
      - name: Alert on failure
        if: failure()
        env:
          WEBHOOK: ${{ secrets.ALERT_WEBHOOK_URL }}
        run: |
          msg="Production deploy FAILED on ${GITHUB_REPOSITORY}@${GITHUB_REF_NAME}. Run: ${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID}"
          curl -sS -X POST -H 'Content-Type: application/json' \
            -d "{\"text\": \"$msg\", \"content\": \"$msg\"}" \
            "$WEBHOOK"
