@atlas/admin#

Django-style admin panel that auto-generates CRUD API routes from @atlas/db schemas.

Exports#

Factory#

  • admin(config: AdminConfig) — creates admin routes from config, returns { routes: Route[], mount: (existing: Route[]) => Route[] }
  • model(config: ModelConfig) — creates a model configuration

Types#

  • AdminConfig — top-level config: { db, models, basePath?, auth? }
  • ModelConfig — per-model config: { schema, listFields?, searchFields?, filterFields?, relations?, actions?, bulkActions?, readOnly? }
  • CustomAction<T> — custom action: { name, label, handler }
  • BulkAction"delete" | "export"
  • RelationConfig — relation: { schema, foreignKey, label? }
  • QueryPayload — query builder payload: { table, select?, filters?, sort?, limit?, offset?, groupBy? }
  • QueryFilter — filter: { field, op, value? } where op is eq|neq|gt|gte|lt|lte|like|ilike|in|null|notnull

Generated Routes#

For each model with table name T at basePath (default /admin):

MethodPathDescription
GET{base}/api/schemaAll model metadata
GET{base}/api/{T}List (paginated, searchable, filterable, sortable)
GET{base}/api/{T}/:idGet one record
POST{base}/api/{T}Create record (unless readOnly)
PUT{base}/api/{T}/:idUpdate record (unless readOnly)
DELETE{base}/api/{T}/:idDelete record (unless readOnly)
POST{base}/api/{T}/bulkBulk action (unless readOnly)
POST{base}/api/{T}/actionCustom action
GET{base}/api/{T}/:id/relations/{R}Related records
POST{base}/api/queryExecute query builder payload
POST{base}/api/query/previewPreview SQL without executing

List endpoint query params: ?page=1&limit=20&sort=name&order=asc&search=foo&filter.status=active

Usage#

import { admin, model } from "@atlas/admin"
import { defineSchema, column, connect } from "@atlas/db"
import { serve, get, pipe, json } from "@atlas/server"

const users = defineSchema("users", {
  id: column.serial().primaryKey(),
  email: column.text().unique(),
  name: column.text(),
})

const posts = defineSchema("posts", {
  id: column.serial().primaryKey(),
  title: column.text(),
  userid: column.integer(),
})

const db = connect({ driver: "sqlite", path: "./app.db" })

const panel = admin({
  db,
  basePath: "/admin",
  auth: { secret: "my-secret" },
  models: [
    model({
      schema: users,
      searchFields: ["email", "name"],
      filterFields: ["name"],
      bulkActions: ["delete", "export"],
      relations: [{ schema: posts, foreignKey: "userid" }],
      actions: [{
        name: "deactivate",
        label: "Deactivate",
        handler: async (db, ids) => ({ message: `Deactivated ${ids.length}` }),
      }],
    }),
    model({ schema: posts, readOnly: true }),
  ],
})

serve({
  port: 3000,
  routes: panel.mount([
    get("/", pipe(c => json(c, 200, { status: "ok" }))),
  ]),
})

UI Components#

Frontend React SPA in ui/:

FileExportDescription
ui/app.tsxAdminAppMain SPA shell (sidebar + content, client-side routing)
ui/dashboard.tsxDashboardOverview page with model record counts
ui/list.tsxModelListModel list view (table, search, filters, sort, pagination, bulk actions)
ui/detail.tsxDetailModel detail/edit view (auto-generated form from schema)
ui/create.tsxCreateModel create view (empty form)
ui/query.tsxQueryBuilderVisual query builder (select, filter, sort, group, preview SQL, execute)
ui/components/sidebar.tsxAdminSidebarNav sidebar with model links and query builder link
ui/components/filter.tsxFilterBuilderRow-based filter builder
ui/components/bulkbar.tsxBulkBarBulk action toolbar (appears when rows selected)
ui/shell.tsadminHtmlGenerates the HTML shell for serving the SPA
ui/entry.tsxBrowser entry point, mounts AdminApp
ui/index.htmlHTML template for Bun HTML imports
ui/styles.cssBase styles

The admin SPA is served at GET {basePath} and GET {basePath}/*. Uses React, Mantine, TanStack Table, and lucide-react.

Dependencies#

  • @atlas/db — schema, query builder, connection
  • @atlas/server — pipe, pipeline, router, json, parseJson
  • @atlas/auth — requireAuth (optional, when auth config provided)
  • @mantine/core, @mantine/hooks, @mantine/form — UI components and hooks
  • @tanstack/react-table — table with sorting, selection, pagination
  • react, react-dom — rendering
  • lucide-react — icons
Canonical sourcepackages/admin/AGENTS.md
Type to search guides and package references.