Module Concept
A module is a self-contained unit that can contribute to one or more runtime surfaces:| Surface | What it provides |
|---|---|
| Server | HTTP route handlers mounted on the Elysia app, plus action catalog entries for discoverable operations. |
| CLI | Action aliases, output formatters, and preflight hooks that extend the mdcms command. |
| Studio | UI extension points including routes, navigation items, slot widgets, field kinds, and editor nodes. |
Module Package Type
Every module conforms to theMdcmsModulePackage type exported from @mdcms/shared:
manifest.kind field distinguishes infrastructure modules (core) from business-domain modules (domain). The dependsOn array declares inter-module dependencies that the loader validates at boot time.
Loading Lifecycle
Modules are registered at compile time inpackages/modules/src/index.ts and loaded during server startup through a three-phase process:
Build load report
buildServerModuleLoadReport() validates every registered module package
against the Zod schema, checks manifest compatibility (API version, core
version range), resolves the dependency graph, and produces a
ServerModuleLoadReport.Load modules
loadServerModules() reads from the installedModules compile-time
registry and delegates to the build step. If any module fails validation or
has unresolvable dependencies, the server refuses to start.Core Modules
MDCMS ships with two first-party modules:core.system
core.system
Kind:
coreProvides the foundational infrastructure surface: health checks (/healthz), Studio bootstrap endpoint, authentication routes, user management, API key management, RBAC grant management, and invite flows.domain.content
domain.content
Kind:
domainProvides the content domain surface: document CRUD, schema registry sync, media upload and management, webhook dispatch, environment cloning/promotion, search, and content migration execution.server and cli surfaces. The module registry in packages/modules/src/index.ts sorts them deterministically by manifest id before exposing them to the loader.
Action Catalog
Every server-side operation is registered as an action — a discoverable, self-describing API endpoint. Actions are collected from all loaded modules and exposed through a unified catalog.GET /api/v1/actions— Returns all actions visible to the current principal.GET /api/v1/actions/:id— Returns a single action by id.
Studio Extensibility Surfaces
The Studio component exposes several extension points that modules can populate:| Surface | Description |
|---|---|
routes | Additional React Router routes mounted inside the Studio shell. |
navItems | Navigation entries added to the Studio sidebar. |
slotWidgets | Widgets rendered in named layout slots across Studio pages. |
fieldKinds | Custom form field renderers for schema-driven frontmatter editing. |
editorNodes | Custom TipTap/ProseMirror nodes for the MDX editor. |
actionOverrides | Replace or wrap default action behaviors (e.g., custom publish flow). |
settingsPanels | Additional panels on the Studio settings page. |
| Slot ID | Location |
|---|---|
dashboard.main | Main content area of the dashboard page. |
content.list.toolbar | Toolbar above the content list table. |
content.editor.header.actions | Action buttons in the document editor header. |
content.editor.sidebar | Sidebar panels in the document editor. |
settings.general | General settings section. |
In v1, Studio extensibility surfaces are defined but only consumed by
first-party modules. The contract is stable and documented for future
third-party use.
v1 Limitation
The current module system supports first-party modules only. All modules are compiled into the server binary at build time via thepackages/modules/ registry. There is no dynamic plugin loading, no remote module resolution, and no third-party module marketplace.
The module contract (MdcmsModulePackage, ModuleManifest, compatibility checks) is designed with future extensibility in mind, but v1 restricts the surface to modules maintained within the MDCMS monorepo.
Multi-Tenancy Model
MDCMS implements a two-level isolation hierarchy: projects and environments.Project Isolation
A project is the top-level tenant boundary. Each project owns:- Its own schema (content types and field definitions)
- Its own content (documents and versions)
- Its own environments (independent content spaces)
- Its own media (uploaded files in S3)
- Its own webhooks (event subscriptions)
- Its own users and API keys (scoped access control)
marketing-site) and are completely isolated from one another at the database level.
Environment Isolation
Within a project, each environment maintains:- Independent documents — Editing content in
stagingdoes not affectproduction. - Independent versions — Publish history is per-environment.
- Schema overlays — Environments that extend another inherit the base schema and can add or modify fields.
Target Routing
Every scoped API request must include explicit targeting headers:400 error. Routes that require only project context (environments API) require X-MDCMS-Project alone.