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]>