# Input schema

`form-schema.json` is the editable source of truth for the generated Pydantic models. The build now reads this file first, generates `src/generated_models.py`, then passes those generated Pydantic classes into the existing form compiler to create `web/data/compiled-models.json`.

The important flow is:

```text
form-schema.json -> generated Pydantic classes -> compiled form artifact -> website renderer
```

This means the Pydantic classes are no longer the hand-written starting point. They are generated output. The input schema is the file to edit when adding or changing a document form.

## Top-level fields

`schemaVersion` identifies the format of the input schema. The current value is `pydantic-form-input-schema/v1`.

`description` is a human-readable note about the schema file.

`documents` is the ordered list of model names that should be compiled into website pages. A class can exist in `classes` as a supporting nested model without appearing in `documents`.

`classes` contains every generated Pydantic class. Classes should be ordered so supporting classes appear before the document classes that reference them.

## Class fields

Each class object has a `name`, a `role`, and a list of `fields`. The role is either `document` for a top-level page model or `supporting` for nested classes used by other models. A class can also include `title` to generate `model_config = ConfigDict(title=...)` and `docstring` to generate a Python class docstring.

Each field object has a `name` and a Python-style `type`, such as `str`, `Optional[str]`, `Optional[Date]`, `List[SalesOrderLine]`, or `SalesOrderFooter`. The generator writes this type directly into the generated Python model, so it must be a valid annotation supported by the generated file imports.

A field should use `required: true` when it should be emitted as `Field(...)`. Optional fields usually use `default: null`. Nested objects or lists usually use `defaultFactory`, such as `SalesOrderFooter` or `list`, so each generated model instance gets its own nested value.

`title` and `description` become Pydantic `Field` metadata. The form compiler uses that metadata for labels and help text. `constraints` can hold simple Pydantic field constraints such as `ge`, `le`, `gt`, `lt`, `min_length`, `max_length`, and `pattern`.

## Example

```json
{
  "schemaVersion": "pydantic-form-input-schema/v1",
  "description": "Editable source schema for generated Pydantic document models.",
  "documents": ["SalesOrderForm"],
  "classes": [
    {
      "name": "SalesOrderLine",
      "role": "supporting",
      "fields": [
        {
          "name": "product",
          "type": "str",
          "title": "Product",
          "description": "Printed column: Product.",
          "required": true
        },
        {
          "name": "qty",
          "type": "Optional[str]",
          "title": "Qty",
          "description": "Printed column: Qty.",
          "default": null
        }
      ]
    },
    {
      "name": "SalesOrderForm",
      "role": "document",
      "fields": [
        {
          "name": "order_lines",
          "type": "List[SalesOrderLine]",
          "title": "Order lines",
          "description": "Main repeated product line-item body of the sales order form.",
          "defaultFactory": "list"
        }
      ]
    }
  ]
}
```

The example generates a `SalesOrderLine` class and a `SalesOrderForm` class. Because `order_lines` is a list field whose name ends in `_lines`, the downstream form compiler classifies it as a line-item collection and the website renders it as aligned horizontal rows.

## Build command

Run this from the project root:

```bash
python compile.py
```

The command reads `form-schema.json`, regenerates `src/generated_models.py`, then writes the compiled website artifact to `web/data/compiled-models.json`.

## Example data

Example payloads live next to `form-schema.json` in an `examples/` directory. Each form has its own directory named after the generated document model, and each JSON file inside that directory is one sample payload for that form.

```text
examples/
  SalesOrderForm/
    1.json
    2.json
    3.json
  PurchaseOrder/
    1.json
```

During `python compile.py`, the build generates the Pydantic classes first, then validates every example JSON file against the matching generated class. Valid examples are packaged into `web/data/examples.json` for the static website. On a form page, numbered example buttons load those payloads into the form so the Form and JSON views can be inspected with realistic data.
