diff --git a/Repo-docs-INSTALLATION-AND-DEPLOYMENT-ARCHITECTURE.md b/Repo-docs-INSTALLATION-AND-DEPLOYMENT-ARCHITECTURE.md new file mode 100644 index 0000000..783cac1 --- /dev/null +++ b/Repo-docs-INSTALLATION-AND-DEPLOYMENT-ARCHITECTURE.md @@ -0,0 +1,233 @@ + + +> Mirrored from `/mnt/DATA/git/govoplan/docs/INSTALLATION_AND_DEPLOYMENT_ARCHITECTURE.md`. +> Origin: `repository`. +> Active tasks and changing state belong in Gitea issues; this wiki page is durable project context. + +--- +# Installation And Deployment Architecture + +## Goal + +A supported GovOPlaN installation starts with one downloaded, verified +bootstrap artifact. The administrator answers a bounded set of questions and +receives a working base system. Re-running the same tool repairs or +reconfigures that installation instead of creating unrelated state. + +The canonical product journey remains +[System Administrator Lifecycle User Story](SYSTEM_ADMINISTRATOR_LIFECYCLE_USER_STORY.md). +This document defines the deployer boundary and the first executable slice. + +## First Executable Slice + +`tools/deployment/govoplan-deploy.py` is a standard-library-only deployment +compiler and reconciler. It can be tested without installing GovOPlaN itself. + +It currently supports: + +- evaluation and self-hosted profiles; +- managed or external PostgreSQL; +- managed, external, or evaluation-only disabled Redis; +- disabled mail, an external relay declaration, or an evaluation-only + GreenMail service; +- durable local file storage or external S3-compatible storage; +- Core, base, or full initial module selections; +- deterministic Compose JSON accepted by Compose v2; +- generated secrets stored in a private `0600` file; +- plan, render, doctor, status, and apply commands; +- an installation lock, migration-before-start ordering, readiness polling, + and an applied-state receipt; +- idempotent reconfiguration that preserves generated secrets; +- service removal without implicit data-volume deletion. + +Create a local evaluation bundle: + +```sh +./.venv/bin/python tools/deployment/govoplan-deploy.py init \ + --directory /tmp/govoplan-evaluation \ + --profile evaluation \ + --postgres managed \ + --redis managed \ + --mail test-mail \ + --module-set base +``` + +Inspect the generated intent and host requirements: + +```sh +./.venv/bin/python tools/deployment/govoplan-deploy.py doctor \ + --directory /tmp/govoplan-evaluation +``` + +Change a component without rotating existing generated secrets: + +```sh +./.venv/bin/python tools/deployment/govoplan-deploy.py configure \ + --directory /tmp/govoplan-evaluation \ + --redis external \ + --redis-url 'rediss://:password@redis.example.org:6379/0' +``` + +The private installation directory contains: + +| File | Purpose | +| --- | --- | +| `installation.json` | Versioned, non-secret desired state | +| `secrets.env` | Deployment-local secrets and external service bindings | +| `compose.json` | Deterministic generated Compose definition | +| `plan.json` | Latest desired-state diff and readiness findings | +| `receipt.json` | Last successfully applied immutable identities | +| `.deployment.lock` | Same-host operation exclusion | + +The specification contract is +[`installation-spec.schema.json`](installation-spec.schema.json). + +Build the same dependency-free tool as one downloadable artifact: + +```sh +./.venv/bin/python tools/deployment/build-deployer-zipapp.py \ + --output /tmp/govoplan-deploy.pyz +python /tmp/govoplan-deploy.pyz --help +``` + +## Current Production Gates + +The tool deliberately reports blockers instead of pretending the source tree is +a production distribution: + +1. **OCI release artifacts.** The release pipeline does not yet publish pinned + multi-architecture API and WebUI images. +2. **Signed distribution manifest.** A channel manifest must bind exact image + digests, Compose compatibility, SBOM/provenance references, and revocation + state. Recording a URL and checksum is not signature verification. +3. **First administrator.** Production needs a one-time, restricted enrollment + identity. The development bootstrap must not be enabled in production. +4. **Image/module composition.** The selected module set must be proven present + in the exact image or installed from verified offline artifacts before it is + enabled. +5. **Deployment agent.** Web updates need a separate privileged reconciler with + a typed command allowlist. The API and browser must never receive the Docker + socket or arbitrary shell access. + +`apply --allow-unverified-images` is therefore restricted to the evaluation +profile. It explicitly acknowledges both mutable image identities and +unverified image/module composition. It is a local test escape hatch, not a +production setting. + +## Component Choices + +### PostgreSQL + +`managed` creates a persistent PostgreSQL container and private generated +credentials. `external` requires an explicit `DATABASE_URL`; switching from +managed to external cannot reuse the old `postgres` Docker hostname +accidentally. + +Production policy should support external managed databases and local managed +PostgreSQL equally at the application boundary. Backup, point-in-time recovery, +high availability, and major-version upgrades remain deployment properties. + +### Redis + +`managed` creates an authenticated, append-only Redis container. `external` +requires an explicit `REDIS_URL`. `disabled` is evaluation-only and disables +workers while recording the single-process login-throttle risk acknowledgement. + +Production base installations include Redis because durable queues, distributed +throttling, notifications, scheduled work, and transactional event delivery +must survive API restarts. + +### Mail + +The first slice distinguishes: + +- `disabled`; +- `external-relay`, which records the infrastructure decision but leaves Mail + server/credential creation as a visible post-install task; +- `test-mail`, an evaluation-only GreenMail service. + +A bundled production mail server is intentionally not a default. Operating one +requires DNS, reverse DNS, TLS, DKIM, SPF, DMARC, reputation, abuse handling, +queue monitoring, and upgrade policy. A later profile may support an +operator-selected MTA/relay, but it must expose these requirements rather than +presenting a container as a complete mail service. + +### File Storage + +`local` uses a durable Compose volume and is appropriate for one-host +installations. `s3` requires endpoint, region, access key, secret key, and +bucket values. Self-hosted S3 endpoints must use HTTPS. + +Local storage must be included in backup and restore drills. Horizontal API or +worker scale-out requires shared/object storage. + +## Reconfiguration Semantics + +`installation.json` is desired state. `receipt.json` is the last successfully +applied state. `plan` compares their canonical hashes and service sets. + +- Adding a managed component creates its service and persistent volume. +- Removing a component removes its service container on apply. +- Volumes are retained by default; deleting data requires a separate, + deliberately destructive workflow. +- Existing generated credentials are retained unless an explicit future rotate + operation is requested. +- Managed-to-external transitions require the new endpoint in the same + operation. +- Migrations run as a one-shot service before API/worker replacement. +- Health must recover before a new receipt is committed. + +This is sufficient for one-host reconciliation. Production updates additionally +need backup/restore gates, maintenance/drain state, database compatibility +windows, image signature verification, and rollback/forward-recovery policy. + +## Web Update Boundary + +The intended update path is: + +1. Ops reads the non-secret installation receipt and reports management mode, + current release, component health, and update availability. +2. An authorized administrator asks Core to create a typed deployment request, + for example `reconcile_release` or `rollback_release`. +3. Core persists the reviewed immutable plan, actor, expected current receipt, + and idempotency key. +4. A separately deployed, narrow deployment agent claims the request. +5. The agent verifies signatures/digests, acquires a fenced deployment lock, + backs up, pulls, migrates, reconciles, probes health, and writes evidence. +6. Ops presents durable progress and the resulting receipt. + +The agent owns container-runtime access. It accepts no command strings from the +browser and has no domain-data permissions. Installations managed by Kubernetes, +systemd, or another external orchestrator expose read-only status and an export +of the reviewed update recipe instead of a non-functional update button. + +## Distribution Workflow + +The downloadable entry point should eventually be: + +```sh +curl --proto '=https' --tlsv1.2 --fail --location \ + https://govoplan.add-ideas.de/install/v1/bootstrap.pyz \ + --output govoplan-bootstrap.pyz +python3 govoplan-bootstrap.pyz init +``` + +The published documentation must include an independent checksum/signature +verification command before execution. The zipapp then downloads only a signed +distribution manifest, verifies it against an embedded or explicitly installed +keyring, and renders the same installation contract implemented here. + +The source-tree script is the test harness for that future zipapp. It is not yet +the internet bootstrap artifact. + +## Verification + +Run the focused tests: + +```sh +./.venv/bin/python -m unittest -v tests.test_deployment_installer +``` + +The tests cover profile restrictions, secret persistence, external endpoint +requirements, S3 policy, Compose service selection, secret non-disclosure, +private file modes, first-plan generation, and receipt-based idempotency.