Files
DevRunbook release export cfd2804e27
Managed validation / full (push) Successful in 3m18s
Publish DevRunbook source
2026-09-03 04:09:17 +02:00

200 lines
11 KiB
Markdown

# DevRunbook operator guide
## Supported topology
The supported MVP deployment is one Docker Compose project containing PostgreSQL 17, the one-shot migration service, web, and worker. PostgreSQL is private to the Compose network. DevRunbook remains usable without Gitea.
The examples below assume a release checkout and Docker Compose 2.40 or newer. Replace `devrunbook-prod` only with another stable, explicit project name. Never reuse a development or restore project for production.
## Fresh installation
Create a release checkout, then create a restricted environment file:
```sh
git clone --branch RELEASE_TAG --depth 1 REPOSITORY_URL devrunbook
cd devrunbook
cp .env.example .env
chmod 600 .env
```
Generate independent values. PostgreSQL credentials use hexadecimal characters so the password is URL-safe inside `DATABASE_URL`:
```sh
openssl rand -hex 24 # POSTGRES_PASSWORD
openssl rand -hex 32 # SESSION_SECRET
openssl rand -base64 32 # INTEGRATION_ENCRYPTION_KEY
openssl rand -hex 24 # BOOTSTRAP_TOKEN
```
Set `PUBLIC_BASE_URL` to the exact externally visible URL. The reference Compose
file binds the web port to `127.0.0.1`; keep that binding and place a maintained
HTTPS reverse proxy on the same host in front of it for internet-facing use.
Changing the binding to a LAN or wildcard address is an explicit operator risk
decision, not a prerequisite. Keep `REGISTRATION_MODE=closed`. Do not commit
`.env`, print it in support output, or store the encryption key in an ordinary
backup.
Build and start the complete stack:
```sh
docker compose -p devrunbook-prod --env-file .env build
docker compose -p devrunbook-prod --env-file .env up -d
docker compose -p devrunbook-prod --env-file .env ps
curl --fail http://127.0.0.1:3000/health/live
curl --fail http://127.0.0.1:3000/health/ready
```
Open `PUBLIC_BASE_URL/setup`, provide the bootstrap token, create the first owner, and verify that 28 built-in playbooks are reported. The bootstrap endpoint is unavailable after setup completes. Retain the bootstrap token only according to the instance recovery policy.
`/health/live` proves that the web process responds. `/health/ready` additionally requires the database, compatible schema, configuration, artifact storage, and required encryption-key versions. A Gitea outage does not make the entire application unready.
## Unraid
The supported Unraid path is Compose Manager or an equivalent Compose plugin because DevRunbook has three long-running/stateful roles. Create these directories first:
```sh
mkdir -p /mnt/user/appdata/devrunbook/postgres
mkdir -p /mnt/user/appdata/devrunbook/content
mkdir -p /mnt/user/appdata/devrunbook/artifacts
mkdir -p /mnt/user/appdata/devrunbook/backups
chmod 700 /mnt/user/appdata/devrunbook/postgres
chmod 700 /mnt/user/appdata/devrunbook/backups
cp unraid/devrunbook-icon.svg /mnt/user/appdata/devrunbook/devrunbook-icon.svg
```
Set `UNRAID_APPDATA_ROOT=/mnt/user/appdata/devrunbook` in the restricted environment file, then use the bind-mount override:
```sh
export COMPOSE_FILE=docker-compose.yml:unraid/docker-compose.unraid.yml
docker compose -p devrunbook-prod --env-file .env build
docker compose -p devrunbook-prod --env-file .env up -d
```
Do not mount over `/content`, publish PostgreSQL, enable privileged mode, or
mount the Docker socket. Configure a same-host reverse proxy to the selected
loopback web port. [unraid/devrunbook.xml](../unraid/devrunbook.xml) is an
incomplete web-container reference for operators who manage PostgreSQL and the
worker separately; its registry, immutable image, support URL and TLS
distribution policy must be selected before it can be published as an
installable community template. It is not a replacement for the recommended
complete Compose stack.
## Upgrade and migration preflight
Read the release notes and create a complete backup before replacing images. Run the read-only preflight from the candidate migration image:
```sh
docker compose -p devrunbook-prod --env-file .env run --rm migrate \
./packages/db/node_modules/.bin/tsx scripts/release/migration-preflight.mts
```
Exit code `0` means no detected blocker; `2` means migration must not proceed. The JSON records the expected nine migrations, history divergence, PostgreSQL baseline, nullable legacy run keys, invalid integration-secret envelopes, draft-digest mismatches, malformed evaluation digests, and the published-content immutability trigger.
After a successful preflight:
```sh
docker compose -p devrunbook-prod --env-file .env stop web worker
docker compose -p devrunbook-prod --env-file .env build
docker compose -p devrunbook-prod --env-file .env up -d migrate
docker compose -p devrunbook-prod --env-file .env up -d web worker
docker compose -p devrunbook-prod --env-file .env ps
```
Verify login, library search, one playbook detail, manual-profile composition, generation, Markdown download, Run Pack verification, worker recovery, and any configured Gitea connection.
DevRunbook does not provide automatic down migrations. Retaining the prior image is useful only when release notes explicitly state that the upgraded schema remains backward-compatible. Otherwise rollback means restoring the pre-upgrade backup into an empty database and starting the retained prior image. Never point an older image at a newer database without release-specific evidence.
## Backup
The backup script validates the exact Compose project, resolves only its labeled volumes, stops web and worker to quiesce writes, creates a PostgreSQL custom dump and both volume archives, writes non-secret metadata, and generates `SHA256SUMS`. It resumes services that were running. The destination must be a new absolute directory.
```sh
sh scripts/release/backup.sh \
--project devrunbook-prod \
--env-file "$(pwd)/.env" \
--output /mnt/user/appdata/devrunbook/backups/RELEASE_TIMESTAMP \
--application-version RELEASE_VERSION \
--application-commit "$(git rev-parse HEAD)"
```
Back up every required `INTEGRATION_ENCRYPTION_KEY_VERSION` separately in an operator secret store. The metadata lists required version labels but never key values. Losing a required key makes the corresponding integration token unrecoverable.
Copy the backup off-host and verify its checksum file there:
```sh
cd /path/to/copied/backup
sha256sum --check --strict SHA256SUMS
```
## Empty-target restore drill
Restore only to a new project whose name matches `devrunbook-*-restore-*`. The script refuses any pre-existing project container or labeled volume, verifies every checksum, confirms the target database and file volumes are empty, restores data, applies pending migrations, and starts web and worker.
Create a new restricted environment file with a new PostgreSQL password and session/bootstrap secrets. Supply the original integration encryption keys under their recorded version labels.
```sh
sh scripts/release/restore-empty-target.sh \
--project devrunbook-release-restore-001 \
--backup /absolute/path/to/backup \
--env-file /absolute/path/to/restore.env
```
After restore, verify readiness, catalog count, owner login, workspace authorization, repository profiles and revisions, generated prompt digest, artifact bytes and digest, private playbook versions/review evidence, job state, audit records, and integration-token decryption/connection when configured. The script deliberately does not delete a failed or completed restore project; inspect it first and remove only its exact containers and volumes after evidence is retained.
## Password reset and degraded integrations
Issue a single-use local reset link from the worker image. Treat the URL as a secret and do not paste it into logs or tickets:
```sh
docker compose -p devrunbook-prod --env-file .env run --rm worker \
node dist/operator/password-reset.js operator@example.com
```
When Gitea is unavailable, retain the last repository snapshot and use manual profiles. Do not weaken network policy or expose a token to diagnose availability. Readiness should remain healthy unless a configured encryption key is missing.
## Retention enforcement
`ARTIFACT_RETENTION_DAYS` is applied when an artifact is generated. Run the bounded retention command from the release worker image on the operator's preferred schedule:
```sh
docker compose -p devrunbook-prod --env-file .env run --rm worker \
node dist/operator/artifact-retention.js
```
The command accepts no user-provided path. It processes only expired, database-referenced SHA-256 storage keys under `ARTIFACT_ROOT`, treats already-missing bytes idempotently, removes the corresponding artifact metadata, and appends `artifact.retention_deleted` audit evidence. The immutable generated-run snapshot, rendered prompt, provenance and digest remain in PostgreSQL so historical runs stay reproducible.
Operational-log retention remains the responsibility of the Docker logging driver or external collector; configure it to match `LOG_RETENTION_DAYS`. Audit-event pruning is intentionally not automated in this release because append-only governance evidence and backup policy must be reconciled before deletion. `AUDIT_RETENTION_DAYS` therefore records operator policy but is not a destructive scheduler.
## Logs, storage, and removal
Application logs are structured and redact configured secret paths. Body, prompt, repository content, cookies, authorization headers, passwords, tokens, keys, and encrypted envelopes must not be added to support output. Inspect service logs with a bounded time range:
```sh
docker compose -p devrunbook-prod --env-file .env logs --since 30m web worker migrate
docker system df
df -h /mnt/user/appdata/devrunbook
```
Before removing an instance, create and copy a verified backup and separately confirm encryption-key custody. Resolve the exact project resources before deletion:
```sh
docker compose -p devrunbook-prod --env-file .env ps -a
docker volume ls --filter label=com.docker.compose.project=devrunbook-prod
```
Only after those names are reviewed should an operator use `docker compose ... down --volumes`. This irreversibly removes the database and application volumes and is intentionally not automated by DevRunbook.
## Performance fixture
The benchmark command refuses initialized instances and requires both a database name ending in `_benchmark` and an explicit acknowledgement. Apply migrations to a disposable PostgreSQL database first:
```sh
export DATABASE_URL=postgresql://USER:PASSWORD@HOST/devrunbook_release_benchmark
export DEVRUNBOOK_PERFORMANCE_ACK=isolated-benchmark-database
export DEVRUNBOOK_APPLICATION_COMMIT="$(git rev-parse HEAD)"
pnpm db:migrate
pnpm release:benchmark --seed-and-benchmark --iterations=100 > performance.json
```
The fixture deterministically creates 1,000 playbook identities and ten published versions each. The JSON records dataset digest, hardware/runtime/database details, warm-up and sample counts, P50/P95/P99, and comparison with the 500 ms search and 400 ms detail reference targets. It is evidence only when run on the declared release environment; the presence of the script is not a passing result.