Appearance
What are the artifact types?
A plugin is a folder of JSON files. Each file is an artifact of one type, and each type lives in its own subfolder of spk-assembly/metadata/. This page is the map: what each one is, and which guide covers it.
The manifest
| File | What it is |
|---|---|
spk-assembly/plugin.json | the manifest — id, version, mainClass, schemaName, roles, dependencies. Create a plugin |
Data
| Folder | Type | One-line description | Guide |
|---|---|---|---|
metadata/entities/ | entity | a table you declare by its fields; the Entity Engine generates DDL + CRUD REST | Add an entity |
metadata/provider/ | data provider | a name → REST base path mapping; a page's metadata.dataSource points here | Add a data provider |
metadata/data_view/ | data view | a declared read-only SQL join over physical tables | Add a data provider |
metadata/data_service/ | data service | a parameterized query: count / search / get / composite | Add a KPI |
metadata/seed-data/ | seed data | rows to upsert on install, idempotently | Seed data on install |
Screens
| Folder | Type | One-line description | Guide |
|---|---|---|---|
metadata/page/ | page | one screen — rows/columns of blocks, plus page-level metadata.dataSource | Build a page |
metadata/menu/ | menu | a tree of navigation nodes pointing at routes | Add menus |
metadata/i18n/ | translations | en.json etc. — dotted key → text | Add i18n |
metadata/application/ | application | (standalone plugins) the top-level product surface | Tutorial ch.1 |
metadata/module/ | module | (standalone plugins) a functional area inside an application; pages attach here | Tutorial ch.1 |
Logic
| Folder | Type | One-line description | Guide |
|---|---|---|---|
metadata/rules/ | entity rule | declarative logic at a lifecycle point — reject / set value / execute service / start workflow | Add business rules |
metadata/workflow/ | workflow | a multi-stage approval process | Add an approval workflow |
Code
| Path | What it is |
|---|---|
spk-assembly/lib/*.jar | optional — a compiled Plugin subclass and its deps, only if the plugin ships Java extensions. A pure-JSON plugin has no lib/ and leaves mainClass null. Create a plugin; for a complete real example pairing this with a custom React component, Build a plugin with custom React + Java code |
A custom block — a real React component of your own, no Java required — is not a spk-assembly/metadata/ file at all; it's registered at runtime through @erp/block-engine/@erp/block-adapter-mui. See Add a custom block.
Scheduled jobs are not their own artifact type
A scheduled job is not a file you write. It's a row you seed into a shared platform config entity (entity_status_date_sweep_config, entity_aggregation_config, entity_cadence_config, entity_compliance_config) plus an AFTER_CREATE register rule. The generic job engine does the rest. See the job guides.
The two file shapes
Most artifact files use a wrapper:
json
{ "name": "...", "description": "...", "definition": { /* the real contract */ }, "metadata": {}, "modules": [] }Entities use { "entity": {...}, "fields": [...] }. Pages use the wrapper with definition holding a contractVersion: 1 object. erp schema pull <name> shows you the exact shape for each.