Definitions and Runtime
A schema declaration is an immutable description. Runtime state is the changing experience of one person filling out or submitting a form.
The four contracts
| Contract | Created by | Contains | Does not contain |
|---|---|---|---|
| Source declaration | Your TypeScript | Collections, fields, validation metadata, input intent, and optional layout | Visitor values or errors |
databaseSchema | createSchema() or the orchestrator | Normalized database objects plus toJSONSchema() and checksum() | UI layout |
uiFormTree | The orchestrator | Render collections, steps, conditions, repeaters, and branches | Current values, errors, or submission state |
Published FormSchema | BusinessDash dashboard/API | A Live form contract consumed by forms.schema(), <BdForm>, and createFormController() | Your local orchestration tree |
In 0.9.50 there is no adapter from uiFormTree to the published
FormSchema expected by createFormController(). Do not pass one contract
where the other is required.
One declaration, isolated outputs
const definition = createFormSchemaOrchestrator([projects])
export default definition.databaseSchema
export const projectFormTree = definition.uiFormTree
The default export is deliberately narrow: the CLI can see the database artifact but cannot accidentally upload layout or application state.
Your renderer reads uiFormTree as a definition and keeps live state
separately:
type ProjectFormState = {
values: Record<string, unknown>
touched: Set<string>
dirty: Set<string>
errors: Record<string, string>
activeBranch?: string
currentStep: number
submitting: boolean
}
Source, draft, and Live
The CLI compiles local source and compares it with the promoted Live data
model. sync-data-model proposes a draft; it does not silently promote it.
local TypeScript → compiled artifact → migration plan → draft → human promotion → Live
This separation lets CI produce deterministic proposals while a person remains the gate for exposure changes and destructive migrations.
Next: Validation and Form State.