Skip to content

Formalize contract schema as JSON Schema #18

Description

@mryhmln

Problem

The form contract YAML uses keywords like data-table, side-nav, field-array, etc., but nothing machine-readable defines what those keywords mean, what they render, or what properties each requires. The vocabulary is currently implicit across three places:

  • TypeScript unions in types.ts — define what values are valid but not what they do
  • contract-reference.ts — human-readable docs, but it's a string blob embedded in code, not parseable
  • FormRenderer.tsx — the actual behavior, buried in implementation

An adapter author today would have to reverse-engineer the renderer to understand what display: data-table requires (columns config, source property) or what component: field-array expects (sub-fields, min_items/max_items).

Proposal

Create a formal contract schema as a JSON Schema written in YAML (e.g. contract.schema.yaml). Since the entire contract system is YAML-based, keeping the schema in YAML maintains consistency. JSON Schema is format-agnostic — tools like ajv can validate YAML documents against a schema loaded from .yaml.

Example sketch:

# contract.schema.yaml
type: object
required: [form]
properties:
  form:
    type: object
    required: [id, title, schema, layout, pages]
    properties:
      id:
        type: string
        pattern: "^[a-z][a-z0-9-]*$"
        description: Unique form identifier (kebab-case)
      title:
        type: string
        description: Display title shown in the form header
      layout:
        type: object
        required: [navigation, display]
        properties:
          navigation:
            enum: [step-indicator, side-nav, in-page, top-nav, none]
            description: How users move between pages
          display:
            enum: [paginated, scrollable, accordion, split-panel, data-table]
            description: How page content is arranged
      pages:
        type: array
        items:
          $ref: '#/$defs/Page'

$defs:
  Page:
    type: object
    required: [id, title]
    properties:
      id:
        type: string
      display:
        description: Per-page display override
        enum: [paginated, scrollable, accordion, split-panel, data-table]
      fields:
        type: array
        items:
          $ref: '#/$defs/Field'
  Field:
    type: object
    required: [ref, component]
    properties:
      ref:
        type: string
        description: Dot-path into the data model
      component:
        enum: [text-input, date-input, radio, select, checkbox-group, field-array]
      width:
        enum: [full, half, third, two-thirds]
      # ... conditional rules for field-array requiring sub-fields, etc.

What this enables

  • Validation — tooling can validate contracts against the schema before runtime
  • Adapter authoring — implementers can understand the full surface area without reading TypeScript
  • Documentation — generate human-readable docs from the schema instead of maintaining contract-reference.ts by hand
  • IDE support — YAML editors can provide autocomplete and inline error checking via the $schema directive

Starting point

The contract-reference.ts content and types.ts unions already capture much of this — the work is formalizing them into a machine-readable YAML-based JSON Schema. Conditional requirements (e.g., data-table display requires columns) can use JSON Schema's if/then keywords.


Moved from codeforamerica/safety-net-blueprint#81

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions