4.3 KiB
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/at0.1.0. - Zod-validated public schema (
FormSchema,FieldDefinition,FormSection,ValidationRule,ConditionalRule). - Extensible
FieldRegistrywith 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
AbortSignalpropagation 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<FormEventMap>from@suaveplan/events. - JSON serialise / deserialise round-trip with versioned wire format.
- Zod schema generator:
toZodSchema(form). - Submission pipeline:
prepare → validate → transform → submitwith injectableSubmitter. - Six stable
FORM_BUILDER.*error codes viadefineCodes. - 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<FormEventMap> 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.