UI: Auto-Rendered Admin & Custom Pages
Summary
The UI axis of an Aetos app is a published React client, not code written per application. Two npm packages carry the whole surface:
| Package | Role |
|---|---|
@aetoskia/react-openapi |
Renders a complete admin panel (CRUD tables, forms, filters, sorting, pagination, uploads) from the app's openapi.yaml — zero UI code. |
@aetoskia/react-auth |
Auth contexts and pages (login/register/me) wired to the auth-server, plus the axios client with token handling. |
Both publish to the private registry https://npm.aetoskia.com. The server
spec is the single source of truth: the same openapi.yaml that drives
openapi-first routing drives the admin UI, through x- extension fields
(see below).
Scaffold
The client template is a Vite + MUI app with:
src/openapi-config.ts— points the renderer at the app's spec and the auth-server's spec;.env.example—VITE_API_BASE_URL(app API) andVITE_AUTH_BASE_URL(auth-server);- a
Homepage that auto-lists every resource the spec declares, and aHeader/Footer/theme scaffold.
Custom pages are ordinary React routes layered on top; the auto-rendered admin
is available per resource at #/resource/<name>.
x- extensions: how the spec steers the UI
The admin renderer reads a catalog of OpenAPI extension fields (x-resource,
x-list-columns, x-display-format, x-label, x-order, x-hidden,
x-sortable, x-filterable, x-autocomplete, x-fk, x-ui-type,
x-upload, x-sse, x-profile, and the auth wiring x-server-url /
x-login-path / x-me-path / …) declared on schemas and properties.
The catalog is canonical in the react-openapi source, not in this doc. Read it from the MCP bundle:
The app's own spec carries the per-resource values; the catalog explains what
each field does. The template's openapi.yaml shows the convention on the
example Job schema.
Golden rules
- The spec owns the UI. Add a resource or rename a column in
openapi.yaml; the admin follows. Never fork the renderer per app. - Custom pages for workflows, auto-render for CRUD. Anything that is "list / create / edit / delete an entity" is a spec concern; anything that is a bespoke workflow is a React page.
- Auth is consumed, never re-implemented.
@aetoskia/react-authholds tokens and calls the auth-server endpoints declared by the x- wiring; pages read the context. - Publish, don't vendor. UI shared across apps belongs in
@aetoskia/react-openapior@aetoskia/react-auth(SemVer, tag-triggered npm release), not copy-pasted into app trees.
Notes
- The server template ships authless by default (see 22 – Auth Integration); the client template pairs with it and degrades to "no login" until a security scheme is declared.
- The standards app + client templates are the full-stack reference: the
server spec carries the x- extensions, and the client renders the admin from
it. The wiki's Reference App walkthrough (
06_reference_app) documents the pairing end to end.