Skip to content

1. Create the plugin

Scaffold

bash
erp plugin create example-plugin --name "Office Equipment" --type business-app

The folder is example-plugin/ to match this docs tree. The plugin id we use is office-equipment — set below. (In real life pick one name and use it for both.)

You get example-plugin/spk-assembly/ with empty metadata/* folders and a plugin.json with "mainClass": null.

Edit the manifest

spk-assembly/plugin.json — the finished version (real file):

json
{
  "id": "office-equipment",
  "name": "Office Equipment",
  "version": "1.0.3",
  "type": "business-application",
  "schemaName": "erp_core",
  "vendor": "ACME Corp",
  "license": "Proprietary",
  "licenseTier": "free",
  "category": "custom",
  "erpVersion": "*",
  "minErpVersion": "1.0",
  "maxErpVersion": "99.0",
  "mainClass": null,
  "dependencies": [],
  "optionalDependencies": [],
  "owner": "business",
  "editable": false,
  "extendable": true,
  "capabilitiesProvided": [],
  "capabilitiesRequired": [],
  "featureFlags": [],
  "configSchemaJson": null,
  "roles": [
    {
      "name": "Office Equipment Manager",
      "code": "OFFICE_EQUIPMENT_MANAGER",
      "description": "Full control of the Office Equipment module.",
      "permissionKeys": [
        "OeqCategory.View", "OeqCategory.Create", "OeqCategory.Edit",
        "OeqEquipment.View", "OeqEquipment.Create", "OeqEquipment.Edit",
        "OeqCheckout.View", "OeqCheckout.Create", "OeqCheckout.Submit", "OeqCheckout.Approve",
        "Dashboard.View"
      ]
    }
  ],
  "runtimeModes": ["embedded"],
  "serviceDeployment": null
}

Key choices:

  • id: "office-equipment" — used in every route, page id, and i18n key from here on. Chosen once.
  • role.name and role.code are prefixed (Office Equipment Manager / OFFICE_EQUIPMENT_MANAGER). A plain "Equipment Manager" would collide with another installed plugin's role and fail the install — this actually happened while writing the tutorial.
  • schemaName: "erp_core" — the scaffold default. See the note in Add an entity about when a dedicated schema is worth it; for this module erp_core is fine end to end, including the reminder job in chapter 7.

No Java class

This tutorial module ships zero Java. plugin.json keeps "mainClass": null exactly as the scaffold wrote it, and there is no spk-assembly/lib/. On install the platform loads the plugin through a built-in generic no-op PF4J entry point — start/stop/enable/disable/upgrade, migrations, and data seeding all run normally. Everything the module does is JSON under spk-assembly/metadata/.

You would only add a Java class (a Plugin subclass, compiled against pf4j + slf4j-api, jar in spk-assembly/lib/, mainClass set to its FQN) for behaviour the Entity / Query / Rule / Workflow / Job engines genuinely can't express — this module never needs one.

The application and module (standalone plugin)

A standalone plugin (one that isn't part of a bigger suite like HCM) ships its own application and module so its pages are routable.

spk-assembly/metadata/application/office-equipment-app.json (real file):

json
{
  "name": "office-equipment-app",
  "description": "The Office Equipment plugin's own Application.",
  "definition": {
    "id": "office-equipment",
    "titleKey": "office-equipment.application.title",
    "urlSlug": "office-equipment",
    "homeRoute": "/app/office-equipment/equipment/office-equipment/equipment-register",
    "tier": "solution",
    "icon": "devices",
    "color": "#2563EB"
  }
}

spk-assembly/metadata/module/office-equipment-module.json (real file):

json
{
  "name": "office-equipment",
  "description": "The single Module the Office Equipment pages attach to.",
  "definition": {
    "id": "office-equipment-module",
    "titleKey": "office-equipment.module.title",
    "urlSlug": "equipment",
    "tier": "solution",
    "icon": "inventory_2",
    "color": "#2563EB"
  },
  "applications": ["office-equipment-app"]
}

The reachable URL for a page is /app/<app urlSlug>/<module urlSlug>/<pluginId>/<page name> — so /app/office-equipment/equipment/office-equipment/equipment-register.

Verify

bash
erp plugin test example-plugin/spk-assembly
Plugin Tests
────────────────────────────────────────
✓ plugin.json:valid-json
1 passed, 0 failed, 0 semantic warning(s), 3 skipped

A healthy empty plugin. Next: give it a table.

Next: 2. The equipment category entity + seeded data