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>.