200 lines
11 KiB
Markdown
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.
|