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