Admin UI

A built-in, no-build admin page for browsing and editing the data behind your auto-generated REST API. It is a single page — admin.html plus the admin.js ES module — that the browser loads directly: pure fetch + DOM, no bundler, no framework, no dependencies. It works against whatever collections you declare in backend/collections.toml; it discovers them at runtime.

Open it at /admin.

What it does

collections in a sidebar. If none are declared, it shows a friendly empty state pointing you at the auto-API docs — nothing breaks.

GET /api/collections/<name>/records and renders the records in a table, newest first. Columns are id, created, then one per declared field.

uses the same substring/semantic search the API exposes, so it follows whatever embedding configuration the server has.

field schema — a text input for text, a number input for int/float, a checkbox for bool, with required fields marked. It POSTs JSON and refreshes the list. Validation errors (400 {"error": "..."}) are surfaced inline above the form.

inputs. Save computes only the changed fields and sends them as a PATCH; if nothing changed it just closes. Server validation errors appear under the row.

refreshes.

It is built only on the public API surface documented in Auto-generated REST API — there is no special admin endpoint.

Field types

The form and inline editors map each declared field type to an input:

| Field type | Input | Sent as | | ---------- | ----- | ------- | | text | text input | JSON string | | int | number input (step=1) | JSON number | | float | number input (step=any) | JSON number | | bool | checkbox | JSON boolean |

Empty non-boolean inputs are omitted from the request body, so the server's own required validation still applies and reports back inline.

Accessibility

Real <button> elements, labelled inputs, aria-current on the active collection, required fields marked with field-required, and an aria-live content region so screen readers announce when the view changes. It reuses the design system (.btn, .card, .table, .field, .badge, .empty, .search) with a small amount of admin-scoped CSS in the page.

Verifying it works

The demo site ships a posts collection (title text required, body text).

  1. Open /admin.
  2. The sidebar lists posts. Click it.
  3. You should see a "New record" form (Title + Body) and a records table.
  4. Create a record with a title; it appears at the top of the table.
  5. Try creating one with an empty title — the 400 validation error shows inline.
  6. Edit a row, change the title, Save — the table updates.
  7. Delete a row, confirm — it disappears.

The page logs breadcrumbs to the console you can check:

[admin] init
[admin] loaded 1 collections
[admin] selected collection posts
[admin] loaded N records for posts
[admin] created record id=…
[admin] updated record id=…
[admin] deleted record id=…