Files
Ekklesia/docs/module-development/README.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

2.8 KiB

Module development

An Ekklesia module is a backend capability package. It owns business behavior and data declarations; it never owns components, styles, layouts, renderers, navigation, or other UI.

Required package shape

Each immediate child of modules/ must contain:

modules/example/
├── ekklesia.module.json
├── package.json
└── src/server/index.ts

package.json must use ESM, a strict semantic version, a unique package name, and:

{
  "ekklesia": {
    "layer": "module"
  }
}

Its version must match the module manifest version. Internal package dependencies use workspace: ranges and supported package entrypoints.

Manifest

The canonical manifest is inert JSON so discovery can validate a module without executing it:

{
  "manifestVersion": 1,
  "id": "calendar",
  "name": "Calendar",
  "version": "0.1.0",
  "compatibility": {
    "platform": "^0.1.0",
    "moduleSdk": "^0.1.0"
  },
  "dependencies": {
    "modules": {
      "required": {
        "people": "^0.1.0"
      }
    },
    "capabilities": {
      "optional": ["media.items"]
    }
  },
  "capabilities": ["calendar.events"],
  "permissions": ["calendar.events.read"],
  "storage": {
    "buckets": [
      {
        "id": "assets",
        "description": "Private event assets owned by Calendar."
      }
    ]
  },
  "entrypoints": {
    "server": "./src/server/index.ts"
  }
}

Module, capability, and permission identifiers are lowercase and namespaced. Entrypoints must begin with ./, stay inside the package, and exist. Unknown manifest properties are rejected, including presentation fields such as components or renderers.

Storage bucket IDs are logical names scoped to the module. Modules may request multiple buckets. Core will later map them to deployment-specific physical S3 buckets and provide scoped access; module code must not configure SeaweedFS or other S3 clients directly.

Discovery behavior

Run:

pnpm modules:validate

Discovery checks every installed module atomically. It rejects malformed manifests, duplicate IDs or package names, version mismatches, incompatible platform or SDK ranges, missing required modules or capabilities, incompatible installed dependencies, cycles, and missing or escaping entrypoints. Missing optional dependencies are allowed. Valid modules are ordered dependency-first with stable identifier sorting.

Discovery does not load server code. Lifecycle execution, route/job registration, Drizzle schema aggregation and migrations, and physical bucket provisioning are deliberately deferred.

Start from the template

Copy templates/module to modules/<your-module-id> and follow its README. The template is part of the workspace and is validated by the same contracts and discovery implementation as installed modules.