Support/Builder Guide/Binding Contracts

Builder Guide

Binding Contracts

Use the binding catalog and live checklist/contacts page contract to connect React template blocks to bounded, authorized server data and actions.

Open raw .md
Catalog bindings
4
Live example
Checklist + Contacts
Browser SQL access
Never
Authorization
Server enforced

A binding contract connects a React template block to an installed, bounded server operation. The page stores a public bindingKey and an optional dataKey; it stores no SQL, database route, tenant identity, credential or authorization rule.

Note

The binding catalog is an authoring allowlist. It tells Puck which installed keys and child data paths a builder may select. It does not grant access to records or actions.

Binding catalog

The current local Puck catalog is developer-kit/local-puck/binding-catalog.json. Each entry gives the stable binding name and the bounded child documents that blocks may select with dataKey.

Binding keyPurposeAvailable data keys
work-orders.presentationWork Orders presentationmetrics, byStatus, recent, trend, table, timeline
checklists-signoffs.presentationChecklists & Signoffs presentationtasks
contacts.presentationContacts presentationtable
company-news.presentationCompany News presentationtable, feed, metrics
Copy the complete binding catalog
{
  "schemaVersion": 1,
  "bindings": [
    {
      "bindingKey": "work-orders.presentation",
      "title": "Work Orders presentation",
      "dataKeys": ["metrics", "byStatus", "recent", "trend", "table", "timeline"]
    },
    {
      "bindingKey": "checklists-signoffs.presentation",
      "title": "Checklists & Signoffs presentation",
      "dataKeys": ["tasks"]
    },
    {
      "bindingKey": "contacts.presentation",
      "title": "Contacts presentation",
      "dataKeys": ["table"]
    },
    {
      "bindingKey": "company-news.presentation",
      "title": "Company News presentation",
      "dataKeys": ["table", "feed", "metrics"]
    }
  ]
}

Several blocks can reuse one binding. For example, Work Orders can render metrics, a status distribution, recent records, a trend, a grid and a timeline from one authorized presentation document. Reuse avoids issuing a broad record query for every visual block.

Live checklist and Contacts page contract

The shipped pages/live-checklist-contacts.json example composes two independent live contracts. The checklist task list uses checklists-signoffs.presentation with dataKey: tasks. The Contacts grid uses contacts.presentation with dataKey: table.

Copy the complete live checklist and Contacts page JSON
{
  "blocks": [
    {
      "_id": "live-actions-header",
      "_type": "core.page-header",
      "props": {
        "title": "Live checklist and contact actions",
        "lead": "These components receive only the records and actions authorized for the signed-in user. Checklist toggles use optimistic concurrency; contact actions refetch their scoped presentation after each write."
      }
    },
    {
      "_id": "live-actions-layout",
      "_type": "core.container",
      "props": {
        "layout": "grid",
        "gridMode": "twelve-column",
        "gap": "normal"
      },
      "children": [
        {
          "_id": "live-actions-checklist-card",
          "_type": "core.card",
          "props": {
            "title": "Checklist work",
            "description": "Items outside the user's DataRole and Location scope are never sent to the browser.",
            "responsive": {
              "desktop": { "span": 5 },
              "tablet": { "span": 12 },
              "mobile": { "span": 12 }
            }
          },
          "children": [
            {
              "_id": "live-actions-checklist",
              "_type": "core.task-list",
              "bindingKey": "checklists-signoffs.presentation",
              "dataKey": "tasks",
              "props": {}
            }
          ]
        },
        {
          "_id": "live-actions-contacts-card",
          "_type": "core.card",
          "props": {
            "title": "Recent contacts",
            "description": "The grid is bounded to 25 visible contacts and each row declares only its currently valid favorite action.",
            "responsive": {
              "desktop": { "span": 7 },
              "tablet": { "span": 12 },
              "mobile": { "span": 12 }
            }
          },
          "children": [
            {
              "_id": "live-actions-contacts",
              "_type": "core.presentation-grid",
              "bindingKey": "contacts.presentation",
              "dataKey": "table",
              "props": {}
            }
          ]
        }
      ]
    }
  ]
}

The layout and presentation remain editable. Changing card widths, titles, responsive spans or component styling does not change the server contract. Changing a bindingKey or dataKey must still reference an installed catalog entry and pass server validation.

How the runtime resolves a binding

  1. The page renderer collects unique binding keys from visible, registered blocks.
  2. The native runtime requests GET /api/runtime/data/<bindingKey> under the current same-origin user session. Headless applications can resolve 1–24 keys with POST /v1/apps/{saasAppId}/runtime/bindings and a delegated-user credential.
  3. The server resolves the tenant from the real host and requires the authenticated SaaS app, AppAccount and user context.
  4. The registered binding chooses a reviewed stored procedure. That procedure applies tenant, DataRole, Location, record visibility, soft-delete and action-entitlement rules before returning JSON.
  5. The React block receives a typed loading/data/error state and selects only its configured dataKey.

A native binding response has this envelope:

{
  "contractVersion": 1,
  "bindingKey": "checklists-signoffs.presentation",
  "data": {
    "tasks": {
      "presentationVersion": 1,
      "kind": "task-list",
      "items": []
    }
  }
}
Important

A page definition is presentation, not data authority. Never replace a binding with browser SQL, a connector secret, an arbitrary stored-procedure name or a client-supplied SaaS/AppAccount/User identifier.

Live actions, revisions and exact refresh

Bindings are read contracts. A checklist toggle or Contacts favorite uses the separate Lego action broker at POST /api/runtime/lego/actions. The rendered row receives only server-issued record, field and action identifiers that are currently available to that user.

{
  "contractVersion": 1,
  "pageKey": "LiveChecklistContacts",
  "blockId": "live-actions-checklist",
  "actionId": "server-issued-action-guid",
  "recordId": "server-issued-record-guid",
  "expectedRevision": 7,
  "values": {
    "checked": true
  }
}
  1. The browser sends the saved page key, block ID, server-issued action ID, record ID, expected revision when required, and validated input values.
  2. The broker reloads the saved page and catalog, confirms that the block declares the action, then calls the typed module service.
  3. The endpoint and stored procedure independently re-authorize the operation. A displayed action ID is user-interface intent, not proof of permission.
  4. A successful result names the exact binding that became stale. React reloads only that binding with ?refresh=true.
  5. A stale checklist revision returns HTTP 409. The optimistic state is removed, the current binding is fetched again, and the user can retry against the current revision.

Use these contracts in a template

  1. Open the page in hosted Puck or the local Puck editor.
  2. Select a data-aware block such as core.task-list or core.presentation-grid.
  3. Choose its bindingKey from the binding catalog.
  4. Choose a dataKey declared by that catalog entry.
  5. Save and validate the draft, then publish it through the normal version-fenced workflow.
  6. Exercise loading, empty, populated, forbidden, stale-write and successful-mutation states with a real route-resolved disposable tenant.

An unknown binding name does not create an API or query. Adding a binding is a separate reviewed application contract with a stable key, approved stored procedure, mandatory server context, bounded output schema, cache policy and authorization tests.

Continue with the local Puck binding editor, interactive API presentations, and the headless application kit.

Capability review: 2026-09-14. For exact current technical availability, use the generated API Map and first-class module inventory.