Scrum4Me/docs/Ideas/beelink-scrum4me-server-install-and-worker-plan.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

10 KiB

title status audience language last_updated
Installatieplan — Beelink Ubuntu Scrum4Me server en worker-aanpassingen draft
maintainer
operator
ai-agent
nl 2026-05-10

Installatieplan — Beelink Ubuntu Scrum4Me server en worker-aanpassingen

Doel

Deze notitie beschrijft de huidige Beelink-installatie en het vervolgplan om de Scrum4Me workers geschikt te maken voor drie rollen:

worker-idea
worker-implementation
worker-orchestrator

De server draait nu als LAN-host voor Scrum4Me. Productie-internettoegang met domein en HTTPS is nog een latere stap.

Hardware

Onderdeel Waarde
Machine Beelink mini-PC
CPU Intel Core i5-12450H
RAM zichtbaar in Ubuntu 16 GB
Max RAM volgens hardware 32 GB
Disk 468 GB bruikbaar na Ubuntu-installatie
IP 192.168.0.154

Opmerking: Ubuntu ziet momenteel ongeveer 16 GB RAM. De hardware meldt een maximum van 32 GB, maar dat betekent niet dat 32 GB bruikbaar/geplaatst is.

Huidige Installatie

Ubuntu

Ubuntu Server is geïnstalleerd op de hele disk.

Belangrijke keuzes:

  • Ubuntu Server 24.04 LTS.
  • Geen Ubuntu Desktop.
  • Geen LVM.
  • Geen aparte GPU-drivers.
  • Geen Windows dual boot meer.
  • Hostname: scrum4me-server.
  • Sleep/hibernate uitgeschakeld.
  • Swapfile vergroot naar 16 GB.

Controle:

hostnamectl
free -h
swapon --show
df -h

Directorystructuur

Alle service-data staat onder:

/srv/scrum4me

Structuur:

/srv/scrum4me/postgres       database data
/srv/scrum4me/repos          GitHub clones
/srv/scrum4me/worker-cache   worker caches
/srv/scrum4me/worker-logs    worker logs
/srv/scrum4me/worker-state   worker state
/srv/scrum4me/backups        Postgres backups
/srv/scrum4me/compose        Docker Compose files
/srv/scrum4me/caddy          Caddy config/data

Docker

Docker Engine draait native op Ubuntu.

Controle:

docker run hello-world
docker compose version

Postgres

Postgres draait als Docker container:

container: scrum4me-postgres
image: postgres:17

Host mapping:

127.0.0.1:5432 -> postgres:5432

Host-app gebruikt:

DATABASE_URL="postgresql://scrum4me:<password>@127.0.0.1:5432/scrum4me"
DIRECT_URL="postgresql://scrum4me:<password>@127.0.0.1:5432/scrum4me"

Containers gebruiken:

DATABASE_URL=postgresql://scrum4me:<password>@postgres:5432/scrum4me
DIRECT_URL=postgresql://scrum4me:<password>@postgres:5432/scrum4me

DB-test:

docker exec -e PGPASSWORD="$DBPASS" scrum4me-postgres \
  psql -h 127.0.0.1 -U scrum4me -d scrum4me \
  -c "select current_user, current_database();"

Scrum4Me Web

Repo:

/srv/scrum4me/repos/Scrum4Me

Build:

cd /srv/scrum4me/repos/Scrum4Me
rm -rf .next
npm run build

Runtime:

systemd service: scrum4me-web

Service startcommand:

npm run start -- -H 0.0.0.0

Controle:

systemctl status scrum4me-web --no-pager
curl -I http://127.0.0.1:3000/login

Caddy

Caddy draait als Docker container:

container: scrum4me-caddy

Caddy reverse proxyt:

http://192.168.0.154 -> Caddy -> 172.18.0.1:3000 -> Scrum4Me web

Caddyfile:

:80 {
  reverse_proxy 172.18.0.1:3000
}

Controle:

curl -I http://192.168.0.154/login
docker logs --tail=50 scrum4me-caddy

LAN Session Config

Omdat de server nu via HTTP op LAN draait, is secure session cookie tijdelijk uitgezet.

Env:

SESSION_COOKIE_SECURE="false"

Code-aanpassing:

secure: process.env.SESSION_COOKIE_SECURE === 'true',

Later, bij domein + HTTPS:

