Skip to main content

Solution Package

Schema id: solution-package@1 Machine-readable schema: solution-package.schema.json

The canonical, plain-text representation of an exported Solution. A Solution package is the unit of environment promotion: it is produced by exporting a Solution from a source environment and consumed by importing it into a target environment. The package is self-describing — it carries both the manifest (which components the Solution contains) and the embedded canonical definitions of every Model-Driven component, so an import re-creates real entities, forms, views, and plugin steps rather than dangling references.

Validation is enforced identically for every origin: a package built by the export tool, submitted by an API call, or generated by an AI assistant is validated against this same schema before the deployment pipeline touches the target environment. A hand-written or generated file that conforms to this schema is safe to import.

Shape​

A package is a JSON object with these members:

FieldTypeRequiredNotes
formatVersionintegeryesThe package format version. Currently 1.
publisherNamestringyesThe owning publisher's display name.
publisherPrefixstringyesThe publisher's short lower-case prefix (e.g. par). Recreated on import if absent in the target tenant.
solutionNamestringyesThe Solution's name.
versionstringyesSemantic version major.minor.patch (e.g. 1.0.0).
descriptionstring | nullnoOptional Solution description.
requiresarray | nullnoThe solutions this one is built on: { solutionName, minVersion? }. Checked against the target environment before anything is written; a missing or older one refuses the import.
componentsarrayyesThe manifest: one entry per component (type + logical name).
modelComponentsobjectyesThe embedded canonical definitions, grouped by type.
customAppsarray | nullnoEmbedded Custom App manifests. Optional so packages produced before Custom Apps existed still validate; each item is additionally validated against custom-app-manifest@1 at materialization.
webResourcesarray | nullnoEmbedded Web Resources (Section 6.15): application files stored in the database, each carrying its content (UTF-8 text for text types, Base64 for binary). Optional so older packages still validate; each item's metadata is re-validated against web-resource-manifest@1 and its content hash-checked at materialization.
customControlsarray | nullnoEmbedded Custom Controls (§28), each carrying its whole build archive Base64-encoded, so a control's code moves with the solution rather than being fetched from an external host. Each item's manifest is additionally validated against custom-control-manifest@1 at materialization, and its archive checked against the declared contentHash — the point at which the code that was reviewed and the code that runs are shown to be the same.

Manifest component (components[])​

FieldTypeRequiredNotes
componentTypestringyesOne of Entity, Form, View, App, CustomApp, CustomControl, Process, Report, WebResource, PolicyDefinition, SecurityRole, SavedQuery, Dashboard, BusinessRule, Script. (App is a Model-Driven App's site map; CustomApp is a hand-written React app.)
logicalNamestringyesPublisher-prefixed; lower-case, allowing _, ., /, - for path-like Web Resource names (e.g. par_invoice, par_/dashboard/app.js).
componentReferenceIdstring | nullnoThe component's own id in its subsystem, if any.

Embedded definitions (modelComponents)​

An object with arrays of component-definition entries — entities, forms, views, pluginSteps, and the optional apps (Model-Driven Apps). Ordering carries dependency intent: entities are materialized first, then forms/views/plugin steps, then apps (whose navigation references entities by logical name). apps is optional so a package produced before apps travelled still validates and imports.

seedData (optional) is the one list whose entries are rows rather than definitions: one seed-data@1 document per table — the table's logical name in both the logicalName and entity slots — holding the rows the table's Seed Data view returned on export. An import materializes it last of all and upserts each row by its id through the ordinary record write path, writing only the columns the row carries and never deleting; a row the target refuses is skipped and named in the import's status detail. See Ship seed data with a solution.

FieldTypeRequiredNotes
logicalNamestringyesThe component's logical name.
entitystringyesThe owning entity's logical name (the entity's own name, for an entity).
jsonstringyesThe component's canonical JSON definition (an entity definition, form, view, or plugin-step wrapper — each validated against its own schema at materialization).
isDefaultbooleannoFor forms/views: whether this is the entity's default.

One validation path. The json payload of each embedded component is not re-validated by this package schema; instead each is validated against its own published schema (for example Model-Driven Entity Definition, Form, View, Plugin Step) as it is materialized — the same check a designer save performs.

Example​

{
"formatVersion": 1,
"publisherName": "Parsware",
"publisherPrefix": "par",
"solutionName": "Sales",
"version": "1.0.0",
"description": "Core sales entities.",
"components": [
{ "componentType": "Entity", "logicalName": "par_invoice" },
{ "componentType": "Form", "logicalName": "par_invoice_main" }
],
"modelComponents": {
"entities": [
{ "logicalName": "par_invoice", "entity": "par_invoice", "json": "{ ...entity definition... }" }
],
"forms": [
{ "logicalName": "par_invoice_main", "entity": "par_invoice", "json": "{ ...form definition... }", "isDefault": true }
],
"views": [],
"pluginSteps": []
}
}

How it is used​

  • Export reads the manifest and the real definitions from a source environment, producing a package at GET /solutions/{id}/export?sourceEnvironmentId=….
  • Import validates the package against this schema, resolves dependencies (every form/view/plugin-step must target an entity bundled in the package), passes any approval gate, then materializes the components into the target environment's isolated schema — at POST /solution-imports.

Versioning​

Older schema versions are kept alongside new ones so already-deployed Solutions keep validating after the schema evolves. A breaking change is published as a new version (solution-package@2) rather than editing this one; a package carries its own formatVersion so the pipeline can reject a version it does not support.