59 lines
7.4 KiB
Markdown
59 lines
7.4 KiB
Markdown
# Deployment V1
|
|
|
|
Target control plane: Portainer at `https://docker.cin.su`.
|
|
|
|
Recommended V1 deployment topology:
|
|
- `assistant-core-runtime`
|
|
- `assistant-continuity-runtime`
|
|
- `assistant-commit-runtime` (isolated privileged runtime)
|
|
- `assistant-cognitive-worker` (replaceable, no canonical ownership)
|
|
- PostgreSQL 18.6
|
|
- NATS as replaceable integration transport
|
|
|
|
Temporal is intentionally **not** the canonical owner of future obligations. If/when Temporal is added, loss of Temporal must be recoverable from canonical continuity state.
|
|
|
|
The initial stack definition is `deploy/docker-compose.prod.yml`. Portainer may deploy it from Git after the repository has been pushed.
|
|
|
|
Project-built production images receive `org.opencontainers.image.revision` and `org.opencontainers.image.source` OCI labels. Promotion must set `ASSISTANT_SOURCE_REVISION` to the full merged `origin/main` SHA before `docker compose build/up`; the default `unknown` is intentionally rejected by artifact confirmation. After all project containers are running, execute:
|
|
|
|
```powershell
|
|
$revision = git rev-parse origin/main
|
|
powershell -ExecutionPolicy Bypass -File .\deploy\windows\Confirm-DomovoyProductionArtifact.ps1 -Revision $revision -DockerContext docker-prod
|
|
```
|
|
|
|
The confirmation script accepts the promotion only when every project-built container has that revision label, then atomically records its exact Docker image ID in `%LOCALAPPDATA%\Domovoy\monitoring\deployment-manifest.json` and the private NAS monitoring directory. Production health compares every running label and image ID to this manifest and becomes degraded on drift. The manifest is non-secret operational evidence; it is not canonical Assistant state.
|
|
|
|
The first external operation adds `assistant-notification-receiver-1` on production host port `18081`. Caddy applies `deploy/caddy/assistent.caddy`, routing only `https://assistent.cin.su/delivery/*` to that port and all other paths to Creator Web on `18080`. The receiver has an isolated durable volume and no Assistant database access. Commit success means an immutable receiver receipt exists; Windows display and human reading are not Commit outcomes.
|
|
|
|
Migrations `010_capability_notification_binding.sql` and `011_commit_notification_envelope.sql` must be applied before the new runtimes start. The initial Capability binding is owner-local for `domovoy-creator-principal`, revision 1, capability `prospective-notification-delivery`, origin `https://assistent.cin.su`, delivery path `/delivery/v1/deliveries`, receipt path `/delivery/v1/receipts`, protocol `IDEMPOTENT_RECEIPT_V1`, and secret reference `domovoy-notification-write-v1`.
|
|
|
|
`deploy/windows/Invoke-DomovoyNotificationReceiver.ps1` polls the receipt list with the read-only credential, displays up to three unseen local notifications, and records only rebuildable receipt IDs under `%LOCALAPPDATA%\Domovoy`. `Register-DomovoyNotificationTask.ps1` registers the current-user task every two minutes and at logon. It requires an interactive session for display and never uses `docker-test`.
|
|
|
|
Credentials/API deployment automation is deliberately not embedded. Use `PORTAINER_API_KEY` from an external secret source or deploy through Portainer UI/API after authenticating.
|
|
|
|
The single Creator login is configured with external `CREATOR_USERNAME` and `CREATOR_PASSWORD` values. They issue the same bounded Creator session and never select Actor, Principal, Scope or Authority. Keep `CREATOR_BOOTSTRAP_TOKEN` as a separate recovery/automation credential; none of these values belongs in Git, compose defaults for production, image layers or logs.
|
|
|
|
In production, `CREATOR_PASSWORD`, `CREATOR_BOOTSTRAP_TOKEN`, and `CREATOR_SESSION_SIGNING_KEY` are materialized as files in the external `assistant_core_secrets` Docker volume. `core-runtime` receives only the corresponding `_FILE` paths and mounts that volume read-only. Direct environment values remain a development compatibility path and fail closed if combined with `_FILE`.
|
|
|
|
## PostgreSQL recovery
|
|
|
|
Production backups run only on `docker.cin.su`; this project must not use the shared `docker-test` host. `deploy/backup-postgres.sh` creates an atomic, mode-0600 logical backup under `/home/m/assistant-backups/postgres`. Each completed directory contains the application database, cluster roles without role passwords, database/owner metadata, and `SHA256SUMS`. Partial output is never promoted to a completed backup directory, and no automatic retention deletion is performed.
|
|
|
|
`deploy/verify-postgres-restore.sh <backup-directory>` verifies all hashes and restores into an isolated PostgreSQL 18.6 container backed by tmpfs. It never mounts or writes `assistant_assistant_pg`, and removes its temporary container on exit. A backup is operationally accepted only after this restore check passes.
|
|
|
|
The production user crontab installs the single entry from `deploy/cron/assistant-postgres-backup.crontab`. It runs the backup and restore check daily at 00:15 UTC (03:15 Europe/Moscow), survives host reboot without a persistent login session, and writes a private operational log beside the backups.
|
|
|
|
## Encrypted off-host backup
|
|
|
|
`deploy/windows/Sync-PostgresBackupToNas.ps1` copies only a completed, hash-verified production backup over SSH, archives it locally, encrypts it with GnuPG AES-256, verifies an immediate decrypt round trip, and atomically publishes ciphertext plus a non-secret manifest under `\\nas\MST\codex\_backups\domovoy\postgres`. Temporary plaintext is removed on exit. The script is idempotent and never deletes existing backups.
|
|
|
|
`deploy/windows/Test-PostgresBackupFromNas.ps1 -VerifyRemoteRestore` verifies the NAS ciphertext hash, decrypts it with the DPAPI-protected recovery key, checks every source hash, and performs a full isolated PostgreSQL restore on `docker.cin.su`. `deploy/windows/Register-PostgresBackupNasTask.ps1` generates the key when absent, atomically backs up only its DPAPI ciphertext to the NAS, and registers current-user daily and logon triggers. The task intentionally does not use `docker-test`.
|
|
|
|
## Production health monitoring
|
|
|
|
`deploy/windows/Test-DomovoyProductionHealth.ps1` is an external, rebuildable operational projection; it is not a canonical Core `Monitor`. It checks all expected production containers, HTTPS health, TLS expiry, public DNS agreement, production backup age and hashes, NAS backup age and ciphertext hash, cron, and the off-host backup task. Thresholds are 30 hours for the production backup, 36 hours for the NAS copy, and 21 remaining certificate days.
|
|
|
|
The script atomically writes the latest JSON snapshot to `%LOCALAPPDATA%\Domovoy\monitoring\status.json` and `\\nas\MST\codex\_monitoring\domovoy\status.json`, then exits nonzero when any check is degraded. `deploy/windows/Register-DomovoyProductionHealthTask.ps1` registers a current-user execution every 15 minutes and at logon. Monitoring never uses `docker-test` and never mutates product state.
|
|
|
|
`deploy/windows/Invoke-DomovoyProductionMonitoring.ps1` runs health collection in a child process and then evaluates `deploy/windows/Send-DomovoyHealthNotification.ps1`, including when health is degraded. The notifier shows a local Windows notification on the first degraded observation, recovery, and no more than one continuing-failure reminder per six hours. Its suppression state is an external, non-canonical JSON file at `%LOCALAPPDATA%\Domovoy\monitoring\notification-state.json` and may be regenerated. Notifications require the registered user to have an interactive Windows session; no external notification service or credential is used.
|