Appearance
8. Menus, i18n, validate, publish
The menu
spk-assembly/metadata/menu/office-equipment-menu.json (real file) — one group node Office Equipment with three children pointing at the three pages' route.pattern values, modules: ["office-equipment"].
Because this is a standalone plugin (it ships its own application, chapter 1), there is no master menu scaffold to keep in sync — one menu file is enough.
The translations
spk-assembly/metadata/i18n/en.json (real file) — a flat map of every i18n key the three pages, the menu, the app and the module reference (~70 keys):
json
{
"office-equipment.application.title": "Office Equipment",
"office-equipment.module.title": "Equipment",
"office-equipment.equipment-register.title": "Equipment Register",
"office-equipment.equipment-register.newBtn": "New",
"office-equipment.equipment-register.column.asset_tag": "Asset Tag",
"office-equipment.equipment-checkout.status.OVERDUE": "Overdue",
"office-equipment.equipment-checkout.status.DUE_SOON": "Due Soon"
}A missing key is caught by erp plugin test as I18N-001.
Validate everything
bash
erp plugin validate example-plugin/spk-assembly
erp plugin test example-plugin/spk-assemblyvalidated 3 page(s) — clean
Plugin Tests
────────────────────────────────────────
✓ page:equipment-catalog.json
✓ page:equipment-checkout.json
✓ page:equipment-register.json
✓ plugin.json:valid-json
4 passed, 0 failed, 0 semantic warning(s), 3 skippedAnd the docs example runner, which also schema-validates every artifact:
bash
node developer-docs/examples/test-examples.mjs
# ... All examples valid.Build
bash
erp plugin build example-plugin/spk-assembly -o example-plugin/office-equipment-1.0.0.spkvalidated 3 page(s) — clean
packaged 33 files -> example-plugin/office-equipment-1.0.0.spk (231986 bytes)
sha256: ...Publish
bash
erp plugin publish example-plugin/office-equipment-1.0.0.spk --tenant 2installed:
{"pluginId":"office-equipment","version":"1.0.0","state":"installed","pf4jState":"STARTED", ...}Confirm it's all live
bash
# pages
$ erp api get "/api/v1/authoring/pages?module=office-equipment"
[ {"name":"equipment-catalog", "route":{"pattern":"/office-equipment/equipment-catalog"}, ...},
{"name":"equipment-checkout", ...}, {"name":"equipment-register", ...} ]
# seeded reference data
$ erp api get "/api/v1/entities/oeq_category/records/query?size=10"
{"rows":[{"category_code":"LAPTOP", ...}, ... ],"total":4}
# the reminder job
$ erp api get "/api/v1/jobs/engine-entity.status-date-sweep"
{"status":"ENABLED", ...}
# the approval rule
$ erp api get "/api/v1/entity-rules?entityType=oeq_checkout"
[{"name":"oeq_checkout_submit_workflow","active":true, ...}]Open /app/office-equipment/equipment/office-equipment/equipment-register in your ERP. The module is complete: three working pages, seeded categories, an approval workflow, and a nightly reminder sweep — and you wrote one line of Java.
Iterating from here
To change anything: edit the file, bump plugin.json version, rebuild, re-publish. Don't uninstall to iterate — see Publish and upgrade for why.