Quickback Docs

Quickback CMS

Schema-driven admin interface that renders your entire backend from Quickback definitions — zero UI code per table.

Early Access

The Quickback CMS is in early access. It works with any Quickback-compiled API that outputs a schema registry. Expect active development and potential changes.

Quickback CMS

A schema-driven admin interface that reads schema-registry.json generated by the Quickback compiler. Every table, column, action, view, and security rule is rendered automatically. Zero UI code per table.

Overview

The CMS generates its entire UI from your Quickback definitions. Define a table with columns, guards, masking, views, and actions in your feature files. Run the compiler. The CMS reads the resulting schema registry and renders a complete admin interface — data tables, inline editing, action dialogs, role-based access, and field masking — all without writing a single line of UI code.

Key Features

  • Schema-driven — Zero UI code per table. Add a table, recompile, and it appears in the CMS.
  • Dashboard — Stats grid and feature cards showing tables, columns, actions, views, and masked fields at a glance.
  • Custom pages — Split-panel layouts with drag-and-drop, matching engine, and page-level actions for workflows like reconciliation.
  • Embedded in your Worker — Set cms: true in config. The CMS is served as static assets from the same Cloudflare Worker as your API — same origin, no CORS, auth cookies work naturally.
  • Dual view modes — Table browse mode for navigation and Data Table mode for spreadsheet-style editing.
  • Role-based access — Owner, admin, and member roles with live switching. CRUD buttons hidden when unauthorized.
  • Multi-tenant & single-tenant — Org-scoped access by default, with single-tenant mode for simpler projects.
  • Inline spreadsheet editing — Excel/Google Sheets-like editing with keyboard navigation (arrows, Tab, Enter, Escape).
  • FK typeahead — Server-side search for foreign key fields with debounced queries and keyboard navigation.
  • Field masking — Email, phone, SSN, and redaction patterns applied per role. Masked fields show a lock icon.
  • Custom actions — Action dialogs with auto-generated input forms, access filtering, CMS metadata (icons, categories, confirmations), and side effects warnings.
  • Views — Named column-level projections per role. "All Fields" plus custom views in the toolbar.
  • Auto-form generation — Create and edit forms built from guards (createable/updatable fields).
  • Display column auto-detection — FK labels resolved automatically from name, title, label, code, and other common patterns.

Architecture

The CMS sits at the end of the Quickback compilation pipeline:

Quickback Definitions (feature files)
        |
        v
    Compiler
        |
        v
  schema-registry.json
        |
        v
    CMS reads it
        |
        v
  Renders admin UI

Your feature definitions are the single source of truth. The compiler extracts all metadata — columns, types, guards, masking rules, views, actions, validation, and firewall config — into a static JSON file. The CMS consumes that file and renders the appropriate UI for each table.

How Embedded Serving Works

When cms: true is set, the compiler builds the CMS SPA from source at compile time (with your project-specific env vars baked in) and outputs the assets to src/apps/cms/. It also configures wrangler.toml:

[assets]
binding = "ASSETS"
directory = "src/apps"
not_found_handling = "none"
run_worker_first = true

All requests go through the Worker first. The Worker handles SPA routing — serving CMS at /cms/ on the unified domain and at root (/) on a custom CMS domain. API paths (/api/*, /auth/*, etc.) are handled by Hono as normal.

See Multi-Domain Architecture for details on hostname-based routing.

Zero UI Code

The CMS generates its entire UI from your Quickback definitions. Add a table, recompile, and it appears in the CMS. No UI code to write.

Quick Start

1. Enable CMS in config

quickback/quickback.config.ts
export default defineConfig({
  name: "my-app",
  cms: true,
  // ...providers
});

2. Compile

quickback compile

The compiler generates schema-registry.json and copies CMS static assets to src/apps/. It also adds an [assets] section to wrangler.toml so Cloudflare serves the CMS SPA automatically.

3. Run

npm run dev

Open your Worker URL in a browser — the CMS is served at the root. API routes (/api/*, /auth/*, etc.) pass through to your Hono app as normal. Everything runs on the same origin — no CORS configuration needed, auth cookies work naturally.

Optional: Custom CMS domain

cms: { domain: "cms.example.com" }

This adds a custom domain route to wrangler.toml. Both domains serve the same Worker — api.example.com for the API, cms.example.com for the CMS. The compiler also auto-infers a unified quickback.example.com domain where everything is available. See Multi-Domain Architecture.

Optional: Restrict CMS to admins

cms: { domain: "cms.example.com", access: "admin" }

With access: "admin", access is gated on user.role === "admin" (the user-table role from Better Auth's admin plugin) at four layers — defense in depth:

  1. Account UI link — the "Go to CMS" button is hidden for non-admins.
  2. CMS SPA shell — the Worker returns 403 Admin access required before serving index.html to a non-admin. Unauthenticated requests are redirected to the login page.
  3. /api/v1/schema — the CMS metadata endpoint checks ctx.userRole === "admin" and returns 403 otherwise.
  4. custom_view CRUD — the CMS-internal saved-views table is gated on userRole: ["admin"] (see the userRole access primitive) rather than org membership.

Your resource CRUD endpoints (/api/v1/<resource>) are not affected — they continue to use the per-resource crud.access.roles you defined.

Default is access: "user" — any authenticated user can access the CMS.

Optional: Skip SPA rebuild

After the first compile, you can skip rebuilding the CMS SPA on subsequent compiles:

cms: { build: false }

This is useful when you're iterating on API features and don't need to rebuild the CMS UI each time — it saves significant compile time. Set build: true (or omit it) when you need to update the CMS assets.

Optional: Custom output directory

cms: { outputDir: "my-custom-path/cms" }

This changes where the compiled CMS assets are placed (relative to project root), instead of the default src/apps/cms/.

Next Steps

On this page