355 lines
16 KiB
Markdown
355 lines
16 KiB
Markdown
# GovOPlaN Release Dependencies
|
|
|
|
Release installs must not depend on sibling checkout paths. Local development can keep editable installs and `file:` WebUI links, but release packaging should resolve modules from tagged git refs or from a package registry.
|
|
|
|
## Backend
|
|
|
|
Local development:
|
|
|
|
```bash
|
|
cd /mnt/DATA/git/govoplan-core
|
|
./.venv/bin/python -m pip install -r requirements-dev.txt
|
|
```
|
|
|
|
Release install from a core checkout plus tagged module repositories:
|
|
|
|
```bash
|
|
cd /mnt/DATA/git/govoplan-core
|
|
./.venv/bin/python -m pip install -r requirements-release.txt
|
|
```
|
|
|
|
`.[server]` is resolved relative to the current working directory. If you create the virtualenv elsewhere, still run the install command from the core checkout:
|
|
|
|
```bash
|
|
cd /mnt/DATA/git/govoplan-core
|
|
/tmp/govoplan-release-test/bin/python -m pip install -r requirements-release.txt
|
|
```
|
|
|
|
`requirements-release.txt` pins the module repositories to the release tag. Update those refs when cutting a release:
|
|
|
|
```text
|
|
govoplan-access git@git.add-ideas.de:add-ideas/govoplan-access.git v0.1.4
|
|
govoplan-admin git@git.add-ideas.de:add-ideas/govoplan-admin.git v0.1.4
|
|
govoplan-tenancy git@git.add-ideas.de:add-ideas/govoplan-tenancy.git v0.1.4
|
|
govoplan-policy git@git.add-ideas.de:add-ideas/govoplan-policy.git v0.1.4
|
|
govoplan-audit git@git.add-ideas.de:add-ideas/govoplan-audit.git v0.1.4
|
|
govoplan-files git@git.add-ideas.de:add-ideas/govoplan-files.git v0.1.4
|
|
govoplan-mail git@git.add-ideas.de:add-ideas/govoplan-mail.git v0.1.4
|
|
govoplan-campaign git@git.add-ideas.de:add-ideas/govoplan-campaign.git v0.1.4
|
|
govoplan-calendar git@git.add-ideas.de:add-ideas/govoplan-calendar.git v0.1.4
|
|
```
|
|
|
|
## Runtime Module Package Changes
|
|
|
|
The admin module manager can hot-enable and hot-disable packages that are
|
|
already installed. It does not install or uninstall Python/npm packages from
|
|
inside the running server.
|
|
|
|
For runtime package changes, create an operator install plan in Admin > System >
|
|
Modules. The module manager shows the trusted installer preflight status and
|
|
blocks unsafe uninstalls before the operator touches packages.
|
|
|
|
Preflight from the server shell:
|
|
|
|
```bash
|
|
govoplan-module-installer --format shell
|
|
```
|
|
|
|
Apply from a controlled operator shell while maintenance mode is active:
|
|
|
|
```bash
|
|
govoplan-module-installer --apply --build-webui
|
|
```
|
|
|
|
For real install/uninstall work, prefer supervised mode with the deployment's
|
|
restart command and health endpoint:
|
|
|
|
```bash
|
|
govoplan-module-installer \
|
|
--supervise \
|
|
--migrate \
|
|
--build-webui \
|
|
--health-url http://127.0.0.1:8000/health \
|
|
--restart-command '<restart govoplan server>'
|
|
```
|
|
|
|
To let the admin UI trigger package work without executing pip/npm inside a
|
|
FastAPI request, run the installer daemon in a separate operator shell. This is
|
|
the preferred development/early-production mode for now because the operator can
|
|
watch output, stop before queueing risky changes, and keep restart commands
|
|
deployment-specific:
|
|
|
|
```bash
|
|
govoplan-module-installer \
|
|
--daemon \
|
|
--migrate \
|
|
--build-webui \
|
|
--database-backup-command 'pg_dump --format=custom "$GOVOPLAN_DATABASE_URL" > "$GOVOPLAN_DATABASE_BACKUP_PATH"' \
|
|
--database-restore-check-command 'pg_restore --list "$GOVOPLAN_DATABASE_BACKUP_PATH" >/dev/null' \
|
|
--database-restore-command 'pg_restore --clean --if-exists --dbname "$GOVOPLAN_DATABASE_URL" "$GOVOPLAN_DATABASE_BACKUP_PATH"' \
|
|
--health-url http://127.0.0.1:8000/health \
|
|
--restart-command '<restart govoplan server>'
|
|
```
|
|
|
|
Admin > System > Modules can then queue the saved install plan as a supervised
|
|
request. Install rows can be planned directly from the approved package catalog;
|
|
uninstall rows are generated from installed, disabled modules so the Python
|
|
distribution and WebUI package names do not need to be typed by hand. The
|
|
daemon claims one queued request at a time and writes request/run records below
|
|
`runtime/module-installer`. For process-manager one-shot usage or tests, use
|
|
`--daemon-once`. The daemon also writes
|
|
`runtime/module-installer/daemon.status.json`; check it with:
|
|
|
|
```bash
|
|
govoplan-module-installer --daemon-status --format json
|
|
```
|
|
|
|
The installer uses a runtime lock, snapshots `pip freeze` plus WebUI
|
|
`package.json`/`package-lock.json`, writes a run record below
|
|
`runtime/module-installer/runs`, and marks planned rows as applied only after
|
|
all commands succeed. When `--migrate` is used with a `sqlite:///` database URL,
|
|
the installer also snapshots the SQLite database with SQLite's backup API before
|
|
running migrations. For other database engines, pass external backup/restore
|
|
hooks:
|
|
|
|
```bash
|
|
govoplan-module-installer \
|
|
--supervise \
|
|
--migrate \
|
|
--database-backup-command 'pg_dump --format=custom "$GOVOPLAN_DATABASE_URL" > "$GOVOPLAN_DATABASE_BACKUP_PATH"' \
|
|
--database-restore-check-command 'pg_restore --list "$GOVOPLAN_DATABASE_BACKUP_PATH" >/dev/null' \
|
|
--database-restore-command 'pg_restore --clean --if-exists --dbname "$GOVOPLAN_DATABASE_URL" "$GOVOPLAN_DATABASE_BACKUP_PATH"' \
|
|
--health-url http://127.0.0.1:8000/health \
|
|
--restart-command '<restart govoplan server>'
|
|
```
|
|
|
|
The backup command runs before migrations. The restore-check command validates
|
|
the produced backup artifact before migrations proceed, without restoring over
|
|
the live database. The restore command is stored in the run record and runs
|
|
during rollback unless an override is passed to `--rollback`.
|
|
|
|
Supervised mode treats package command failure, migration failure, restart
|
|
failure, and health timeout as rollback triggers. It restores the Python/WebUI
|
|
package snapshots, re-runs the restart command when supplied, and restores the
|
|
saved install plan state so the operator can correct it. The supervisor must
|
|
run outside the FastAPI server process; the admin UI saves and validates plans
|
|
but does not mutate packages from an HTTP request.
|
|
|
|
After a successful install plan, the installer adds installed modules to saved
|
|
startup state by default so the restarted server can discover and enable them.
|
|
After a successful uninstall plan, the installer removes uninstalled modules
|
|
from saved startup state by default. Use
|
|
`--no-activate-installed-modules` or
|
|
`--keep-uninstalled-modules-in-desired` only for staged rollout workflows that
|
|
will update module state separately.
|
|
|
|
Uninstall is non-destructive by default. A planned uninstall row can set
|
|
`destroy_data: true` to request destructive module retirement. The module must
|
|
provide an automated retirement provider, and the installer snapshots the
|
|
database before dropping module-owned tables. For SQLite this uses the built-in
|
|
snapshot path; for PostgreSQL or another non-SQLite database, provide
|
|
`--database-backup-command`, `--database-restore-check-command`, and
|
|
`--database-restore-command`. If a destructive run fails during package removal,
|
|
the installer restores the database snapshot before returning the failed run
|
|
result; supervised restart/health failures also roll back through the normal
|
|
supervisor path.
|
|
|
|
Package rollback is automatic. SQLite database rollback is automatic for
|
|
installer runs that used `--migrate` and captured a database snapshot.
|
|
Non-SQLite rollback is automatic when the run used
|
|
`--database-backup-command` and `--database-restore-command`; otherwise migrated
|
|
non-SQLite runs are blocked before package changes are applied.
|
|
|
|
Rollback uses the saved run snapshot:
|
|
|
|
```bash
|
|
govoplan-module-installer --rollback <run-id>
|
|
govoplan-module-installer --rollback <run-id> --database-restore-command '<override restore command>'
|
|
```
|
|
|
|
Database hook commands run with these environment variables:
|
|
|
|
- `GOVOPLAN_INSTALLER_RUN_DIR`: the run snapshot directory
|
|
- `GOVOPLAN_DATABASE_URL`: the configured database URL
|
|
- `GOVOPLAN_DATABASE_BACKUP_PATH`: a suggested backup artifact path inside the
|
|
run directory
|
|
- `GOVOPLAN_DATABASE_BACKUP_METADATA`: optional JSON metadata path that backup
|
|
commands may write for operator diagnostics
|
|
|
|
Avoid embedding secrets directly in commands; prefer environment variables,
|
|
service credentials, or deployment-local secret injection.
|
|
|
|
Inspect installer history and lock state from the operator shell:
|
|
|
|
```bash
|
|
govoplan-module-installer --list-runs --format json
|
|
govoplan-module-installer --show-run <run-id> --format json
|
|
govoplan-module-installer --lock-status --format json
|
|
govoplan-module-installer --list-requests --format json
|
|
govoplan-module-installer --show-request <request-id> --format json
|
|
govoplan-module-installer --cancel-request <request-id> --format json
|
|
govoplan-module-installer --retry-request <request-id> --format json
|
|
```
|
|
|
|
Package catalogs can be local files or remote static resources, for example
|
|
served by `govoplan-web`. Set `GOVOPLAN_MODULE_PACKAGE_CATALOG` for a local file
|
|
or `GOVOPLAN_MODULE_PACKAGE_CATALOG_URL` for a remote catalog matching
|
|
`docs/module-package-catalog.example.json`; the admin UI will show those entries
|
|
and can save them into the install plan. This keeps the release approval
|
|
decision outside the running server while avoiding hand-typed package refs.
|
|
Remote catalogs can be cached for offline inspection:
|
|
|
|
```bash
|
|
GOVOPLAN_MODULE_PACKAGE_CATALOG_URL=https://govoplan.example/catalogs/v1/channels/stable.json
|
|
GOVOPLAN_MODULE_PACKAGE_CATALOG_CACHE=/srv/govoplan/runtime/catalog-cache/stable.json
|
|
```
|
|
|
|
Validate the catalog before handing it to operators:
|
|
|
|
```bash
|
|
govoplan-module-installer --validate-package-catalog docs/module-package-catalog.example.json --format json
|
|
```
|
|
|
|
Release catalogs should be signed, channel-gated, expiring, and sequence
|
|
tracked. The supported signing format is an Ed25519 signature over the
|
|
canonical catalog JSON object with the `signature` and `signatures` fields
|
|
removed. Core accepts the legacy single `signature` field and the newer
|
|
`signatures` array used during key rotation. Sign a catalog with:
|
|
|
|
```bash
|
|
govoplan-module-installer \
|
|
--sign-package-catalog docs/module-package-catalog.example.json \
|
|
--catalog-signing-key-id release-key-1 \
|
|
--catalog-signing-private-key /path/to/ed25519-private.pem
|
|
```
|
|
|
|
Validate an approved release catalog with:
|
|
|
|
```bash
|
|
govoplan-module-installer \
|
|
--validate-package-catalog docs/module-package-catalog.example.json \
|
|
--require-signed-catalog \
|
|
--approved-catalog-channel stable \
|
|
--catalog-trusted-key release-key-1=<base64-ed25519-public-key> \
|
|
--format json
|
|
```
|
|
|
|
For the admin UI/daemon path, configure the same policy through environment
|
|
variables:
|
|
|
|
```bash
|
|
GOVOPLAN_MODULE_PACKAGE_CATALOG=/path/to/catalog.json
|
|
GOVOPLAN_MODULE_PACKAGE_CATALOG_REQUIRE_SIGNATURE=true
|
|
GOVOPLAN_MODULE_PACKAGE_CATALOG_APPROVED_CHANNELS=stable
|
|
GOVOPLAN_MODULE_PACKAGE_CATALOG_TRUSTED_KEYS='{"release-key-1":"<base64-ed25519-public-key>"}'
|
|
GOVOPLAN_MODULE_PACKAGE_CATALOG_SEQUENCE_STATE=/srv/govoplan/runtime/catalog-sequences.json
|
|
GOVOPLAN_MODULE_PACKAGE_CATALOG_ENFORCE_SEQUENCE=true
|
|
```
|
|
|
|
Trusted keys can also be loaded from
|
|
`GOVOPLAN_MODULE_PACKAGE_CATALOG_TRUSTED_KEYS_FILE`. A URL-backed keyring is
|
|
supported for development and tightly controlled deployments through
|
|
`GOVOPLAN_MODULE_PACKAGE_CATALOG_TRUSTED_KEYS_URL` plus
|
|
`GOVOPLAN_MODULE_PACKAGE_CATALOG_TRUSTED_KEYS_CACHE`, but production systems
|
|
should pin trusted keys locally.
|
|
|
|
Catalog entries can declare `license_features`. If
|
|
`GOVOPLAN_LICENSE_ENFORCEMENT=true`, core blocks planning catalog installs
|
|
whose required features are not present in the configured offline license:
|
|
|
|
```bash
|
|
GOVOPLAN_LICENSE_FILE=/srv/govoplan/license.json
|
|
GOVOPLAN_LICENSE_TRUSTED_KEYS_FILE=/srv/govoplan/trust/license-keyring.json
|
|
GOVOPLAN_LICENSE_ENFORCEMENT=true
|
|
```
|
|
|
|
See `docs/CATALOG_TRUST_AND_LICENSING.md` for key rotation, replay protection,
|
|
and licensing details. See `docs/RELEASE_CATALOG_WORKFLOW.md` for the concrete
|
|
release-machine workflow that generates signing keys and publishes signed
|
|
catalogs through `govoplan-web`. Unsigned catalogs remain usable for local
|
|
development when signature enforcement is off, but the admin UI labels them as
|
|
unsigned.
|
|
|
|
Install rows must use tagged package/git refs or registry packages, not local
|
|
`file:` or workspace links. The installer daemon can run `npm install` and
|
|
`npm run build` for WebUI package changes; that is the supported path. Browser
|
|
remote bundles are still experimental and should be treated as a controlled
|
|
deployment option, not the normal install/uninstall mechanism.
|
|
|
|
Module manifests can declare core compatibility bounds and uninstall guard
|
|
providers. Preflight blocks incompatible manifest contracts/core versions,
|
|
active modules, desired startup state, protected modules, and active dependents.
|
|
Default uninstall is non-destructive: module data and schema remain dormant if
|
|
the package is removed. Persistent-data guards therefore warn by default instead
|
|
of requiring export/delete. A module that supports explicit data/schema
|
|
retirement should register a retirement provider. When `destroy_data` is set on
|
|
an uninstall plan row, that provider is allowed to destroy module-owned data
|
|
after the installer has captured a database snapshot; otherwise it is used only
|
|
for preflight reporting.
|
|
|
|
## WebUI
|
|
|
|
Local development uses `webui/package.json`, which may point at sibling module checkouts while active development is happening.
|
|
|
|
Release WebUI installs should use `webui/package.release.json`. It points module dependencies at the same tagged git repositories. After the module tags referenced there exist, generate the committed release lockfile without touching the development package files:
|
|
|
|
```bash
|
|
cd /mnt/DATA/git/govoplan-core
|
|
scripts/generate-release-lock.sh
|
|
cd webui
|
|
PATH=/home/zemion/.nvm/versions/node/v22.22.3/bin:$PATH /home/zemion/.nvm/versions/node/v22.22.3/bin/npm run build
|
|
```
|
|
|
|
The module repositories include root-level npm package manifests so git installs can resolve `@govoplan/access-webui`, `@govoplan/admin-webui`, `@govoplan/files-webui`, `@govoplan/mail-webui`, `@govoplan/campaign-webui`, and `@govoplan/calendar-webui` from repository roots even though their source lives below `webui/src`.
|
|
|
|
The normal release path is automated by `scripts/push-release-tag.sh`: it bumps or accepts the target version, updates Python/WebUI/module manifest versions, commits/tags/pushes the module repositories first, regenerates `webui/package-lock.release.json`, and then commits/tags/pushes core. If the working tree has already been bumped, pass the current version explicitly:
|
|
|
|
```bash
|
|
cd /mnt/DATA/git/govoplan-core
|
|
scripts/push-release-tag.sh --version 0.1.2
|
|
```
|
|
|
|
The script also includes GovOPlaN roadmap/scaffold module repositories that do not yet have package metadata. Those repositories are committed, tagged, and pushed with the same release tag, but they are tag-only until they contain `pyproject.toml`, module manifests, or WebUI packages. Tag-only repositories are not listed in `requirements-release.txt` or `webui/package.release.json`.
|
|
|
|
Current tag-only module repositories:
|
|
|
|
- `govoplan-addresses`
|
|
- `govoplan-appointments`
|
|
- `govoplan-cases`
|
|
- `govoplan-connectors`
|
|
- `govoplan-dms`
|
|
- `govoplan-erp`
|
|
- `govoplan-fit-connect`
|
|
- `govoplan-forms`
|
|
- `govoplan-identity-trust`
|
|
- `govoplan-idm`
|
|
- `govoplan-ledger`
|
|
- `govoplan-notifications`
|
|
- `govoplan-ops`
|
|
- `govoplan-payments`
|
|
- `govoplan-portal`
|
|
- `govoplan-reporting`
|
|
- `govoplan-scheduling`
|
|
- `govoplan-search`
|
|
- `govoplan-tasks`
|
|
- `govoplan-templates`
|
|
- `govoplan-workflow`
|
|
- `govoplan-xoev`
|
|
- `govoplan-xrechnung`
|
|
- `govoplan-xta-osci`
|
|
|
|
### Release lockfile strategy
|
|
|
|
The supported release composition currently is the full Multi Seal Mail product: core plus access, admin, tenancy, policy, audit, files, mail, campaign, and calendar. Keep one committed full-product release lockfile at `webui/package-lock.release.json`, generated from `webui/package.release.json` in a clean release workspace. Development `package-lock.json` may continue to point at local `file:` dependencies.
|
|
|
|
Frontend module permutations are regression-tested through `GOVOPLAN_WEBUI_MODULE_PACKAGES` and temporary build output, not through committed lockfiles for every possible combination. If a smaller composition becomes a separately shipped product, add an explicit release manifest and lockfile pair for that product, for example `package.release.files-mail.json` and `package-lock.release.files-mail.json`, generated in a clean release workspace from tagged git dependencies.
|
|
|
|
## Release Checklist
|
|
|
|
- Keep Python package versions, WebUI package versions, and git tags aligned.
|
|
- Tag core, access, admin, tenancy, policy, audit, files, mail, campaign, calendar, and scaffold module repositories together.
|
|
- Update `requirements-release.txt` and `webui/package.release.json` when the release tag changes.
|
|
- Generate the committed full-product release lockfile from `package.release.json` with `scripts/generate-release-lock.sh`.
|
|
- Add separate release manifest/lockfile pairs only for module compositions that are shipped as their own products.
|
|
- Do not commit local sibling paths into release manifests.
|