Skip to content

Plugin Authoring

A system-core plugin is a TypeScript package that declares an AppCapability and registers a backend via installCapabilityPlugin(). The UI layer generates admin pages automatically from the capability's crudResources — no Vue files required in the plugin package.

Package layout

packages/plugin-<name>/
  src/
    backend/
      <resource>/
        api.ts
        prisma.ts
        index.ts
    i18n/
      en.json
      fr.json
    types/
      index.ts
    index.ts
  package.json
  tsup.config.ts

Capability contract

ts
import type { AppCapability } from '@system-core/core/platform'

export const capability: AppCapability = {
  id: 'plugin-<name>',
  label: 'My Plugin',
  version: '0.1.0',

  // CMS content types this plugin manages
  prismaModels: ['MyModel'],

  // API routes the backend mounts
  apiRoutes: [{ path: '/admin/<name>', methods: ['GET', 'POST', 'PUT', 'DELETE'] }],

  // CRUD resource schemas — the UI generates list + edit pages from these
  crudResources: [
    {
      resource: '<name>',
      label: 'Items',
      labelSingular: 'Item',
      apiPath: '/admin/<name>',
      fields: [
        { key: 'title',     label: 'Title',   type: 'text',     required: true },
        { key: 'body',      label: 'Body',    type: 'richtext'                 },
        { key: 'status',    label: 'Status',  type: 'select',
          options: ['draft', 'published'] },
        { key: 'publishAt', label: 'Publish', type: 'datetime'                 }
      ],
      defaultSortField: 'title',
      defaultSortDirection: 'asc',
      softDelete: true
    }
  ],

  // Admin nav entries
  adminNav: {
    groups: [
      {
        label: 'My Plugin',
        icon: 'folder',
        items: [{ to: '/admin/cms/<name>', label: 'Items', icon: 'list' }]
      }
    ]
  },

  // Admin pages (auto-resolved from crudResources — only override when custom)
  adminPages: []
}

Field types

AppCapabilityCrudFieldType supports:

TypeUse
textShort single-line string
textareaMulti-line plain text
richtextHTML WYSIWYG
markdownMarkdown editor
numberNumeric input
selectSingle-value dropdown
multiselectMulti-value dropdown
toggle / booleanCheckbox
date / time / datetime / daterangeDate pickers
mediaMedia picker (uploads)
fileFile attachment
colorColour picker
slugAuto-slug from another field
relationRelated record picker
jsonRaw JSON editor
arrayRepeatable sub-fields

Backend registration

ts
import { installCapabilityPlugin } from '@system-core/core/platform'
import { capability } from './index'
import en from './i18n/en.json'
import fr from './i18n/fr.json'

export const backend = installCapabilityPlugin(capability, {
  version: capability.version,
  order: 100,

  // Seed UI strings on first install — idempotent
  seedTranslations: { en, fr },

  extension: ctx => ({
    createDeps(prisma) {
      return {
        items: createItemDeps(prisma, ctx)
      }
    }
  })
})

UI strings (i18n)

Each plugin ships locale JSON files under src/i18n/. Keys follow the pattern <plugin>.<surface>.<label>:

json
{
  "events.list.title": "Events",
  "events.list.empty": "No events yet",
  "events.action.new": "New Event",
  "events.field.startDate": "Start date"
}

Strings are written to the database on first install (namespace: 'ui:plugin-<capability-id>'). They are never overwritten once admin edits exist.

At runtime they are available via system.uiStrings and the public config endpoint.

API path convention

Admin API routes use the /admin/<resource> prefix — no leading /api:

ts
// Correct
apiPath: '/admin/events'

// Incorrect — do not use /api prefix
apiPath: '/api/admin/events'

Peer plugin dependencies

Declare peer capability requirements using peerCapabilities:

ts
export const capability: AppCapability = {
  id: 'plugin-foo',
  peerCapabilities: ['plugin-bar'],
  // ...
}

installCapabilityPlugin validates peer presence at install time.

Full example

See packages/plugin-blog and packages/plugin-events in the repository for complete working examples.

system-core documentation for maintainers, integrators, and AI build agents.