Project structure and source model
A Workspace UI Project is one versioned tree of UTF-8 text files stored in
the workspace database. You author everything under src/ and the project
README.md; Moltaro maintains the page manifest and owns the build toolchain
and every generated project file. Workspace UI code is trusted workspace code
compiled by Moltaro — the boundary is governance and review, not a
hostile-code sandbox.
Stored source tree
Section titled “Stored source tree”workspace-ui.jsonsrc/ pages/ components/ stores/ api/ locales/ en.json uk.json de.json pl.json es.jsonREADME.mdBesides workspace-ui.json and README.md, every file must live under
src/ and end in .vue, .ts, or .json. Reserved segments such as
node_modules, dist, build, bin, obj, and .git are rejected, as
are Windows device names and paths longer than 512 characters. Page code
goes to src/pages, shared components to src/components, Pinia stores to
src/stores, API clients to src/api, and every user-facing string to all
five locale files — see
Pages, components, and stores.
workspace-ui.json and the five files under src/locales/ are the required
system skeleton. UI Studio hides the manifest behind its typed Pages
registry and protects the locale files from rename and deletion. The
manual-edit and archive APIs still include the physical manifest as the
portable source contract, but they do not permit renaming or deleting required
system files. README.md and ordinary page, component, store, and client files
remain author-owned. A manifest with an empty Pages array is a valid empty
project; Check and Build do not require a placeholder page.
The manifest
Section titled “The manifest”workspace-ui.json is declarative page metadata, not code. In UI Studio, edit
this metadata through Pages: choose a component, title key, icon,
Default or Fullscreen layout, optional nested route, and required
permissions. Saving creates a new immutable revision. Removing a registration
does not delete its source or localization files.
For ZIP and Configuration API authoring, FormatVersion is required and
currently 1. Each entry in Pages declares one runtime page that end users
open at /apps/<pageKey>:
{ "FormatVersion": 1, "Pages": [ { "Key": "record-details", "Component": "src/pages/RecordDetailsPage.vue", "TitleKey": "pages.record-details.title", "Icon": "mdi-card-account-details-outline", "Layout": "Default", "RequiredPermissions": [], "Route": { "Path": "entities/:entityId/instances/:instanceId" } } ]}Keyis the stable route and runtime identity of the page.Componentmust resolve to one.vuefile insidesrc/pages.TitleKeymust exist in all supported locale files.Iconuses the standardmdi-icon naming.LayoutisDefault(standard app shell) orFullscreen(the page owns the viewport). A missing or unknown value is a build error, never an implicit fallback.RequiredPermissionsentries are normalized and deduplicated; unknown keys produce build diagnostics instead of being silently ignored.Route.Pathis optional and declares sub-routes below the page: a relative path of lowercase kebab-case literals and named:parametersegments, without leading or trailing slashes, duplicate parameter names, or query/hash characters.
The manifest cannot declare arbitrary route prefixes, navigation sections, script URLs, stylesheets, or external origins.
Platform-owned generated files
Section titled “Platform-owned generated files”package.json, lockfiles (package-lock.json, pnpm-lock.yaml,
yarn.lock), tsconfig*.json, vite.config.*, eslint.config.*, and the
host type declarations (env.d.ts) are generated by Moltaro and are never
part of the stored source. A Studio or API save that targets one of these
paths is rejected as unsupported; a ZIP upload that contains them simply
ignores those entries and imports only the source files.
Source limits
Section titled “Source limits”Source is text only and must be strictly valid UTF-8; files containing binary data are rejected. A project holds at most 500 files, at most 512 KiB per file, and at most 5 MiB of total source.
Immutable revisions
Section titled “Immutable revisions”Source history is a sequence of immutable revisions: every save, upload, or template application creates a new revision with a checksum of the canonical source tree, and existing revisions are never edited in place. Each revision records how it was created:
| Source kind | Created by |
|---|---|
Provisioned | Moltaro creation of the empty required source skeleton |
ArchiveUpload | An uploaded ZIP source archive |
ManualEdit | Manual edits through UI Studio or the API |
TemplateApply | Applying a source template or the Page Wizard |
File changes carry the expected content hash of the file they replace, so
concurrent edits fail with a conflict instead of overwriting each other.
Disposable revisions can be deleted through
DELETE /api/workspace/admin/ui-project/revisions/{revisionId}.
Editing flows
Section titled “Editing flows”UI Studio (Constructor area, group Automation & logic, route
/business-logic/ui-development, requires the Manage source permission)
edits the stored tree directly. Create page opens the Page Wizard as the
primary authoring action; generic blank-file creation is not offered. Advanced
source templates remain available from the overflow menu. Save creates a
manual-edit revision via
POST /api/workspace/admin/ui-project/source-revisions/manual-edit, while
save and check and save and build live in the adjacent Save menu and
additionally queue through
POST /api/workspace/admin/ui-project/builds. Queuing requires the
RevisionId of an immutable revision — Kind 0 is a Check (validate
only, no artifact) and Kind 1 is a Build that produces an inactive
immutable artifact. The persistent Draft — publish required status opens
UI Project and remains until the working revision’s artifact is active.
Activation is a separate explicit step described in
Build, publish, and upgrade.
UI Project (route /business-logic/ui-project) owns the ZIP round
trip. GET /api/workspace/admin/ui-project/download returns a
deterministic ZIP of the stored source — the same revision always downloads
byte-identical source — plus a pinned, generated IDE scaffold for local
Vue-aware editing. POST /api/workspace/admin/ui-project/upload imports
only the allowed source files as one immutable ArchiveUpload revision and
never queues a build automatically. Because source is delivered to browsers
at runtime, never place confidential external API secrets in it — see
Calling external APIs.
Source templates
Section titled “Source templates”GET /api/workspace/admin/ui-project/source-templates lists ten
deterministic templates, previewed and applied through
.../source-templates/preview and .../source-templates/apply:
workspace-ui-page— a minimal page component.workspace-ui-page-logic— ause<Name>Pagecomposable.workspace-ui-component— a shared component insrc/components.workspace-ui-pinia-store— a namespaced Pinia store.workspace-ui-moltaro-api-client— a typed Moltaro API client module.workspace-ui-command-client— a typed, abortable client for one published synchronous C# command.workspace-ui-function-job-client— typed enqueue and bounded-wait helpers for one published C# background function.workspace-ui-external-api-client— an external HTTP client module.workspace-ui-locale-section— a page locale section in all five files.workspace-ui-page-starter— a complete page: component, page logic, store, both API clients, locale sections, and a manifest entry with the parameterized routeentities/:entityId/instances/:instanceId(both named parameters are required). This advanced template is applied only when an author explicitly selects it; workspace provisioning never applies it.
Template keys are kebab-case (up to 64 characters) and drive generated file
names such as src/pages/<Name>Page.vue and src/stores/<key>Store.ts.
The Page Wizard
Section titled “The Page Wizard”The Page Wizard on the UI Studio surface is a guided front end over the
page-generator endpoints (.../page-generators/catalog, .../preview,
.../apply). It supports four kinds: Blank (empty page scaffold),
Entity list (a grid page over a selected entity), Entity details
(a single-record page), and External API example with the Frankfurter
exchange-rates preset that calls the public Frankfurter currency API. Every
generation is previewed as an exact file diff, applies as one
TemplateApply revision, and can optionally place the page as a root leaf
in a user menu for eligible
administrators. After generation, build the draft from the Save menu, open UI
Project from the Draft status, and activate the resulting artifact.