# 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 `$schema` is 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: ```json { "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`. ```json { "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` Component names are schema-unique within a page. Because runtime template and binding paths do not carry a page ID, use project-wide unique names in authored applications to avoid ambiguous references. ```json { "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..value}}` or `{{variables.}}`. 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. ```json { "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: ```json { "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 `authenticationType` field 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` | — | Values substituted into matching bare URL placeholders; runtime component/variable templates are resolved before backend substitution. | | `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`. ```json { "id": "bind_status_panel", "source": "actions.action_trigger_workflow.response.body.status", "target": "components.statusPanel.value", "trigger": "onSuccess" } ``` Action-response bindings support `actions..response[.body.]` sources with `onSuccess`. Table selection uses `components..selectedRow` with `onChange`. Component targets are checked for compatible `.value`, Dropdown `.options`, or Table `.rows` properties. A `variables.` target must be declared, but v1.0.0 assigns its response value without runtime type coercion or enforcement. ### `Variable` A named global or page variable. Required field: `type`. Omitted `scope` means `global` for compatibility; `scope: "page"` requires a valid owning `pageId`. Page scope records the intended owner, but v1.0.0 does not enforce that ownership across every template or binding reference. Allowed `type` values: `string` · `number` · `boolean` · `object` · `array` ```json { "lastRunStatus": { "type": "string", "scope": "page", "pageId": "page_home", "defaultValue": "", "description": "Status returned by the most recent workflow trigger." } } ``` ### `ProjectSettings` Optional canvas and display configuration. ```json { "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`: ```bash # 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 1. Open any example `.json` file. 2. The `"$schema"` field at the top of the file points to the schema. 3. VS Code will underline validation errors inline and provide autocomplete. ### In Conductor The backend applies this schema plus the semantic rules in [Project Validation](VALIDATION.md) before create, update, save, load acceptance, and publication. The JSON Editor uses the same validation contract before Apply. Validation failures leave the last valid project and stored row unchanged. > 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.