Skip to content

Build, publish, and upgrade

The Workspace UI Project separates three deliberate steps: check the source, build an immutable artifact, and activate that artifact for end users. A save is not a deploy and a successful build is not a release. Workspace UI code is trusted workspace code compiled by Moltaro — the boundary is governance and review (permissions, immutable revisions, audited activation), not a hostile-code sandbox.

Everything on this page is available in the Constructor area — UI Studio (/business-logic/ui-development) and UI Project (/business-logic/ui-project), group Automation & logic — and through the admin API under /api/workspace/admin/ui-project, part of the Configuration API. UI Studio shows Draft — publish required whenever its working revision is not the active artifact. That status opens UI Project, so the path from a newly created page to Build and Activate remains visible without relying on hidden toolbar actions.

POST /builds queues one operation for one immutable source revision. The request requires a RevisionId — there is no implicit “latest source” build — and a Kind:

  • Check (Kind = 0) validates the revision through the compile pipeline and produces no artifact.
  • Build (Kind = 1) runs the same pipeline and stores a successful result as an inactive immutable artifact.

Builds run in the background; the build record reports Status (Queued, Running, Succeeded, Failed, Cancelled), Stage, and ProgressPercent. Structured compiler diagnostics stay attached to the build record — code, severity, stage, message, path, and line/column positions — so a failure is inspectable later without re-running it. A failed check or build never replaces the active artifact: whatever users currently see keeps running.

Exactly one artifact is active at a time. A successful build changes nothing for end users until a caller with the Publish permission activates the artifact. Activation is audited, is rejected for artifacts that do not match the current host contract, and returns RefreshRequired — already-open sessions keep the previous UI until a full WebApp refresh, while new sessions load the new artifact. Active pages are served under /apps/<pageKey> as “Workspace page” and can be linked from user menus as “Workspace UI page” leaves (see User menus).

Three more lifecycle operations complete the picture:

  • Deactivate takes the currently active artifact out of service; end-user pages become unavailable until another activation.
  • Rollback restores a compatible previously published artifact — the fast path back when a release misbehaves.
  • Purge deletes the stored JavaScript/CSS bytes of an inactive artifact while retaining its history metadata (hashes, sizes, versions, publisher).

Artifact state changes carry expected project and artifact row versions and fail with a conflict when concurrent administration changed state first.

Each artifact records the WebApp version, host contract version, and toolchain fingerprint it was built with. GET /compatibility reports whether the packaged build toolchain and runtime contract are ready and, with ?artifactId=, whether one stored artifact still matches the current host contract (IsCompatible, CanActivate, CanRollback, plus safe localized diagnostics).

After a Moltaro update, the active artifact may no longer match the new host contract. Source revisions are stored server-side, so the remedy is a rebuild from the stored source followed by a new activation. A breaking host-contract change can additionally require source edits before the rebuild succeeds; the check pipeline and its diagnostics report exactly what broke.

