@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 iseq|neq|gt|gte|lt|lte|like|ilike|in|null|notnull
Generated Routes#
For each model with table name T at basePath (default /admin):
| Method | Path | Description |
|---|---|---|
| GET | {base}/api/schema | All model metadata |
| GET | {base}/api/{T} | List (paginated, searchable, filterable, sortable) |
| GET | {base}/api/{T}/:id | Get one record |
| POST | {base}/api/{T} | Create record (unless readOnly) |
| PUT | {base}/api/{T}/:id | Update record (unless readOnly) |
| DELETE | {base}/api/{T}/:id | Delete record (unless readOnly) |
| POST | {base}/api/{T}/bulk | Bulk action (unless readOnly) |
| POST | {base}/api/{T}/action | Custom action |
| GET | {base}/api/{T}/:id/relations/{R} | Related records |
| POST | {base}/api/query | Execute query builder payload |
| POST | {base}/api/query/preview | Preview 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/:
| File | Export | Description |
|---|---|---|
ui/app.tsx | AdminApp | Main SPA shell (sidebar + content, client-side routing) |
ui/dashboard.tsx | Dashboard | Overview page with model record counts |
ui/list.tsx | ModelList | Model list view (table, search, filters, sort, pagination, bulk actions) |
ui/detail.tsx | Detail | Model detail/edit view (auto-generated form from schema) |
ui/create.tsx | Create | Model create view (empty form) |
ui/query.tsx | QueryBuilder | Visual query builder (select, filter, sort, group, preview SQL, execute) |
ui/components/sidebar.tsx | AdminSidebar | Nav sidebar with model links and query builder link |
ui/components/filter.tsx | FilterBuilder | Row-based filter builder |
ui/components/bulkbar.tsx | BulkBar | Bulk action toolbar (appears when rows selected) |
ui/shell.ts | adminHtml | Generates the HTML shell for serving the SPA |
ui/entry.tsx | — | Browser entry point, mounts AdminApp |
ui/index.html | — | HTML template for Bun HTML imports |
ui/styles.css | — | Base 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, paginationreact,react-dom— renderinglucide-react— icons