@sparkerp/plugin-sdk 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (142) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +61 -0
  3. package/bundle/blocks.json +12229 -0
  4. package/bundle/catalog.json +32475 -0
  5. package/bundle/docs/applications/hcm/employee-profile.md +144 -0
  6. package/bundle/docs/concepts/artifact-types.md +80 -0
  7. package/bundle/docs/concepts/glossary.md +124 -0
  8. package/bundle/docs/concepts/overview.md +88 -0
  9. package/bundle/docs/concepts/page-data-flow.md +84 -0
  10. package/bundle/docs/concepts/plugin-lifecycle.md +81 -0
  11. package/bundle/docs/concepts/sdk-modes.md +71 -0
  12. package/bundle/docs/docs.json +109 -0
  13. package/bundle/docs/guides/add-a-cadence-job.md +134 -0
  14. package/bundle/docs/guides/add-a-compliance-job.md +139 -0
  15. package/bundle/docs/guides/add-a-create-edit-form.md +167 -0
  16. package/bundle/docs/guides/add-a-custom-block.md +225 -0
  17. package/bundle/docs/guides/add-a-data-provider.md +216 -0
  18. package/bundle/docs/guides/add-a-kpi.md +154 -0
  19. package/bundle/docs/guides/add-a-reminder-job.md +181 -0
  20. package/bundle/docs/guides/add-an-aggregation-job.md +153 -0
  21. package/bundle/docs/guides/add-an-approval-workflow.md +222 -0
  22. package/bundle/docs/guides/add-an-entity.md +170 -0
  23. package/bundle/docs/guides/add-business-rules.md +147 -0
  24. package/bundle/docs/guides/add-i18n.md +121 -0
  25. package/bundle/docs/guides/add-menus.md +149 -0
  26. package/bundle/docs/guides/build-a-code-plugin.md +141 -0
  27. package/bundle/docs/guides/build-a-page.md +213 -0
  28. package/bundle/docs/guides/build-a-polyglot-service-plugin.md +201 -0
  29. package/bundle/docs/guides/build-a-tenant-extension-service.md +149 -0
  30. package/bundle/docs/guides/create-a-plugin.md +172 -0
  31. package/bundle/docs/guides/expose-a-plugin-operation-as-an-ai-tool.md +114 -0
  32. package/bundle/docs/guides/index.md +53 -0
  33. package/bundle/docs/guides/publish-and-upgrade.md +152 -0
  34. package/bundle/docs/guides/responsive-plugin.md +117 -0
  35. package/bundle/docs/guides/seed-data-on-install.md +127 -0
  36. package/bundle/docs/guides/set-up-the-sdk.md +120 -0
  37. package/bundle/docs/guides/use-the-mcp-server.md +104 -0
  38. package/bundle/docs/guides/validate-and-test.md +119 -0
  39. package/bundle/docs/guides/wire-a-pages-data.md +153 -0
  40. package/bundle/docs/quickstart/index.md +118 -0
  41. package/bundle/docs/recipes/condition-based-compliance-flag.md +70 -0
  42. package/bundle/docs/recipes/cross-plugin-offboarding-fanout.md +68 -0
  43. package/bundle/docs/recipes/cross-row-aggregation.md +67 -0
  44. package/bundle/docs/recipes/entity-with-approval-workflow.md +72 -0
  45. package/bundle/docs/recipes/index.md +40 -0
  46. package/bundle/docs/recipes/install-lifecycle-data-seeding.md +76 -0
  47. package/bundle/docs/recipes/kpi-dashboard-page.md +92 -0
  48. package/bundle/docs/recipes/master-detail-page.md +84 -0
  49. package/bundle/docs/recipes/n-days-before-reminder.md +72 -0
  50. package/bundle/docs/recipes/per-row-document-generator.md +65 -0
  51. package/bundle/docs/recipes/related-record-lookup-field.md +74 -0
  52. package/bundle/docs/recipes/resolved-reference-grid-column.md +63 -0
  53. package/bundle/docs/recipes/scheduled-record-generation.md +68 -0
  54. package/bundle/docs/reference/action.md +18 -0
  55. package/bundle/docs/reference/block-definition.md +35 -0
  56. package/bundle/docs/reference/block-instance.md +33 -0
  57. package/bundle/docs/reference/composite-pack-manifest.md +33 -0
  58. package/bundle/docs/reference/connector-definition.md +36 -0
  59. package/bundle/docs/reference/data-service-definition.md +22 -0
  60. package/bundle/docs/reference/data-view-definition.md +26 -0
  61. package/bundle/docs/reference/entity-aggregation-config.md +38 -0
  62. package/bundle/docs/reference/entity-cadence-config.md +33 -0
  63. package/bundle/docs/reference/entity-compliance-config.md +37 -0
  64. package/bundle/docs/reference/entity-cross-plugin-action-config.md +37 -0
  65. package/bundle/docs/reference/entity-definition.md +18 -0
  66. package/bundle/docs/reference/entity-document-generator-config.md +35 -0
  67. package/bundle/docs/reference/entity-rule-definition.md +29 -0
  68. package/bundle/docs/reference/entity-status-date-sweep-config.md +27 -0
  69. package/bundle/docs/reference/form.md +35 -0
  70. package/bundle/docs/reference/index.md +37 -0
  71. package/bundle/docs/reference/menu.md +26 -0
  72. package/bundle/docs/reference/mobile-nav.md +22 -0
  73. package/bundle/docs/reference/page-template.md +29 -0
  74. package/bundle/docs/reference/page.md +44 -0
  75. package/bundle/docs/reference/plugin-manifest.md +54 -0
  76. package/bundle/docs/reference/plugin-seed-data.md +21 -0
  77. package/bundle/docs/reference/print-template-definition.md +22 -0
  78. package/bundle/docs/reference/provider-definition.md +22 -0
  79. package/bundle/docs/reference/report-definition.md +22 -0
  80. package/bundle/docs/reference/rule.md +30 -0
  81. package/bundle/docs/reference/workflow-definition.md +28 -0
  82. package/bundle/docs/troubleshooting/grid-shows-zero-rows.md +82 -0
  83. package/bundle/docs/troubleshooting/job-never-runs.md +89 -0
  84. package/bundle/docs/troubleshooting/known-gotchas.md +193 -0
  85. package/bundle/docs/troubleshooting/publishing-errors.md +119 -0
  86. package/bundle/docs/tutorial/01-create-the-plugin.md +157 -0
  87. package/bundle/docs/tutorial/02-category-entity-and-seed.md +94 -0
  88. package/bundle/docs/tutorial/03-equipment-entity.md +121 -0
  89. package/bundle/docs/tutorial/04-equipment-register-page.md +153 -0
  90. package/bundle/docs/tutorial/05-checkout-entity-and-page.md +116 -0
  91. package/bundle/docs/tutorial/06-checkout-approval-workflow.md +139 -0
  92. package/bundle/docs/tutorial/07-return-due-reminder-job.md +129 -0
  93. package/bundle/docs/tutorial/08-menus-i18n-publish.md +123 -0
  94. package/bundle/docs/tutorial/index.md +72 -0
  95. package/bundle/examples/backend/modules/hcm-assets/spk-assembly/metadata/seed-data/hcm-assets-aggregation-configs.json +18 -0
  96. package/bundle/examples/backend/modules/hcm-assets/spk-assembly/metadata/seed-data/hcm-assets-cadence-configs.json +9 -0
  97. package/bundle/examples/backend/modules/hcm-assets/spk-assembly/metadata/seed-data/hcm-assets-compliance-configs.json +74 -0
  98. package/bundle/examples/backend/modules/hcm-assets/spk-assembly/metadata/seed-data/hcm-assets-cross-plugin-configs.json +9 -0
  99. package/bundle/examples/backend/modules/hcm-assets/spk-assembly/metadata/seed-data/hcm-assets-document-configs.json +9 -0
  100. package/bundle/examples/backend/modules/hcm-assets/spk-assembly/metadata/seed-data/hcm-assets-sweep-configs.json +260 -0
  101. package/bundle/examples/backend/modules/hcm-compensation/spk-assembly/metadata/entities/hcm_salary_planning_entry.json +41 -0
  102. package/bundle/examples/backend/modules/hcm-compensation/spk-assembly/metadata/page/salary-planning.json +1 -0
  103. package/bundle/examples/backend/modules/hcm-employee/spk-assembly/metadata/page/promotions.json +10944 -0
  104. package/bundle/examples/backend/modules/hcm-employee/spk-assembly/metadata/workflow/employee.movement.json +44 -0
  105. package/bundle/examples/backend/modules/hcm-employee/spk-assembly/metadata/workflow/employee.promotion-acknowledge.json +19 -0
  106. package/bundle/examples/backend/modules/hcm-employee/spk-assembly/metadata/workflow/employee.resignation.json +29 -0
  107. package/bundle/examples/example-patterns.mjs +94 -0
  108. package/bundle/manifest.json +14 -0
  109. package/bundle/schemas/action.schema.json +102 -0
  110. package/bundle/schemas/block-definition.schema.json +222 -0
  111. package/bundle/schemas/block-instance.schema.json +139 -0
  112. package/bundle/schemas/composite-pack-manifest.schema.json +160 -0
  113. package/bundle/schemas/connector-definition.schema.json +29 -0
  114. package/bundle/schemas/data-service-definition.schema.json +64 -0
  115. package/bundle/schemas/data-view-definition.schema.json +148 -0
  116. package/bundle/schemas/entity-aggregation-config.schema.json +32 -0
  117. package/bundle/schemas/entity-cadence-config.schema.json +27 -0
  118. package/bundle/schemas/entity-compliance-config.schema.json +31 -0
  119. package/bundle/schemas/entity-cross-plugin-action-config.schema.json +31 -0
  120. package/bundle/schemas/entity-definition.schema.json +126 -0
  121. package/bundle/schemas/entity-document-generator-config.schema.json +29 -0
  122. package/bundle/schemas/entity-rule-definition.schema.json +75 -0
  123. package/bundle/schemas/entity-status-date-sweep-config.schema.json +21 -0
  124. package/bundle/schemas/form.schema.json +281 -0
  125. package/bundle/schemas/menu.schema.json +106 -0
  126. package/bundle/schemas/mobile-nav.schema.json +53 -0
  127. package/bundle/schemas/page-template.schema.json +46 -0
  128. package/bundle/schemas/page.schema.json +292 -0
  129. package/bundle/schemas/plugin-manifest.schema.json +139 -0
  130. package/bundle/schemas/plugin-seed-data.schema.json +24 -0
  131. package/bundle/schemas/print-template-definition.schema.json +90 -0
  132. package/bundle/schemas/provider-definition.schema.json +27 -0
  133. package/bundle/schemas/report-definition.schema.json +96 -0
  134. package/bundle/schemas/rule.schema.json +82 -0
  135. package/bundle/schemas/workflow-definition.schema.json +42 -0
  136. package/bundle/validators/block-engine.mjs +23222 -0
  137. package/bundle/validators/page-engine.mjs +21645 -0
  138. package/erp-cli/authoring-root.mjs +344 -0
  139. package/erp-cli/erp.mjs +4065 -0
  140. package/erp-cli/example-patterns.mjs +94 -0
  141. package/erp-mcp-server/index.mjs +818 -0
  142. package/package.json +27 -0
