Appearance
2. The equipment category entity + seeded data
The entity
spk-assembly/metadata/entities/oeq_category.json (real file):
json
{
"entity": {
"name": "oeq_category",
"tableName": "oeq_category",
"label": "{\"en\":\"Equipment Category\"}",
"category": "office-equipment",
"icon": "category",
"color": "#2563EB",
"pkStrategy": "identity"
},
"fields": [
{ "fieldName": "category_code", "label": "\"Category Code\"", "dataType": "text", "nullable": false, "required": true, "isUnique": true, "isIndexed": true, "isDisplayField": true, "displayOrder": 1 },
{ "fieldName": "category_name", "label": "\"Category Name\"", "dataType": "text", "nullable": false, "required": true, "displayOrder": 2 },
{ "fieldName": "description", "label": "\"Description\"", "dataType": "text", "nullable": true, "required": false, "displayOrder": 3 },
{ "fieldName": "status", "label": "\"Status\"", "dataType": "enum", "nullable": false, "required": true, "isIndexed": true, "defaultValue": "ACTIVE", "typeParams": "{\"enumValues\":[\"ACTIVE\",\"INACTIVE\"]}", "displayOrder": 4 },
{ "fieldName": "seeded_by", "label": "\"Seeded By\"", "dataType": "text", "nullable": true, "required": false, "displayOrder": 5 }
]
}Note the two JSON-encoding rules: entity.label is "{\"en\":\"...\"}" (an i18n object as a string), each field label is "\"...\"" (a JSON string literal). A bare string in either place fails the install.
seeded_by is a plain text column the seeder will stamp with the plugin id.
The seed data
spk-assembly/metadata/seed-data/office-equipment-categories.json (real file):
json
{
"entity": "oeq_category",
"keyFields": ["category_code"],
"source": "office-equipment",
"rows": [
{ "category_code": "LAPTOP", "category_name": "Laptops", "description": "Portable computers", "status": "ACTIVE", "seeded_by": "office-equipment" },
{ "category_code": "MONITOR", "category_name": "Monitors", "description": "External displays", "status": "ACTIVE", "seeded_by": "office-equipment" },
{ "category_code": "PHONE", "category_name": "Phones", "description": "Mobile handsets", "status": "ACTIVE", "seeded_by": "office-equipment" },
{ "category_code": "HEADSET", "category_name": "Headsets", "description": "Audio headsets", "status": "ACTIVE", "seeded_by": "office-equipment" }
]
}keyFields: ["category_code"]— the natural key. Re-installs match on this and never duplicate.source: "office-equipment"— stamped intoseeded_by.
Verify
bash
erp schema validate spk-assembly/metadata/entities/oeq_category.json --schema entity-definition
erp schema validate spk-assembly/metadata/seed-data/office-equipment-categories.json --schema plugin-seed-dataBoth print OK — ... matches schema ....
After the module is published (chapter 8), this is what the seeding did — from the real install log:
PluginDataSeedInstaller: office-equipment-categories.json -> entity oeq_category (tenant 2): 4 created, 0 updated, 0 unchangedand the rows are live:
bash
$ erp api get "/api/v1/entities/oeq_category/records/query?size=10"
{ "rows": [
{ "id": 1, "category_code": "LAPTOP", "category_name": "Laptops", "status": "ACTIVE", "seeded_by": "office-equipment" },
{ "id": 2, "category_code": "MONITOR", "category_name": "Monitors", "status": "ACTIVE", "seeded_by": "office-equipment" },
{ "id": 3, "category_code": "PHONE", "category_name": "Phones", "status": "ACTIVE", "seeded_by": "office-equipment" },
{ "id": 4, "category_code": "HEADSET", "category_name": "Headsets", "status": "ACTIVE", "seeded_by": "office-equipment" }
], "total": 4 }Publish again with a fifth category and only that one is inserted — the seeder is idempotent by keyFields.