Skip to content

feat: [dasc] Form v2#441

Open
kozmaadrian wants to merge 26 commits into
mainfrom
form-v2
Open

feat: [dasc] Form v2#441
kozmaadrian wants to merge 26 commits into
mainfrom
form-v2

Conversation

@kozmaadrian
Copy link
Copy Markdown
Contributor

@kozmaadrian kozmaadrian commented May 13, 2026

Test url: https://da.live/form?nx=form-v2#/kozmaadrian/da-sc/forms/demo-v2

Form Block: v2 Review Guide

This guide covers the scope and motivation behind the change, and walks through the architecture and design decisions of the new implementation.

Part 1: v1 vs v2

The problems in v1

1. Schema spec was weak. v1 accepted almost any JSON Schema and tried its best to render it. No rules, no docs about what's allowed, no warning when a schema used something the editor didn't actually support. There was no spec authors could rely on. Business impact: a schema chosen early in a project can turn out to be unworkable in production. Rewriting it means touching every document built on top, which risks blocking launches and eroding trust whenever a "valid" schema produces a broken form.

2. Not testable. There was no way to test one piece on its own. Checking schema compilation, validation, or a single mutation required building the whole model (full document, full schema, full path) every time. The only real feedback loop was opening the browser. Business impact: bugs can slip through to users instead of being caught earlier. The team risks growing cautious about touching anything important. Bug fixes take longer because reproducing an issue means recreating the session by hand.

3. Not reusable. Nothing ran outside the browser. If another tool (DA import, MCP, an AI agent, a migration script) needed to read or validate the same data, it had to re-implement validation, schema resolution, and serialization from scratch. Copies drift. Business impact: every new integration pays the full cost again. AI, MCP, automation: none of it is practical without rewriting the same logic per channel, and the copies risk producing inconsistent data.

4. Mixed layers. Data handling, UI, and network calls were all tangled together. A new feature can touch any of them, and a change in one place can break something far away. Business impact: simple features risk taking weeks. New engineers have to learn everything at once. "Safe" edits can produce regressions that only surface in production.


Part 2: Overview of v2

Why it is built the way it is

v2 splits the code into three layers, and each layer has one job. Nothing leaks across a boundary.

┌──────────────────────────────────┐
│  ui/   (rendering only)          │  reads state, calls core mutations
├──────────────────────────────────┤
│  app/  (orchestration)           │  wires core to the network and DOM
├──────────────────────────────────┤
│  core/ (pure logic, no DOM)      │  schema, model, validation, mutations
└──────────────────────────────────┘

core/ is the most important layer. It runs anywhere JavaScript runs: no DOM, no fetch, no globals. It loads in Node.js, in an MCP server, in a CLI, or in a test runner. The ui/ layer knows the DOM but knows nothing about schemas or validation. app/ is the thin glue between them. The boundary lives in the imports. There's no build tool enforcing it, so it's worth checking in review.

File structure

v1                                  v2
──────────────────────────────────  ──────────────────────────────────────────
data/                               core/          ← pure logic, no DOM
  model.js                            index.js     ← public API (createCore)
utils/                                schema.js    ← schema compiler
  html2json.js                        model.js     ← document model builder
  json2html.js                        mutate.js    ← pure mutation functions
  pointer.js                          validation.js
  schema.js                           pointer.js
  validator.js                        clone.js
  value-resolver.js
views/                              app/           ← orchestration
  editor.js                           context.js   ← loading state machine
  sidebar.js                          da-api.js    ← network layer
  preview.js                          serialize.js
  components/                         html2json.js
    array-item-menu/                  json2html.js
    reorder-dialog/                 ui/            ← rendering only
form.js                               editor.js
form.css                              sidebar.js
                                      preview.js
                                      array-menu.js
                                      reorder.js
                                    docs/
                                      architecture.md
                                      schema-spec.md
                                      schema-builder.md
                                      model-builder.md
                                      request-flow.md
                                      performance-review.md
                                      headless-consumer.md
                                    form.js

This isn't just a rename. The three folders make the rule real: ui/ can import from core/, but core/ never imports from ui/, app/, or anything browser-related. That's what makes the core headless and testable.


Part 3: What this PR really solves

Each of the four v1 pains has a direct answer in v2. This is the short version of what a reviewer is approving.

Schema authors know what works. schema-spec.md lists exactly which JSON Schema features the form supports. The compiler (schema-builder.md) checks every schema and reports anything outside that list as a schema issue, so the author sees it in the editor right away, not after building a form on top of it. No more rewriting a schema because a feature you used silently fails.

Anything can be unit-tested. Schema compilation, model building, mutations, validation, type coercion: each one has its own tests that run without a browser. Bugs get caught before they reach users.

One source of truth, reused everywhere. createCore() gives the same API to the editor, an MCP server, an AI agent, a migration script, or a CLI. No second copy to keep in sync. The next thing we build on top of forms (AI assist, bulk migration, anything) just calls createCore(). headless-consumer.md shows how.

Three layers, no cross-talk. core/, app/, ui/ are real folders. Imports only go one direction. New engineers learn one layer at a time. A bug stays in the layer where it was made. Schema work won't break the renderer, and the other way around.

Bonus: every file in core/ and the load path is documented in docs/

Part 4: Same UX

The editor looks and behaves identically to v1. This is a full internal rewrite — no visible change was the goal. Fields, validation feedback, array controls, the sidebar, and the preview panel all work as before.

da-sc-v2

Part 5: Scores

These scores were generated by Claude after deep analysis of the v1 and v2 source code. They are not a formal benchmark — the intent is to give a reviewer a quick, grounded orientation.

v1 v2
Code simplicity ★★☆☆☆ ★★★★☆
Cleanliness & consistency ★★☆☆☆ ★★★★★
A new engineer can understand it ★★☆☆☆ ★★★★☆
Follows codebase best practices ★★☆☆☆ ★★★★★
Testability (without a browser) ★☆☆☆☆ ★★★★★
Correctness under real usage ★★☆☆☆ ★★★★★
Ready for AI / MCP / agent integration ★☆☆☆☆ ★★★★★
Error visibility ★★☆☆☆ ★★★★☆

@aem-code-sync
Copy link
Copy Markdown

aem-code-sync Bot commented May 13, 2026

Hello, I'm the AEM Code Sync Bot and I will run some actions to deploy your branch.
In case there are problems, just click the checkbox below to rerun the respective action.

  • Re-sync branch
Commits

@kozmaadrian kozmaadrian requested review from hannessolo and mhaack May 13, 2026 18:17
@kozmaadrian kozmaadrian mentioned this pull request May 13, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant