Skip to content

Client Admin — the spec-driven frontend

The client sample (standards/src/templates/client/) renders a full admin — auth pages, resource lists, forms, detail views — from the server's openapi.yaml, driven entirely by the x- extension fields. There are no hand-written screens per resource.

What ships

A Vite + React + MUI app wiring the two Aetos packages:

  • @aetoskia/react-openapi — fetches ${VITE_API_BASE_URL}/openapi.json, builds the router and the resource admin from the spec's schemas and x- fields (list columns, autocomplete, fk pickers, enum selects, hidden fields…)
  • @aetoskia/react-auth — login/register/logout against the auth-server paths declared in the spec's securitySchemes.bearerAuth, and attaches the JWT to every API call
  • a shared MUI theme (src/shared-theme/) and the shell (Header / Footer / Home)

src/openapi-config.ts is the only configuration:

1
2
3
4
5
6
export const specConfiguration: SpecConfiguration = {
  specUrl: `${apiBase}/openapi.json`,
  baseApiUrl: apiBase,
  title: "Vet Admin",
  getToken: () => tokenStore.get(),
};

Pair it with the sample server

1
2
3
4
cd apps/vet-sample-client
printf 'VITE_API_BASE_URL=http://localhost:8020\nVITE_AUTH_BASE_URL=http://localhost:8020\n' > .env.local
npm install
npm run dev

Open the dev-server URL; the admin lists Parents, Pets, Treatments, Vets, Appointments and Jobs straight from the vet spec. Edit openapi.yaml on the server and the client follows on reload — the spec is the contract on both sides.

Where the x- extensions come from

The canonical catalog lives in the react-openapi package (spec-extensions.ts, served to agents as the specExtensions module of the react-openapi MCP bundle). The worked examples on the server side are the Job schema (enum selects via x-edit-as: select + x-ui-type: enum, x-hidden field masks, x-list-columns) and the FK fields on Appointment (x-fk: {resource: pets, prefetch: true}).

CI

The client ships a drone-npm shape (Type B in Drone Pipelines) and follows the Versioning standard (package.json + CHANGELOG.md).