Case study 03 · Full stack

A versioned, rule-driven form engine

Context
Configurable inspection and evaluation questionnaires for an enterprise client
My role
Built the API essentially on my own, and was the main author of the admin builder in the Angular back office.
When
2024 – now
Stack
.NET · EF Core · SQL Server · FluentValidation · Angular · TypeScript · RxJS

The problem

Inspectors fill in long, multi-step questionnaires on a mobile app, and the questions keep changing: new fields, new options, rules that show or hide sections depending on earlier answers. The people changing the forms are not developers. The apps reading them can’t break every time someone edits a question, and the business needs to know exactly which version of a form produced which answers.

What I did

The API

  • Wizards, forms, nested sections, fields, options, validations and tags, with soft delete and auditing.
  • Automatic versioning: the version rises when the structure changes, including changes deep inside nested sections.
  • Snapshots: a whole wizard is frozen to JSON with a SHA-256 hash. Snapshots can be published, compared with earlier ones, rolled back (which creates a new snapshot from an old one), archived, and checked for whether they’re still current.
  • Conditional rules: show, hide or disable, driven by field values or tags, with AND/OR groups that nest.
  • Option steering: individual options are enabled or disabled by values from an external evaluation system, where “disable wins”.
  • External linking: fields and options can map to external codes. Linked items become read-only, and the snapshot output stays byte-identical so existing hashes don’t change.

The builder

  • A visual condition-set builder that turns query-builder output into rule sets, including conditions it doesn’t display, without losing them.
  • Drag-and-drop ordering of sections, fields and options.
  • A snapshot explorer with an outline view and a diff between versions.
  • Search across the whole form tree, and a move onto the in-house design system.

Decisions and tradeoffs

  • The hash is a contract. Consumers trust a snapshot’s hash. Schema changes, like moving option codes from a child table into a JSON column, were done reversibly and without changing a single published byte.
  • Immutable published versions. Editing never touches what’s live. Publishing is the only way to change what inspectors see, and rollback is just another publish.
  • Owning both ends. Building the API and the builder together meant problems like option order drifting out of sync, or the builder and API disagreeing about state, got fixed at the source instead of being worked around.
admin builderangularforms apidrafts · rules · versionspublishsnapshot v12json + sha-256mobile appinspectorsevaluationservicev11v10rollbackexternal systemcodes · valuessteering① edits never touch what's live② the hash is the contract③ "disable wins" when rules disagree④ rollback is justanother publish
my partexisting
Original, simplified diagram. Not the real system.

Switch on “Show working” for the annotations.