# 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 `$schema` is set in a project file. - Will be used by the backend's validation endpoint (Step 11) to reject malformed saves. - 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 list of `Page` objects. May be empty. | | `actions` | `array` | ✅ | Project-level REST action definitions. May be empty. | | `bindings` | `array` | ✅ | Project-level binding definitions. May be empty. | | `variables` | `object` | ✅ | Named global variable 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", "description": "", "order": 0, "components": [], "events": [] } ``` ### `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` ```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", "actionId": "action_trigger_workflow" } ], "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/{{workflowId}}/run", "headers": { "Content-Type": "application/json", "Accept": "application/json" }, "queryParameters": { "environment": "{{environment}}" }, "pathParameters": { "workflowId": "{{workflowId}}" }, "bodyTemplate": "{\"params\": {{params}}}", "authenticationType": "bearerToken" } ``` 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. Use `{{paramName}}` for path parameter placeholders. | | `headers` | `object` | — | Static request headers. Values may use `{{variableName}}` syntax. | | `queryParameters` | `object` | — | URL query string parameters. Values may use `{{variableName}}` syntax. | | `pathParameters` | `object` | — | Path segment substitutions. Keys match `{{paramName}}` in the URL. | | `bodyTemplate` | `string` | — | Request body template. Use `{{variableName}}` for runtime substitutions. | | `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": "variables.lastRunStatus", "target": "components.statusPanel.message", "trigger": "onChange" } ``` ### `Variable` A named global variable. Required field: `type`. Allowed `type` values: `string` · `number` · `boolean` · `object` · `array` ```json { "lastRunStatus": { "type": "string", "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 the Backend (future — Step 11) The backend will use [`ajv`](https://ajv.js.org/) at runtime to validate project definitions on save: ```ts 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.