Scrum4Me/docs/old/plans/auto-pr-deploy-sync.md
Janpeter Visser b39c3ec2e1
docs(cleanup): archief verouderde plannen, backlog en root-duplicaten (#191)
* docs(cleanup): archief verouderde plannen, backlog en root-duplicaten

- 6 plans naar docs/old/plans/ (PBI-11/75/78, user-settings-store, Local github setup, lees-de-readme — laatste was verkeerde repo)
- docs/backlog/ naar docs/old/backlog/ (pre-MCP statische registry; live werk loopt via Scrum4Me-MCP)
- 6 root-level duplicaten naar docs/old/ (functional, {pbi,story,task}-dialog, product-backlog, backlog)
- 2 landing plans (niet uitgevoerd) krijgen archived: true frontmatter — blijven op plek maar uit INDEX
- scripts/generate-docs-index.mjs: skip docs/old/** + skip archived: true
- CLAUDE.md: rijen docs/backlog/, docs/plans/<key>-*.md, docs/manual/ weg; Track B-sectie verwijderd
- README.md / CHANGELOG.md / docs/plans/v1-readiness.md: link-fixes naar nieuwe locaties

Verify groen (lint + typecheck + 718 tests). docs/INDEX.md geregenereerd.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs(cleanup): registreer handmatige verplaatsingen en fix referenties

- 4 plans verplaatst naar docs/old/plans/ (M10-qr-pairing-login, auto-pr-deploy-sync, docs-restructure-ai-lookup, v1-readiness)
- 3 archive-plans verplaatst naar docs/old/plans/ (archive-map nu leeg)
- ST-1114-copilot-reviews + 3 research-docs naar nieuwe docs/Ideas/ map
- Duplicaat docs/old/2026-04-27-m8-realtime-solo.md verwijderd (origineel zit in docs/old/plans/)
- Link-fixes naar nieuwe locaties:
  - CHANGELOG.md → docs/old/plans/v1-readiness.md
  - docs/runbooks/deploy-control.md → docs/old/plans/auto-pr-deploy-sync.md (2x)
  - docs/runbooks/worker-idempotency.md → docs/old/plans/auto-pr-deploy-sync.md
  - docs/plans/docs-restructure-pbi-spec.md → docs/old/plans/docs-restructure-ai-lookup.md (4x text + 2x href)
- docs/INDEX.md geregenereerd (96 docs, was 100)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 19:46:00 +02:00

18 KiB
Raw Permalink Blame History

Plan — Auto-PR + selectieve deploy-controle + sync-zicht (end-to-end batch flow)

Bij merge: dit plan verplaatsen naar docs/plans/auto-pr-deploy-sync.md conform feedback-memory (plans in docs/plans/).

Context

Drie samenhangende problemen rond de "idee → uitvoeren"-keten:

  1. Worker stopt bij commit. De Scrum4Me NAS-worker werkt lokaal: commits blijven op de machine staan totdat de gebruiker zelf pusht en een PR aanmaakt. Voor batch-uitvoer van story-jobs is dit een harde menselijke gate.
  2. Deploy is alles-of-niets. .github/workflows/ci.yml deployt nu elke push naar main automatisch naar productie en elke PR naar preview. vercel.json heeft geen git.deploymentEnabled: false, dus Vercel's eigen Git-integratie deployt waarschijnlijk parallel mee → dubbele deploys en geen selectieve controle.
  3. Geen zicht op voortgang per Idea/PBI. Concreet getest geval: PBI-33 wordt nu de eerste sprint-batch — er is geen git-voetafdruk (geen branch/commit/PR met "PBI-33"), geen activiteitenlog-entry, en geen UI-pagina die per Story toont of er een ClaudeJob loopt, een commit gepusht is, of een PR open/merged is. De data zit in Story.status, ClaudeJob.pushed_at/branch/pr_url, Pbi.pr_url/pr_merged_at — er is alleen geen view die het joint.

Doel: de complete keten plan → job → commit → push → PR → auto-merge → deploy in één coherent ontwerp leggen, met (a) selectieve deploy-controle als veiligheidsklep en (b) een sync-tab die per Idea laat zien wat er werkelijk in git/PR-land gebeurd is.

Vastgelegde keuzes

Deploy-controle

  1. Mechanisme: PR-labels (B) + path-filter (C) gecombineerd.
  2. Eigenaar: GitHub Actions-workflow (A). Vercel Git-integratie uit.
  3. Defaults: PR → preview, push naar main → productie.
  4. Override-richtingen:
    • skip-deploy label: voorkomt preview-deploy op een PR.
    • force-deploy label: forceert deploy ook als path-filter doc-only zegt.

Auto-PR (uit IDEA-007-grill)

  1. Triggers in worker: na elke succesvolle update_job_status('done') pusht de worker; na laatste story van een PBI maakt de worker een PR aan en activeert auto-merge (SQUASH).
  2. Auth: GITHUB_TOKEN als omgevingsvariabele op de worker; geen UI of GitHub App in v1.
  3. Foutafhandeling: push/PR-aanmaak-fail → update_job_status('failed', error: …); geen force-push, geen automatische retry.

Interactie tussen beide

  1. Worker-PRs gebruiken hetzelfde labelsysteem als alle andere PRs. Default = preview deploy, auto-merge wacht op CI groen, na merge prod-deploy (mits path-filter zegt "code"). De worker zet geen labels automatisch — als je batch-output zonder preview wilt mergen moet je skip-deploy zelf toevoegen, of preview later uitzetten via een product-instelling (out-of-scope v1).
  2. Implementatievolgorde: eerst deploy-controle (infra, onafhankelijk), daarna auto-PR (afhankelijk van stabiele deploy-flow).

Architectuur in één plaat

                                      auto-merge wacht op
[story-job DONE] ─push branch─┐       deploy-preview groen
                              ▼              │
[laatste story?]──ja──[PR + auto-merge]──CI──┴──merge naar main
                                              │
                                       [job: ci] altijd
                                              │
                                       [paths-filter]
                                              │
                                              ├ PR    → deploy-preview
                                              │        if code && !skip-deploy
                                              │        || force-deploy
                                              │
                                              └ push  → deploy-production
                                                       if code

Deel A — Deploy-controle

A.1 vercel.json — Vercel Git-deploy uitzetten

{
  "$schema": "https://openapi.vercel.sh/vercel.json",
  "git": { "deploymentEnabled": false },
  "crons": [
    { "path": "/api/cron/expire-questions", "schedule": "0 4 * * *" },
    { "path": "/api/cron/cleanup-agent-artifacts", "schedule": "0 3 * * *" }
  ]
}

Effect: Vercel deployt niet meer automatisch op git-events. Alleen vercel deploy vanuit de workflow (met VERCEL_TOKEN) maakt nog deployments.

A.2 .github/workflows/ci.yml — path-filter + label-checks

Triggers uitbreiden met workflow_dispatch:

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]
  workflow_dispatch:
    inputs:
      target:
        type: choice
        description: Deploy target
        options: [preview, production]
        default: preview

Nieuwe job vóór de deploy-jobs:

  changes:
    name: Detect deploy-relevant changes
    runs-on: ubuntu-latest
    needs: ci
    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 if-conditie aanpassen:

  deploy-preview:
    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')
      )

deploy-production if-conditie aanpassen:

  deploy-production:
    needs: [ci, changes]
    if: |
      github.ref == 'refs/heads/main'
      && github.event_name == 'push'
      && needs.changes.outputs.code == 'true'

Nieuwe deploy-manual job voor workflow_dispatch met inputs.targetvercel deploy of vercel deploy --prod.

A.3 GitHub-labels aanmaken

gh label create skip-deploy  --color BFBFBF --description "Preview-deploy overslaan"
gh label create force-deploy --color 0E8A16 --description "Forceer deploy ondanks path-filter"

A.4 Documentatie

docs/runbooks/deploy-control.md — triggers, labels, path-filter, voorbeelden. CLAUDE.md § Deployment-regel verwijst naar runbook.


Deel B — Auto-PR (worker → GitHub)

B.1 Acceptatiecriteria (uit IDEA-007)

  • AC 1 — Push per story: Na succesvolle update_job_status('done') pusht de worker via HTTPS (https://$GITHUB_TOKEN@github.com/…) naar origin. Push-timestamp via nieuwe MCP-call in ClaudeJob.pushed_at.
  • AC 2 — Detectie laatste story: Nieuwe MCP-call check_pbi_complete retourneert { complete: boolean, pbi_id }.
  • AC 3 — PR aanmaken: Op complete: true POST naar /repos/{owner}/{repo}/pulls; titel/body uit PBI-naam + voltooide stories; PR-URL via set_pbi_pr.
  • AC 4 — Auto-merge activeren: Direct na PR-aanmaak GraphQL enablePullRequestAutoMerge (SQUASH).
  • AC 5 — Foutafhandeling: push/PR-fail → update_job_status('failed', error); PR-URL blijft bewaard voor handmatige inspectie.

B.2 Server-side wijzigingen (Scrum4Me-repo)

Velden bestaan al in schema:

  • Product.auto_pr Boolean @default(false) (regel 176)
  • Pbi.pr_url String? + Pbi.pr_merged_at DateTime? (regel 207208)
  • ClaudeJob.pushed_at DateTime? + ClaudeJob.pr_url String? + ClaudeJob.branch String? (regel 335, 338, 339)

Geen migratie nodig.

Server actions / REST: bestaande set_pbi_pr en mark_pbi_pr_merged MCP-tools blijven. Nieuwe action:

  • actions/jobs.tsrecordJobPushedAtAction(jobId) voor pushed_at-write (als die nog niet via MCP gaat).

B.3 MCP-laag (scrum4me-mcp-repo)

Nieuwe tool:

  • check_pbi_complete(pbi_id) → { complete: boolean, pbi_id }. Leest alle ClaudeJobs gelinkt aan PBI; aggregeert status. complete = true als alle story-jobs status DONE hebben.

Uitbreiding bestaande tool:

  • update_job_status: bij status: 'done' ook pushed_at accepteren (worker geeft timestamp door).
  • set_pbi_pr: ongewijzigd, bestaat al.

Schema-drift watchdog (docs/runbooks/mcp-integration.md) moet groen voor merge.

B.4 Worker-laag (lokaal Claude-CLI worker)

Nieuwe stappen na elke story:

1. update_job_status('done', pushed_at: null)  ← bestaand
2. git push https://$GITHUB_TOKEN@github.com/$OWNER/$REPO.git $BRANCH
3. record_pushed_at(job_id, now)               ← nieuwe MCP-call
4. { complete } = check_pbi_complete(pbi_id)
5. if complete:
     prNumber = POST /repos/.../pulls
     set_pbi_pr(pbi_id, pr_url)
     enablePullRequestAutoMerge(prNumber, MERGE_METHOD: SQUASH)
6. on any HTTP/git failure → update_job_status('failed', error)

GITHUB_TOKEN-scope: repo voor private, public_repo voor public. Documenteer in worker-readme.

B.5 Repo-instellingen (handmatig, one-time)

  • GitHub repo Settings → General → "Allow auto-merge" → aanvinken.
  • Branch protection op main: required CI checks = ci, deploy-preview is niet required (kan skipped zijn door label).

Deel C — Interactie & demo-policy

C.1 Interactie deploy-controle ↔ auto-PR

Scenario Preview-deploy Prod-deploy bij merge
Worker maakt PR met code-changes (default) runt runt
Worker maakt PR met skip-deploy (manueel toegevoegd) skipped runt
Worker maakt PR met enkel docs-changes (path-filter) skipped skipped
User voegt force-deploy toe aan doc-only PR runt runt (path-filter) of (doc-only push)

Auto-merge wacht op required CI checks. deploy-preview mag skipped zijn — branch protection markeert hem niet als required.

C.2 Demo-policy

Auto-PR-flow draait op de worker, niet vanuit de webapp. Geen demo-sessie kan deze code triggeren — geen extra proxy.ts of session.isDemo-guards nodig. Wel: check_pbi_complete MCP-call moet requireWriteAccess doen (consistent met andere write-MCP-tools), zodat demo-tokens hem niet kunnen aanroepen.



Deel D — Sync-tab op Idea-detail (zicht op voortgang)

D.1 Wat bestaat al

  • model StoryLog (prisma/schema.prisma:251) met types IMPLEMENTATION_PLAN | TEST_RESULT | COMMIT, plus commit_hash, commit_message, metadata. Dit is de activiteitenlog.
  • MCP-tools log_implementation, log_commit, log_test_result schrijven naar deze tabel.
  • UI-component components/shared/story-log.tsx rendert StoryLogEntry[] met type-styling.
  • Story.status, ClaudeJob.pushed_at/branch/pr_url, Pbi.pr_url/pr_merged_at zijn al gevuld door bestaande flows.

Geen nieuwe tabellen, geen migraties.

D.2 Nieuwe tab op /ideas/[id]

Voeg vijfde tab Sync toe (naast Idee · Grill · Plan · Timeline) op Idea-detail-page. Alleen zichtbaar als Idea.status === 'PLANNED' en pbi_id gevuld.

Layout per tab-content:

  • Header: PBI-link + pr_url + pr_merged_at als badge.
  • Per Story (volgorde uit PBI): collapsible card met:
    • Story-header: code · titel · status-badge.
    • Job-rij: voor elke ClaudeJob (kind=TASK_IMPLEMENTATION) gelinkt aan een Task van deze Story → status, branch, pushed_at, pr_url. Toont "geen job" als nog niets gequeued.
    • Activity-log: <StoryLog logs={logs} repoUrl={product.repo_url} /> — bestaande component, ongewijzigd.

D.3 Server-laag

Nieuwe loader in app/(app)/ideas/[id]/page.tsx (of nieuw sync-tab-server.ts):

async function loadIdeaSyncData(ideaId: string, userId: string) {
  // Auth-scope: idea.user_id === userId (M12-keuze 2)
  return prisma.idea.findFirst({
    where: { id: ideaId, user_id: userId },
    include: {
      pbi: {
        include: {
          stories: {
            orderBy: { sort_order: 'asc' },
            include: {
              tasks: { include: { claude_jobs: true } },
              logs: { orderBy: { created_at: 'desc' } },
            },
          },
        },
      },
    },
  })
}

Server-only. Nooit importeren in client component (zie hardstop *-server.ts regel).

D.4 Realtime refresh

Sync-tab abonneert op bestaande SSE-streams:

  • app/api/realtime/solo/route.tsJobPayload voor job-status-updates (al uitgebreid met kind en idea_id per Deel B).
  • app/api/realtime/notifications/route.ts — voor StoryLog-inserts; als story_logs nog geen pg_notify-trigger heeft, voeg er een toe (nieuwe migratie, payload {op: 'INSERT', entity: 'story_log', id, story_id}).

Op event → router.refresh() of revalidate van Sync-tab data.

D.5 PBI-33 als live testgeval

PBI-33 is nu in TODO + gequeued als ClaudeJobs (gebruiker bevestigt: "taken op TODO gezet en claude-job aangemaakt"). Verwacht gedrag zodra deze sprint live is:

Moment Sync-tab toont
Job QUEUED "Wachtend op worker"
Job RUNNING Status RUNNING + log-entry IMPLEMENTATION_PLAN
Worker commit log-entry COMMIT (hash + message)
Worker test log-entry TEST_RESULT (status)
Worker push (Deel B AC 1) branch + pushed_at zichtbaar
Laatste story → PR PBI.pr_url zichtbaar
Auto-merge PBI.pr_merged_at zichtbaar

Als één van deze niet verschijnt: bug in MCP-tool of worker (niet in sync-tab zelf).


Bestanden

Wijziging Pad
Edit vercel.json
Edit .github/workflows/ci.yml
Nieuw docs/runbooks/deploy-control.md
Edit CLAUDE.md (verwijzing toevoegen)
Nieuw (mcp-repo) src/tools/check-pbi-complete.ts
Edit (mcp-repo) src/tools/update-job-status.ts (pushed_at)
Edit actions/jobs.ts (optioneel: record-pushed-at)
Edit Worker-script (post-story-hook + PR-aanmaak)
Doc docs/runbooks/auto-pr-flow.md (worker-flow)
Nieuw app/(app)/ideas/[id]/sync-tab-server.ts
Nieuw components/ideas/idea-sync-tab.tsx
Edit app/(app)/ideas/[id]/page.tsx (5e tab toevoegen)
Migratie prisma/migrations/<ts>_story_logs_notify/migration.sql (pg_notify-trigger op story_logs)
Edit app/api/realtime/notifications/route.ts (story_log-payload doorlaten)
GitHub (extern) Labels skip-deploy, force-deploy aanmaken
GitHub (extern) Repo Settings → "Allow auto-merge" aan
Vercel-dashboard git.deploymentEnabled: false actief verifiëren

Implementatievolgorde

  1. Deel A — Deploy-controle

    1. vercel.json aanpassen
    2. ci.yml uitbreiden (path-filter, labels, dispatch)
    3. Labels op GitHub aanmaken
    4. Runbook + CLAUDE.md-verwijzing
    5. Test-PR voor elk scenario (zie Verificatie)
  2. Deel D — Sync-tab (kan parallel met B; alleen DB-reads + UI)

    1. loadIdeaSyncData server-loader
    2. idea-sync-tab.tsx component met <StoryLog>-hergebruik
    3. 5e tab in app/(app)/ideas/[id]/page.tsx
    4. pg_notify-trigger op story_logs + SSE-route uitbreiden
    5. Live test op PBI-33 (sprint loopt al — check of activity verschijnt zodra worker logs schrijft)
  3. Deel B — Auto-PR

    1. MCP check_pbi_complete + update_job_status(pushed_at) PR (parallel-repo, schema-drift-watchdog groen)
    2. Worker-hook: push na done, PR + auto-merge bij complete
    3. Repo-instelling "Allow auto-merge" aan
    4. End-to-end smoke met één test-PBI

Verificatie

Lokaal:

npm run lint && npm test && npm run build

Workflow-syntax:

gh workflow view ci.yml

End-to-end deploy-controle:

  1. Doc-only PRdeploy-preview skipped.
  2. Doc-only PR + force-deploydeploy-preview runt.
  3. Code-PR + skip-deploydeploy-preview skipped.
  4. Code-PR zonder labelsdeploy-preview runt.
  5. Push naar main met code-changedeploy-production runt.
  6. Push naar main doc-onlydeploy-production skipped.
  7. workflow_dispatch target=production → manuele prod.
  8. Vercel dashboard → geen auto-deploy bij geforceerde test-push.

End-to-end auto-PR:

  1. Maak een test-PBI met 1 story + 1 task.
  2. Worker draait → na done: pushed_at gevuld, branch op origin zichtbaar.
  3. check_pbi_completecomplete: true.
  4. PR verschijnt op GitHub met titel = PBI-naam, body = story-list.
  5. Auto-merge actief; CI groen → squash-merge.
  6. mark_pbi_pr_merged getriggerd door pull_request: closed-webhook (al bestaand) → Pbi.pr_merged_at gevuld.
  7. Push-event op maindeploy-production runt (path-filter ja).
  8. Failure-test: revoke GITHUB_TOKEN tijdelijk → push faalt → update_job_status('failed') met error; geen PR aangemaakt.

Out-of-scope (v1)

  • UI-toggle voor auto_pr per product (veld bestaat, geen UI-wiring).
  • GitHub App-installatie (per-repo tokens, scopes-finetuning).
  • Multi-repo PBI's (huidig ontwerp: één repo_url per PBI).
  • Force-push / non-fast-forward retry-flow.
  • Notificaties (Slack, e-mail) bij merge of CI-failure.
  • Rollback-flow bij gemergende regressie.
  • Migratie naar vercel.ts (knowledge-update beveelt het aan; later).
  • Auto-skip preview-deploy specifiek voor worker-PRs op basis van product-instelling.