If the active artifact is runtime-incompatible, only its custom /apps/* pages are unavailable; core Moltaro remains usable. Fix any source diagnostics, run Build, review the newly stored inactive artifact, Activate explicitly, and then perform a full browser refresh. Failed or stale checks/builds preserve the source revisions, history, and prior artifact, and no update or build auto-activates output.

All routes live under /api/workspace/admin/ui-project and are gated by the Workspace UI Project permission group — View, Manage source, Build, Publish. Owner, Admin, and Configurator hold all of them implicitly.

EndpointPermissionPurpose
GET /statusany of the groupProject status; provisions the empty six-file system skeleton for source-capable callers
GET /revisions, GET /revisions/{revisionId}View, Manage source, or BuildImmutable source revisions, newest first
GET /source-treeManage sourceSource-tree metadata for one revision
GET /source-filesManage sourceOne UTF-8 source file by revision and path
POST /source-revisions/manual-editManage sourceCreate one immutable manual-edit revision
GET /source-templatesManage sourceDeterministic source templates
POST /source-templates/preview, POST /source-templates/applyManage sourcePreview, or apply a template as one revision
GET /page-generators/catalogManage sourceTyped page-generator, entity-field, and working-page capabilities
POST /page-generators/preview, POST /page-generators/applyManage sourcePreview or apply one generated page; menu placement needs a trusted role
DELETE /revisions/{revisionId}Manage sourceDelete a disposable revision and its non-artifact build history
GET /downloadManage sourceDeterministic source and generated IDE-project ZIP
POST /uploadManage sourceUpload a ZIP as one immutable revision, without auto-queuing a build
GET /builds, GET /builds/{buildId}View or BuildCheck and build history with diagnostics
POST /buildsBuildQueue a check or build for one revision
POST /builds/{buildId}/cancelBuildRequest cancellation of a queued or running build
GET /artifacts, GET /artifacts/{artifactId}View or PublishStored artifacts, newest first
GET /compatibilityView or PublishToolchain, runtime-contract, and optional artifact compatibility
POST /artifacts/{artifactId}/activatePublishActivate one compatible inactive artifact
POST /artifacts/{artifactId}/deactivatePublishDeactivate the currently active artifact
POST /artifacts/{artifactId}/rollbackPublishRoll back to a compatible previously published artifact
POST /artifacts/{artifactId}/purgePublishPurge bytes from an inactive artifact, retaining history metadata

The full authoring loop works headlessly with a service-account API key sent as Authorization: Bearer <api-key> (see the integration quickstart). Enums are serialized as numbers; the OpenAPI document names each value through x-enum-varnames.

1. Read the project state (View). GET /status returns the project status and, for source-capable callers, provisions only workspace-ui.json plus the five empty locale files on first call. It never creates sample pages, stores, clients, translations, or a README.

2. Read the source (Manage source). GET /source-tree lists file metadata for the working or a requested revision; GET /source-files?path=src/pages/MachineStatusPage.vue returns one UTF-8 file.

3. Edit (Manage source). Create an immutable revision from file changes:

POST /api/workspace/admin/ui-project/source-revisions/manual-edit
Authorization: Bearer <api-key>
Content-Type: application/json
{
"BaseRevisionId": "0197f2…",
"BaseSourceChecksum": "5f8a…",
"Comment": "Add machine status page",
"Changes": [
{ "Operation": 0, "Path": "src/pages/MachineStatusPage.vue",
"ContentUtf8": "<template>…</template>" }
]
}

Operation 0 upserts, 1 renames (with NewPath), 2 deletes. Alternatives that also produce one immutable revision: POST /source-templates/apply, POST /page-generators/apply, or POST /upload with a ZIP. Each response — like GET /revisions — carries the new revision Id.

4. Check, then build (Build). RevisionId is required; a null value is rejected. Queue a check first ("Kind": 0), and once it passes, a build:

{ "RevisionId": "0197f3…", "Kind": 1 }

The response is the queued build record with its Id.

5. Poll the build (View or Build). GET /builds/{buildId} until Status is 2 (Succeeded), 3 (Failed), or 4 (Cancelled). On failure, read the attached diagnostics:

{
"Status": 3,
"ErrorSummary": "1 error",
"Diagnostics": { "Diagnostics": [
{ "Code": "TS2304", "Severity": 2, "Message": "Cannot find name 'refx'.",
"Path": "src/pages/useMachineStatusPage.ts", "StartLine": 12 }
] }
}

6. Find the artifact (View or Publish). GET /artifacts lists stored artifacts newest first; match the new one by its BuildId and RevisionId. It is inactive until published.

7. Activate (Publish):

POST /api/workspace/admin/ui-project/artifacts/{artifactId}/activate
{ "ExpectedProjectRowVersion": "…", "ExpectedArtifactRowVersion": "…" }

The result reports RefreshRequired: true.

8. Tell users to refresh. Open sessions keep the previous UI until a full WebApp refresh; after refreshing, users see the new pages under /apps/<pageKey>.

An authoring declaration update can change the host fingerprint even while HostContractVersion remains 1. For example, the typed grid getColumnState() method and the embedded-component contract (Components registration, useComponentContext()) each required an updated declaration. After installing the corresponding Moltaro build, refresh the IDE project files, check and rebuild existing source, activate the compatible artifact, and fully refresh the browser. Do not change fingerprints manually or reuse an older artifact to bypass compatibility validation. Template improvements do not rewrite your saved source; copy the required explicit attach bindings into existing pages.