From 6e5c91b6fa15d4c6b1b9b11b06eae1eb7909607b Mon Sep 17 00:00:00 2001 From: Madhura68 Date: Tue, 5 May 2026 23:31:34 +0200 Subject: [PATCH 1/4] feat(T-553): vercel.json git.deploymentEnabled=false + GitHub-labels Vercel's eigen Git-integratie uitzetten zodat de GitHub Actions workflow de enige bron van deploy-truth wordt. Plus labels skip-deploy en force-deploy aangemaakt voor selectieve controle in volgende taken. Co-Authored-By: Claude Opus 4.7 (1M context) --- vercel.json | 1 + 1 file changed, 1 insertion(+) diff --git a/vercel.json b/vercel.json index 311c925..cbf80c2 100644 --- a/vercel.json +++ b/vercel.json @@ -1,5 +1,6 @@ { "$schema": "https://openapi.vercel.sh/vercel.json", + "git": { "deploymentEnabled": false }, "crons": [ { "path": "/api/cron/expire-questions", From fe56d4e0c1aba8693e95178c4707c3f03f448ffa Mon Sep 17 00:00:00 2001 From: Madhura68 Date: Tue, 5 May 2026 23:35:22 +0200 Subject: [PATCH 2/4] feat(T-554/T-555/T-556): selectieve deploy-controle in workflow Drie samenhangende wijzigingen in ci.yml: T-554: Nieuwe `changes` job met dorny/paths-filter@v3 die per push/PR detecteert of er deploy-relevante paden zijn gewijzigd. Output `code` boolean wordt door de deploy-jobs gelezen. T-555: deploy-preview if-conditie checkt nu `needs.changes.outputs.code` plus PR-labels: deployt als (code-changed AND niet skip-deploy) OR force-deploy. deploy-production deployt alleen bij code-changed pushes naar main (path-filter op productie). T-556: workflow_dispatch trigger toegevoegd met `target: preview | production` input + nieuwe deploy-manual job. Geeft handmatige re-deploy via Actions-tab. CI-job slaat workflow_dispatch over (geen nieuwe code, alleen redeploy). Co-Authored-By: Claude Opus 4.7 (1M context) --- .github/workflows/ci.yml | 93 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 89 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e9b47e8..ffc478b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -5,11 +5,19 @@ on: branches: [main] pull_request: branches: [main] + workflow_dispatch: + inputs: + target: + type: choice + description: Deploy target + options: [preview, production] + default: preview jobs: ci: name: Lint, Typecheck, Test & Build runs-on: ubuntu-latest + if: github.event_name != 'workflow_dispatch' steps: - name: Checkout @@ -49,11 +57,46 @@ jobs: DIRECT_URL: ${{ secrets.DIRECT_URL }} SESSION_SECRET: ${{ secrets.SESSION_SECRET }} + changes: + name: Detect deploy-relevant changes + runs-on: ubuntu-latest + needs: ci + if: github.event_name != 'workflow_dispatch' + outputs: + code: ${{ steps.filter.outputs.code }} + steps: + - uses: actions/checkout@v5 + - uses: dorny/paths-filter@v3 + id: filter + with: + filters: | + code: + - 'app/**' + - 'components/**' + - 'lib/**' + - 'actions/**' + - 'stores/**' + - 'prisma/**' + - 'public/**' + - 'package.json' + - 'package-lock.json' + - 'next.config.ts' + - 'tsconfig.json' + - 'vercel.json' + - 'proxy.ts' + - 'middleware.ts' + - '.github/workflows/**' + deploy-preview: name: Deploy Preview (PR) runs-on: ubuntu-latest - needs: ci - if: github.event_name == 'pull_request' + needs: [ci, changes] + if: | + github.event_name == 'pull_request' && ( + (needs.changes.outputs.code == 'true' + && !contains(github.event.pull_request.labels.*.name, 'skip-deploy')) + || contains(github.event.pull_request.labels.*.name, 'force-deploy') + ) steps: - name: Checkout @@ -80,8 +123,11 @@ jobs: deploy-production: name: Deploy Production (main) runs-on: ubuntu-latest - needs: ci - if: github.ref == 'refs/heads/main' && github.event_name == 'push' + needs: [ci, changes] + if: | + github.ref == 'refs/heads/main' + && github.event_name == 'push' + && needs.changes.outputs.code == 'true' steps: - name: Checkout @@ -110,3 +156,42 @@ jobs: env: VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }} VERCEL_PROJECT_ID: ${{ secrets.VERCEL_PROJECT_ID }} + + deploy-manual: + name: Deploy Manual (workflow_dispatch) + runs-on: ubuntu-latest + if: github.event_name == 'workflow_dispatch' + + steps: + - name: Checkout + uses: actions/checkout@v5 + + - name: Setup Node.js + uses: actions/setup-node@v5 + with: + node-version: '24' + cache: 'npm' + + - name: Install dependencies + run: npm ci + + - name: Install Vercel CLI + run: npm install -g vercel@latest + + - name: Run database migrations (production only) + if: inputs.target == 'production' + run: npx prisma migrate deploy + env: + DATABASE_URL: ${{ secrets.DATABASE_URL }} + DIRECT_URL: ${{ secrets.DIRECT_URL }} + + - name: Deploy + run: | + if [ "${{ inputs.target }}" = "production" ]; then + vercel deploy --prod --token=${{ secrets.VERCEL_TOKEN }} + else + vercel deploy --token=${{ secrets.VERCEL_TOKEN }} + fi + env: + VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }} + VERCEL_PROJECT_ID: ${{ secrets.VERCEL_PROJECT_ID }} From ee793e9af4c19cff63432c5f03067b02c6a92129 Mon Sep 17 00:00:00 2001 From: Madhura68 Date: Tue, 5 May 2026 23:36:48 +0200 Subject: [PATCH 3/4] docs(T-557): deploy-control runbook + CLAUDE.md verwijzing docs/runbooks/deploy-control.md beschrijft triggers (push/PR/dispatch), path-filter, labels (skip-deploy/force-deploy), beslismatrix per scenario, voorbeelden en troubleshooting. CLAUDE.md hardstop-regel "Deployment" verwijst naar runbook. Co-Authored-By: Claude Opus 4.7 (1M context) --- CLAUDE.md | 2 +- docs/INDEX.md | 1 + docs/runbooks/deploy-control.md | 160 ++++++++++++++++++++++++++++++++ 3 files changed, 162 insertions(+), 1 deletion(-) create mode 100644 docs/runbooks/deploy-control.md diff --git a/CLAUDE.md b/CLAUDE.md index 0b85bf0..ea2dbb5 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -56,7 +56,7 @@ Volledige MCP-tool documentatie: [docs/runbooks/mcp-integration.md](./docs/runbo - **Enum:** DB UPPER_SNAKE ↔ API lowercase — uitsluitend via `lib/task-status.ts` - **Foutcodes:** 400 = parse-fout, 422 = Zod-validatie, 403 = demo-token - **Server/client grens:** `*-server.ts` bevat DB/node-only; nooit importeren in client component -- **Deployment:** `npm run lint && npm test && npm run build` vóór elke PR +- **Deployment:** `npm run lint && npm test && npm run build` vóór elke PR. Selectieve deploy-controle (labels + path-filter): zie [docs/runbooks/deploy-control.md](./docs/runbooks/deploy-control.md) --- diff --git a/docs/INDEX.md b/docs/INDEX.md index e575498..b541fcc 100644 --- a/docs/INDEX.md +++ b/docs/INDEX.md @@ -111,6 +111,7 @@ Auto-generated on 2026-05-05 from front-matter and headings. | [Realtime smoke-checklist — PBI / Story / Task](./realtime-smoke.md) | `realtime-smoke.md` | active | 2026-05-03 | | [Agent-flow: open issues & decision log](./runbooks/agent-flow-pitfalls.md) | `runbooks/agent-flow-pitfalls.md` | active | 2026-05-03 | | [Branch, PR & Commit Strategy](./runbooks/branch-and-commit.md) | `runbooks/branch-and-commit.md` | active | 2026-05-03 | +| [Deploy-controle: triggers, labels, path-filter](./runbooks/deploy-control.md) | `runbooks/deploy-control.md` | active | 2026-05-05 | | [Vercel Deployment](./runbooks/deploy-vercel.md) | `runbooks/deploy-vercel.md` | active | 2026-05-03 | | [MCP Integration — Scrum4Me Tools](./runbooks/mcp-integration.md) | `runbooks/mcp-integration.md` | active | 2026-05-03 | | [v1.0 Smoke Test Checklist](./runbooks/v1-smoke-test.md) | `runbooks/v1-smoke-test.md` | active | 2026-05-04 | diff --git a/docs/runbooks/deploy-control.md b/docs/runbooks/deploy-control.md new file mode 100644 index 0000000..8e59331 --- /dev/null +++ b/docs/runbooks/deploy-control.md @@ -0,0 +1,160 @@ +--- +title: "Deploy-controle: triggers, labels, path-filter" +status: active +audience: [contributor, ai-agent] +language: nl +last_updated: 2026-05-05 +when_to_read: "Vóór een PR mergen, vóór doc-only changes pushen, of bij troubleshooting van Vercel-deployments." +--- + +# Deploy-controle + +Selectieve controle over wanneer Vercel-deployments worden uitgevoerd +vanuit de GitHub Actions workflow `.github/workflows/ci.yml`. Vercel's +eigen Git-integratie staat **uit** (`vercel.json: git.deploymentEnabled: +false`) — de workflow is de enige bron van deploy-truth. + +--- + +## Triggers en defaults + +| Event | Default-deploy | +|---|---| +| `push` naar `main` | Productie (`vercel deploy --prod`) — alleen als path-filter zegt "code" | +| `pull_request` naar `main` | Preview (`vercel deploy`) — alleen als path-filter zegt "code" en geen `skip-deploy` label | +| `workflow_dispatch` | Handmatig — kies `target: preview \| production` in Actions-tab | + +CI (lint, typecheck, test, build) draait **altijd** op push/PR — ook +voor doc-only changes. Alleen de deploy-jobs respecteren path-filter +en labels. + +--- + +## Path-filter + +Job `changes` (dorny/paths-filter@v3) zet output `code=true` als +één van deze paden gewijzigd is: + +``` +app/** +components/** +lib/** +actions/** +stores/** +prisma/** +public/** +package.json +package-lock.json +next.config.ts +tsconfig.json +vercel.json +proxy.ts +middleware.ts +.github/workflows/** +``` + +Wijzigingen aan `docs/`, `CLAUDE.md`, `README.md`, `.vscode/**`, etc. +zetten `code=false` → **geen deploy** (zelfs niet preview). + +--- + +## Labels (alleen op PRs) + +| Label | Effect | +|---|---| +| `skip-deploy` | Preview-deploy overslaan, ook als path-filter "code" zegt | +| `force-deploy` | Preview-deploy forceren, ook als path-filter "geen code" zegt | + +Beide labels werken alleen op **PR's**. Op pushes naar `main` heeft +alleen path-filter invloed (productie-gate). + +--- + +## Beslismatrix per scenario + +| Trigger | Path-filter | Labels | Resultaat | +|---|---|---|---| +| PR met code-change | `code=true` | (geen) | ✅ Preview-deploy | +| PR met code-change | `code=true` | `skip-deploy` | ❌ Preview overgeslagen | +| PR met doc-only | `code=false` | (geen) | ❌ Geen deploy | +| PR met doc-only | `code=false` | `force-deploy` | ✅ Preview-deploy | +| PR met code-change | `code=true` | `skip-deploy` + `force-deploy` | ✅ `force-deploy` wint | +| Push main code | `code=true` | n.v.t. | ✅ Productie-deploy + migrate | +| Push main doc-only | `code=false` | n.v.t. | ❌ Geen deploy | +| `workflow_dispatch` `target=preview` | n.v.t. | n.v.t. | ✅ Manuele preview | +| `workflow_dispatch` `target=production` | n.v.t. | n.v.t. | ✅ Manuele prod + migrate | + +--- + +## Voorbeelden + +**Doc-only PR die je niet wil deployen** (default): + +```bash +git checkout -b docs/fix-typo +# alleen docs/foo.md aanpassen +git commit -am "docs: typo" +gh pr create +# → CI runt, deploy-preview = SKIPPED +``` + +**Doc-only PR die je wél visueel wil checken**: + +```bash +gh pr create +gh pr edit --add-label force-deploy +# → CI runt, deploy-preview RUNT +``` + +**Code-PR die je niet wil deployen** (bv. WIP): + +```bash +gh pr create +gh pr edit --add-label skip-deploy +# → CI runt, deploy-preview SKIPPED +``` + +**Manuele productie-redeploy zonder push**: + +1. GitHub repo → Actions → CI workflow → "Run workflow" knop +2. `target: production` → Run +3. → `deploy-manual` job draait `prisma migrate deploy` + `vercel deploy --prod` + +--- + +## Troubleshooting + +**Probleem**: Twee deploys verschijnen op Vercel-dashboard per push. + +→ Check `vercel.json` bevat `"git": { "deploymentEnabled": false }`. Zo +niet: Vercel's eigen Git-integratie deployt parallel naast de workflow. + +**Probleem**: Mijn PR met code-change deployt geen preview. + +→ Check labels: heb je `skip-deploy` aangezet? Verwijder het label of +voeg `force-deploy` toe. +→ Check `changes`-job output in Actions-tab: zegt het `code=false`? +Mogelijk staat je wijziging buiten de path-filter (bv. een nieuw +top-level bestand). Pas filter aan in `ci.yml` als nodig. + +**Probleem**: Push naar main triggert geen prod-deploy. + +→ Check Actions-tab `changes`-job output. `code=false` betekent geen +deploy. +→ Forceer via `workflow_dispatch` met `target=production`. + +**Probleem**: `workflow_dispatch` toont geen "Run workflow" knop. + +→ Workflow moet minstens één keer op de default branch (main) hebben +gedraaid voordat de knop verschijnt. Eerste keer: merge naar main of +push direct naar main. + +--- + +## Referenties + +- Workflow: `.github/workflows/ci.yml` +- Vercel-config: `vercel.json` +- Plan: `docs/plans/auto-pr-deploy-sync.md` Deel A +- Branch- & commit-strategie: [`docs/runbooks/branch-and-commit.md`](./branch-and-commit.md) +- Auto-PR-flow (toekomstig): `docs/plans/auto-pr-deploy-sync.md` Deel B From a57eadbbd343de84f27cf6061f7ae116fa0d4a46 Mon Sep 17 00:00:00 2001 From: Madhura68 Date: Wed, 6 May 2026 00:14:18 +0200 Subject: [PATCH 4/4] fix(ci): permissions block voor dorny/paths-filter API-toegang dorny/paths-filter@v3 leest PR-changed-files via de GitHub API. Default GITHUB_TOKEN heeft op deze repo geen pull-requests:read permission, waardoor de action faalde met "Resource not accessible by integration". Workflow-level permissions toegevoegd: contents:read + pull-requests:read. Geen andere wijzigingen aan jobs nodig. Co-Authored-By: Claude Opus 4.7 (1M context) --- .github/workflows/ci.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ffc478b..aab01af 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -13,6 +13,10 @@ on: options: [preview, production] default: preview +permissions: + contents: read + pull-requests: read + jobs: ci: name: Lint, Typecheck, Test & Build