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.
Checks and builds
Section titled “Checks and builds”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.
Explicit activation
Section titled “Explicit activation”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.
Compatibility after a Moltaro update
Section titled “Compatibility after a Moltaro update”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.
Endpoints and permissions
Section titled “Endpoints and permissions”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.
| Endpoint | Permission | Purpose |
|---|---|---|
GET /status | any of the group | Project status; provisions the empty six-file system skeleton for source-capable callers |
GET /revisions, GET /revisions/{revisionId} | View, Manage source, or Build | Immutable source revisions, newest first |
GET /source-tree | Manage source | Source-tree metadata for one revision |
GET /source-files | Manage source | One UTF-8 source file by revision and path |
POST /source-revisions/manual-edit | Manage source | Create one immutable manual-edit revision |
GET /source-templates | Manage source | Deterministic source templates |
POST /source-templates/preview, POST /source-templates/apply | Manage source | Preview, or apply a template as one revision |
GET /page-generators/catalog | Manage source | Typed page-generator, entity-field, and working-page capabilities |
POST /page-generators/preview, POST /page-generators/apply | Manage source | Preview or apply one generated page; menu placement needs a trusted role |
DELETE /revisions/{revisionId} | Manage source | Delete a disposable revision and its non-artifact build history |
GET /download | Manage source | Deterministic source and generated IDE-project ZIP |
POST /upload | Manage source | Upload a ZIP as one immutable revision, without auto-queuing a build |
GET /builds, GET /builds/{buildId} | View or Build | Check and build history with diagnostics |
POST /builds | Build | Queue a check or build for one revision |
POST /builds/{buildId}/cancel | Build | Request cancellation of a queued or running build |
GET /artifacts, GET /artifacts/{artifactId} | View or Publish | Stored artifacts, newest first |
GET /compatibility | View or Publish | Toolchain, runtime-contract, and optional artifact compatibility |
POST /artifacts/{artifactId}/activate | Publish | Activate one compatible inactive artifact |
POST /artifacts/{artifactId}/deactivate | Publish | Deactivate the currently active artifact |
POST /artifacts/{artifactId}/rollback | Publish | Roll back to a compatible previously published artifact |
POST /artifacts/{artifactId}/purge | Publish | Purge bytes from an inactive artifact, retaining history metadata |
Authoring through the API
Section titled “Authoring through the API”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-editAuthorization: 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>.