SESSION_COOKIE_SECURE="true"

Daarna:

rm -rf .next
npm run build
sudo systemctl restart scrum4me-web

Migrations

De database is gemigreerd.

Belangrijke migration-notitie:

20260506101436_restore_todos_table kan op een bestaande DB falen met:

relation "todos" already exists

Voor deze server is de juiste aanpak:

npx prisma migrate resolve --applied 20260506101436_restore_todos_table
npx prisma migrate deploy

Controle:

npx prisma migrate status
docker exec -it scrum4me-postgres psql -U scrum4me -d scrum4me -c "\dt public.users"

Admin en Product

Admin user is aangemaakt via:

npx tsx scripts/create-admin.ts janpeter '<password>'

Login werkt.

Product aanmaken werkt.

Backups

Backup-script:

/srv/scrum4me/backup-postgres.sh

Script:

#!/usr/bin/env bash
set -euo pipefail

BACKUP_DIR="/srv/scrum4me/backups"
STAMP="$(date +%Y%m%d-%H%M%S)"
FILE="$BACKUP_DIR/scrum4me-$STAMP.sql.gz"

mkdir -p "$BACKUP_DIR"

docker exec scrum4me-postgres pg_dump -U scrum4me scrum4me | gzip > "$FILE"

find "$BACKUP_DIR" -type f -name 'scrum4me-*.sql.gz' -mtime +14 -delete

echo "backup written: $FILE"

Test:

/srv/scrum4me/backup-postgres.sh
ls -lh /srv/scrum4me/backups

Cron:

15 3 * * * /srv/scrum4me/backup-postgres.sh >> /srv/scrum4me/backups/backup.log 2>&1

Worker-Idea Installatie

Worker compose-service:

worker-idea
container: scrum4me-worker-idea
health: http://127.0.0.1:18081/health

Belangrijke env-waarden:

SCRUM4ME_BASE_URL=http://caddy
SCRUM4ME_TOKEN=<raw Scrum4Me API token>

DATABASE_URL=postgresql://scrum4me:<password>@postgres:5432/scrum4me
DIRECT_URL=postgresql://scrum4me:<password>@postgres:5432/scrum4me

GH_TOKEN=<GitHub token>
GH_PRECLONE_REPOS=madhura68/Scrum4Me,madhura68/scrum4me-mcp,madhura68/scrum4me-docker

CLAUDE_CODE_OAUTH_TOKEN=<Claude Code OAuth token>

Token-validatie:

read -s -p "Scrum4Me token: " TOKEN; echo
curl -i -H "Authorization: Bearer $TOKEN" http://127.0.0.1:3000/api/products
unset TOKEN

Verwacht:

HTTP/1.1 200 OK

Worker health:

curl http://127.0.0.1:18081/health

Gezonde idle-output bevat:

{
  "status": "idle",
  "heartbeatAgeSeconds": 1,
  "consecutiveFailures": 0
}

Huidige Worker-Beperking

De Docker worker is gezond, maar Scrum4Me UI toont mogelijk nog:

geen Claude worker actief

Oorzaak:

  • De Docker health-server draait altijd.
  • De daemon-loop draait altijd.
  • Maar de DB-tabel claude_workers wordt nu alleen bijgewerkt door de MCP stdio-server.
  • Die MCP stdio-server start pas binnen een echte Claude/MCP job-run.
  • Bij een lege queue is de Docker worker dus idle en gezond, maar verschijnt hij niet als actieve worker in de UI.

Controle:

docker exec -it scrum4me-postgres psql -U scrum4me -d scrum4me \
  -c "select t.id, t.label, w.id as worker_id, w.last_seen_at from api_tokens t left join claude_workers w on w.token_id=t.id order by t.created_at desc;"

Gezonde Docker-worker maar lege presence:

label       | worker_id | last_seen_at
worker-idea |           |

Worker Aanpassingsplan

Doelrollen

worker-idea
  IDEA_GRILL
  IDEA_MAKE_PLAN
  PLAN_CHAT

worker-implementation
  TASK_IMPLEMENTATION
  SPRINT_IMPLEMENTATION
  later STORY_IMPLEMENTATION

worker-orchestrator
  PR_REVIEW
  CI_TRIAGE
  MERGE_CONFLICT_RESOLUTION
  REPAIR_FAILED_JOB
  CONTEXT_SUMMARY

