conductor/docs/SCHEMA.md
Victor Wiebe 498003f83d
Some checks failed
Release production image / production-image (push) Has been cancelled
Prepare Conductor v1.0.0 release
2026-08-08 14:21:40 -04:00

317 lines
13 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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 (1200 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.<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.
```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.<actionId>.response[.body.<field>]` sources with `onSuccess`. Table selection uses `components.<tableName>.selectedRow` with `onChange`. Component targets are checked for compatible `.value`, Dropdown `.options`, or Table `.rows` properties. A `variables.<name>` 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.