Appearance
Seed config and reference data on install
What you're doing
Making data rows travel with the .spk instead of a manual per-tenant POST. Two things need seeding:
- reference data you own — equipment categories, status pick-lists, default settings.
- rows in shared platform config tables —
entity_status_date_sweep_config,entity_aggregation_config,entity_cadence_config, etc. — that make your scheduled jobs exist.
One file per data set under spk-assembly/metadata/seed-data/. The PluginDataSeedInstaller upserts them on every install, upgrade, and auto-provision — idempotently, keyed by the fields you nominate.
The complete example
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" }
]
}Line by line
entity— the target entityname. It must already exist — ship it inmetadata/entities/if your plugin owns it.keyFields— the natural key. On re-install, a row matching allkeyFieldsis updated only if a non-key value changed, otherwise inserted. Never duplicated. Choose a key that is genuinely unique (category_code, notcategory_name).source— your plugin id. Written into aseeded_byfield if the entity has one — handy forWHERE seeded_by = 'office-equipment'cleanup later.rows— plain field maps. No tenant id — the installer supplies it.
Idempotency in practice
Publish the plugin, then publish it again with a fifth category added. The installer log shows:
PluginDataSeedInstaller: office-equipment-categories.json -> entity oeq_category (tenant 2): 1 created, 0 updated, 4 unchangedThe four existing rows are left alone; only the new one is inserted. Verified against the tutorial module — the first install logged 4 created, and no re-run ever duplicates them.
Seeding shared platform config (the important use)
The job guides (reminder, aggregation, cadence, compliance) all seed a row into a shared config entity. For those you also ship:
- the shared config entity file (
entity_status_date_sweep_config.jsonetc.) so a fresh environment that predates it gains the table. The installer is idempotent-additive: an existing table just gains any missing columns. Ship only the additive fields your rows need — see the tutorial'sentity_status_date_sweep_config.json. - an
AFTER_CREATEregister rule on the config entity, callingensure<Job>Registered, so the first seeded row auto-registers the job. (The status-date-sweep job's register rule ships with the platform; the others you ship yourself — see each job guide.)
Ground yourself first
bash
erp schema pull plugin-seed-data
erp examples patterns --kind jobs # "install-lifecycle-data-seeding"How to verify it worked
bash
erp schema validate spk-assembly/metadata/seed-data/office-equipment-categories.json --schema plugin-seed-dataOK — ... matches schema "plugin-seed-data"After publishing:
bash
erp api get "/api/v1/entities/oeq_category/records/query?size=10"json
{ "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" }
], "total": 4 }Common mistakes
| Symptom | Cause | Fix |
|---|---|---|
| re-install duplicates rows | keyFields not actually unique | pick a real key |
| seed fails: entity not found | didn't ship the metadata/entities/*.json | ship it |
| job doesn't register despite seeding | no AFTER_CREATE register rule (for aggregation/cadence/compliance) | ship it |
a null in keyFields matches nothing / everything | key field is optional and unset in some rows | keep key fields non-null in every row |
What to read next
- Add a scheduled reminder job
- Recipe: install-lifecycle data seeding
- Tutorial chapter 2: the category entity + seeded data