# Proposal: Enterprise migration of `@suaveplan/form-builder` - **Status**: PROPOSED - **Package**: `@suaveplan/form-builder` - **Category / plugin**: `ui` / `forms` - **Tier**: universal (zero browser, zero React, zero Node) - **Design**: ./design.md - **Spec delta**: ./specs/form-builder/spec.md ## Why `@suaveplan/form-builder` is the canonical universal-tier schema engine for dynamic forms in the Suaveplan monorepo. The upstream copy at `../suaveplan/packages/universal/form-builder` ships only ten field types, a thin synchronous validation surface (eight built-in rules), a single conditional operator family (`eq` / `neq` / `in`), no dependency graph, no undo/redo, no submission pipeline, no Zod schema generator, and no OpenTelemetry instrumentation. The renderer-agnostic schema engine is expected to drive every form surface in the monorepo (admin panels, marketing onboarding flows, the internal vault wizard), and the current surface is too thin to serve them. This migration ports the package onto `genesis` at enterprise quality: full field-type registry, async validation, cross-field validators, dependency-graph driven re-evaluation, undo/redo, JSON serialisation round-trip, Zod schema generation, OTel instruments, and a stable error-code namespace. ## What changes - New package `packages/ui/forms/form-builder/` at `0.1.0`. - Zod-validated public schema (`FormSchema`, `FieldDefinition`, `FormSection`, `ValidationRule`, `ConditionalRule`). - Extensible `FieldRegistry` with 17 built-in field types: `text`, `number`, `email`, `url`, `tel`, `password`, `select`, `multiselect`, `checkbox`, `radio`, `textarea`, `date`, `file`, `range`, `hidden`, `group`, `array`. - Sync + async validation pipeline with `AbortSignal` propagation and 11 built-in rule kinds (`required`, `minLength`, `maxLength`, `min`, `max`, `pattern`, `email`, `url`, `oneOf`, `equalsField`, `custom`). - Conditional logic with 9 operators (`eq`, `neq`, `in`, `notIn`, `gt`, `lt`, `gte`, `lte`, `contains`) and boolean composition (`and`, `or`, `not`). - Field-level dependency graph with topological evaluation and cycle detection. - Undo / redo on schema-mutation operations. - Form-state machine emitting typed events through `EventBus` from `@suaveplan/events`. - JSON serialise / deserialise round-trip with versioned wire format. - Zod schema generator: `toZodSchema(form)`. - Submission pipeline: `prepare → validate → transform → submit` with injectable `Submitter`. - Six stable `FORM_BUILDER.*` error codes via `defineCodes`. - OTel instruments: three counters + two histograms. ## Parity Checklist | Capability | Upstream | Migrated | Notes | |---|---|---|---| | `FormBuilder` class | ✅ | ✅ | Public API preserved. | | Field types | ✅ (10) | ⬆️ (17) | Added `url`, `tel`, `password`, `multiselect`, `range`, `group`, `array`. | | Validation rules | ✅ (8) | ⬆️ (11) | Added `url`, `oneOf`, `equalsField`. Async + cross-field validators added. | | Conditional operators | ✅ (3) | ⬆️ (9 + boolean) | Added `notIn`, `gt`, `lt`, `gte`, `lte`, `contains`, plus `and` / `or` / `not`. | | Sections | ✅ | ✅ | Plus `removeSection`. | | Event bus | ✅ | ✅ | Migrated from `EventEmitter` to `EventBus` from `@suaveplan/events`. | | Error codes | ✅ | ⬆️ | Migrated from `BaseError` to `defineCodes("FORM_BUILDER", …)`. | | Dependency graph + topo eval | 🚫 | ⬆️ | New: required for chained conditional fields. | | Undo / redo | 🚫 | ⬆️ | New: bounded mutation-history stack. | | JSON round-trip | partial | ⬆️ | `serialiseForm` / `deserialiseForm` with Zod validation. | | Zod schema generator | 🚫 | ⬆️ | New: `toZodSchema(form)` for `react-hook-form` consumers. | | Submission pipeline | 🚫 | ⬆️ | New: pluggable `Submitter` with hooks. | | OTel instrumentation | 🚫 | ⬆️ | New: 3 counters + 2 histograms. | | Field registry (extensibility) | 🚫 | ⬆️ | New: downstream packages can contribute field types. | ## Impact ### Affected dependents None on `genesis` (form-builder is a leaf at migration time). Downstream integration with `@suaveplan/react-forms` is a follow-up change. Upstream main-branch consumers remain on the unmigrated copy until their own migration land. ### Risk Low. New package in a leaf position. Public API behaviour is exercised at 100% coverage.