@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.
- package/LICENSE +21 -0
- package/README.md +61 -0
- package/bundle/blocks.json +12229 -0
- package/bundle/catalog.json +32475 -0
- package/bundle/docs/applications/hcm/employee-profile.md +144 -0
- package/bundle/docs/concepts/artifact-types.md +80 -0
- package/bundle/docs/concepts/glossary.md +124 -0
- package/bundle/docs/concepts/overview.md +88 -0
- package/bundle/docs/concepts/page-data-flow.md +84 -0
- package/bundle/docs/concepts/plugin-lifecycle.md +81 -0
- package/bundle/docs/concepts/sdk-modes.md +71 -0
- package/bundle/docs/docs.json +109 -0
- package/bundle/docs/guides/add-a-cadence-job.md +134 -0
- package/bundle/docs/guides/add-a-compliance-job.md +139 -0
- package/bundle/docs/guides/add-a-create-edit-form.md +167 -0
- package/bundle/docs/guides/add-a-custom-block.md +225 -0
- package/bundle/docs/guides/add-a-data-provider.md +216 -0
- package/bundle/docs/guides/add-a-kpi.md +154 -0
- package/bundle/docs/guides/add-a-reminder-job.md +181 -0
- package/bundle/docs/guides/add-an-aggregation-job.md +153 -0
- package/bundle/docs/guides/add-an-approval-workflow.md +222 -0
- package/bundle/docs/guides/add-an-entity.md +170 -0
- package/bundle/docs/guides/add-business-rules.md +147 -0
- package/bundle/docs/guides/add-i18n.md +121 -0
- package/bundle/docs/guides/add-menus.md +149 -0
- package/bundle/docs/guides/build-a-code-plugin.md +141 -0
- package/bundle/docs/guides/build-a-page.md +213 -0
- package/bundle/docs/guides/build-a-polyglot-service-plugin.md +201 -0
- package/bundle/docs/guides/build-a-tenant-extension-service.md +149 -0
- package/bundle/docs/guides/create-a-plugin.md +172 -0
- package/bundle/docs/guides/expose-a-plugin-operation-as-an-ai-tool.md +114 -0
- package/bundle/docs/guides/index.md +53 -0
- package/bundle/docs/guides/publish-and-upgrade.md +152 -0
- package/bundle/docs/guides/responsive-plugin.md +117 -0
- package/bundle/docs/guides/seed-data-on-install.md +127 -0
- package/bundle/docs/guides/set-up-the-sdk.md +120 -0
- package/bundle/docs/guides/use-the-mcp-server.md +104 -0
- package/bundle/docs/guides/validate-and-test.md +119 -0
- package/bundle/docs/guides/wire-a-pages-data.md +153 -0
- package/bundle/docs/quickstart/index.md +118 -0
- package/bundle/docs/recipes/condition-based-compliance-flag.md +70 -0
- package/bundle/docs/recipes/cross-plugin-offboarding-fanout.md +68 -0
- package/bundle/docs/recipes/cross-row-aggregation.md +67 -0
- package/bundle/docs/recipes/entity-with-approval-workflow.md +72 -0
- package/bundle/docs/recipes/index.md +40 -0
- package/bundle/docs/recipes/install-lifecycle-data-seeding.md +76 -0
- package/bundle/docs/recipes/kpi-dashboard-page.md +92 -0
- package/bundle/docs/recipes/master-detail-page.md +84 -0
- package/bundle/docs/recipes/n-days-before-reminder.md +72 -0
- package/bundle/docs/recipes/per-row-document-generator.md +65 -0
- package/bundle/docs/recipes/related-record-lookup-field.md +74 -0
- package/bundle/docs/recipes/resolved-reference-grid-column.md +63 -0
- package/bundle/docs/recipes/scheduled-record-generation.md +68 -0
- package/bundle/docs/reference/action.md +18 -0
- package/bundle/docs/reference/block-definition.md +35 -0
- package/bundle/docs/reference/block-instance.md +33 -0
- package/bundle/docs/reference/composite-pack-manifest.md +33 -0
- package/bundle/docs/reference/connector-definition.md +36 -0
- package/bundle/docs/reference/data-service-definition.md +22 -0
- package/bundle/docs/reference/data-view-definition.md +26 -0
- package/bundle/docs/reference/entity-aggregation-config.md +38 -0
- package/bundle/docs/reference/entity-cadence-config.md +33 -0
- package/bundle/docs/reference/entity-compliance-config.md +37 -0
- package/bundle/docs/reference/entity-cross-plugin-action-config.md +37 -0
- package/bundle/docs/reference/entity-definition.md +18 -0
- package/bundle/docs/reference/entity-document-generator-config.md +35 -0
- package/bundle/docs/reference/entity-rule-definition.md +29 -0
- package/bundle/docs/reference/entity-status-date-sweep-config.md +27 -0
- package/bundle/docs/reference/form.md +35 -0
- package/bundle/docs/reference/index.md +37 -0
- package/bundle/docs/reference/menu.md +26 -0
- package/bundle/docs/reference/mobile-nav.md +22 -0
- package/bundle/docs/reference/page-template.md +29 -0
- package/bundle/docs/reference/page.md +44 -0
- package/bundle/docs/reference/plugin-manifest.md +54 -0
- package/bundle/docs/reference/plugin-seed-data.md +21 -0
- package/bundle/docs/reference/print-template-definition.md +22 -0
- package/bundle/docs/reference/provider-definition.md +22 -0
- package/bundle/docs/reference/report-definition.md +22 -0
- package/bundle/docs/reference/rule.md +30 -0
- package/bundle/docs/reference/workflow-definition.md +28 -0
- package/bundle/docs/troubleshooting/grid-shows-zero-rows.md +82 -0
- package/bundle/docs/troubleshooting/job-never-runs.md +89 -0
- package/bundle/docs/troubleshooting/known-gotchas.md +193 -0
- package/bundle/docs/troubleshooting/publishing-errors.md +119 -0
- package/bundle/docs/tutorial/01-create-the-plugin.md +157 -0
- package/bundle/docs/tutorial/02-category-entity-and-seed.md +94 -0
- package/bundle/docs/tutorial/03-equipment-entity.md +121 -0
- package/bundle/docs/tutorial/04-equipment-register-page.md +153 -0
- package/bundle/docs/tutorial/05-checkout-entity-and-page.md +116 -0
- package/bundle/docs/tutorial/06-checkout-approval-workflow.md +139 -0
- package/bundle/docs/tutorial/07-return-due-reminder-job.md +129 -0
- package/bundle/docs/tutorial/08-menus-i18n-publish.md +123 -0
- package/bundle/docs/tutorial/index.md +72 -0
- package/bundle/examples/backend/modules/hcm-assets/spk-assembly/metadata/seed-data/hcm-assets-aggregation-configs.json +18 -0
- package/bundle/examples/backend/modules/hcm-assets/spk-assembly/metadata/seed-data/hcm-assets-cadence-configs.json +9 -0
- package/bundle/examples/backend/modules/hcm-assets/spk-assembly/metadata/seed-data/hcm-assets-compliance-configs.json +74 -0
- package/bundle/examples/backend/modules/hcm-assets/spk-assembly/metadata/seed-data/hcm-assets-cross-plugin-configs.json +9 -0
- package/bundle/examples/backend/modules/hcm-assets/spk-assembly/metadata/seed-data/hcm-assets-document-configs.json +9 -0
- package/bundle/examples/backend/modules/hcm-assets/spk-assembly/metadata/seed-data/hcm-assets-sweep-configs.json +260 -0
- package/bundle/examples/backend/modules/hcm-compensation/spk-assembly/metadata/entities/hcm_salary_planning_entry.json +41 -0
- package/bundle/examples/backend/modules/hcm-compensation/spk-assembly/metadata/page/salary-planning.json +1 -0
- package/bundle/examples/backend/modules/hcm-employee/spk-assembly/metadata/page/promotions.json +10944 -0
- package/bundle/examples/backend/modules/hcm-employee/spk-assembly/metadata/workflow/employee.movement.json +44 -0
- package/bundle/examples/backend/modules/hcm-employee/spk-assembly/metadata/workflow/employee.promotion-acknowledge.json +19 -0
- package/bundle/examples/backend/modules/hcm-employee/spk-assembly/metadata/workflow/employee.resignation.json +29 -0
- package/bundle/examples/example-patterns.mjs +94 -0
- package/bundle/manifest.json +14 -0
- package/bundle/schemas/action.schema.json +102 -0
- package/bundle/schemas/block-definition.schema.json +222 -0
- package/bundle/schemas/block-instance.schema.json +139 -0
- package/bundle/schemas/composite-pack-manifest.schema.json +160 -0
- package/bundle/schemas/connector-definition.schema.json +29 -0
- package/bundle/schemas/data-service-definition.schema.json +64 -0
- package/bundle/schemas/data-view-definition.schema.json +148 -0
- package/bundle/schemas/entity-aggregation-config.schema.json +32 -0
- package/bundle/schemas/entity-cadence-config.schema.json +27 -0
- package/bundle/schemas/entity-compliance-config.schema.json +31 -0
- package/bundle/schemas/entity-cross-plugin-action-config.schema.json +31 -0
- package/bundle/schemas/entity-definition.schema.json +126 -0
- package/bundle/schemas/entity-document-generator-config.schema.json +29 -0
- package/bundle/schemas/entity-rule-definition.schema.json +75 -0
- package/bundle/schemas/entity-status-date-sweep-config.schema.json +21 -0
- package/bundle/schemas/form.schema.json +281 -0
- package/bundle/schemas/menu.schema.json +106 -0
- package/bundle/schemas/mobile-nav.schema.json +53 -0
- package/bundle/schemas/page-template.schema.json +46 -0
- package/bundle/schemas/page.schema.json +292 -0
- package/bundle/schemas/plugin-manifest.schema.json +139 -0
- package/bundle/schemas/plugin-seed-data.schema.json +24 -0
- package/bundle/schemas/print-template-definition.schema.json +90 -0
- package/bundle/schemas/provider-definition.schema.json +27 -0
- package/bundle/schemas/report-definition.schema.json +96 -0
- package/bundle/schemas/rule.schema.json +82 -0
- package/bundle/schemas/workflow-definition.schema.json +42 -0
- package/bundle/validators/block-engine.mjs +23222 -0
- package/bundle/validators/page-engine.mjs +21645 -0
- package/erp-cli/authoring-root.mjs +344 -0
- package/erp-cli/erp.mjs +4065 -0
- package/erp-cli/example-patterns.mjs +94 -0
- package/erp-mcp-server/index.mjs +818 -0
- package/package.json +27 -0
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
3
|
+
"$id": "https://erp.internal/schema/spk-plugin-manifest.schema.json",
|
|
4
|
+
"title": "SpkPluginManifest",
|
|
5
|
+
"description": "The real, actual shape of a hot-loadable PF4J .spk business-application plugin's own spk-assembly/plugin.json — id/name/version/permissions/roles/dependencies, confirmed against every already-shipped module (hcm-performance, hcm-organization, hcm-learning, ~30 more). Added 2026-09-03 — the pre-existing 'plugin-manifest' schema-registry entry (frontend/packages/plugin-sdk/schema/plugin-manifest.schema.json, now separately registered as 'composite-pack-manifest') is a genuinely DIFFERENT, newer contract (contractVersion/publisher/distribution/12 extension-point 'contributions') for a different artifact type (a composite pack / Country-or-Industry-Pack / Code-Plugin-style TS manifest) — validating any real shipped .spk plugin.json against it always FAILed (confirmed live against hcm-performance's own plugin.json, found while building hcm-learning's Course Catalog batch), even though erp_list_schemas' own 'plugin-manifest' description ('plugin.json's own manifest contract (id/version/permissions/roles/dependencies)') describes THIS shape, not that one. This schema is the fix: 'plugin-manifest' now points here.",
|
|
6
|
+
"type": "object",
|
|
7
|
+
"required": ["id", "name", "version"],
|
|
8
|
+
"properties": {
|
|
9
|
+
"id": { "type": "string", "pattern": "^[a-z][a-z0-9-]*$" },
|
|
10
|
+
"name": { "type": "string" },
|
|
11
|
+
"version": { "type": "string", "pattern": "^(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)$" },
|
|
12
|
+
"type": { "type": "string" },
|
|
13
|
+
"vendor": { "type": "string" },
|
|
14
|
+
"license": { "type": "string" },
|
|
15
|
+
"licenseTier": { "type": "string" },
|
|
16
|
+
"category": { "type": "string" },
|
|
17
|
+
"erpVersion": { "type": "string" },
|
|
18
|
+
"minErpVersion": { "type": "string" },
|
|
19
|
+
"maxErpVersion": { "type": "string" },
|
|
20
|
+
"mainClass": { "type": ["string", "null"], "description": "Fully-qualified PF4J plugin main class. Optional (null/absent) for a pure-JSON plugin that ships zero Java classes -- the platform loads it via the built-in JsonOnlyPlugin entry point." },
|
|
21
|
+
"schemaName": { "type": "string", "description": "App-owned Postgres schema this plugin's Entity-Engine tables route to — see feedback-entity-engine-tables-must-route-to-app-schema." },
|
|
22
|
+
"scope": { "type": "string", "enum": ["global", "tenant"], "default": "global", "description": "Tenant-Safe Plugin & Extension Architecture spec §54. 'global' (default, every manifest that predates this field): a shared plugin installable by any tenant. 'tenant': a private single-tenant L5 extension — MUST also set tenantId, and if it carries Java code (mainClass, or type java-extension/code-plugin) it MUST declare runtimeModes: ['service'] — the shared runtime refuses to load it (ExtensionInstallValidator, spec §11/§28.10/§74)." },
|
|
23
|
+
"tenantId": { "type": "string", "description": "Spec §54 — the owning tenant of a scope:'tenant' plugin. Required iff scope=='tenant'; must match the tenant the plugin is installed into. Absent for a global plugin." },
|
|
24
|
+
"erpApiVersion": { "type": "string", "description": "Spec §25 — the ERP extension-API contract version this plugin targets (e.g. '5.0'), distinct from erpVersion/minErpVersion (platform build versions). Optional; informational in E1." },
|
|
25
|
+
"supportedApplications": { "type": "array", "items": { "type": "string" }, "description": "Spec §25 — applications this extension supports, e.g. ['HCM']. Optional; empty/absent means unconstrained." },
|
|
26
|
+
"dependencies": { "type": "array", "items": { "type": "string" } },
|
|
27
|
+
"optionalDependencies": { "type": "array", "items": { "type": "string" } },
|
|
28
|
+
"permissions": { "type": "array", "items": { "type": "string" }, "description": "Legacy flat permission-key catalogue; real installs read roles[].permissionKeys instead (PluginRoleInstaller) — commonly left empty on modules whose roles[] is populated." },
|
|
29
|
+
"owner": { "type": "string" },
|
|
30
|
+
"editable": { "type": "boolean" },
|
|
31
|
+
"extendable": { "type": "boolean" },
|
|
32
|
+
"capabilitiesProvided": { "type": "array", "items": { "type": "string" } },
|
|
33
|
+
"capabilitiesRequired": { "type": "array", "items": { "type": "string" } },
|
|
34
|
+
"featureFlags": { "type": "array", "items": { "type": "string" } },
|
|
35
|
+
"configSchemaJson": { "type": ["object", "string", "null"] },
|
|
36
|
+
"frontendBundle": {
|
|
37
|
+
"type": "object",
|
|
38
|
+
"description": "Optional — dynamic frontend-plugin-loading (ai/patterns/code-plugin-sdk.md). Absent on every plugin.json that predates it.",
|
|
39
|
+
"required": ["fileId"],
|
|
40
|
+
"properties": {
|
|
41
|
+
"fileId": { "type": "string" },
|
|
42
|
+
"entrypointExport": { "type": "string" }
|
|
43
|
+
}
|
|
44
|
+
},
|
|
45
|
+
"roles": {
|
|
46
|
+
"type": "array",
|
|
47
|
+
"items": {
|
|
48
|
+
"type": "object",
|
|
49
|
+
"required": ["name", "code", "permissionKeys"],
|
|
50
|
+
"properties": {
|
|
51
|
+
"name": { "type": "string" },
|
|
52
|
+
"code": { "type": "string", "pattern": "^[A-Z][A-Z0-9_]*$" },
|
|
53
|
+
"description": { "type": "string" },
|
|
54
|
+
"permissionKeys": { "type": "array", "items": { "type": "string" } }
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
},
|
|
58
|
+
"runtimeModes": {
|
|
59
|
+
"type": "array",
|
|
60
|
+
"items": { "type": "string", "enum": ["embedded", "service"] },
|
|
61
|
+
"description": "Added 2026-09-03 (real gap — this field is genuinely load-bearing on every shipped plugin.json today, e.g. hcm-learning's own [\"embedded\"], but was entirely absent from this schema until now, so erp_get_schema/erp schema pull misrepresented the real manifest shape). Which Plugin Runtime modes this plugin can run under: 'embedded' (loaded in-process via PF4J, the only behavior every pre-existing manifest declares) and/or 'service' (its own standalone Spring Boot process, routed to over HTTP — see PluginManifest#runtimeModes' own Javadoc in engine-plugin-api). Defaults to ['embedded'] when absent. Declaring 'service' here does not itself switch anything — the actual mode is chosen per-plugin via Studio's Plugin Runtime toggle (erp_core.application.deployment_type)."
|
|
62
|
+
},
|
|
63
|
+
"serviceRuntime": {
|
|
64
|
+
"type": ["string", "null"],
|
|
65
|
+
"enum": ["java", "python", "nodejs", null],
|
|
66
|
+
"description": "Added 2026-09-14 (Polyglot Plugin Runtime initiative, PluginManifest#serviceRuntime's own Javadoc in engine-plugin-api). Which language a Service-mode plugin's own process is implemented in. Only meaningful when runtimeModes contains 'service' — an embedded-only plugin is always Java (nothing else can load into the JVM), and installing a manifest that sets this to 'python'/'nodejs' without declaring 'service' in runtimeModes fails install (PluginCodeLifecycle#validateServiceRuntime). null/absent defaults to 'java' — every manifest that predates this field keeps its exact current behavior. Real, proven implementations exist for all three values: hello-plugin-service (java), hello-plugin-service-python (python), hello-plugin-service-node (nodejs) — see 'Build a Service-mode plugin in Python or Node.js' for the SDK and full build/deploy path for each."
|
|
67
|
+
},
|
|
68
|
+
"serviceFramework": {
|
|
69
|
+
"type": ["string", "null"],
|
|
70
|
+
"enum": ["spring-boot", "fastapi", "express", null],
|
|
71
|
+
"description": "Added 2026-09-14, same initiative as serviceRuntime — purely informational (shown as a read-only chip in Studio's Plugin Runtime panel; not validated against serviceRuntime today, so keep them consistent yourself: spring-boot pairs with java, fastapi with python, express with nodejs). null/absent defaults to 'spring-boot'."
|
|
72
|
+
},
|
|
73
|
+
"serviceDeployment": {
|
|
74
|
+
"type": ["object", "null"],
|
|
75
|
+
"description": "Added 2026-09-03 (same real-gap fix as runtimeModes). Recommended deployment/runtime defaults for this plugin when run in 'service' mode (PluginManifest.PluginServiceDeploymentSpec in engine-plugin-api). null (the default for almost every manifest) means Studio seeds an empty config the admin fills in the first time they switch this plugin to Service mode. Only healthPath/timeoutMs/heartbeatIntervalSeconds actually drive runtime behavior today (health checks, proxy call timeout) — docker/kubernetes/cloud are real, persisted, Studio-editable data for a future Deployment Manager, not wired to any live provisioning API.",
|
|
76
|
+
"properties": {
|
|
77
|
+
"process": {
|
|
78
|
+
"type": ["object", "null"],
|
|
79
|
+
"description": "Local/Windows-process deployment — the mode this platform actually runs and tests today.",
|
|
80
|
+
"properties": {
|
|
81
|
+
"port": { "type": ["integer", "null"] },
|
|
82
|
+
"startupCommand": { "type": ["string", "null"] },
|
|
83
|
+
"workingDirectory": { "type": ["string", "null"] },
|
|
84
|
+
"env": { "type": ["object", "null"], "additionalProperties": { "type": "string" } }
|
|
85
|
+
}
|
|
86
|
+
},
|
|
87
|
+
"docker": {
|
|
88
|
+
"type": ["object", "null"],
|
|
89
|
+
"description": "Container image parameters — real data, not acted on by this codebase (no Docker Engine API calls).",
|
|
90
|
+
"properties": {
|
|
91
|
+
"image": { "type": ["string", "null"] },
|
|
92
|
+
"containerPort": { "type": ["integer", "null"] },
|
|
93
|
+
"env": { "type": ["object", "null"], "additionalProperties": { "type": "string" } },
|
|
94
|
+
"resources": { "$ref": "#/definitions/resourceLimits" }
|
|
95
|
+
}
|
|
96
|
+
},
|
|
97
|
+
"kubernetes": {
|
|
98
|
+
"type": ["object", "null"],
|
|
99
|
+
"description": "Kubernetes Deployment/Service parameters — real data, not acted on by this codebase (no Kubernetes API calls; manifests under deploy/kubernetes/ are applied by hand via kubectl).",
|
|
100
|
+
"properties": {
|
|
101
|
+
"namespace": { "type": ["string", "null"] },
|
|
102
|
+
"replicas": { "type": ["integer", "null"] },
|
|
103
|
+
"serviceName": { "type": ["string", "null"] },
|
|
104
|
+
"image": { "type": ["string", "null"] },
|
|
105
|
+
"imagePullPolicy": { "type": ["string", "null"] },
|
|
106
|
+
"resources": { "$ref": "#/definitions/resourceLimits" },
|
|
107
|
+
"livenessProbePath": { "type": ["string", "null"] },
|
|
108
|
+
"readinessProbePath": { "type": ["string", "null"] },
|
|
109
|
+
"env": { "type": ["object", "null"], "additionalProperties": { "type": "string" } },
|
|
110
|
+
"secretRefs": { "type": ["array", "null"], "items": { "type": "string" } }
|
|
111
|
+
}
|
|
112
|
+
},
|
|
113
|
+
"cloud": {
|
|
114
|
+
"type": ["object", "null"],
|
|
115
|
+
"description": "Informational only — which cloud (if any) this deployment targets, and its region. Not read by any provisioning code in this codebase.",
|
|
116
|
+
"properties": {
|
|
117
|
+
"provider": { "type": ["string", "null"] },
|
|
118
|
+
"region": { "type": ["string", "null"] }
|
|
119
|
+
}
|
|
120
|
+
},
|
|
121
|
+
"healthPath": { "type": ["string", "null"], "description": "Path (relative to service_url) this plugin's health check calls. Defaults to '/actuator/health' when absent." },
|
|
122
|
+
"timeoutMs": { "type": ["integer", "null"], "description": "Outbound proxy call timeout in milliseconds. Defaults to 5000 when absent." },
|
|
123
|
+
"heartbeatIntervalSeconds": { "type": ["integer", "null"], "description": "Expected self-registration heartbeat cadence, used only to size ApplicationServiceRegistry's staleness TTL (3x this value). Defaults to 10 when absent." }
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
},
|
|
127
|
+
"definitions": {
|
|
128
|
+
"resourceLimits": {
|
|
129
|
+
"type": ["object", "null"],
|
|
130
|
+
"description": "CPU/memory requests+limits, Kubernetes resource-quantity string convention (e.g. '500m', '512Mi').",
|
|
131
|
+
"properties": {
|
|
132
|
+
"requestsCpu": { "type": ["string", "null"] },
|
|
133
|
+
"requestsMemory": { "type": ["string", "null"] },
|
|
134
|
+
"limitsCpu": { "type": ["string", "null"] },
|
|
135
|
+
"limitsMemory": { "type": ["string", "null"] }
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
3
|
+
"$id": "https://erp.platform/schema/plugin-seed-data.schema.json",
|
|
4
|
+
"title": "Plugin install-lifecycle seed-data file (metadata/seed-data/*.json)",
|
|
5
|
+
"description": "Declares Entity-Engine data rows a plugin seeds on install/upgrade/auto-provision, idempotently (upsert by keyFields), for the installing tenant. Applied by PluginDataSeedInstaller. Generalizes plugin.json roles[] to arbitrary entity data - notably the shared platform config entities entity_status_date_sweep_config / entity_aggregation_config / entity_cadence_config / workflow_reminder_config. See ai/patterns/plugin-install-data-seeding.md.",
|
|
6
|
+
"type": "object",
|
|
7
|
+
"required": ["entity", "keyFields", "rows"],
|
|
8
|
+
"additionalProperties": false,
|
|
9
|
+
"properties": {
|
|
10
|
+
"entity": { "type": "string", "description": "Entity Engine entity name the rows belong to. Must already exist (ship it in metadata/entities/ if the plugin owns it)." },
|
|
11
|
+
"keyFields": {
|
|
12
|
+
"type": "array",
|
|
13
|
+
"minItems": 1,
|
|
14
|
+
"items": { "type": "string" },
|
|
15
|
+
"description": "The natural-key fields that uniquely identify a row. On re-install, a row matching all keyFields is updated (only if a non-key value changed); otherwise inserted. Never produces duplicates."
|
|
16
|
+
},
|
|
17
|
+
"source": { "type": "string", "description": "The plugin id. Stamped into a seeded_by field when the entity has one." },
|
|
18
|
+
"rows": {
|
|
19
|
+
"type": "array",
|
|
20
|
+
"items": { "type": "object" },
|
|
21
|
+
"description": "The rows to upsert. Each is a plain field map for the entity - no tenant id (the installer supplies it)."
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
3
|
+
"$id": "https://erp.internal/schema/print-template-definition.schema.json",
|
|
4
|
+
"title": "PrintTemplateDefinitionArtifact",
|
|
5
|
+
"$comment": "CLOSED 2026-09-03 (mcp-12), same as report-definition.schema.json: a real Print Template is now shipped — backend/modules/hcm-organization/spk-assembly/metadata/print_template/organization-tag-label.json, a minimal single-entity Badge-sized label (name/code/QR-code) over the real `organization_tag` entity. Installed live via the same hcm-organization plugin upgrade (1.0.91->1.0.92) that shipped the sibling Report above — confirmed via `GET /api/v1/authoring/print-templates` returning a real, owned, published row (id 1), and via a real authenticated Playwright session opening Studio's Print Template Designer (Data source/Fields correctly resolved, category 'Labels', zero Problems) and its own live Preview tab (real band rendering: bold name, code caption, an actually-rendered QR code image, real Export PDF/Word/Excel buttons present). `erp schema validate` passes against this real file. Derived directly from frontend/packages/print-engine/src/types.ts's PrintTemplateDefinition/PrintBand/PrintElement (imports ReportBandKind/ReportGroupLevel/ReportSortLevel from @erp/report-engine, respected here via $ref). The synthetic print-template-definition.example.json in this same directory is kept as a secondary fixture.",
|
|
6
|
+
"description": "Print Template Designer's content model — Report's band/element sibling, diverging in three ways: a physical mm-based page, data binding up to one level of parent+children, and free-form merge-tag prose text. Element `content.kind` is a large discriminated union (see the TS source); this schema constrains the common/required fields and leaves `properties`/kind-specific fields as an open object rather than re-deriving all ~10 content kinds field-by-field.",
|
|
7
|
+
"type": "object",
|
|
8
|
+
"required": ["name", "definition"],
|
|
9
|
+
"properties": {
|
|
10
|
+
"name": { "type": "string" },
|
|
11
|
+
"description": { "type": "string" },
|
|
12
|
+
"metadata": { "type": "object" },
|
|
13
|
+
"modules": { "type": "array", "items": { "type": "string" } },
|
|
14
|
+
"definition": {
|
|
15
|
+
"type": "object",
|
|
16
|
+
"required": ["contractVersion", "templateCategory", "page", "bands"],
|
|
17
|
+
"properties": {
|
|
18
|
+
"contractVersion": { "type": "number", "enum": [1] },
|
|
19
|
+
"templateCategory": {
|
|
20
|
+
"type": "string",
|
|
21
|
+
"enum": ["Payslip", "Invoice", "Tax Invoice", "Purchase Order", "Sales Order", "Quotation", "Delivery Challan", "Goods Receipt Note", "Purchase Requisition", "Expense Voucher", "Payment Voucher", "Receipt", "Credit Note", "Debit Note", "Employee ID Card", "Visitor ID Card", "Offer Letter", "Appointment Letter", "Confirmation Letter", "Promotion Letter", "Transfer Letter", "Experience Letter", "Relieving Letter", "Salary Revision Letter", "Warning Letter", "Termination Letter", "Employment Contract", "Joining Kit", "Leave Approval Letter", "Attendance Certificate", "Training Certificate", "Performance Letter", "Asset Handover Form", "Exit Clearance Form", "Certificates", "Labels", "Barcode Labels", "QR Code Labels", "Custom Document"]
|
|
22
|
+
},
|
|
23
|
+
"dataSource": {
|
|
24
|
+
"type": ["object", "null"],
|
|
25
|
+
"properties": {
|
|
26
|
+
"kind": { "type": "string", "enum": ["entity", "entity-with-children"] },
|
|
27
|
+
"entityId": { "type": "number" },
|
|
28
|
+
"entityName": { "type": "string" },
|
|
29
|
+
"fields": { "type": "array", "items": { "type": "string" } },
|
|
30
|
+
"parent": { "type": "object" },
|
|
31
|
+
"children": { "type": "array" }
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
"page": {
|
|
35
|
+
"type": "object",
|
|
36
|
+
"required": ["sizePreset", "widthMm", "heightMm", "orientation", "marginsMm", "bleedMm"],
|
|
37
|
+
"properties": {
|
|
38
|
+
"sizePreset": { "type": "string", "enum": ["A4", "A5", "Letter", "Legal", "Thermal-58mm", "Thermal-80mm", "ID-Card", "Badge", "Custom"] },
|
|
39
|
+
"widthMm": { "type": "number" },
|
|
40
|
+
"heightMm": { "type": "number" },
|
|
41
|
+
"orientation": { "type": "string", "enum": ["portrait", "landscape"] },
|
|
42
|
+
"marginsMm": { "type": "object", "properties": { "top": { "type": "number" }, "right": { "type": "number" }, "bottom": { "type": "number" }, "left": { "type": "number" } } },
|
|
43
|
+
"bleedMm": { "type": "object", "properties": { "top": { "type": "number" }, "right": { "type": "number" }, "bottom": { "type": "number" }, "left": { "type": "number" } } }
|
|
44
|
+
}
|
|
45
|
+
},
|
|
46
|
+
"groupLevels": { "type": "array", "description": "ReportGroupLevel[] — same shape as report-definition.schema.json's groupLevels items." },
|
|
47
|
+
"sortLevels": { "type": "array", "description": "ReportSortLevel[] — same shape as report-definition.schema.json's sortLevels items." },
|
|
48
|
+
"bands": {
|
|
49
|
+
"type": "array",
|
|
50
|
+
"items": {
|
|
51
|
+
"type": "object",
|
|
52
|
+
"required": ["id", "kind", "heightPx", "elements"],
|
|
53
|
+
"properties": {
|
|
54
|
+
"id": { "type": "string" },
|
|
55
|
+
"kind": { "type": "string", "enum": ["report-header", "report-footer", "page-header", "page-footer", "group-header", "group-footer", "detail"] },
|
|
56
|
+
"groupLevelId": { "type": "string" },
|
|
57
|
+
"name": { "type": "string" },
|
|
58
|
+
"heightPx": { "type": "number" },
|
|
59
|
+
"visible": { "type": "boolean" },
|
|
60
|
+
"elements": {
|
|
61
|
+
"type": "array",
|
|
62
|
+
"items": {
|
|
63
|
+
"type": "object",
|
|
64
|
+
"required": ["id", "position", "content"],
|
|
65
|
+
"properties": {
|
|
66
|
+
"id": { "type": "string" },
|
|
67
|
+
"position": { "type": "object", "required": ["x", "y", "width", "height"] },
|
|
68
|
+
"content": {
|
|
69
|
+
"type": "object",
|
|
70
|
+
"required": ["kind"],
|
|
71
|
+
"properties": {
|
|
72
|
+
"kind": { "type": "string", "enum": ["literal", "block", "field", "merge-text", "formula", "table", "repeating-section", "barcode"] }
|
|
73
|
+
},
|
|
74
|
+
"description": "Open per-kind fields (type/properties/fieldName/template/expression/columns/elements/format/valueTemplate/...) — see PrintElementContent's discriminated union in the TS source; not re-derived field-by-field here."
|
|
75
|
+
},
|
|
76
|
+
"locked": { "type": "boolean" },
|
|
77
|
+
"style": { "type": "object" },
|
|
78
|
+
"visibility": { "type": "object" }
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
},
|
|
85
|
+
"variables": { "type": "array" },
|
|
86
|
+
"locale": { "type": "string", "description": "BCP-47 tag, e.g. \"ar\"/\"en\". Absent means \"en\"/LTR." }
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
3
|
+
"$id": "https://erp.internal/schema/provider-definition.schema.json",
|
|
4
|
+
"title": "ProviderDefinitionArtifact",
|
|
5
|
+
"description": "The real on-disk authoring shape for a Data Provider JSON artifact (spk-assembly/metadata/provider/*.json), served by ProviderAuthoringController (backend/platform-runtime/engine-form) — a thin JsonArtifactAuthoringController subclass, same wrapper every artifact type of this family uses. `definition` matches frontend/apps/studio/src/ProviderDesigner.tsx's ProviderDefinitionForm exactly (confirmed against a live shipped file, crm-leads-provider.json).",
|
|
6
|
+
"type": "object",
|
|
7
|
+
"required": ["name", "definition"],
|
|
8
|
+
"properties": {
|
|
9
|
+
"name": { "type": "string" },
|
|
10
|
+
"description": { "type": "string" },
|
|
11
|
+
"metadata": { "type": "object" },
|
|
12
|
+
"modules": { "type": "array", "items": { "type": "string" } },
|
|
13
|
+
"definition": {
|
|
14
|
+
"type": "object",
|
|
15
|
+
"required": ["kind", "connectionRef", "basePath", "supports"],
|
|
16
|
+
"properties": {
|
|
17
|
+
"kind": { "type": "string", "enum": ["rest", "mock", "graphql", "offline", "ai", "connector"] },
|
|
18
|
+
"connectionRef": { "type": "string", "description": "\"self\" for this platform's own backend; otherwise a named external connection." },
|
|
19
|
+
"basePath": { "type": "string" },
|
|
20
|
+
"supports": {
|
|
21
|
+
"type": "array",
|
|
22
|
+
"items": { "type": "string", "enum": ["search", "get", "create", "update", "patch", "delete", "export", "import", "bulkUpdate"] }
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
3
|
+
"$id": "https://erp.internal/schema/report-definition.schema.json",
|
|
4
|
+
"title": "ReportDefinitionArtifact",
|
|
5
|
+
"$comment": "CLOSED 2026-09-03 (mcp-12): a real Report is now shipped — backend/modules/hcm-organization/spk-assembly/metadata/report/organization-tag-list.json, a minimal listing report over the real `organization_tag` Entity Engine entity (id 1). Installed live via `erp-organization`'s real plugin upgrade path (spark package + POST /api/v1/authoring/plugins/hcm-organization/upload, 1.0.91->1.0.92) — confirmed via `GET /api/v1/authoring/reports` returning a real, owned, published row (id 1, ownerPlugin hcm-organization), and via a real authenticated Playwright session opening Studio's Report Designer for it (Data source/Fields/Sort order all correctly resolved, zero Problems) and its own live Preview tab (real band rendering: title, column headers, 5 synthetic detail rows). `erp schema validate` passes against this real file. This schema is derived directly from frontend/packages/report-engine/src/types.ts's ReportDefinition/ReportBand/ReportElement and from ReportAuthoringController/BiReportAuthoringController's shared JsonArtifactAuthoringController wrapper convention — now validated against a genuinely real, installed artifact, not only the synthetic report-definition.example.json in this same directory (still kept as a secondary fixture).",
|
|
6
|
+
"description": "A report's band/element content model — bands are a vertical stack of fixed-height Report/Page Header/Footer, Group Header/Footer, and Detail sections that repeat once per data group/row.",
|
|
7
|
+
"type": "object",
|
|
8
|
+
"required": ["name", "definition"],
|
|
9
|
+
"properties": {
|
|
10
|
+
"name": { "type": "string" },
|
|
11
|
+
"description": { "type": "string" },
|
|
12
|
+
"metadata": { "type": "object" },
|
|
13
|
+
"modules": { "type": "array", "items": { "type": "string" } },
|
|
14
|
+
"definition": {
|
|
15
|
+
"type": "object",
|
|
16
|
+
"required": ["contractVersion", "dataSource", "groupLevels", "sortLevels", "bands"],
|
|
17
|
+
"properties": {
|
|
18
|
+
"contractVersion": { "type": "number", "enum": [1] },
|
|
19
|
+
"dataSource": {
|
|
20
|
+
"type": ["object", "null"],
|
|
21
|
+
"properties": {
|
|
22
|
+
"kind": { "type": "string", "enum": ["entity"] },
|
|
23
|
+
"entityId": { "type": "number" },
|
|
24
|
+
"entityName": { "type": "string" },
|
|
25
|
+
"fields": { "type": "array", "items": { "type": "string" } }
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
"groupLevels": {
|
|
29
|
+
"type": "array",
|
|
30
|
+
"items": {
|
|
31
|
+
"type": "object",
|
|
32
|
+
"required": ["id", "field", "sortDirection"],
|
|
33
|
+
"properties": { "id": { "type": "string" }, "field": { "type": "string" }, "sortDirection": { "type": "string", "enum": ["asc", "desc"] } }
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
"sortLevels": {
|
|
37
|
+
"type": "array",
|
|
38
|
+
"items": {
|
|
39
|
+
"type": "object",
|
|
40
|
+
"required": ["field", "direction"],
|
|
41
|
+
"properties": { "field": { "type": "string" }, "direction": { "type": "string", "enum": ["asc", "desc"] } }
|
|
42
|
+
}
|
|
43
|
+
},
|
|
44
|
+
"bands": {
|
|
45
|
+
"type": "array",
|
|
46
|
+
"items": {
|
|
47
|
+
"type": "object",
|
|
48
|
+
"required": ["id", "kind", "heightPx", "elements"],
|
|
49
|
+
"properties": {
|
|
50
|
+
"id": { "type": "string" },
|
|
51
|
+
"kind": { "type": "string", "enum": ["report-header", "report-footer", "page-header", "page-footer", "group-header", "group-footer", "detail"] },
|
|
52
|
+
"groupLevelId": { "type": "string", "description": "Required for group-header/group-footer bands." },
|
|
53
|
+
"name": { "type": "string" },
|
|
54
|
+
"heightPx": { "type": "number" },
|
|
55
|
+
"visible": { "type": "boolean" },
|
|
56
|
+
"elements": {
|
|
57
|
+
"type": "array",
|
|
58
|
+
"items": {
|
|
59
|
+
"type": "object",
|
|
60
|
+
"required": ["id", "position", "content"],
|
|
61
|
+
"properties": {
|
|
62
|
+
"id": { "type": "string" },
|
|
63
|
+
"position": {
|
|
64
|
+
"type": "object",
|
|
65
|
+
"required": ["x", "y", "width", "height"],
|
|
66
|
+
"properties": { "x": { "type": "number" }, "y": { "type": "number" }, "width": { "type": "number" }, "height": { "type": "number" }, "zIndex": { "type": "number" } }
|
|
67
|
+
},
|
|
68
|
+
"content": {
|
|
69
|
+
"type": "object",
|
|
70
|
+
"required": ["kind"],
|
|
71
|
+
"properties": {
|
|
72
|
+
"kind": { "type": "string", "enum": ["literal", "block", "field"] },
|
|
73
|
+
"type": { "type": "string", "enum": ["text", "image", "shape", "line", "page-number", "date"] },
|
|
74
|
+
"properties": { "type": "object" },
|
|
75
|
+
"blockType": { "type": "string" },
|
|
76
|
+
"fieldName": { "type": "string" },
|
|
77
|
+
"format": { "type": "string" }
|
|
78
|
+
}
|
|
79
|
+
},
|
|
80
|
+
"locked": { "type": "boolean" }
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
},
|
|
87
|
+
"pageSize": { "type": "string", "enum": ["A4", "Letter", "Legal"] },
|
|
88
|
+
"orientation": { "type": "string", "enum": ["portrait", "landscape"] },
|
|
89
|
+
"margins": {
|
|
90
|
+
"type": "object",
|
|
91
|
+
"properties": { "top": { "type": "number" }, "right": { "type": "number" }, "bottom": { "type": "number" }, "left": { "type": "number" } }
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://erp-platform.dev/schema/rule-definition/v1",
|
|
4
|
+
"title": "Rule definition (contract version 1)",
|
|
5
|
+
"description": "The frozen canonical Rule JSON (Phase 3 W1-03, ADR 0008). A rule binds an event pattern to a Phase 2 action chain through the seven match dimensions and the enforced priority bands (1=Security, 5=Validation, 10=Business, 100=Notification). 'actions' entries are full Action definitions validated against the frozen Action schema (../../action-engine/schema/action-definition.schema.json); this schema constrains only their identity shape to keep the two artifacts independently versionable.",
|
|
6
|
+
"type": "object",
|
|
7
|
+
"properties": {
|
|
8
|
+
"id": { "type": "string", "minLength": 1 },
|
|
9
|
+
"name": {
|
|
10
|
+
"type": "string",
|
|
11
|
+
"minLength": 1,
|
|
12
|
+
"description": "Stable marketplace-facing name (Phase 21 §4c)."
|
|
13
|
+
},
|
|
14
|
+
"description": { "type": "string" },
|
|
15
|
+
"event": {
|
|
16
|
+
"type": "string",
|
|
17
|
+
"pattern": "^([A-Za-z*][A-Za-z0-9_-]*|\\*\\*)(\\.([A-Za-z0-9_*-]+|\\*\\*))*$",
|
|
18
|
+
"description": "Dotted event-name pattern: '*' matches one segment, trailing '**' matches any remainder."
|
|
19
|
+
},
|
|
20
|
+
"priority": {
|
|
21
|
+
"type": "integer",
|
|
22
|
+
"minimum": 1,
|
|
23
|
+
"description": "One of the band values 1/5/10/100 unless priorityOverride is true. Bands confer timing and veto rights (ADR 0008 §4): security(1) and validation(5) run synchronously pre-commit and can veto; business(10) sync; notification(100) async post-commit."
|
|
24
|
+
},
|
|
25
|
+
"priorityOverride": {
|
|
26
|
+
"type": "boolean",
|
|
27
|
+
"description": "Explicit opt-out of the band constraint. Deliberate, visible, audited."
|
|
28
|
+
},
|
|
29
|
+
"enabled": { "type": "boolean", "default": true },
|
|
30
|
+
"scope": {
|
|
31
|
+
"type": "object",
|
|
32
|
+
"description": "Match dimensions beyond event name and tenant. Unset means any.",
|
|
33
|
+
"properties": {
|
|
34
|
+
"block": { "type": "string" },
|
|
35
|
+
"form": { "type": "string" },
|
|
36
|
+
"page": { "type": "string" },
|
|
37
|
+
"workflow": { "type": "string" },
|
|
38
|
+
"role": { "type": "string" }
|
|
39
|
+
},
|
|
40
|
+
"additionalProperties": false
|
|
41
|
+
},
|
|
42
|
+
"watchedFields": {
|
|
43
|
+
"type": "array",
|
|
44
|
+
"items": { "type": "string", "minLength": 1 },
|
|
45
|
+
"description": "Fire only when one of these data fields changed between data.old and data.new (ADR 0008 §2). Fires when old/new are absent (creation)."
|
|
46
|
+
},
|
|
47
|
+
"condition": {
|
|
48
|
+
"type": "string",
|
|
49
|
+
"description": "Phase 1 expression over ${event.*} plus the ambient scopes. Boolean true fires; false/Null skips; non-Boolean/unresolvable is a distinct observable skip."
|
|
50
|
+
},
|
|
51
|
+
"suppressSelfTrigger": {
|
|
52
|
+
"type": "boolean",
|
|
53
|
+
"description": "Don't re-fire from events this rule's own actions caused (ADR 0008 §5)."
|
|
54
|
+
},
|
|
55
|
+
"actions": {
|
|
56
|
+
"type": "array",
|
|
57
|
+
"minItems": 1,
|
|
58
|
+
"description": "Phase 2 action chain(s), executed by the Action Engine with its frozen retry/timeout/error semantics.",
|
|
59
|
+
"items": {
|
|
60
|
+
"type": "object",
|
|
61
|
+
"properties": {
|
|
62
|
+
"id": { "type": "string", "minLength": 1 },
|
|
63
|
+
"type": { "type": "string", "pattern": "^[a-zA-Z][a-zA-Z0-9_-]*$" },
|
|
64
|
+
"name": { "type": "string", "minLength": 1 }
|
|
65
|
+
},
|
|
66
|
+
"required": ["id", "type", "name"]
|
|
67
|
+
}
|
|
68
|
+
},
|
|
69
|
+
"metadata": {
|
|
70
|
+
"type": "object",
|
|
71
|
+
"description": "Marketplace-publishable shape (Phase 21 §4c): version required at publish time.",
|
|
72
|
+
"properties": {
|
|
73
|
+
"version": { "type": "string" },
|
|
74
|
+
"tags": { "type": "array", "items": { "type": "string" } },
|
|
75
|
+
"author": { "type": "string" },
|
|
76
|
+
"publisher": { "type": "string" }
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
},
|
|
80
|
+
"required": ["id", "name", "event", "priority", "actions"],
|
|
81
|
+
"additionalProperties": false
|
|
82
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
3
|
+
"$id": "https://erp.internal/schema/workflow-definition.schema.json",
|
|
4
|
+
"title": "WorkflowDefinitionArtifact",
|
|
5
|
+
"description": "The REAL on-disk authoring shape for a workflow-definition JSON artifact (spk-assembly/metadata/workflow/*.json) — confirmed 2026-09-02 against live shipped files (crm-leads' lead.merge.json, hcm-employee's employee.transfer.json), not derived from the WorkflowDefinition Java record's field names alone. The Java record's own *Json columns (stagesJson/tasksJson/transitionsJson/approversJson/slasJson/escalationsJson/notificationsJson/metadataJson) are each persisted as a raw JSON string — so the artifact authors them as JSON-encoded STRINGS, not nested objects, except approvalPermissions which is a real top-level array. This schema types each *Json property as a string (its own inner shape is documented in the nested $comment/examples below since JSON Schema can't directly constrain 'this string, when parsed, matches...'). See ai/workflows/README.md's 'Domain module integration recipe'.",
|
|
6
|
+
"type": "object",
|
|
7
|
+
"required": ["name", "stagesJson", "tasksJson", "transitionsJson"],
|
|
8
|
+
"properties": {
|
|
9
|
+
"name": { "type": "string", "description": "Unique per tenant; a domain module's REST layer starts instances by this exact name, e.g. \"employee.transfer\"." },
|
|
10
|
+
"description": { "type": "string" },
|
|
11
|
+
"stagesJson": {
|
|
12
|
+
"type": "string",
|
|
13
|
+
"$comment": "Parses to a string[] of ordered stage codes, e.g. [\"manager\",\"hr\",\"finance\",\"it\"]. A single-actor self-decide flow uses [\"only\"]. Example literal value: \"[\\\"manager\\\",\\\"hr\\\"]\""
|
|
14
|
+
},
|
|
15
|
+
"tasksJson": {
|
|
16
|
+
"type": "string",
|
|
17
|
+
"$comment": "Parses to an array of {taskKey, stage, taskType, kind, payload:{approvalObject, amount, dueInSeconds}}. taskType/kind are typically \"approval\"/\"human\". approvalObject is the string approvalPermissions entries reference."
|
|
18
|
+
},
|
|
19
|
+
"transitionsJson": {
|
|
20
|
+
"type": "string",
|
|
21
|
+
"$comment": "Parses to an array of {fromStage, toStage, condition}. condition is a composable {all:[...]}/{any:[...]}/{not:...} tree or a single {field, op, value} leaf, evaluated against the instance's context (which always includes \"decision\": \"approved\"|\"rejected\" from the just-decided stage, plus whatever extraContext the submitter supplied at startInstance). A stage with no matching outgoing transition completes the instance. Example: \"[{\\\"fromStage\\\":\\\"manager\\\",\\\"toStage\\\":\\\"hr\\\",\\\"condition\\\":{\\\"field\\\":\\\"decision\\\",\\\"op\\\":\\\"eq\\\",\\\"value\\\":\\\"approved\\\"}}]\""
|
|
22
|
+
},
|
|
23
|
+
"approversJson": { "type": "string", "default": "{}", "$comment": "Legacy/reserved — real shipped workflows leave this \"{}\" and use the top-level approvalPermissions array instead." },
|
|
24
|
+
"slasJson": { "type": "string", "default": "[]" },
|
|
25
|
+
"escalationsJson": { "type": "string", "default": "[]" },
|
|
26
|
+
"notificationsJson": { "type": "string", "default": "[]" },
|
|
27
|
+
"metadataJson": { "type": "string", "default": "{}" },
|
|
28
|
+
"approvalPermissions": {
|
|
29
|
+
"type": "array",
|
|
30
|
+
"description": "Which role (by its stable role.code, never a mutable display name) may decide which named approvalObject task.",
|
|
31
|
+
"items": {
|
|
32
|
+
"type": "object",
|
|
33
|
+
"required": ["roleCode", "approvalObject"],
|
|
34
|
+
"properties": {
|
|
35
|
+
"roleCode": { "type": "string" },
|
|
36
|
+
"approvalObject": { "type": "string", "description": "Matches a tasksJson entry's payload.approvalObject." },
|
|
37
|
+
"maxAmount": { "type": ["number", "null"], "description": "Optional approval-limit gate; null for a plain non-amount-gated approval." }
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|