JSON Driven

One component renders any model. The layout is data, not code.
45,091 lines of code replaced by 1,759 lines of JSON

What Changed

Before — Code Per Model

  • OrderDetail.tsx 438 lines
  • InvoiceDetail.tsx 412 lines
  • ProposalDetail.tsx 395 lines
  • PurchaseDetail.tsx 401 lines
  • CustomerDetail.tsx 367 lines
  • PaymentDetail.tsx 344 lines
  • ItemDetail.tsx 298 lines
  • ... 40+ more files ~400 each
Every field change = code change = build = deploy

After — Data Per Model

  • DynamicDetail.tsx ~800 lines
  • DataBrowser.tsx ~960 lines
  • + 61 JSON layout Settings ~30 each
Field change = edit a JSON record. No build. No deploy.

How It Works

1

Layout JSON

A Setting record stores the field layout for each model — which fields, what order, what grouping, what format.

2

One Renderer

DynamicDetail reads the layout, fetches the record, and renders the form. Same component for all 61 models.

3

User Edits

Design Mode lets users drag fields, change groups, and save — the layout updates in the database, not in code.

Design Mode In Action

Watch: a user drags "Terms" from Header to Customer. The JSON updates. No build. No deploy.
Order — ORD-1042 Design Mode
Header
Order #ORD-1042
Statusconfirmed
Date2026-08-10
TermsNet 30
Customer
CompanyRiverside Sports
AttentionMike Chen
Address142 River Rd, Austin TX
Layout JSON (live)
{
  "groups": [
    {
      "label": "Header",
      "fields": [
        "ida",
        "status",
        "dt_created",
        "terms"
      ]
    },
    {
      "label": "Customer",
      "fields": [
        "company",
        "attention",
        "address_full"
      ]
    }
  ]
}

The Layout Is Just JSON

Layout JSON (stored in Setting)
{
  "model": "order",
  "title": "Order",
  "groups": [
    {
      "label": "Header",
      "fields": [
        { "field": "ida", "label": "Order #" },
        { "field": "status" },
        { "field": "dt_created",
          "format": "date" },
        { "field": "terms" }
      ]
    },
    {
      "label": "Customer",
      "fields": [
        { "field": "company" },
        { "field": "attention" },
        { "field": "address_full" }
      ]
    }
  ]
}
What It Renders
Header
  Order #    ORD-1042
  Status     confirmed
  Date       2026-08-10
  Terms      Net 30

Customer
  Company    Riverside Sports
  Attention  Mike Chen
  Address    142 River Rd, Austin TX

Print Reports Work The Same Way

The same JSON-driven pattern renders print documents. Panels are sections. Fields are data.
H

Company Header

Logo, address, contact info

A

Address Blocks

Bill To / Ship To / Info columns

L

Line Items

Repeating rows with footer totals

$

Totals

Subtotal, tax, shipping, total

C

Comments

Public notes, scope text

?

Conditional Text

Rules-based content (dunning messages)

S

Signature

Preamble + signature blocks

F

Footer

Page footer with reference fields

Settings Scope

Level 4

System

Default layout shipped with WebClerk. Every installation starts here.

Level 3

Organization

Company-wide customization. All users in this org see these layouts.

Level 2

Role

Sales sees different fields than warehouse. Same model, different view.

Level 1

User

Personal layout. Drag fields, save. Only you see it. Highest priority.

Three UI Paths

Business Forms

ui.json

Customer-facing detail pages. Clean, grouped, formatted for daily use.

  • DynamicDetail renderer
  • Design Mode editing
  • Scoped per user/role/org
  • 61 models covered

Admin / DataBrowser

db.json

Raw data access for admins. Every field visible, searchable, editable.

  • DataBrowser renderer
  • All fields exposed
  • JSON field deep editing
  • Bulk operations

Custom Interaction

ui.tsx

Complex workflows that need custom code. Gantt charts, visual editors, dashboards.

  • Hand-coded React
  • Only when JSON can't do it
  • Rare — most models don't need it
  • Always the last resort

The Layout Is Data. The Code Is Universal.

Add a model, add a Setting. No .tsx file. No build. No deploy. The renderer already knows how to draw it.

Built for WebClerk