18 Modules
A module is the package one feature comes in: a class that describes everything the feature adds, shipped in one assembly, usually a NuGet package. The site adds it with one line.
A plugin is a smaller part that hooks into something else: a transaction plugin into the store's writes, an interface plugin into the CMS interface (chapter 20). A module can bring both kinds, and an interface plugin can also stand alone.
The examples build two modules: venues, the places where events are held, and events, which
builds on it.
- A module — A module derives from CmsModule (namespace Relatude.DB.CMS.Modules), has a name, and says in Configure what it is made of. The smallest useful module is a model type and some data to start with:
- Adding modules — AddModule runs Configure at once, before the app is built. Services, settings and rendering options are added then; the rest waits for each database to start. Adding a module twice adds it once, so a package and the host…
- The database's start — The modules hook into every database's start through Relatude.DB's start-up services (chapter 2), so nothing in the host's setup can replace them. A database starts in three steps: The datamodel. After the host's…
- Seed data — Seed steps are numbered. Each runs once per database, in order, as the master admin. The database stores the last step it ran (at cms/modules/{name}.json in its storage), so a step added in an update runs alone at the…
- Transaction plugins and jobs — TransactionPlugin<T>() registers a NodeTransactionPlugin, created with the application's services. A write reaches it in one of two forms, and a rule about values must check both: the whole node (OnBeforeNodeAction: an…
- Settings — Settings<TDefinition>() registers a Relatude.DB custom settings set. It gets its own tab in the admin UI, beside each database's settings or the server's, as Scope says:
- Commands — Command(type, handler, readOnly) adds a command to the CMS API (chapter 17). It runs as the signed-in user: ctx.Db is the store with the user's read access, and ctx.Root is the whole store, for checks the server makes…
- Routes — Endpoints(e => …) maps the module's own routes, for visitors rather than editors: a feed, a form post, a webhook. MapRelatudeCMS() maps them. While the module is not active, they are left out of routing, so a request…
- Rendering and views — Rendering(o => …) adds code defaults, selectors and template kinds to the site's rendering options (chapter 8). Views() adds the views, controllers and Razor Pages compiled into the module, so a module built as a Razor…
- The interface plugin — InterfacePlugin() gives the module a plugin for the CMS interface (chapter 20): an ES module whose default export is definePlugin(…), embedded in the module's assembly with the files it imports:
- Interface plugins without a module — An interface plugin with no server code needs no module. List it in the admin UI's CMS tab under Interface plugins, with a name, an address and whether it loads. The address is a path on the site, such as…
- Turning a module off — List the modules to turn off, by name and separated by commas, in the admin UI's CMS tab under Modules › Modules turned off. This applies at once. A module that depends on one that is off is off too.
- The license — RequiresLicense("feature") keeps a module inactive while the installation's license is known to lack the feature: no API key, an invalid key, a license disabled or run out, or one without the feature. For a module that…
- Where a module stands — CmsModules.StatusOf(name, store) returns a module's state on a database, with a Reason when it is not active:
- Shipping a module — A module is a class library that references Relatude.DB.CMS, packed with dotnet pack. With views, it is a Razor class library: