Support/Builder Guide/Professional Template Foundation

Builder Guide

Professional Template Foundation

Build polished, responsive SaaS pages from registry-backed components, copyable compositions, token-safe themes and server-scoped data bindings.

Components
9
Page compositions
3
Theme presets
3
Data scope
Server enforced

The Professional Template Foundation is a registry-backed starting point for polished BuildWithHQ applications. It adds nine presentation components, three complete page compositions, and three theme presets without creating a second renderer, a second permission system, or a client-side data layer.

Note

The page compositions work as immediate static previews. Live values must use a registered server-side binding. Existing SaaS databases need the reviewed component-registry release migration before these blocks appear in Puck; builders must never insert registry or theme rows directly.

Download the Builder Developer Kit

Download Professional Foundation Developer Kit 1.0.0 (46.8 KiB). Verify SHA-256 80bed0dc00e3e19ca65e3e7566fffedc5ac35b89d3102e6e582f86731f4b7b51, or download the adjacent checksum file.

A builder working entirely in BuildWithHQ does not need the repository or its maintainer test commands. Install the exact published Template Library version, open its pages in Puck, and customize them. Download the kit when you want standalone styled and unstyled React, canonical page and theme JSON, the public capability catalog, OpenAPI, the server-side TypeScript SDK, or MCP/CLI setup material.

SurfaceUseIdentity boundary
Builder and PuckInstall, edit, validate and publish template pages.Short-lived Builder identity and account ownership.
Developer API and MCPOperate on one SaaS app's authorized data and integrations.App-bound credential with mcp.use plus each tool's scope.
Headless ReactPaint already-authorized results in a custom interface.Your server holds the API credential; the browser never does.

The app-scoped MCP endpoint is https://api.buildwithhq.com/v1/apps/{saasAppId}/mcp. Tool discovery is authoritative, and sensitive mutation tools remain absent unless server policy explicitly enables them.

