12 KiB
SCHEMA.md
Conductor Project JSON Schema
This document describes the canonical JSON schema for Conductor project definitions and explains how to use it.
Location
shared/schemas/conductor-project.schema.json
The schema lives in shared/ so it is accessible to both the backend (Node.js/TypeScript) and any future frontend tooling without duplicating the file.
Purpose
Every Conductor project is represented as a single structured JSON document — the project definition. This document is the authoritative source of truth for a project. All editors (Visual Editor, JSON Editor) read from and write to this document. The backend persists it as-is to SQLite.
The JSON schema:
- Documents the exact shape of a valid project definition.
- Enables offline validation during development.
- Drives IDE autocomplete and inline error highlighting when
$schemais set in a project file. - Is used by the backend validation/persistence endpoints to reject malformed saves atomically.
- Makes project definitions portable, diffable in Git, and importable/exportable.
Schema Version
The current schema version is 0.1.0 (semver).
Every project definition must include a schemaVersion field:
{
"schemaVersion": "0.1.0",
"project": { ... }
}
Consumers (backend, editor, preview runtime) must check the MAJOR version component. A document with a higher major version than the consumer understands should be rejected with a clear error.
Top-Level Structure
| Field | Type | Required | Description |
|---|---|---|---|
schemaVersion |
string |
✅ | Schema version in MAJOR.MINOR.PATCH format. |
project |
object |
✅ | Root project object containing all definitions. |
project Fields
| Field | Type | Required | Description |
|---|---|---|---|
id |
string |
✅ | Stable unique identifier (UUID or URL-safe slug). Must not change. |
name |
string |
✅ | Human-readable display name (1–200 characters). |
description |
string |
— | Optional free-text description. Defaults to "". |
pages |
array |
✅ | Ordered non-empty list of Page objects. |
actions |
array |
✅ | Project-level REST action definitions. May be empty. |
bindings |
array |
✅ | Project-level binding definitions. May be empty. |
variables |
object |
✅ | Named global or page-scoped declarations. May be empty ({}). |
settings |
object |
✅ | Project display and canvas settings. May be empty ({}). |
Key Sub-Types
Page
Represents one view in the project. Required fields: id, name, components.
{
"id": "page_home",
"name": "Home",
"slug": "home",
"showInNavigation": true,
"description": "",
"order": 0,
"components": [],
"events": []
}
Page slugs are unique URL-safe segments. Older documents may omit them; the runtime derives a deterministic slug. showInNavigation: false hides a page from automatic navigation but is not authorization. project.settings.defaultPageId selects the base-route page; otherwise the first ordered page is the compatibility default. Page events support onLoad (first visit in the loaded session) and onEnter (return visits).
Component
A UI element placed on a page canvas. Required fields: id, type, name, position, size.
Allowed type values:
Button · TextInput · TextArea · Dropdown · Checkbox · RadioGroup · Label · Table · JsonViewer · StatusPanel · Container
{
"id": "cmp_launch_btn",
"type": "Button",
"name": "launchButton",
"position": { "x": 24, "y": 284 },
"size": { "width": 160, "height": 44 },
"properties": {
"label": "Launch Workflow",
"visible": true,
"disabled": false
},
"events": [
{
"event": "onClick",
"navigateToPageId": "page_results"
}
],
"bindings": []
}
ComponentEvent.inputMap is retained in schema version 0.1.0 for compatibility
but is not consumed by Preview. Request values are configured in REST action
templates using {{components.<name>.value}} or {{variables.<name>}}.
Visual request-input authoring must write those executed request fields.
Action (REST Action)
A REST API call definition. Required fields: id, name, method, url, authenticationType.
Allowed method values: GET · POST · PUT · PATCH · DELETE
Allowed authenticationType values: anonymous · bearerToken · basicAuth · apiKeyHeader · apiKeyQueryParameter. Credential-backed actions use secretReferenceId, an opaque ID resolved only by the backend; anonymous actions omit it.
{
"id": "action_trigger_workflow",
"name": "Trigger Workflow",
"description": "Calls the Concert RIA API to trigger a workflow run.",
"method": "POST",
"url": "https://api.example.com/workflows/run",
"headers": {
"Content-Type": "application/json",
"Accept": "application/json"
},
"queryParameters": {
"environment": "{{components.environment.value}}"
},
"pathParameters": {
"workflowId": "configured-static-id"
},
"bodyTemplate": "{\"requestedBy\": \"{{variables.currentUser}}\"}",
"authenticationType": "bearerToken",
"secretReferenceId": "opaque-server-secret-id"
}
New response mappings belong in top-level project.bindings, not inside the action:
{
"id": "bind_trigger_status",
"source": "actions.action_trigger_workflow.response.body.data.status",
"target": "variables.lastStatus",
"trigger": "onSuccess"
}
Security note: Never store actual secret values (passwords, tokens, API keys) in the project definition. The
authenticationTypefield declares the authentication strategy only; the backend resolves credentials from server-side secrets at execution time.
REST Action Fields
| Field | Type | Required | Description |
|---|---|---|---|
id |
string |
✅ | Unique identifier within the project. |
name |
string |
✅ | Human-readable action name shown in the Actions panel. |
description |
string |
— | Optional description of what this action does. |
method |
string |
✅ | HTTP method: GET, POST, PUT, PATCH, or DELETE. |
url |
string |
✅ | Target URL; may use executed component/variable templates. |
headers |
object |
— | Request headers; values may use executed templates. |
queryParameters |
object |
— | Query parameters; values may use executed templates. |
pathParameters |
object |
— | Static path substitutions; runtime templates are not supported here. |
bodyTemplate |
string |
— | Request body string with component/variable templates. |
authenticationType |
string |
✅ | Authentication strategy (see allowed values above). Credentials are never stored here. |
responseMapping |
array |
— | Deprecated legacy action-local mappings. New mappings use top-level project.bindings. |
REST actions do not have a configurable timeout field in schema version
0.1.0. The backend applies a fixed 30-second execution timeout to every
proxied request. A configurable timeout is deferred until the proxy-policy work
can define safe minimum and maximum limits consistently.
Binding
Declares data flow between a source and a target. Required fields: id, source, target.
{
"id": "bind_status_panel",
"source": "variables.lastRunStatus",
"target": "components.statusPanel.message",
"trigger": "onChange"
}
Variable
A named global or page variable. Required field: type. Omitted scope means global for compatibility; scope: "page" requires a valid owning pageId.
Allowed type values: string · number · boolean · object · array
{
"lastRunStatus": {
"type": "string",
"scope": "page",
"pageId": "page_home",
"defaultValue": "",
"description": "Status returned by the most recent workflow trigger."
}
}
ProjectSettings
Optional canvas and display configuration.
{
"theme": "system",
"defaultPageId": "page_home",
"canvasWidth": 1280,
"canvasHeight": 900
}
Example Files
| File | Description |
|---|---|
examples/project-definitions/valid-minimal.json |
Smallest valid project definition (one empty page). |
examples/project-definitions/valid-full.json |
Full example: Concert Workflow Launcher with all features. |
examples/project-definitions/valid-rest-actions.json |
Showcases all five authentication types across seven REST actions. No canvas components — validates the action model in isolation. |
examples/project-definitions/valid-visual-rest-actions.json |
Slice 2 visual-authoring fixture covering anonymous GET/POST request fields. |
examples/project-definitions/invalid-missing-required.json |
Intentionally invalid document showing schema errors. |
Validation
Using ajv-cli (recommended)
Install once globally or run via npx:
# Install globally
npm install -g ajv-cli ajv-formats
# Validate a valid document — should print: valid
ajv validate \
-s shared/schemas/conductor-project.schema.json \
-d examples/project-definitions/valid-minimal.json \
--spec=draft2020
# Validate the full example
ajv validate \
-s shared/schemas/conductor-project.schema.json \
-d examples/project-definitions/valid-full.json \
--spec=draft2020
# Validate the REST actions showcase (all five auth types)
ajv validate \
-s shared/schemas/conductor-project.schema.json \
-d examples/project-definitions/valid-rest-actions.json \
--spec=draft2020
# Validate the intentionally invalid document — should print validation errors
ajv validate \
-s shared/schemas/conductor-project.schema.json \
-d examples/project-definitions/invalid-missing-required.json \
--spec=draft2020
Using VS Code
- Open any example
.jsonfile. - The
"$schema"field at the top of the file points to the schema. - VS Code will underline validation errors inline and provide autocomplete.
In the Backend (future — Step 11)
The backend will use ajv at runtime to validate project definitions on save:
import Ajv from 'ajv';
import schema from '../../shared/schemas/conductor-project.schema.json';
const ajv = new Ajv({ strict: true });
const validate = ajv.compile(schema);
function validateProjectJson(doc: unknown): string[] {
const valid = validate(doc);
if (valid) return [];
return (validate.errors ?? []).map(e => `${e.instancePath} ${e.message}`);
}
This is documented here for reference. The validation endpoint itself is not part of Step 7.
Versioning Policy
| Change type | Version bump |
|---|---|
| Add optional field | MINOR |
| Add required field or remove existing field | MAJOR |
| Change allowed enum values | MAJOR |
| Clarify description with no structural change | PATCH |
Schema Stability
The schema is currently at 0.x (pre-stable). Breaking changes may occur between minor versions until 1.0.0 is declared.