OSS-first docs
These docs teach the open system first: contracts, generated surfaces, runtimes, governance, and incremental adoption. Studio shows up as the operating layer on top, not as the source of truth.
This document defines the canonical contracts for declarative forms.
Overview
•
`FormSpec` (in `@lssm-tech/lib.contracts-spec/forms`) declares:
•
`meta` (extends `OwnerShipMeta`) + `key`/`version` for stability.
•
`model` (`@lssm-tech/lib.schema` `SchemaModel`) as the single source of truth.
•
`fields` built from `FieldSpec` kinds: `text`, `email`, `textarea`, `select`, `checkbox`, `radio`, `switch`, `autocomplete`, `address`, `phone`, `number`, `percent`, `currency`, `date`, `time`, `datetime`, `duration`, `group`, `array`.
•
`text.password` for masked current/new password fields with password-manager hints.
•
field-level `readOnly` support that preserves submitted values.
•
Optional `layout`, `layout.flow`, `actions`, `policy.flags`, `constraints` and `renderHints`.
•
Relations DSL provides `visibleWhen`, `enabledWhen`, `requiredWhen` based on predicates.
•
Entity-bound projections use `projection.parts` for form-to-entity-path
part bindings and `projection.relatedEdges` for references to actual entity `EdgeSpec` relations. Part bindings do not own graph cardinality.
•
`FormRegistry.getByEntityProjection(entityKey, projectionKind, version?)`
deterministically resolves quick/full/intake/edit/part forms by entity projection metadata instead of by renderable form key only.
•
`buildZodWithRelations(spec)` augments the base zod with conditional rules and constraints.
•
Entity-bound projections are declared with optional `projection` metadata:
`quick`, `full`, `intake`, `edit`, and `part` forms remain normal renderable `FormSpec` objects while `FormProjectionSpec.entity` binds them to a canonical `ContractEntitySpec.meta.key`.
•
`captureFormIntake(spec, values)` is permissive by design: it returns
`accepted: true` for partial values and records missing completion debt.
•
`evaluateFormCompletion(spec, values)` is the strict readiness companion:
it reports missing `FormCompletionDebt` for a completion profile without invalidating the permissive capture result.
•
React adapter renders with React Hook Form + driver API for UI components.
Rich field contracts
•
`autocomplete` supports local filtering or resolver-backed search, including debounce/min-query hints and configurable submit-value mapping.
•
Resolver-backed autocomplete stays runtime-neutral: forms declare `resolverKey`, dependency paths, and optional args while host renderers provide the actual fetcher.
•
`email` represents one string email-address field; schema validation remains model-owned while renderers supply email input affordances.
•
`address` uses the canonical `AddressFormValue` object shape.
•
`phone` uses the canonical `PhoneFormValue` object shape.
•
`number`, `percent`, and `currency` map numeric schema intent to native input controls while preserving locale, precision, rounding, and currency-display metadata.
•
`date`, `time`, `datetime`, and `duration` map temporal schema intent to native controls while preserving locale, timezone, unit, and display metadata.
•
`array` remains the canonical dynamic-field primitive and can repeat grouped item layouts.
•
`text` can declare `password.purpose` as `current` or `new`; renderers map those to masked controls and `current-password` / `new-password` autocomplete hints.
Progressive form layout
•
`layout.flow.kind: "sections"` groups existing fields into accessible sections while keeping all sections visible.
•
`layout.flow.kind: "steps"` uses the same section metadata for progressive, one-section-at-a-time rendering.
•
`FormSectionSpec.fieldNames` references existing immediate field names; field definitions stay in `FormSpec.fields`.
•
Unlisted fields remain visible so flow metadata cannot accidentally drop required model inputs.
•
`text` and `textarea` can declare portable `inputGroup` addons for text and host-resolved icons.
Entity-bound projections and intake
•
Entity-bound form work is entity-first: canonical identity and true entity-to-entity relations stay on entity contracts.
•
Forms remain renderable projections. Quick, full, edit, intake, and part forms should be discoverable by entity key, projection kind, and optional version.
•
Form part bindings describe sub-capture surfaces such as identity or address. They must not overload `EdgeSpec`, which remains reserved for real entity graph relations and cardinality.
•
Capture acceptance and strict readiness are separate. Quick or message intake can accept partial values and return completion debt; stricter profiles can later report missing fields without rejecting the original capture.
•
Communication runtime intake hooks should map normalized messages into entity-bound intake payloads with source refs and completion debt. They should not implement full AI extraction, database persistence, or CommunicationOS UI.
•
The public documentation/migration subpath for this first-pass guidance is `@lssm-tech/lib.contracts-spec/forms/entity-bound`.
•
Form configuration chrome is a design-system concern: reuse `FormConfigShell`, `FormConfigMenuBar`, and `FormConfigPanel` from `@lssm-tech/lib.design-system/forms` instead of forking configuration panels in examples or apps.
•
FormSpec and FormConfig docs describe render/config metadata only. Persistence of drafts, submissions, credentials, or tenant state remains host-owned and approval-gated; examples should expose deterministic proof maps, not storage guarantees.
Layout and Groups
•
`FormSpec.layout` and `group.layout` can declare 1-4 responsive columns, gap size, and default field orientation.
•
`field.layout.colSpan` lets fields span one or more grid columns or the full row.
•
`wrapper.orientation` remains a compatibility alias for `layout.orientation`.
•
`group.legendI18n` renders as the semantic legend, falling back to `labelI18n`.
Driver API (UI-agnostic)
Host apps supply a driver mapping slots to components:
•
Required: `Field`, `FieldLabel`, `FieldDescription`, `FieldError`, `Input`, `Textarea`, `Select`, `Checkbox`, `RadioGroup`, `Switch`, `Autocomplete`, `AddressField`, `PhoneField`, `NumberField`, `PercentField`, `CurrencyField`, `DateField`, `TimeField`, `DateTimeField`, `DurationField`, `Button`.
•
Optional: `FieldContent`, `FieldGroup`, `FieldSet`, `FieldLegend`, `FieldSeparator`, `InputGroup`, `InputGroupAddon`, `InputGroupInput`, `InputGroupTextarea`, `InputGroupText`, `InputGroupIcon`, and `PasswordInput`.
•
Autocomplete drivers should accept optional `loading`, `error`, `emptyText`, `loadingText`, and `errorText` props so resolver-backed fields can expose async state without embedding transport details in the contract.
Use `createFormRenderer({ driver })` to obtain a `render(spec)` function.
Arrays and Groups
•
`array` items are rendered with `useFieldArray`, honoring `min`/`max` and add/remove controls.
•
`array.of` can repeat grouped multi-field rows.
•
`group` composes nested fields and provides optional legend/description/layout.
Feature Flags
•
Declare `policy.flags` on forms to signal gating. Gate usage at host boundary; avoid scattering flags across individual fields.
Example
Use the exported `RichFieldsShowcaseForm` as the canonical reference for readonly, password, autocomplete, address, phone, temporal, layout, and input-group field authoring.