Skip to main content

Integrator guide — authoring a virtual app by hand

This guide walks you through creating a new virtual app in OpenBuilt without using the visual editor (which lives in chain spec openbuilt-page-editor — not yet shipped). At this stage, OpenBuilt is integrator-only: you write JSON and the runtime renders it.

What you author

A virtual app is one record in OpenBuilt's Application OR schema. The shape is:

{
"slug": "permit-tracker", // kebab-case, 2–48 chars
"name": "Permit Tracker",
"description": "Track building permits through review stages.",
"version": "0.1.0",
"status": "draft", // draft → published → archived
"manifest": {
"version": "1.0.0",
"dependencies": ["openregister"],
"menu": [ ... ],
"pages": [ ... ]
}
}

The manifest object validates against @conduction/nextcloud-vue/src/schemas/app-manifest.schema.json. The closed type enum for pages is index | detail | dashboard | logs | settings | chat | files | form | custom.

Step-by-step

  1. Pick a slug. Must be kebab-case, 2–48 chars, unique within your organisation. The synthetic appId in CnAppRoot becomes openbuilt-${slug}.
  2. Design your schemas in OpenRegister directly (the OpenBuilt schema editor lands in chain spec openbuilt-schema-editor). At minimum: one schema per primary entity your app shows.
  3. Author the manifest as JSON. The canonical example is the seeded hello-world Application — open it in OpenBuilt's manifest editor (top-bar OpenBuilt entry → Virtual apps → hello-world) and read its manifest.
  4. Save as draft while iterating. The textarea editor validates each save against the canonical schema; you see the failing JSON path on save error.
  5. Transition to published when ready (via OR's lifecycle endpoint or the editor's Publish action — landing in chain spec openbuilt-versioning). On publish, OpenBuilt's lifecycle creates the corresponding BuiltAppRoute so /builder/{slug} becomes reachable.

Manifest checklist

Per ADR-024:

  • version (semver) — your app's content version
  • dependencies — list of NC app IDs that must be installed (almost always ["openregister"])
  • menu[] — at least one entry; supports one level of children[]
  • pages[] — at least one entry; every page's id MUST be unique and match a vue-router route name
  • label / title strings are i18n KEYS, not literals. The consuming app's t() resolves them. Use kebab.dot.notation: myapp.permits.title.list.

Per ADR-007:

  • Every translation key MUST exist in l10n/en.json AND l10n/nl.json of the OpenBuilt repo (until per-virtual-app translations land in chain spec openbuilt-page-editor).

Reading the seed manifest

The seeded hello-world Application is the canonical reference. Its manifest exercises:

  • index page → drives CnIndexPage with register: openbuilt, schema: hello-message, three columns
  • detail page → drives CnDetailPage keyed on :id
  • form page → drives CnFormPage with mode: create and submitEndpoint going to OR's REST

See lib/Repair/SeedHelloWorld.php buildHelloWorldManifest() for the full JSON.

When you hit a limit

The closed type enum can't be extended from a manifest — adding a new page type requires a library-level openspec change in @conduction/nextcloud-vue. If you need something the four built-in types can't express:

  1. Confirm the requirement isn't satisfied by form (the most flexible built-in).
  2. Open an issue on ConductionNL/nextcloud-vue describing the new page type's shape.
  3. As an interim, mount a custom Vue component via type: "custom" + component: "MyCustomPage" and register the component in OpenBuilt's customComponents map. (Note: spec #1 only ships the built-in types — the customComponents registry surface lands when a real consumer needs it.)

What does NOT work yet (spec #1 limitations)

  • No visual editor — JSON textarea only. Visual editor: chain spec openbuilt-page-editor.
  • No schema designer — schemas must be authored in lib/Settings/openbuilt_register.json and imported via the repair step. Runtime schema authoring: chain spec openregister-runtime-schema-api.
  • No draft preview — only published apps appear at /builder/{slug}. Draft preview: chain spec openbuilt-versioning.
  • No per-app permissions — auth-only visibility for v1; everyone in your organisation sees every virtual app. Per-app RBAC: chain spec openbuilt-rbac.
  • No export to a real Nextcloud app — virtual-only. Export pipeline: chain spec openbuilt-export-to-real-app.

If any of these limitations block your project, talk to Conduction — chain spec prioritisation can shift.