* 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>
605 lines
10 KiB
Markdown
605 lines
10 KiB
Markdown
---
|
|
title: "Installatieplan — Beelink Ubuntu Scrum4Me server en worker-aanpassingen"
|
|
status: draft
|
|
audience: [maintainer, operator, ai-agent]
|
|
language: nl
|
|
last_updated: 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:
|
|
|
|
```text
|
|
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:
|
|
|
|
```bash
|
|
hostnamectl
|
|
free -h
|
|
swapon --show
|
|
df -h
|
|
```
|
|
|
|
### Directorystructuur
|
|
|
|
Alle service-data staat onder:
|
|
|
|
```text
|
|
/srv/scrum4me
|
|
```
|
|
|
|
Structuur:
|
|
|
|
```text
|
|
/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:
|
|
|
|
```bash
|
|
docker run hello-world
|
|
docker compose version
|
|
```
|
|
|
|
### Postgres
|
|
|
|
Postgres draait als Docker container:
|
|
|
|
```text
|
|
container: scrum4me-postgres
|
|
image: postgres:17
|
|
```
|
|
|
|
Host mapping:
|
|
|
|
```text
|
|
127.0.0.1:5432 -> postgres:5432
|
|
```
|
|
|
|
Host-app gebruikt:
|
|
|
|
```env
|
|
DATABASE_URL="postgresql://scrum4me:<password>@127.0.0.1:5432/scrum4me"
|
|
DIRECT_URL="postgresql://scrum4me:<password>@127.0.0.1:5432/scrum4me"
|
|
```
|
|
|
|
Containers gebruiken:
|
|
|
|
```env
|
|
DATABASE_URL=postgresql://scrum4me:<password>@postgres:5432/scrum4me
|
|
DIRECT_URL=postgresql://scrum4me:<password>@postgres:5432/scrum4me
|
|
```
|
|
|
|
DB-test:
|
|
|
|
```bash
|
|
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:
|
|
|
|
```text
|
|
/srv/scrum4me/repos/Scrum4Me
|
|
```
|
|
|
|
Build:
|
|
|
|
```bash
|
|
cd /srv/scrum4me/repos/Scrum4Me
|
|
rm -rf .next
|
|
npm run build
|
|
```
|
|
|
|
Runtime:
|
|
|
|
```text
|
|
systemd service: scrum4me-web
|
|
```
|
|
|
|
Service startcommand:
|
|
|
|
```bash
|
|
npm run start -- -H 0.0.0.0
|
|
```
|
|
|
|
Controle:
|
|
|
|
```bash
|
|
systemctl status scrum4me-web --no-pager
|
|
curl -I http://127.0.0.1:3000/login
|
|
```
|
|
|
|
### Caddy
|
|
|
|
Caddy draait als Docker container:
|
|
|
|
```text
|
|
container: scrum4me-caddy
|
|
```
|
|
|
|
Caddy reverse proxyt:
|
|
|
|
```text
|
|
http://192.168.0.154 -> Caddy -> 172.18.0.1:3000 -> Scrum4Me web
|
|
```
|
|
|
|
Caddyfile:
|
|
|
|
```caddyfile
|
|
:80 {
|
|
reverse_proxy 172.18.0.1:3000
|
|
}
|
|
```
|
|
|
|
Controle:
|
|
|
|
```bash
|
|
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:
|
|
|
|
```env
|
|
SESSION_COOKIE_SECURE="false"
|
|
```
|
|
|
|
Code-aanpassing:
|
|
|
|
```ts
|
|
secure: process.env.SESSION_COOKIE_SECURE === 'true',
|
|
```
|
|
|
|
Later, bij domein + HTTPS:
|
|
|
|
```env
|
|
SESSION_COOKIE_SECURE="true"
|
|
```
|
|
|
|
Daarna:
|
|
|
|
```bash
|
|
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:
|
|
|
|
```text
|
|
relation "todos" already exists
|
|
```
|
|
|
|
Voor deze server is de juiste aanpak:
|
|
|
|
```bash
|
|
npx prisma migrate resolve --applied 20260506101436_restore_todos_table
|
|
npx prisma migrate deploy
|
|
```
|
|
|
|
Controle:
|
|
|
|
```bash
|
|
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:
|
|
|
|
```bash
|
|
npx tsx scripts/create-admin.ts janpeter '<password>'
|
|
```
|
|
|
|
Login werkt.
|
|
|
|
Product aanmaken werkt.
|
|
|
|
### Backups
|
|
|
|
Backup-script:
|
|
|
|
```text
|
|
/srv/scrum4me/backup-postgres.sh
|
|
```
|
|
|
|
Script:
|
|
|
|
```bash
|
|
#!/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:
|
|
|
|
```bash
|
|
/srv/scrum4me/backup-postgres.sh
|
|
ls -lh /srv/scrum4me/backups
|
|
```
|
|
|
|
Cron:
|
|
|
|
```cron
|
|
15 3 * * * /srv/scrum4me/backup-postgres.sh >> /srv/scrum4me/backups/backup.log 2>&1
|
|
```
|
|
|
|
## Worker-Idea Installatie
|
|
|
|
Worker compose-service:
|
|
|
|
```text
|
|
worker-idea
|
|
container: scrum4me-worker-idea
|
|
health: http://127.0.0.1:18081/health
|
|
```
|
|
|
|
Belangrijke env-waarden:
|
|
|
|
```env
|
|
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:
|
|
|
|
```bash
|
|
read -s -p "Scrum4Me token: " TOKEN; echo
|
|
curl -i -H "Authorization: Bearer $TOKEN" http://127.0.0.1:3000/api/products
|
|
unset TOKEN
|
|
```
|
|
|
|
Verwacht:
|
|
|
|
```text
|
|
HTTP/1.1 200 OK
|
|
```
|
|
|
|
Worker health:
|
|
|
|
```bash
|
|
curl http://127.0.0.1:18081/health
|
|
```
|
|
|
|
Gezonde idle-output bevat:
|
|
|
|
```json
|
|
{
|
|
"status": "idle",
|
|
"heartbeatAgeSeconds": 1,
|
|
"consecutiveFailures": 0
|
|
}
|
|
```
|
|
|
|
## Huidige Worker-Beperking
|
|
|
|
De Docker worker is gezond, maar Scrum4Me UI toont mogelijk nog:
|
|
|
|
```text
|
|
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:
|
|
|
|
```bash
|
|
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:
|
|
|
|
```text
|
|
label | worker_id | last_seen_at
|
|
worker-idea | |
|
|
```
|
|
|
|
## Worker Aanpassingsplan
|
|
|
|
### Doelrollen
|
|
|
|
```text
|
|
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:
|
|
|
|
```text
|
|
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()`:
|
|
|
|
```ts
|
|
const { userId, tokenId } = await getAuth()
|
|
await registerWorker({ userId, tokenId })
|
|
const heartbeat = startHeartbeat({ userId, tokenId, intervalMs: 10_000 })
|
|
```
|
|
|
|
In `finally`:
|
|
|
|
```ts
|
|
heartbeat.stop()
|
|
```
|
|
|
|
Niet unregisteren bij normale idle-exit. Anders gaat de UI-indicator flikkeren tussen iteraties.
|
|
|
|
### Acceptatie
|
|
|
|
Bij lege queue:
|
|
|
|
```bash
|
|
curl http://127.0.0.1:18081/health
|
|
```
|
|
|
|
toont:
|
|
|
|
```text
|
|
status idle
|
|
```
|
|
|
|
En:
|
|
|
|
```sql
|
|
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
|
|
|
|
```env
|
|
SCRUM4ME_WORKER_ROLE=idea
|
|
```
|
|
|
|
Toegestane waarden:
|
|
|
|
```text
|
|
idea
|
|
implementation
|
|
orchestrator
|
|
```
|
|
|
|
### Claimfilter
|
|
|
|
`tryClaimJob` krijgt een role/capability-filter.
|
|
|
|
Mapping:
|
|
|
|
```text
|
|
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:
|
|
|
|
```text
|
|
role
|
|
worker_name
|
|
container_name
|
|
last_status
|
|
last_job_id
|
|
last_error
|
|
```
|
|
|
|
UI toont dan:
|
|
|
|
```text
|
|
Idea worker online / idle
|
|
Implementation worker offline
|
|
Orchestrator online / idle
|
|
```
|
|
|
|
## Fase 4 — Orchestrator Jobs
|
|
|
|
Nieuwe job kinds:
|
|
|
|
```text
|
|
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:
|
|
|
|
```bash
|
|
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:
|
|
|
|
```bash
|
|
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.
|