docs: handleiding + functionele + technische specificatie

Drie nieuwe markdown-bestanden onder /docs:

- handleiding.md — voor de dagelijkse gebruiker: eerste login, modules,
  veelvoorkomende taken (Caddy editen, sprint mergen via flow), wat
  expliciet niet vanuit de UI kan, log-locaties bij incidenten,
  veiligheidsadvies.

- specs/functional.md — wat de app doet: scope per module met
  acceptatiecriteria, flow state-machine (pending/running/success/
  failed/cancelled/timeout), hard limits (1 actieve flow, 64KB log
  knippen, 24u session), expliciete buiten-scope-lijst.

- specs/technical.md — hoe het werkt: 3-process architectuur
  (dashboard container + agent op host + Postgres), stack-tabel met
  versies en redenen, data-model (User/Session/FlowRun/FlowStep),
  auth-flow met CSRF, agent-protocol over SSE, security-eigenschappen
  per laag.

Lengtes pragmatisch gekozen — geen completeness-fetisj, wel genoeg
om iemand die nieuw is in de codebase binnen 30 min te oriënteren.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Janpeter Visser 2026-05-13 22:35:49 +02:00
parent 44e9280de1
commit fda7be3214
3 changed files with 545 additions and 0 deletions

147
docs/specs/functional.md Normal file
View file

