# 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 ```bash cp -r /standards/src/templates/client apps/-client cd apps/-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) and `VITE_AUTH_BASE_URL` (auth-server); - a `Home` page that auto-lists every resource the spec declares, and a `Header`/`Footer`/theme scaffold. Custom pages are ordinary React routes layered on top; the auto-rendered admin is available per resource at `#/resource/`. --- ## 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 1. **The spec owns the UI.** Add a resource or rename a column in `openapi.yaml`; the admin follows. Never fork the renderer per app. 2. **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. 3. **Auth is consumed, never re-implemented.** `@aetoskia/react-auth` holds tokens and calls the auth-server endpoints declared by the x- wiring; pages read the context. 4. **Publish, don't vendor.** UI shared across apps belongs in `@aetoskia/react-openapi` or `@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](22_auth_integration.md)); 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.