@@ -0,0 +1,94 @@
1
+ /**
2
+ * The curated, named-SHAPE example catalog shared by `erp examples patterns`
3
+ * (tools/erp-cli/erp.mjs) and the MCP server's `erp_examples_patterns` tool
4
+ * (tools/erp-mcp-server/index.mjs) — a single source of truth so a developer
5
+ * driving purely through the CLI and one driving purely through an MCP
6
+ * client see the identical catalog, never two copies that can drift. Pure
7
+ * data, no side effects, safe to import from either entrypoint (unlike
8
+ * importing erp.mjs itself, which runs its own CLI main() at import time).
9
+ */
10
+ export const EXAMPLE_PATTERNS = {
11
+ workflow: [
12
+ {
13
+ name: "single-stage-self-decide",
14
+ description: "One actor both requests and immediately decides — models what would otherwise be a bare permission-gated direct action as a real, auditable, later-upgradable workflow instance. stagesJson: [\"only\"], transitionsJson: [] (no transitions needed, the one task's own decision ends the instance), approvalPermissions has exactly the role(s) that would have held the old direct-action permission. Caller: submit() then immediately decideHumanTask() in the same request.",
15
+ file: "backend/modules/hcm-employee/spk-assembly/metadata/workflow/employee.promotion-acknowledge.json",
16
+ },
17
+ {
18
+ name: "multi-stage-linear",
19
+ description: "A fixed sequence of real approvers, no branching. stagesJson: [\"manager\", \"hr\"], one transition (manager->hr) gated on {field:\"decision\",op:\"eq\",value:\"approved\"}, no transition out of the last stage — reaching it with no match completes the instance.",
20
+ file: "backend/modules/hcm-employee/spk-assembly/metadata/workflow/employee.resignation.json",
21
+ },
22
+ {
23
+ name: "multi-stage-conditional-branching",
24
+ description: "Stage routing depends on server-computed booleans passed via extraContext at startInstance (never omitted, so the condition evaluator never treats a missing field as false). transitionsJson conditions use {field,op,value} or {any:[...]}/{all:[...]} composition; a stage can be skipped entirely (hr->finance only if costCenterChanged||businessUnitChanged; hr->executive directly if neither changed but highImpact did). Empty-match at any stage completes the instance.",
25
+ file: "backend/modules/hcm-employee/spk-assembly/metadata/workflow/employee.movement.json",
26
+ },
27
+ ],
28
+ page: [
29
+ {
30
+ name: "related-record-lookup-field",
31
+ description: "2026-09-03, real gap found and fixed (a module built entirely by AI agents shipped every foreign-key field — employee_id, course_id, provider_id, etc. — as a bare text/number input the user had to type a raw numeric id into, module-wide, because this pattern was undiscoverable). ANY page field whose value is another entity's id must be a `core.lookup` block (or `core.select`/`core.autocomplete` for a small, static or already-loaded option set), never a plain text/number input. `core.lookup`'s properties: `value` (binding to the field), `recordType` (documentation-only label, e.g. \"Employee\"), `optionsSourceKey` (the REAL routing key — the `name` of a published Data Service artifact, spk-assembly/metadata/data_service/*.json, that this lookup calls server-side with a `search` parameter and expects back `{value,label}` rows). `committed` event fires with `event.new` = the picked record's id. If the target entity doesn't already have a search-shaped Data Service, author one first (`erp examples search employee-search --kind data-service` and `--kind data-view` show the real recipe: a `dataView` source + a `contains` filter on `${param.search}` + one required `search` parameter) — never skip straight to a text input because no Data Service exists yet.",
32
+ file: "backend/modules/hcm-employee/spk-assembly/metadata/page/promotions.json",
33
+ },
34
+ {
35
+ name: "resolved-reference-grid-column",
36
+ description: "2026-09-03, real gap found and fixed (a JSON-first module's grids showed a raw FK id — employee_id — in a `core.grid` column even though the SAME page's create dialog already used `core.lookup` for that field; the grid has no field-level lookup concept, only a `name`/`type`/`headerKey`/`renderAs` column spec). Do NOT bind a grid column or a detail-view value to a raw *_id field — check the entity's own field metadata first (`erp schema pull entity-definition` -> `properties.fields.items.properties.flags`'s own description covers this) for `flags.reference.entityType`; if present, GET .../records/query and GET .../records/{id} already return a sibling `<fieldName>_label` key (e.g. `employee_id` -> `employee_id_label`) with zero extra code — bind the column/value to that key instead. If the field ISN'T marked yet: set `\"flags\":\"{\\\"reference\\\":{\\\"entityType\\\":\\\"Employee\\\"}}\"` on it via `PUT /api/v1/entities/{id}/fields/{fieldId}` (entityType must be a REGISTERED provider — \"Employee\" is the only one shipped today) and the `_label` key appears automatically on the next read, batched once per page load, never per row.",
37
+ file: "backend/modules/hcm-compensation/spk-assembly/metadata/page/salary-planning.json",
38
+ },
39
+ ],
40
+ jobs: [
41
+ {
42
+ name: "n-days-before-reminder-sweep",
43
+ description: "2026-09-10. A 'remind me N days before <date>' background job needs ZERO Java — it is one entity_status_date_sweep_config row (engine-entity.status-date-sweep) with `day_offset` set. e.g. {entity_name:'hcm_asset', when_status_in:'AVAILABLE,ASSIGNED,IN_USE', date_field:'warranty_expiry_date', compare_op:'lte', day_offset:30, set_field:'warranty_alert_30d', set_status_to:'true', active:true} fires when warranty_expiry_date <= now+30d. Use a distinct flag field per window (30d/14d/7d) so windows are independently queryable and the reminder never touches the lifecycle `status` enum. Ship the rows via metadata/seed-data/*.json so they travel with the plugin. Schema: `erp_get_schema entity-status-date-sweep-config`. Doc: ai/patterns/generic-entity-status-date-sweep.md.",
44
+ file: "backend/modules/hcm-assets/spk-assembly/metadata/seed-data/hcm-assets-sweep-configs.json",
45
+ },
46
+ {
47
+ name: "cross-row-aggregation-into-summary-entity",
48
+ description: "2026-09-10. A 'reconcile/roll-up count or total across many rows and store the result' job = one entity_aggregation_config row (engine-entity.aggregation-sweep), no Java. e.g. count hcm_asset grouped by status into a summary entity: {sweep_code:'asset-inventory-reconciliation', source_entity:'hcm_asset', aggregation:'count', group_by_field:'status', target_entity:'hcm_asset_reconciliation', target_key_field:'metric_key', target_key_prefix:'asset_status:', target_value_field:'metric_value', target_timestamp_field:'last_reconciled_at', active:true}. aggregation is count|sum|avg|min|max (last four over agg_field). Use target_key_prefix so several configs can share one summary entity. Schema: `erp_get_schema entity-aggregation-config`. Doc: ai/patterns/generic-aggregation-and-cadence-jobs.md.",
49
+ file: "backend/modules/hcm-assets/spk-assembly/metadata/seed-data/hcm-assets-aggregation-configs.json",
50
+ },
51
+ {
52
+ name: "scheduled-record-generation-cadence",
53
+ description: "2026-09-10. A 'create new records on a schedule' job = one entity_cadence_config row (engine-entity.cadence-generator), no Java. STANDALONE (one row per tick): {cadence_code:'asset-audit-schedule', target_entity:'hcm_asset_audit', interval_days:90, dedupe_target_field:'cadence_marker', template_json:{audit_number:'AUDIT-${date}-${ts}', audit_name:'Scheduled Audit ${date}', status:'DRAFT'}}. SOURCE-DRIVEN (one row per due source row): add source_entity + source_date_field + due_within_days + field_map_json + dedupe_target_field=<a column holding the source id>. template_json string values support ${date} ${ts} ${uuid} ${sourceId}. Schema: `erp_get_schema entity-cadence-config`.",
54
+ file: "backend/modules/hcm-assets/spk-assembly/metadata/seed-data/hcm-assets-cadence-configs.json",
55
+ },
56
+ {
57
+ name: "condition-based-compliance-flagging",
58
+ description: "2026-09-10 (Batch 3). A 'detect rows that violate a policy/compliance condition and flag them, or escalate them' job = one entity_compliance_config row (engine-entity.compliance-sweep), no Java. It evaluates a rule-engine boolean expression (the SAME platform ExpressionEvaluator cross-field validation and Formula fields use — whitelisted funcs only: daysBetween, now, etc.; no ternary/`in`/`^`) against each source row, with the row's own fields + `now` + optional `related_count` in scope. FLAG outcome: {compliance_code:'asset-assignment-compliance', source_entity:'hcm_asset', when_status_in:'ASSIGNED,IN_USE', condition_expr:'custody_acknowledged != true', set_field:'compliance_flag', set_value:'NON_COMPLIANT', active:true} (idempotent — skipped when the field already equals set_value). RELATED-COUNT (cross-record, e.g. license over-allocation): add related_count_entity + related_count_key_field (FK back to source id) + related_count_status_in, then use `related_count` in condition_expr (e.g. 'related_count > entitlement_quantity'). ESCALATION outcome (raise a row in a separate entity, deduped by source id): set escalation_entity + escalation_dedupe_field + field_map_json + escalation_template_json instead of set_field. Ship via metadata/seed-data/*.json + an AFTER_CREATE {type:EXECUTE_SERVICE, service:ensureEntityComplianceSweepJobRegistered} rule on entity_compliance_config. Schema: `erp_get_schema entity-compliance-config`. Doc: ai/patterns/generic-compliance-sweep-job.md.",
59
+ file: "backend/modules/hcm-assets/spk-assembly/metadata/seed-data/hcm-assets-compliance-configs.json",
60
+ },
61
+ {
62
+ name: "target-key-field-id-rollup",
63
+ description: "2026-09-10 (Batch 5+6). To roll child line-items UP onto their own parent record (the true MaintenanceCostSyncJob shape — write synced_cost onto hcm_asset_maintenance keyed by its OWN id, not into a summary entity), set target_key_field:'id' on an entity_aggregation_config row: {sweep_code:'maintenance-cost-rollup', source_entity:'hcm_asset_maintenance_cost', aggregation:'sum', agg_field:'total_cost', group_by_field:'maintenance_id', target_entity:'hcm_asset_maintenance', target_key_field:'id', target_value_field:'synced_cost', target_timestamp_field:'cost_synced_at', active:true}. The bucket key (from group_by_field) IS the parent row's primary key; the fold is written straight onto that row (never a create). Leave target_key_prefix blank. Schema: `erp_get_schema entity-aggregation-config`. Doc: ai/patterns/generic-aggregation-and-cadence-jobs.md.",
64
+ file: "backend/modules/hcm-assets/spk-assembly/metadata/seed-data/hcm-assets-aggregation-configs.json",
65
+ },
66
+ {
67
+ name: "cross-plugin-offboarding-fanout",
68
+ description: "2026-09-10 (Batch 5+6). 'When an employee is separated, auto-create asset return requests / license reclamation rows for everything they hold' = one entity_cross_plugin_action_config row (engine-entity.cross-plugin-action), no Java, no cross-plugin HTTP. {action_code:'asset-separation-return', trigger_entity:'employee', trigger_status_field:'employment_status', trigger_status_in:'TERMINATED,SEPARATED', trigger_key_field:'id', related_entity:'hcm_asset_allocation', related_match_field:'employee_id', related_status_in:'ALLOCATED,ACKNOWLEDGED,IN_USE', create_entity:'hcm_asset_return', create_dedupe_field:'allocation_id' (MUST be a numeric/long column), create_template_json:{status:'REQUESTED', reason:'EMPLOYEE_SEPARATION'}, create_field_map_json:{asset_id:'asset_id', employee_id:'employee_id'}, related_set_field:'status', related_set_value:'RETURN_PENDING', active:true}. The trigger entity can be owned by any plugin. Idempotent via the dedupe field. Schema: `erp_get_schema entity-cross-plugin-action-config`. Doc: ai/patterns/generic-cross-plugin-action-job.md.",
69
+ file: "backend/modules/hcm-assets/spk-assembly/metadata/seed-data/hcm-assets-cross-plugin-configs.json",
70
+ },
71
+ {
72
+ name: "per-row-document-artifact-generation",
73
+ description: "2026-09-10 (Batch 5+6). 'Generate an audit report / certificate document per completed record and stash the file' = one entity_document_generator_config row (engine-entity.document-generator), no Java. {document_code:'asset-audit-report', source_entity:'hcm_asset_audit', when_status_in:'COMPLETED', target_file_field:'report_file_ref_id' (a TEXT column — its non-blank state IS the dedupe marker), format:'json', cabinet_id:<a real DMS cabinet id>, child_entity:'hcm_asset_audit_item', child_match_field:'audit_id', file_name_template:'asset-audit-${id}-${date}.json', active:true}. LIMITATION: the platform print-template render path (engine-print-export PlaywrightPdfRenderer) only renders synthetic sample data via the Studio app — it can't be driven headless against a real record — so this job emits a structured-data artifact (json/csv), not a rendered PDF; template_ref is reserved for when real-record binding ships. Schema: `erp_get_schema entity-document-generator-config`. Doc: ai/patterns/generic-document-generator-job.md.",
74
+ file: "backend/modules/hcm-assets/spk-assembly/metadata/seed-data/hcm-assets-document-configs.json",
75
+ },
76
+ {
77
+ name: "heuristic-predictive-maintenance",
78
+ description: "2026-09-10 (Batch 5). PredictiveMaintenanceJob with NO ML: there is no tabular AI-inference seam (engine-ai-provider is text-gen/embedding only), so predictive-maintenance risk is scored as a DETERMINISTIC HEURISTIC config of the existing generic primitives — an entity_aggregation_config counting recent maintenance events per asset (target_key_field:'id' onto hcm_asset.recent_maintenance_count) plus an entity_compliance_config flagging hcm_asset.maintenance_risk='HIGH' when condition_expr combines real signals already in the data (recent_maintenance_count >= 3, or age past X% of expected_life_months, or open_maintenance_count >= 2). A real model plugs in later via the AiModelProvider seam with an entity_prediction_config, config-shape-compatible. Doc: ai/patterns/generic-compliance-sweep-job.md + the Batch 5 note in hcm-assets IMPLEMENTATION-GAPS.md.",
79
+ file: "backend/modules/hcm-assets/spk-assembly/metadata/seed-data/hcm-assets-predictive-configs.json",
80
+ },
81
+ {
82
+ name: "install-lifecycle-data-seeding",
83
+ description: "2026-09-10. To make Entity-Engine data rows (especially rows in the SHARED platform config entities entity_status_date_sweep_config / entity_aggregation_config / entity_cadence_config / workflow_reminder_config) travel with the .spk instead of a manual per-tenant POST: add metadata/seed-data/<name>.json = {entity, keyFields:[...natural key...], source:'<pluginId>', rows:[...]}. PluginDataSeedInstaller upserts these on every install/upgrade/auto-provision, idempotently by keyFields (matched row updated only if a value changed, else inserted — never duplicated). Also ship metadata/entities/*.json for any entity/column the rows need, and metadata/rules/*.json AFTER_CREATE {type:EXECUTE_SERVICE, service:ensure<Job>Registered} to auto-register the job on first row. Schema: `erp_get_schema plugin-seed-data`. Doc: ai/patterns/plugin-install-data-seeding.md.",
84
+ file: "backend/modules/hcm-assets/spk-assembly/metadata/seed-data/hcm-assets-sweep-configs.json",
85
+ },
86
+ ],
87
+ entities: [
88
+ {
89
+ name: "reference-display-label-field",
90
+ description: "2026-09-03. Any entity field whose value is another entity's real record id (a `long`-typed FK, e.g. `employee_id`) should carry `\"flags\":\"{\\\"reference\\\":{\\\"entityType\\\":\\\"Employee\\\"}}\"` in its field definition — this is the ONE line that turns on automatic id->display-name resolution platform-wide, no Java, no hand-written join. Once set, both the generic grid query (`GET .../records/query`) and single-record read (`GET .../records/{id}`) automatically add a `\"<fieldName>_label\"` key to every row/record where the id resolves (batched: one resolve call per distinct reference-flagged field per page load, never per row) — see `resolved-reference-grid-column` under `--kind page` for the consuming side. `entityType` must be a REGISTERED provider (a plugin that exposes its own `batch-names` endpoint) — \"Employee\" (backed by hcm-employee) is the only one shipped today; an unregistered entityType just produces no `_label` key, never an error.",
91
+ file: "backend/modules/hcm-compensation/spk-assembly/metadata/entities/hcm_salary_planning_entry.json",
92
+ },
93
+ ],
94
+ };