@ -0,0 +1,147 @@
# Functionele specificatie — Ops Dashboard
## Doel
Eén web-UI waarmee de eigenaar van een single-host server-stack (Docker + systemd + Git-checkouts + Caddy + Postgres) dezelfde operaties kan uitvoeren die anders in een SSH-terminal gebeuren — met audit-log, herhaalbare flows en minder typefouten.
**Schaal:** één host, één admin-gebruiker. Multi-host/team is buiten scope.
## Gebruikers en rollen
| Rol | Beschrijving | Hoeveelheid |
|---|---|---|
| **admin** | Volle toegang tot alle modules en flows. Single account, geseed via env. | 1 |
Geen RBAC, geen tenant-isolatie, geen "view-only"-modus. Wie inlogt kan alles.
## Functionele scope per module
### Dashboard (`/`)
5 live status-widgets met auto-refresh ~5s:
| Widget | Data-bron | Indicator |
|---|---|---|
| Docker | `docker ps --format json` | Count van running containers, lijst (naam + status) |
| Git | `git status --short --branch` per pad in `REPO_PATHS` | Branch + dirty-vlag |
| systemd | `systemctl is-active <unit>` per item in `SYSTEMD_UNITS` | Active / Inactive / Failed |
| Caddy | `caddy admin-cmd certificates` (of equiv. shell-output parse) | Aantal certs + dichtstbijzijnde expiry |
| Audit | DB-query op `FlowRun` desc | Laatste run + status |
**Acceptatie:**
- Widget laadt < 1 s na page-load
- Auto-refresh werkt in achtergrond zonder volledig herrenderen
- Bij fout (agent down, command faalt): widget toont rood errorblok, niet de hele page
### Auth (`/login`)
- Email + wachtwoord (single user)
- 5 failed attempts in 1 minuut → 429 rate-limit per IP
- Succesvolle login → session-cookie 24u, HttpOnly, SameSite=strict, Secure (production)
- `/api/auth/logout` invalideert sessie en wist cookie
### Docker (`/docker`)
- Lijst running containers (CONTAINER ID, IMAGE, COMMAND, CREATED, STATUS, PORTS, NAMES)
- Auto-refresh elke 5s
- `/docker/[name]` → detail-page met logs (laatste 200 regels), image-info, environment
- **Geen** start/stop/restart vanuit UI — alleen via flows
### Git (`/git`)
- Per pad in `REPO_PATHS`: huidige branch, ahead/behind count, modified-files-count, laatste 3 commits
- `/git/[repo]` → diff-viewer voor uncommitted changes + commit-historie laatste 20
### systemd (`/systemd`)
- Per unit in `SYSTEMD_UNITS`: active/inactive/failed, last-changed-timestamp
- `/systemd/[unit]` → laatste 100 journal-regels van die unit, met level-filter
- **Restart-actie**: alleen voor units die expliciet in `sudoers.d/ops-agent` met NOPASSWD staan
### Caddy (`/caddy`)
- Toon huidige `/srv/scrum4me/caddy/Caddyfile` met syntax-highlighting
- Toon alle uitgegeven certs (subject, issuer, expiry, dichtstbijzijnde eerst)
- Geel-warning bij expiry < 30 dagen, rood bij < 7 dagen
- `/caddy/edit` → editor met save-knop; save valideert via `caddy validate` voor commit en restart van caddy-container
### Flows (`/flows`)
Twee voor-gedefinieerde flows in YAML in `ops-agent/flows.example/`:
| Flow | Stappen |
|---|---|
| `update_scrum4me_web` | git pull → npm run build → docker compose up -d --build → smoke-test op homepage |
| `update_caddy_config` | write nieuw Caddyfile → caddy validate → docker compose restart caddy → check cert renewal |
Per flow:
- Dry-run default (toont alleen wat het zou doen)
- "Run"-knop voert echt uit; toont live SSE-stream van stdout/stderr per stap
- Bij stap-fail: stop, markeer FlowRun als `failed`, latere stappen niet uitgevoerd
- Bij success: FlowRun = `success`, totaalduur opgeslagen
### Audit (`/audit`)
- Lijst van alle `FlowRun` records, default 50 laatste, sort desc op `started_at`
- Filter op status, datumrange, flow-name
- `/audit/[flow_run_id]` → volledige output per stap, scrollable
### Settings/Backups (`/settings/backups`)
- Lijst van `.sql.gz` bestanden in `/srv/scrum4me/backups`, met size + mtime
- "Backup now"-knop → maakt nieuwe dump met `pg_dumpall` voor alle databases
- Restore: **handmatig vanuit terminal** — UI toont alleen de stappen als runbook
## State-machine flows
```
┌────────┐
│ pending │
└────┬────┘
│ (start request)
┌────▼────┐
│ running │
└────┬────┘
┌────┼────┬────────┐
▼ ▼ ▼ ▼
success failed cancelled timeout (>30min)
```
`pending``running`: bij ontvangst start-request
`running``success`: alle stappen exit-code 0
`running``failed`: een stap exit-code ≠ 0
`running``cancelled`: user klikt cancel
`running``timeout`: na 30 min nog steeds running (cleanup-job)
## Hard limits
- Max 1 actieve flow tegelijk (lock-file in `/var/run/agent/`); 2e start-request → 409 Conflict
- Stdout/stderr per stap geknipt op 64 KB om audit-log niet te laten exploderen
- Session-TTL hard 24 uur, geen "remember me"
- Auto-refresh max 1 keer per 5 seconden om agent niet te overbelasten
## Niet-functionele eisen
| Eis | Doel |
|---|---|
| First load < 1s | Single-user, lokale Postgres, geen onnodige round-trips |
| Module-page TTI < 2s | Server-side render met direct agent-call, geen client-fetch waterval |
| Audit-trail volledig | Elke flow-start logt user + tijdstempel + args; elke command-execution logt exit + duration |
| Geen geheime data in URLs | Tokens in headers, secrets nooit in query-params |
| CSP strict | `script-src 'self' 'unsafe-inline'`; geen externe CDNs |
| HTTPS-only in productie | Caddy auto-ACME; cookies Secure-flag in prod-mode |
## Buiten scope
- Meerdere admins / RBAC
- Meerdere hosts / cluster-management
- Custom container starten (alleen restart bestaande)
- Real-time alerts (geen pager, geen email)
- Externe monitoring-integratie (Grafana/Prometheus/Sentry)
- Wachtwoord-reset-flow / SSO
## Verwante documenten
- [Technische specificatie](./technical.md) — hoe het werkt
- [Handleiding](../handleiding.md) — hoe je het gebruikt
- [Post-install runbook](../runbooks/post-install.md) — eerste deploy