feat: one generic image, with installed modules in installation-owned storage (ADR 0048)
CI / verify (pull_request) Failing after 47s
CI / infrastructure-smoke (pull_request) Skipped
CI / migration-smoke (pull_request) Skipped
CI / image-build (pull_request) Skipped
CI / deploy-smoke (same-origin) (pull_request) Skipped
CI / deploy-smoke (split) (pull_request) Skipped
CI / verify (pull_request) Failing after 47s
CI / infrastructure-smoke (pull_request) Skipped
CI / migration-smoke (pull_request) Skipped
CI / image-build (pull_request) Skipped
CI / deploy-smoke (same-origin) (pull_request) Skipped
CI / deploy-smoke (split) (pull_request) Skipped
The production image now contains zero feature modules and is the same for every installation. Installed modules live in module storage that one Core resolver selects from EKKLESIA_MODULES_DIR: the checkout's modules/ when unset, an absolute path that must exist when set (/var/lib/ekklesia/modules in the image). A relative, blank, missing, or unreadable configured directory fails closed with a sanitized error that never contains the value. - Host configuration reads EKKLESIA_MODULES_DIR. The API, migration plan, apply and validate, module validation, module enablement, and Doctor all resolve it the same way; the test-only API override still takes precedence. - Doctor receives Core's migrations directory explicitly instead of deriving it from the modules directory's parent. - The migration runner retains and reports the applied history of a module that is not installed, and plans and applies Core's and present modules' migrations around it. Core's history and every installed module's history stay strict: a missing or changed applied migration, or a downgrade, still fails. No down migrations, no data deletion. - deploy/Dockerfile copies no module and installs nothing for the module template; .dockerignore excludes modules/ and the build refuses a context that contains it; the runtime has an empty root-owned /var/lib/ekklesia/modules and sets EKKLESIA_MODULES_DIR. - deploy/compose.yaml bind-mounts EKKLESIA_MODULES_HOST_DIR read-only into api and migrate, with create_host_path disabled. - scripts/check-image.sh proves the image holds no modules and that a populated modules/ directory leaves its runtime file system identical; CI runs it. - The split deploy smoke now uses the same generic image: it boots with no modules, installs a self-contained test module packaged from the template (test-only), migrates and restarts, removes it (Core runs, planning reports the retained history, data survives), and restores it with its data. Docs: deploy README (module storage, install/update/remove/restore, the runtime modules target), .env.example, API configuration, module development guide, testing, workflow, security, and the architecture overview. Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
4d28a82937
commit
e36b70d8d4
@@ -652,3 +652,23 @@ Still deliberately absent after Phase 8: a theme editor, a brand builder, or any
|
||||
module store or installer; a standalone host; signed write URLs, resumable uploads, or any body above
|
||||
the absolute ceiling; module-owned offline *content*; and every real feature module, Signage
|
||||
included. Nothing in this pass claims any of them exists.
|
||||
|
||||
[ADR 0048](decisions/0048-generic-image-and-installed-module-storage.md) separates the platform
|
||||
artifact from what an installation installs:
|
||||
|
||||
- **One generic image.** `deploy/Dockerfile` builds one image with zero feature modules, the same
|
||||
for every installation; a checkout's `modules/` never reaches it.
|
||||
- **Module storage.** Installed modules live in installation-owned storage that one Core resolver
|
||||
selects from `EKKLESIA_MODULES_DIR`. The API, every operator command, and Doctor use the same
|
||||
resolver, and Core's own migrations are always found under the platform, never beside the
|
||||
modules. A configured directory that is relative, blank, missing, or unreadable fails closed
|
||||
with a sanitized error.
|
||||
- **Self-contained modules.** An installed module is a self-contained directory with its own
|
||||
production dependencies; the platform lends it none. Discovery still happens only when a process
|
||||
starts, so module changes take effect at a controlled restart and nothing is hot loaded.
|
||||
- **Removing keeps data.** Removing a module's code keeps its data and stored state. The migration
|
||||
runner retains and reports the applied history of a module that is absent, instead of refusing
|
||||
to plan, while Core's history and every installed module's history stay strict, so a returning
|
||||
module that lost or changed an applied migration is still refused.
|
||||
- **Trust is unchanged.** Installed modules are still trusted code; module storage is mounted
|
||||
read-only, which keeps Ekklesia from modifying installed code but does not sandbox it.
|
||||
|
||||
Reference in New Issue
Block a user