Files
Ekklesia/docs/architecture/decisions/0005-static-module-manifests.md
T
ekklesia 57552a21a4
CI / verify (push) Has been cancelled
CI / infrastructure-smoke (push) Has been cancelled
feat: add module contracts and discovery
2026-07-12 22:14:01 -05:00

56 lines
2.9 KiB
Markdown

# 0005: Static module manifests and atomic discovery
- Status: Accepted
- Date: 2026-07-12
## Context
Ekklesia modules must be installable by placing a package in `modules/` without editing Core or a
central registry. Core must validate identity, compatibility, dependencies, capabilities, storage
requirements, and entrypoints before it runs module behavior. Importing an executable TypeScript
manifest would allow top-level module code to run before validation completed.
## Decision
Every module uses one inert, versioned `ekklesia.module.json` manifest. `@ekklesia/contracts` owns
the authoritative Zod schema and serializable types. `@ekklesia/module-sdk` re-exports those public
contracts and provides `defineModule` for typed programmatic validation without becoming a Core
service locator.
Core scans immediate non-hidden directories under the configured modules directory. Discovery
validates all manifests and package metadata, resolves entrypoints without loading them, checks
platform and Module SDK compatibility, resolves module and capability dependencies, and produces a
deterministic dependency-first order. Any error rejects the entire discovery result with sorted,
structured issues; no module server code is partially loaded.
Storage requirements are declarative. A module may request one or more logical buckets in its
manifest, but it cannot create provider clients or select physical bucket names. The later Core
storage service will provision deployment-prefixed physical buckets and give the owning module
scoped handles. Buckets remain private unless a future explicit storage contract says otherwise.
## Alternatives
- Executable `module.ts` manifests were rejected because discovery would cross the code-execution
boundary before validation.
- Embedding the full manifest in `package.json` was rejected because it couples the platform
contract to package-manager metadata and makes the manifest harder to version independently.
- A manually maintained import registry was rejected because every module installation would
require a central source edit.
- Letting modules configure SeaweedFS or S3 clients directly was rejected because Core owns
credentials, provider selection, isolation, and lifecycle.
## Consequences
JSON manifests do not provide TypeScript inference by themselves, so validation commands and clear
path-aware errors are part of the authoring workflow. A JSON Schema can be generated from the
authoritative contract later for editor completion.
Discovery currently proves entrypoint existence but does not import server behavior, execute
lifecycle hooks, provision requested buckets, or register routes, jobs, schemas, and migrations.
Those operations begin only after a complete valid discovery result in later runtime slices.
## Migration implications
The manifest includes `manifestVersion: 1`. Future incompatible shapes require an explicit schema
version and migration path rather than silently changing existing module interpretation.