Fase 1 — Presence Fix

Probleem

Worker-health is nu container-lokaal, maar UI-presence is DB-gebaseerd.

Nu:

curl :18081/health -> online
claude_workers     -> leeg
UI                 -> offline

Gewenst gedrag

Zolang de Docker daemon-loop draait, moet claude_workers.last_seen_at vers blijven, ook als de queue leeg is.

Aanpassing

Verplaats worker-presence naar scrum4me-docker/bin/run-one-job.ts of naar een kleine runner-level heartbeat naast run-agent.sh.

Aanbevolen: in run-one-job.ts, direct na getAuth():

const { userId, tokenId } = await getAuth()
await registerWorker({ userId, tokenId })
const heartbeat = startHeartbeat({ userId, tokenId, intervalMs: 10_000 })

In finally:

heartbeat.stop()

Niet unregisteren bij normale idle-exit. Anders gaat de UI-indicator flikkeren tussen iteraties.

Acceptatie

Bij lege queue:

curl http://127.0.0.1:18081/health

toont:

status idle

En:

select token_id, last_seen_at, now() - last_seen_at from claude_workers;

toont een recente last_seen_at.

Fase 2 — Role-Aware Workers

Probleem

De huidige worker claimt elke job die beschikbaar is. Daardoor kan worker-idea ook implementation jobs claimen.

Nieuwe env

SCRUM4ME_WORKER_ROLE=idea

Toegestane waarden:

idea
implementation
orchestrator

Claimfilter

tryClaimJob krijgt een role/capability-filter.

Mapping:

idea:
  IDEA_GRILL
  IDEA_MAKE_PLAN
  PLAN_CHAT

implementation:
  TASK_IMPLEMENTATION
  SPRINT_IMPLEMENTATION

orchestrator:
  PR_REVIEW
  CI_TRIAGE
  MERGE_CONFLICT_RESOLUTION
  REPAIR_FAILED_JOB
  CONTEXT_SUMMARY

Acceptatie

Test:

  • Queue bevat één IDEA_GRILL en één TASK_IMPLEMENTATION.
  • Alleen worker-idea actief: claimt alleen IDEA_GRILL.
  • Alleen worker-implementation actief: claimt alleen TASK_IMPLEMENTATION.
  • Beide actief: ieder claimt eigen jobtype.

Fase 3 — DB/UI Uitbreiding

Breid claude_workers uit met:

role
worker_name
container_name
last_status
last_job_id
last_error

UI toont dan:

Idea worker            online / idle
Implementation worker  offline
Orchestrator           online / idle

Fase 4 — Orchestrator Jobs

Nieuwe job kinds:

PR_REVIEW
CI_TRIAGE
MERGE_CONFLICT_RESOLUTION
REPAIR_FAILED_JOB
CONTEXT_SUMMARY

Orchestrator mag:

  • PR's inspecteren.
  • CI-fouten samenvatten.
  • Merge conflicts analyseren.
  • Repair jobs aanmaken.
  • Context capsules schrijven.
  • Human escalation vragen.
  • Draft PR naar ready begeleiden.

Orchestrator mag niet:

  • Vrij featurewerk implementeren.
  • Dezelfde branch tegelijk wijzigen als implementation-worker.
  • Auto-mergen zonder checks.
  • Secrets of tokens loggen.

Fase 5 — Deployment

Na code-aanpassing:

cd /srv/scrum4me/repos/scrum4me-docker
git pull
cd /srv/scrum4me/compose
docker compose build worker-idea
docker compose up -d --force-recreate worker-idea

Checks:

curl http://127.0.0.1:18081/health
docker logs -f scrum4me-worker-idea
docker exec -it scrum4me-postgres psql -U scrum4me -d scrum4me \
  -c "select token_id, last_seen_at from claude_workers;"

Aanbevolen Volgorde Vanaf Nu

  1. Test één IDEA_GRILL job met de huidige worker.
  2. Implementeer Fase 1: runner-level presence.
  3. Rebuild worker-idea.
  4. Verifieer UI online/idle bij lege queue.
  5. Implementeer Fase 2: role-aware claiming.
  6. Voeg worker-implementation toe.
  7. Voeg pas daarna worker-orchestrator toe.

Niet meteen drie workers starten zonder role-aware claimfilter.