diff --git a/Repo-docs-MODULE-ARCHITECTURE.-.md b/Repo-docs-MODULE-ARCHITECTURE.-.md index 33fab33..cfaa61b 100644 --- a/Repo-docs-MODULE-ARCHITECTURE.-.md +++ b/Repo-docs-MODULE-ARCHITECTURE.-.md @@ -1,4 +1,4 @@ - + > Mirrored from `/mnt/DATA/git/govoplan-core/docs/MODULE_ARCHITECTURE.md`. > Origin: `repository`. @@ -380,15 +380,14 @@ Hot enable/disable is a core design principle for every module: - Modules can provide `on_activate` and `on_deactivate` hooks for worker, scheduler, cache, or external subscription lifecycle. These hooks must be idempotent and must not mutate another module directly. -- Package install/uninstall remains a deployment/operator action unless the - runtime provides a trusted package installer and rollback path. The admin UI - can activate/deactivate installed packages; it must not remove package files - or attempt dependency-manager operations in-process. +- Package install/uninstall is performed by the trusted operator installer, not + directly inside FastAPI request handlers. The admin UI can save install plans, + show preflight blockers, and activate/deactivate installed packages. The package install-plan API records operator intent only: -- `GET /api/v1/admin/system/modules/install-plan` reads the saved plan and - renders shell commands for the operator. +- `GET /api/v1/admin/system/modules/install-plan` reads the saved plan, + renders shell commands, and returns installer preflight status. - `PUT /api/v1/admin/system/modules/install-plan` saves planned install or uninstall rows. Install rows must use tagged package or git references, not local `file:`/workspace paths. @@ -396,12 +395,37 @@ The package install-plan API records operator intent only: - `govoplan-module-install-plan --format shell` or `python -m govoplan_core.commands.module_install_plan --format shell` renders the same commands from a server shell. +- `govoplan-module-installer --format shell` runs the same preflight checks from + the server shell. +- `govoplan-module-installer --apply --build-webui` executes the saved plan + after preflight passes, snapshots `pip freeze` and WebUI package files, writes + a run record under the runtime installer directory, and marks planned rows as + applied after success. +- `govoplan-module-installer --rollback ` restores the saved package + snapshots and reruns package installation from the previous freeze file. -The running server intentionally reports `install_uninstall_supported=false` -and `package_mutation_supported=false`. This is by design: mutating the -interpreter environment, npm dependency graph, frontend bundle, migrations, and -worker process set from inside the same running app is not safe without a -separate trusted installer, rollback model, and bundle loader. +The installer preflight is intentionally conservative: + +- maintenance mode must be active; +- uninstalling `tenancy`, `access`, or `admin` is blocked; +- uninstalling an active module is blocked; +- uninstalling a module still present in desired startup state is blocked; +- uninstalling a module with active/desired dependents is blocked; +- install refs must be exact versions or tagged git refs; +- WebUI package changes require a WebUI root and trigger rebuild/reload status. + +The running FastAPI server still reports `package_mutation_supported=false` +because dependency-manager operations are not executed inside request handlers. +The trusted mutation boundary is the operator CLI. This keeps the interpreter, +npm dependency graph, frontend bundle, migrations, and worker process set under +process-supervisor control. + +Frontend module loading currently uses the build-time package graph generated by +the core WebUI host. Therefore installing or uninstalling a WebUI package +requires `npm install` plus a WebUI rebuild/reload. True remote runtime bundle +loading would need signed asset manifests, version compatibility checks, CSP +rules, cache invalidation, and rollback at the asset-loader layer; it is a +future deployment hardening track, not the default module installer path. ## Maintenance Mode