@ortha/server-content-manager
v0.0.4
Published
CMS content-type definitions, a schema factory, and a Fastify plugin that registers content types on the server instance. Converts declarative content-type definitions into Sequelize models with automatic base columns, metadata columns, and index generati
Readme
@ortha/server-content-manager
CMS content-type definitions, a schema factory, and a Fastify plugin that registers content types on the server instance. Converts declarative content-type definitions into Sequelize models with automatic base columns, metadata columns, and index generation.
Installation
Internal monorepo dependency — import directly:
import {
contentManagerServerPlugin,
extractDatabaseSchemas
} from '@ortha/server-content-manager';
import type { ContentTypeDefinition } from '@ortha/server-content-manager';Usage
Defining content types
import { DataTypes } from 'sequelize';
import type { ContentTypeDefinition } from '@ortha/server-content-manager';
const articleType: ContentTypeDefinition = {
slug: 'article',
metadata: {
type: 'collection',
modelName: 'Article',
tableName: 'articles',
paranoid: true,
publishable: true,
localizable: false
},
schema: {
label: 'Article',
description: 'Blog articles'
},
fields: [
{
name: 'title',
column: { type: DataTypes.STRING, allowNull: false },
field: { label: 'Title' }
},
{
name: 'body',
column: { type: DataTypes.TEXT, allowNull: true },
field: { label: 'Body' }
}
]
};Registering with the database and server
import { bootstrap } from '@ortha/server-platform-bootstrap';
import { databasePlugin } from '@ortha/server-platform-database';
import {
extractDatabaseSchemas,
contentManagerServerPlugin
} from '@ortha/server-content-manager';
const contentTypes = [articleType];
await bootstrap({
config: bootstrapConfig,
plugins: [
databasePlugin({
...dbConfig,
schemas: [identitySchema, extractDatabaseSchemas(contentTypes)]
}),
contentManagerServerPlugin({ contentTypes })
]
});
// Access at runtime: fastify.contentManager.contentTypesAPI Reference
Functions
| Export | Kind | Description |
| ------------------------------ | -------- | ------------------------------------------------------------------ |
| extractDatabaseSchemas() | function | Converts ContentTypeDefinition[] to Sequelize SchemaDefinition |
| contentManagerServerPlugin() | function | Fastify plugin — decorates fastify.contentManager |
Types
| Export | Kind | Description |
| ---------------------------- | ---- | ---------------------------------------------------------- |
| ContentTypeDefinition | type | Top-level content-type schema (slug, metadata, fields) |
| ContentTypeField | type | Single field definition (name, column, field, localizable) |
| ContentTypeFieldProps | type | Admin UI field properties (label) |
| ContentTypeIndex | type | Index definition (fields, unique, name) |
| ContentTypeMetadata | type | Classification + Sequelize model options |
| ContentTypeSchemaProps | type | Schema-level UI properties (label, description) |
| ContentManagerRegistry | type | Runtime registry shape ({ contentTypes }) |
| ContentManagerPluginConfig | type | Plugin config ({ contentTypes }) |
Metadata Options
| Property | Type | Default | Description |
| ------------- | ------------------------ | -------- | ----------------------------------------------------- |
| type | 'collection' \| 'page' | required | Content-type classification |
| modelName | string | required | PascalCase Sequelize model name |
| tableName | string | required | snake_case database table name |
| paranoid | boolean | false | Enable soft deletes (adds deletedAt) |
| publishable | boolean | false | Enable publication workflow (adds publishedAt) |
| localizable | boolean | false | Enable localisation (adds locale + localeGroupId) |
| indexes | ContentTypeIndex[] | — | Composite or custom indexes |
Auto-Generated Columns
Every content type automatically receives:
- Base columns:
id(UUID primary key),projectId(foreign key to projects),createdAt,updatedAt - Conditional columns (based on metadata):
paranoid: true→deletedAt(soft delete)publishable: true→publishedAt(nullable DATE)localizable: true→locale(required STRING) +localeGroupId(UUID)
Internal Structure
src/lib/
├── types/index.ts # All type definitions + Fastify module augmentation
├── extractDatabaseSchemas/index.ts # ContentTypeDefinition[] → SchemaDefinition
├── baseColumns/index.ts # Base columns: id, projectId, timestamps
├── metadataColumns/index.ts # Conditional columns: deletedAt, locale, publishedAt
├── modelOptions/index.ts # Sequelize model options: tableName, paranoid, indexes
└── contentManagerServerPlugin/index.ts # Fastify plugin: decorates fastify.contentManagerKey Patterns
extractDatabaseSchemas()returns a frozenSchemaDefinitionmatching the database plugin lifecycle.- Column construction is split into
baseColumns(),metadataColumns(), and user-defined fields. - Field
columnvalues are native SequelizeModelAttributeColumnOptions— passed directly tosequelize.define(). contentManagerServerPlugin()decoratesfastify.contentManagerwith a frozen registry for runtime access.- Individual fields can opt in to localisation via
field.localizable: true.
Dependencies
@ortha/server-platform-database—SchemaDefinitiontypefastify-plugin— Fastify plugin wrappersequelize— ORM (peer dependency)
Building
nx build server-content-manager