Copy the MCP connection descriptor
{
  "schemaVersion": 1,
  "name": "BuildWithHQ",
  "transport": "streamable-http",
  "urlTemplate": "https://api.buildwithhq.com/v1/apps/{saasAppId}/mcp",
  "authentication": {
    "type": "bearer",
    "credentialSource": {
      "kind": "environment",
      "name": "BWHQ_API_CREDENTIAL"
    }
  },
  "requiredConfiguration": {
    "saasAppIdEnvironment": "BWHQ_SAAS_APP_ID",
    "minimumScopes": ["mcp.use"],
    "toolScopesAreAdditional": true
  },
  "security": {
    "credentialBoundToExactSaasApp": true,
    "routeAppIsAuthorization": false,
    "physicalRoutingExposed": false,
    "sensitiveMutationsDefaultDenied": true
  }
}
Copy the CLI profile setup
# Install bwhq 0.1.0 from your approved BuildWithHQ package channel first.
# Secrets stay in your environment or secret manager, not in the profile.
bwhq auth profile add `
  --name my-saas `
  --saas-app-id <your-saas-app-id> `
  --base-url https://api.buildwithhq.com `
  --credential-env BWHQ_API_CREDENTIAL `
  --control-plane-base-url https://hello.buildwithhq.com `
  --builder-token-env BWHQ_BUILDER_TOKEN `
  --set-current

bwhq doctor --profile my-saas
bwhq status --profile my-saas
Important

The ZIP contains CLI instructions, not a signed bwhq executable. Publish the CLI through an approved package channel as a separate release. Never ask a builder to compile the repository, and never put BWHQ_API_CREDENTIAL or BWHQ_BUILDER_TOKEN in page JSON, React source, a ZIP, or a prompt.

1. How the foundation works

LayerWhat it ownsWhat it does not own
Component RegistryStable keys, display names, default props, renderer keys and versions.Tenant identity, data scope or SQL.
Canonical page JSONStable block IDs, layout, component properties, children and approved binding keys.Authorization or physical database routing.
SaaS app themeLight/dark/system mode and allowlisted --runtime-* design tokens.Arbitrary executable CSS, script or permissions.
Runtime binding resolverMaps a registered bindingKey to a reviewed, identity-scoped server operation before JSON is returned.Ad-hoc SQL or browser-selected tenant/account IDs.
Template LibraryOwned page harvest, validation, immutable page/component publication and exact-version installation.Silently changing an already installed tenant copy.

At runtime the server resolves the signed-in SaaS app, account, user, DataRoles and Locations. SQL returns only the permitted result. React receives that already-scoped result and paints it. A component never downloads a broad table and filters it in the browser.

2. Use the professional component vocabulary

Component keyUse it forMain properties
core.page-headerPage title, lead and breadcrumb.title, lead, breadcrumb[]
core.stat-tileOne KPI or bounded scalar.label, value, delta, direction, tone
core.cardA titled content group.title, description, tone, child blocks
core.chartAn accessible bar or line summary.title, variant, series[], labels[], tone
core.data-tableA bounded server-scoped list.caption, columns[], optional static rows[]
core.list-rowCompact recent activity or person/work summaries.primary, secondary, trailing, initials, tone
core.badgeStatus and category labels.label, tone
core.section-labelA compact section eyebrow.label
core.empty-stateAn explicit zero-result or missing-proof state.title, body

Use the existing core.container with layout: "stack", "row" or "grid" to compose them. The professional stylesheet makes the grid responsive and keeps the content left-aligned inside the expandable center column.

3. Start from a complete page composition

Each source below is canonical BuildWithHQ page content. The dashboard demonstrates KPIs, a chart and activity. The queue demonstrates status, a bounded table and the correct empty state. The record page is a base for Files, Conversations, Checklists, Workflow, Record Activity and other first-class blocks.

Professional dashboard - copy the complete page JSON
{
  "blocks": [
    {
      "_id": "professional-dashboard-header",
      "_type": "core.page-header",
      "props": {
        "title": "Operations overview",
        "lead": "A focused view of the work, service level, and team activity that need attention today.",
        "breadcrumb": ["Operations", "Overview"]
      }
    },
    {
      "_id": "professional-dashboard-stats",
      "_type": "core.container",
      "props": { "layout": "grid" },
      "children": [
        {
          "_id": "professional-dashboard-stat-open",
          "_type": "core.stat-tile",
          "props": { "label": "Open work", "value": "128", "delta": "12 this week", "direction": "up", "tone": "primary" }
        },
        {
          "_id": "professional-dashboard-stat-due",
          "_type": "core.stat-tile",
          "props": { "label": "Due today", "value": "17", "delta": "4 at risk", "direction": "down", "tone": "warning" }
        },
        {
          "_id": "professional-dashboard-stat-sla",
          "_type": "core.stat-tile",
          "props": { "label": "Within service level", "value": "96%", "delta": "2.4%", "direction": "up", "tone": "success" }
        },
        {
          "_id": "professional-dashboard-stat-waiting",
          "_type": "core.stat-tile",
          "props": { "label": "Waiting on customer", "value": "23", "tone": "neutral" }
        }
      ]
    },
    {
      "_id": "professional-dashboard-detail-grid",
      "_type": "core.container",
      "props": { "layout": "grid" },
      "children": [
        {
          "_id": "professional-dashboard-trend-card",
          "_type": "core.card",
          "props": { "title": "Work completed", "description": "Six-week throughput from the authorized page scope.", "tone": "primary" },
          "children": [
            {
              "_id": "professional-dashboard-trend-chart",
              "_type": "core.chart",
              "props": {
                "title": "Completed work by week",
                "variant": "line",
                "tone": "primary",
                "series": [38, 45, 42, 56, 61, 73],
                "labels": ["W1", "W2", "W3", "W4", "W5", "W6"]
              }
            }
          ]
        },
        {
          "_id": "professional-dashboard-team-card",
          "_type": "core.card",
          "props": { "title": "Recent team activity", "description": "The latest visible changes across this workspace.", "tone": "success" },
          "children": [
            { "_id": "professional-dashboard-team-label", "_type": "core.section-label", "props": { "label": "Recently updated" } },
            { "_id": "professional-dashboard-team-1", "_type": "core.list-row", "props": { "primary": "Preventive maintenance", "secondary": "North facility · Updated 8 minutes ago", "trailing": "Ready", "initials": "PM", "tone": "success" } },
            { "_id": "professional-dashboard-team-2", "_type": "core.list-row", "props": { "primary": "Customer onboarding", "secondary": "West region · Updated 21 minutes ago", "trailing": "Review", "initials": "CO", "tone": "warning" } },
            { "_id": "professional-dashboard-team-3", "_type": "core.list-row", "props": { "primary": "Quarterly inspection", "secondary": "Central office · Updated 46 minutes ago", "trailing": "Open", "initials": "QI", "tone": "primary" } }
          ]
        }
      ]
    }
  ]
}
Professional work queue - copy the complete page JSON
{
  "blocks": [
    {
      "_id": "professional-queue-header",
      "_type": "core.page-header",
      "props": {
        "title": "Work queue",
        "lead": "A bounded, server-scoped table designed for fast triage instead of fetching an entire record graph.",
        "breadcrumb": ["Operations", "Work queue"]
      }
    },
    {
      "_id": "professional-queue-statuses",
      "_type": "core.container",
      "props": { "layout": "row" },
      "children": [
        { "_id": "professional-queue-status-all", "_type": "core.badge", "props": { "label": "All 128", "tone": "primary" } },
        { "_id": "professional-queue-status-progress", "_type": "core.badge", "props": { "label": "In progress 46", "tone": "success" } },
        { "_id": "professional-queue-status-risk", "_type": "core.badge", "props": { "label": "At risk 4", "tone": "warning" } },
        { "_id": "professional-queue-status-blocked", "_type": "core.badge", "props": { "label": "Blocked 3", "tone": "danger" } }
      ]
    },
    {
      "_id": "professional-queue-card",
      "_type": "core.card",
      "props": { "title": "Priority work", "description": "Preview rows; bind this block to an approved list operation for live tenant data.", "tone": "primary" },
      "children": [
        {
          "_id": "professional-queue-table",
          "_type": "core.data-table",
          "props": {
            "caption": "Priority work queue",
            "columns": [
              { "key": "reference", "label": "Reference", "align": "left" },
              { "key": "summary", "label": "Summary", "align": "left" },
              { "key": "owner", "label": "Owner", "align": "left" },
              { "key": "due", "label": "Due", "align": "left" },
              { "key": "status", "label": "Status", "align": "right" }
            ],
            "rows": [
              { "reference": "WO-1048", "summary": "Inspect cooling system", "owner": "Morgan Lee", "due": "Today", "status": "In progress" },
              { "reference": "TK-318", "summary": "Confirm access window", "owner": "Avery Patel", "due": "Today", "status": "Waiting" },
              { "reference": "WO-1051", "summary": "Replace safety signage", "owner": "Jordan Kim", "due": "Tomorrow", "status": "Ready" },
              { "reference": "AP-092", "summary": "Approve completion proof", "owner": "Riley Chen", "due": "Tomorrow", "status": "Review" }
            ]
          }
        }
      ]
    },
    {
      "_id": "professional-queue-empty",
      "_type": "core.empty-state",
      "props": {
        "title": "No work matches this view",
        "body": "Use this state when an approved query returns zero visible rows; do not substitute an unscoped fallback query."
      }
    }
  ]
}
Professional record detail - copy the complete page JSON
{
  "blocks": [
    {
      "_id": "professional-record-header",
      "_type": "core.page-header",
      "props": {
        "title": "WO-1048 · Inspect cooling system",
        "lead": "A composed record view that can sit beside Files, Conversations, Checklists, Workflow, and Record Activity.",
        "breadcrumb": ["Operations", "Work orders", "WO-1048"]
      }
    },
    {
      "_id": "professional-record-statuses",
      "_type": "core.container",
      "props": { "layout": "row" },
      "children": [
        { "_id": "professional-record-status", "_type": "core.badge", "props": { "label": "In progress", "tone": "success" } },
        { "_id": "professional-record-priority", "_type": "core.badge", "props": { "label": "High priority", "tone": "warning" } },
        { "_id": "professional-record-location", "_type": "core.badge", "props": { "label": "North facility", "tone": "neutral" } }
      ]
    },
    {
      "_id": "professional-record-grid",
      "_type": "core.container",
      "props": { "layout": "grid" },
      "children": [
        {
          "_id": "professional-record-summary",
          "_type": "core.card",
          "props": { "title": "Work summary", "description": "Use nested blocks to compose an editable page without bypassing the page contract.", "tone": "primary" },
          "children": [
            { "_id": "professional-record-summary-label", "_type": "core.section-label", "props": { "label": "Scope" } },
            { "_id": "professional-record-summary-text", "_type": "core.text", "props": { "text": "Inspect the rooftop cooling system, capture proof, and submit the completed checklist for approval.", "variant": "body", "align": "left" } },
            { "_id": "professional-record-owner", "_type": "core.list-row", "props": { "primary": "Morgan Lee", "secondary": "Assigned technician", "trailing": "Today", "initials": "ML", "tone": "primary" } }
          ]
        },
        {
          "_id": "professional-record-proof",
          "_type": "core.card",
          "props": { "title": "Completion proof", "description": "Files and photos remain secured native records; the presentation block only explains the state.", "tone": "success" },
          "children": [
            { "_id": "professional-record-proof-empty", "_type": "core.empty-state", "props": { "title": "No proof attached yet", "body": "Attach photos or documents to checklist items before submitting this work for approval." } }
          ]
        }
      ]
    }
  ]
}
Tip

Keep every _id stable while editing. Template upgrades use block identity to compare and merge changes. Give a copied block a new unique ID instead of duplicating an existing one.

4. Edit the pages in Puck

  1. Open an account-owned workshop SaaS and create or open a page in Design mode.
  2. Drag a component from BuildWithHQ components, or load one of the complete page sources above through the supported page authoring flow.
  3. Select the block and edit Component properties (JSON). The field must contain a JSON object; malformed JSON, arrays and scalar values are rejected.
  4. Preview desktop and mobile layouts, save a draft, then publish through the normal page validator.

For example, this is the complete properties object for a stat tile:

{
  "label": "Open work",
  "value": "128",
  "delta": "12 this week",
  "direction": "up",
  "tone": "primary"
}

The editor round-trips these properties into block.props. It preserves canonical block identity, parent/child structure, responsive settings, event bindings, security metadata, bindingKey and dataKey.

5. Choose a token-safe theme

The presets use the existing SaaS app theme contract: themeJson selects light, dark or system; cssVariables contains allowlisted runtime tokens; and designTokensJson sets base spacing and radius. The runtime parses the document fail-closed, stamps the document element, and applies the tokens to painted components.

BuildWithHQ Indigo Light - copy the complete theme JSON
{
  "schemaVersion": 1,
  "themeKey": "buildwithhq-indigo-light",
  "themeJson": { "schemaVersion": 1, "name": "BuildWithHQ Indigo Light", "mode": "light" },
  "cssVariables": {
    "--runtime-primary": "#4b45e8",
    "--runtime-primary-strong": "#302b8e",
    "--runtime-primary-tint": "rgba(75,69,232,.13)",
    "--runtime-page": "#f4f6fb",
    "--runtime-surface": "#ffffff",
    "--runtime-surface-raised": "#f8f9fc",
    "--runtime-ink": "#17202f",
    "--runtime-ink-muted": "#667085",
    "--runtime-line": "#dfe3ed"
  },
  "designTokensJson": { "spacingBase": 8, "radiusBase": 8 }
}
Executive Slate Dark - copy the complete theme JSON
{
  "schemaVersion": 1,
  "themeKey": "executive-slate-dark",
  "themeJson": { "schemaVersion": 1, "name": "Executive Slate Dark", "mode": "dark" },
  "cssVariables": {
    "--runtime-primary": "#9ea8ff",
    "--runtime-primary-strong": "#c7ccff",
    "--runtime-primary-tint": "rgba(158,168,255,.18)",
    "--runtime-page": "#0e1420",
    "--runtime-surface": "#171e2c",
    "--runtime-surface-raised": "#20293a",
    "--runtime-ink": "#edf1f7",
    "--runtime-ink-muted": "#a8b2c4",
    "--runtime-line": "#303b50"
  },
  "designTokensJson": { "spacingBase": 8, "radiusBase": 10 }
}
Service Emerald Light - copy the complete theme JSON
{
  "schemaVersion": 1,
  "themeKey": "service-emerald-light",
  "themeJson": { "schemaVersion": 1, "name": "Service Emerald Light", "mode": "light" },
  "cssVariables": {
    "--runtime-primary": "#16705a",
    "--runtime-primary-strong": "#0d4f40",
    "--runtime-primary-tint": "rgba(22,112,90,.14)",
    "--runtime-page": "#f2f7f5",
    "--runtime-surface": "#ffffff",
    "--runtime-surface-raised": "#f6faf8",
    "--runtime-ink": "#172521",
    "--runtime-ink-muted": "#61716b",
    "--runtime-line": "#d7e5df"
  },
  "designTokensJson": { "spacingBase": 8, "radiusBase": 8 }
}
Important

Do not paste theme JSON into a tenant table or add an arbitrary CSS/script field. Theme writes must go through the supported version-fenced builder contract. Template-pack artifact schema v2 pins pages and effective components, not the optional legacy live ThemeKey lookup; these presets are instead versioned by the developer-kit package lock and ZIP SHA-256. The public builder theme switcher is still a separate delivery step.

6. Replace preview values with live, scoped data

Static values are useful while designing. For live data, register a reviewed binding and put only its stable key on the block. dataKey may select a bounded property from the returned JSON; it is not a query language.

{
  "_id": "visible-work-table",
  "_type": "core.data-table",
  "bindingKey": "work-orders.current-page",
  "dataKey": "items",
  "props": {
    "caption": "Visible work orders",
    "columns": [
      { "key": "reference", "label": "Reference", "align": "left" },
      { "key": "summary", "label": "Summary", "align": "left" },
      { "key": "status", "label": "Status", "align": "right" }
    ]
  }
}

The approved server operation may return shapes like these:

{
  "stat": { "value": 128, "delta": "12 this week", "direction": "up" },
  "chart": {
    "title": "Completed work",
    "series": [38, 45, 42, 56, 61, 73],
    "labels": ["W1", "W2", "W3", "W4", "W5", "W6"]
  },
  "table": {
    "items": [
      { "reference": "WO-1048", "summary": "Inspect cooling system", "status": "In progress" }
    ]
  }
}
  • A stat accepts a scalar or an object with value, delta and direction.
  • A chart accepts finite numeric series plus short labels.
  • A table accepts an array or an object containing items; columns explicitly select display fields.
  • A failed bound table never falls back to its static preview rows. It shows a loading, error or no-visible-data state.
Important

Page JSON must never contain a database name, connection string, SaaSAppId, AppAccountId, UserId, DataRoleId or LocationId as authorization evidence. The server derives identity and scope from the verified session.

7. Turn the workshop pages into a reusable template

  1. Customize the pages in an account-owned workshop SaaS.
  2. Save the selected theme through the supported version-fenced authoring contract when that builder surface is available.
  3. Harvest each owned Page with POST /api/apps/{saasAppId}/template-harvests.
  4. Attach the harvested artifacts to a draft pack and run the existing pack validator.
  5. Publish an immutable Template Library version.
  6. Install that exact version into a different disposable SaaS and run real auth, permission, binding, layout and failure tests before offering it broadly.
Copy the source-kit manifest
{
  "schemaVersion": 1,
  "templateKey": "professional-foundation",
  "templateName": "BuildWithHQ Professional Foundation",
  "version": "1.0.0",
  "description": "Clean-room professional page compositions and theme presets built from the canonical BuildWithHQ component registry.",
  "delivery": "authoring-source-for-exact-version-template-pack",
  "installRequiresExactVersion": true,
  "runtimeDataAccess": "approved-server-scoped-bindings-only",
  "publicDistribution": {
    "kind": "builder-developer-kit",
    "apiBaseUrl": "https://api.buildwithhq.com",
    "mcpEndpointTemplate": "https://api.buildwithhq.com/v1/apps/{saasAppId}/mcp",
    "archiveName": "BuildWithHQ-Professional-Foundation-Developer-Kit-1.0.0.zip"
  },
  "requiredComponents": [
    "core.badge",
    "core.card",
    "core.chart",
    "core.container",
    "core.data-table",
    "core.empty-state",
    "core.list-row",
    "core.page-header",
    "core.section-label",
    "core.stat-tile",
    "core.text"
  ],
  "pages": [
    {
      "pageKey": "ProfessionalDashboard",
      "name": "Professional dashboard",
      "path": "pages/professional-dashboard.json"
    },
    {
      "pageKey": "ProfessionalQueue",
      "name": "Professional work queue",
      "path": "pages/professional-queue.json"
    },
    {
      "pageKey": "ProfessionalRecord",
      "name": "Professional record detail",
      "path": "pages/professional-record.json"
    }
  ],
  "themes": [
    {
      "themeKey": "buildwithhq-indigo-light",
      "name": "BuildWithHQ Indigo Light",
      "path": "themes/buildwithhq-indigo-light.json"
    },
    {
      "themeKey": "executive-slate-dark",
      "name": "Executive Slate Dark",
      "path": "themes/executive-slate-dark.json"
    },
    {
      "themeKey": "service-emerald-light",
      "name": "Service Emerald Light",
      "path": "themes/service-emerald-light.json"
    }
  ],
  "publication": {
    "harvestEndpoint": "POST /api/apps/{saasAppId}/template-harvests",
    "artifactTypes": ["Page"],
    "ownership": "verified-account-owner",
    "destination": "BuildWithHQ_TemplateLibrary",
    "snapshot": "published-immutable-exact-version",
    "exactVersionContents": ["PackSettings", "Page", "Component"],
    "themePresetDelivery": "checksummed-developer-kit-and-version-fenced-builder-theme-write"
  },
  "security": {
    "identitySource": "verified-server-session",
    "pageJsonCarriesAuthority": false,
    "dataBindings": "tenant+datarole+location scoped before serialization"
  }
}

Template installation is snapshot isolation. A later upstream page or component edit can become a new pack version, but it must not silently mutate a tenant that installed an earlier one. Apply a preset theme separately through the version-fenced theme write; do not claim a live theme catalog lookup is part of the immutable pack.

8. Know the fail-closed limits and verify your template

  • Tables render at most 500 rows and 24 declared columns. Keep pagination and filtering on the server.
  • Charts render at most 60 finite points. Use a summarized binding rather than sending raw event history.
  • dataKey is at most eight safe path segments. Missing or invalid paths return no selected data.
  • Text, labels, breadcrumbs and cell values are length-bounded and rendered as React text, not executable HTML.
  • No CDN, arbitrary runtime script, direct SQL connection or physical tenant database selector is introduced.

Repository maintainers run the source, renderer, editor and catalog checks below before releasing a new foundation version. Builders installing an approved exact version do not need these commands:

python -m pytest templates\professional-foundation\tests -q
npm --prefix apps\tenant-runtime test -- src\ProfessionalPrimitives.test.tsx src\PageRenderer.test.tsx src\PuckPageDesignerAdapter.test.ts
npm --prefix apps\tenant-runtime run build

# Regenerate the implementation catalog while retaining runtime observations.
python catalog-generator\generate_catalog.py --observations artifacts\catalog-observations\tenant-runtime-2026-09-03.jsonl
python catalog-generator\generate_catalog.py --check

Then run an authenticated browser journey through the real auth, SQL, API and runtime paths. Check the selected theme, all expected blocks, empty/loading/error states, mobile overflow, keyboard access, cross-tenant rejection and exact result cardinality.

Continue with the complete React component catalog, page authoring guide, and template versioning guide.