- build.py: _TEMPLATE_COMPONENTS rewritten around the vet sample (53 kinds —
per-resource slices, jobs, worked appointment_reminder family, tests);
seed tokens dropped from the manifest ('sample: vet' instead)
- registry.py: get_app_component(kind) no longer renames item/example seeds;
prompts and tool docs updated to 'copy a slice and adapt'
- templates/README.md, 01_build_recipe, 40_ui_admin, wiki/03 updated off the
old seed scheme; repo inventory/config now exclude vet (docs move under
standards; react/vet itself is deleted in a later phase)
- regenerated MCP bundle, vendored templates, and site output
3.4 KiB
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
cp -r <docs>/standards/src/templates/client apps/<your-app>-client
cd apps/<your-app>-client
npm install # deps come from npm.aetoskia.com via .npmrc
npm run dev
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:
docs://modules/react-openapi # module: specExtensions — the full catalog
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.