Skip to main content

Module Registry & SDK — How it works

Overview

The module engine is the platform's extension registry. It records the modules known to a deployment, their versions, dependencies, declared permissions and menu items, and which tenants/facilities have each module activated. It also exposes the module SDK: a self-describing manifest that a future domain plug-in ships, validated read-only before registration.

Data model & ownership

TablePurpose
moduleRegistered module; stable unique module_key.
module_versionVersions of a module.
module_dependencyDeclares one module depends on another.
module_permissionPermissions a module contributes.
module_menu_itemNavigation contributed by a module.
tenant_module_activation / facility_module_activationWhich tenants/facilities have the module on.

Key rules & invariants

  • activation_status is the ModuleActivationStatus enum, not a string (TERM-005). It was free text written straight from the request body and then compared two different ways on the same column: ACTIVE.equals(...) guarded whether dependency validation ran, while ACTIVE.equalsIgnoreCase(...) decided what was served. So POSTing "active" in the wrong case skipped dependency validation entirely and the module was still served as active — menus and permissions included. One lowercase letter activated a module in the UI while bypassing the gate that exists to prevent exactly that. The enum removes the string, so the two-comparison mismatch cannot recur.

    The values are ACTIVE and INACTIVE because the frontend already declared that contract; this types what was in use rather than inventing a vocabulary.

    ⚠ Not the same column: RegisteredModule.status is the separate registry lifecycle field (LifecycleStatus: ACTIVE / SUSPENDED, TERM-008D). Jackson rejects unrecognised values with 400; migration module/006 normalises then CHECK-constrains and HALTs on dirty data. The effective-manifest reader compares the enum directly — it no longer uses equalsIgnoreCase on a free-text string.

  • module_key is unique; activation is gated (dependency validation via ModuleActivationDependencyValidator).

  • Manifest validation is advisory and read-only (M9-006): it checks key/semver format, self-dependency, duplicate dependencies/permissions/menu paths, and extension type/target, and resolves declared dependencies against the registry — but never registers a module, so it does not bypass Module Engine ownership.

API

See the API Reference. Endpoint groups under /api/v1/module: registered modules, versions, dependencies, permissions, menu items, tenant/facility activation, and POST /module-manifests/validate.

Configuration & feature flags

None.

  • Tenant / Facility (activation scope), Access control (module-contributed permissions). Domain plug-ins call this over Feign via exchange.client.module (RegisteredModuleClient, ModuleSdkClient).