diff --git a/react-openapi/mcp/modules/react-openapi.json b/react-openapi/mcp/modules/react-openapi.json index eecd595..aa13134 100644 --- a/react-openapi/mcp/modules/react-openapi.json +++ b/react-openapi/mcp/modules/react-openapi.json @@ -707,7 +707,7 @@ "kind": "variable", "path": "react-openapi.specExtensions", "signature": "specExtensions: SpecExtensionDoc[]", - "docstring": "# OpenAPI `x-` extension catalog (canonical, agent-facing)\n\nThis export is the **canonical machine-readable reference** for every\nvendor extension `react-openapi` understands. Its docstring is rendered\nverbatim into the `react-openapi` MCP bundle by doc-weaver — agents\nbuilding or validating a spec should read it from\n`docs://modules/react-openapi` (object `specExtensions`) rather than\ninferring extensions from examples. The human-facing guide is the package\nREADME; the reference application is `aetos/react/vet` (its\n`server/openapi.yaml` uses nearly every extension below).\n\n## How the spec drives the UI\n\n`AppProvider` loads the OpenAPI document at runtime, validates it, and —\nfor every schema carrying `x-resource` — derives a `ResourceConfig` from\nthe schema's properties and the matching paths. `Admin` then renders a\nsidebar, list/detail/form routes, FK dropdowns and SSE streams from those\nconfigs. No per-resource React code is required; adding a domain to the\nbackend surfaces it in the admin automatically.\n\n## Levels\n\nExtensions attach at five places: **schema** (on a `components.schemas`\nobject; marks a resource), **property** (inside a resource schema's\n`properties`), **path** (on a path item), **operation** (on an operation\nobject), and **securityScheme** (on the `bearerAuth` scheme).\n\n## Required vs optional / strictness\n\nA missing **required** extension is a spec **error**: the admin shows the\nvalidation screen and refuses to render the affected resource. Missing\noptional extensions degrade gracefully (defaults noted below). There are\nno fallbacks for required extensions and no flexible response parsing —\nthe spec is the contract and the admin throws at transform time when it is\nviolated.\n\n## Schema-level extensions\n\n- **`x-resource` (REQUIRED, string)** — marks a schema as an admin\n resource and names its collection path segment (`\"pets\"` maps to\n GET/POST `/pets`). Schemas without it are skipped entirely (use that for\n shared shapes like `Metadata` or error bodies). The value must match an\n existing path; the validator errors if missing.\n- **`x-primary-key` (REQUIRED, string)** — property that uniquely\n identifies a record; used as the `{id}` path parameter in every item\n request and as the FK wire value unless `x-fk.value` overrides it. Must\n reference a property that exists. Validator error if missing.\n- **`x-display-format` (REQUIRED, string template)** — template with\n `{propertyName}` placeholders rendered as the record's human label in\n list rows, detail titles and FK dropdown options, e.g. `\"{name} - #{id}\"`.\n Validator error if missing.\n- **`x-list-columns` (REQUIRED, string[])** — ordered property names shown\n as datatable columns; every entry must exist in `properties`. Cell\n display uses the target resource's `x-display-format` for FK fields and\n the parent resource's formatting for direct fields. Validator error if\n missing or invalid.\n\n## Property-level extensions\n\n- **`x-label` (REQUIRED, string)** — human-readable label for form fields,\n table headers and detail views. Required on every property of a resource\n schema; validator error if missing.\n- **`x-order` (REQUIRED, integer)** — field ordering in forms and detail\n views; lower first, ties broken alphabetically. Required (non-null) on\n every property; validator error if missing. List columns follow\n `x-list-columns`, not `x-order`.\n- **`x-description` (optional, string)** — helper text below form fields\n and placeholder text; falls back to `x-label`.\n- **`x-hidden` (optional, `{ form?, list?, detail? }`)** — per-view\n visibility; missing keys default to false (visible). Typical use: hide\n the auto-generated primary key from forms/lists.\n- **`x-filterable` (optional, boolean, default false)** — marks the field\n as filterable in the datatable filter bar.\n- **`x-sortable` (optional, boolean, default false)** — adds sort controls\n to the column header; clicking sends `?sort=field` (ascending) or\n `?sort=-field` (descending) to the list endpoint in server mode.\n- **`x-fk` (optional, `{ resource, prefetch?, value? }`)** — marks a\n `$ref` property as a foreign key. Non-array → `FkSelectField` (dropdown);\n array with `items.$ref` → `FkMultiSelectField` (multi-select). `resource`\n is the target's `x-resource` value (not the schema name) and must exist;\n the target must have `x-display-format` + `x-primary-key`. `prefetch=true`\n loads all options on mount, false (default) on focus. Options are fetched\n with `GET /{resource}?limit=0` for paginated targets (`limit=0` is the\n server convention for \"all records\") and formatted with the target's\n `x-display-format`. `value` names the wire-value property (defaults to\n the target's primary key). A `$ref` WITHOUT `x-fk` renders read-only\n inline (chips in list/detail, disabled JSON text field in forms).\n- **`x-edit-as` (optional, `\"date\"`)** — edit a date-time property with a\n plain date input; submits midnight of the chosen day.\n- **`x-ui-type` (optional, `\"image\" | \"currency\"`)** — `\"image\"` renders a\n file-upload form field with preview (Avatar in list/detail); with\n `x-upload-url` set and a record id present it POSTs the file there\n (`{id}` substituted) and stores the response URL, otherwise it falls back\n to an inline base64 data URL. `\"currency\"` renders a currency field (also\n settable per-field via `SpecConfiguration.resourceConfig.fieldTypes`).\n- **`x-upload-url` (optional, string path template)** — POST endpoint for\n `x-ui-type: image` uploads, e.g. `/pets/{id}/photo`.\n- **`x-upload` (optional, `{ type, url }`)** — generic file upload; the\n file is POSTed as raw `application/octet-stream` to `url` with a\n `Content-Disposition: attachment; filename=\"...\"` header; the response\n must contain a `saved_as` field which becomes the stored value. `type` is\n one of `image | pdf | html | csv | file` (Avatar vs clickable chip\n display, chip has delete/replace).\n- **`x-autocomplete` (optional, `\"text\" | \"token\" | \"email\" | \"phone\"`)** —\n server-side filter-bar widget hint for text-ish fields.\n\n## Path-level extensions\n\n- **`x-sse` (optional on a path item, boolean)** — marks a path as a\n Server-Sent Events stream. Excluded from CRUD derivation;\n `SseStreamView`/`useItemSse` connect with an EventSource and render the\n streaming resource's records as they arrive. The 200 response must be\n `text/event-stream`; give the event schema display metadata\n (`x-display-format`, `x-list-columns`, `x-primary-key`) so stream rows\n render like a list. Path parameters are supported\n (e.g. `/pets/{id}/actions`).\n\n## Operation-level extensions\n\n- **`x-profile` (optional on an operation, boolean)** — marks a profile\n (current-user) operation. `ProfileRoutes` renders the matching component\n from `SpecConfiguration.profileComponents` by mode: GET → view,\n PUT/PATCH → edit, POST → create.\n\n## securityScheme extensions (auth-server wiring)\n\nCarried on the `bearerAuth` scheme and extracted into `AuthConfig`; the\nbackend may template values from environment (e.g. `\"{AUTH_SERVER}\"`) and\nresolve them before serving the spec. Pair with `@aetoskia/react-auth`.\n\n- **`x-server-url`** — auth-server base URL (`AuthConfig.serverUrl`).\n- **`x-login-path`** — login endpoint path.\n- **`x-register-path`** — registration endpoint path.\n- **`x-logout-path`** — logout endpoint path.\n- **`x-me-path`** — current-user endpoint path (react-auth fetches the\n session user from it whenever the token changes).\n- **`x-introspect-path`** — token-introspection endpoint path.\n\n## Path conventions\n\nFor every schema with `x-resource: ` the spec MUST provide:\n`GET /` (list — populates the datatable), `POST /` (create),\n`GET //{id}` (detail), `PUT` or `PATCH //{id}` (edit — PATCH is\nhonored when present), and `DELETE //{id}` (delete).\n\n## Response conventions (strict — no fallbacks)\n\n- **Paginated list** (collection GET has BOTH `limit` and `offset` query\n params): body MUST be `{ total?, items: [] }`. `total` is optional\n (falls back to `items.length`); `items` is required and must be an\n array; anything else throws.\n- **Non-paginated list**: body MUST be a bare JSON array.\n- **Single item / create / update**: the resource object directly.\n- **Delete**: HTTP 204, no body.\n- **Errors**: FastAPI 422 arrays of `{ loc, msg, type }` (each `msg`\n rendered) or generic `{ detail: string }`.\n\n## Pagination conventions\n\nA resource is paginated iff its collection GET has both `limit` and\n`offset`, and `limit` MUST declare `schema.default` (e.g. 20). The\ndatatable then sends `?limit={rowsPerPage}&offset={page * rowsPerPage}`.\nFK option loading requests `?limit=0` on paginated targets — a server\nconvention meaning \"return all records\" (implement it, e.g. in the list\nhandler's pagination helper).\n\n## Validation rules (spec-validator.ts, in order)\n\n1. `x-primary-key` present. 2. `x-display-format` present.\n3. `x-list-columns` is an array of existing property names. 4. Every\nproperty has `x-label`. 5. Every property has `x-order`. 6. `$ref` without\n`x-fk` → info (read-only inline). 7. `x-fk.resource` matches some schema's\n`x-resource` and that target has `x-display-format` + `x-primary-key`.\n8. The `x-resource` path exists in `paths`. 9. Collection path has GET and\nPOST. 10. Item path has GET, PUT (or PATCH) and DELETE. 11. Paginated\ncollections declare `schema.default` on `limit`. Errors block rendering of\nthe affected resource; warnings/infos render alongside.\n\n## Index\n\nThe array value of this export is the machine-readable index (name, level,\nrequired, value shape, example) of the extensions documented above." + "docstring": "# OpenAPI `x-` extension catalog (canonical, agent-facing)\n\nThis export is the **canonical machine-readable reference** for every\nvendor extension `react-openapi` understands. Its docstring is rendered\nverbatim into the `react-openapi` MCP bundle by doc-weaver — agents\nbuilding or validating a spec should read it from\n`docs://modules/react-openapi` (object `specExtensions`) rather than\ninferring extensions from examples. The human-facing guide is the package\nREADME; the reference application is the standards sample (its\n`standards/src/templates/app/openapi.yaml` uses nearly every extension\nbelow).\n\n## How the spec drives the UI\n\n`AppProvider` loads the OpenAPI document at runtime, validates it, and —\nfor every schema carrying `x-resource` — derives a `ResourceConfig` from\nthe schema's properties and the matching paths. `Admin` then renders a\nsidebar, list/detail/form routes, FK dropdowns and SSE streams from those\nconfigs. No per-resource React code is required; adding a domain to the\nbackend surfaces it in the admin automatically.\n\n## Levels\n\nExtensions attach at five places: **schema** (on a `components.schemas`\nobject; marks a resource), **property** (inside a resource schema's\n`properties`), **path** (on a path item), **operation** (on an operation\nobject), and **securityScheme** (on the `bearerAuth` scheme).\n\n## Required vs optional / strictness\n\nA missing **required** extension is a spec **error**: the admin shows the\nvalidation screen and refuses to render the affected resource. Missing\noptional extensions degrade gracefully (defaults noted below). There are\nno fallbacks for required extensions and no flexible response parsing —\nthe spec is the contract and the admin throws at transform time when it is\nviolated.\n\n## Schema-level extensions\n\n- **`x-resource` (REQUIRED, string)** — marks a schema as an admin\n resource and names its collection path segment (`\"pets\"` maps to\n GET/POST `/pets`). Schemas without it are skipped entirely (use that for\n shared shapes like `Metadata` or error bodies). The value must match an\n existing path; the validator errors if missing.\n- **`x-primary-key` (REQUIRED, string)** — property that uniquely\n identifies a record; used as the `{id}` path parameter in every item\n request and as the FK wire value unless `x-fk.value` overrides it. Must\n reference a property that exists. Validator error if missing.\n- **`x-display-format` (REQUIRED, string template)** — template with\n `{propertyName}` placeholders rendered as the record's human label in\n list rows, detail titles and FK dropdown options, e.g. `\"{name} - #{id}\"`.\n Validator error if missing.\n- **`x-list-columns` (REQUIRED, string[])** — ordered property names shown\n as datatable columns; every entry must exist in `properties`. Cell\n display uses the target resource's `x-display-format` for FK fields and\n the parent resource's formatting for direct fields. Validator error if\n missing or invalid.\n\n## Property-level extensions\n\n- **`x-label` (REQUIRED, string)** — human-readable label for form fields,\n table headers and detail views. Required on every property of a resource\n schema; validator error if missing.\n- **`x-order` (REQUIRED, integer)** — field ordering in forms and detail\n views; lower first, ties broken alphabetically. Required (non-null) on\n every property; validator error if missing. List columns follow\n `x-list-columns`, not `x-order`.\n- **`x-description` (optional, string)** — helper text below form fields\n and placeholder text; falls back to `x-label`.\n- **`x-hidden` (optional, `{ form?, list?, detail? }`)** — per-view\n visibility; missing keys default to false (visible). Typical use: hide\n the auto-generated primary key from forms/lists.\n- **`x-filterable` (optional, boolean, default false)** — marks the field\n as filterable in the datatable filter bar.\n- **`x-sortable` (optional, boolean, default false)** — adds sort controls\n to the column header; clicking sends `?sort=field` (ascending) or\n `?sort=-field` (descending) to the list endpoint in server mode.\n- **`x-fk` (optional, `{ resource, prefetch?, value? }`)** — marks a\n `$ref` property as a foreign key. Non-array → `FkSelectField` (dropdown);\n array with `items.$ref` → `FkMultiSelectField` (multi-select). `resource`\n is the target's `x-resource` value (not the schema name) and must exist;\n the target must have `x-display-format` + `x-primary-key`. `prefetch=true`\n loads all options on mount, false (default) on focus. Options are fetched\n with `GET /{resource}?limit=0` for paginated targets (`limit=0` is the\n server convention for \"all records\") and formatted with the target's\n `x-display-format`. `value` names the wire-value property (defaults to\n the target's primary key). A `$ref` WITHOUT `x-fk` renders read-only\n inline (chips in list/detail, disabled JSON text field in forms).\n- **`x-edit-as` (optional, `\"date\"`)** — edit a date-time property with a\n plain date input; submits midnight of the chosen day.\n- **`x-ui-type` (optional, `\"image\" | \"currency\"`)** — `\"image\"` renders a\n file-upload form field with preview (Avatar in list/detail); with\n `x-upload-url` set and a record id present it POSTs the file there\n (`{id}` substituted) and stores the response URL, otherwise it falls back\n to an inline base64 data URL. `\"currency\"` renders a currency field (also\n settable per-field via `SpecConfiguration.resourceConfig.fieldTypes`).\n- **`x-upload-url` (optional, string path template)** — POST endpoint for\n `x-ui-type: image` uploads, e.g. `/pets/{id}/photo`.\n- **`x-upload` (optional, `{ type, url }`)** — generic file upload; the\n file is POSTed as raw `application/octet-stream` to `url` with a\n `Content-Disposition: attachment; filename=\"...\"` header; the response\n must contain a `saved_as` field which becomes the stored value. `type` is\n one of `image | pdf | html | csv | file` (Avatar vs clickable chip\n display, chip has delete/replace).\n- **`x-autocomplete` (optional, `\"text\" | \"token\" | \"email\" | \"phone\"`)** —\n server-side filter-bar widget hint for text-ish fields.\n\n## Path-level extensions\n\n- **`x-sse` (optional on a path item, boolean)** — marks a path as a\n Server-Sent Events stream. Excluded from CRUD derivation;\n `SseStreamView`/`useItemSse` connect with an EventSource and render the\n streaming resource's records as they arrive. The 200 response must be\n `text/event-stream`; give the event schema display metadata\n (`x-display-format`, `x-list-columns`, `x-primary-key`) so stream rows\n render like a list. Path parameters are supported\n (e.g. `/pets/{id}/actions`).\n\n## Operation-level extensions\n\n- **`x-profile` (optional on an operation, boolean)** — marks a profile\n (current-user) operation. `ProfileRoutes` renders the matching component\n from `SpecConfiguration.profileComponents` by mode: GET → view,\n PUT/PATCH → edit, POST → create.\n\n## securityScheme extensions (auth-server wiring)\n\nCarried on the `bearerAuth` scheme and extracted into `AuthConfig`; the\nbackend may template values from environment (e.g. `\"{AUTH_SERVER}\"`) and\nresolve them before serving the spec. Pair with `@aetoskia/react-auth`.\n\n- **`x-server-url`** — auth-server base URL (`AuthConfig.serverUrl`).\n- **`x-login-path`** — login endpoint path.\n- **`x-register-path`** — registration endpoint path.\n- **`x-logout-path`** — logout endpoint path.\n- **`x-me-path`** — current-user endpoint path (react-auth fetches the\n session user from it whenever the token changes).\n- **`x-introspect-path`** — token-introspection endpoint path.\n\n## Path conventions\n\nFor every schema with `x-resource: ` the spec MUST provide:\n`GET /` (list — populates the datatable), `POST /` (create),\n`GET //{id}` (detail), `PUT` or `PATCH //{id}` (edit — PATCH is\nhonored when present), and `DELETE //{id}` (delete).\n\n## Response conventions (strict — no fallbacks)\n\n- **Paginated list** (collection GET has BOTH `limit` and `offset` query\n params): body MUST be `{ total?, items: [] }`. `total` is optional\n (falls back to `items.length`); `items` is required and must be an\n array; anything else throws.\n- **Non-paginated list**: body MUST be a bare JSON array.\n- **Single item / create / update**: the resource object directly.\n- **Delete**: HTTP 204, no body.\n- **Errors**: FastAPI 422 arrays of `{ loc, msg, type }` (each `msg`\n rendered) or generic `{ detail: string }`.\n\n## Pagination conventions\n\nA resource is paginated iff its collection GET has both `limit` and\n`offset`, and `limit` MUST declare `schema.default` (e.g. 20). The\ndatatable then sends `?limit={rowsPerPage}&offset={page * rowsPerPage}`.\nFK option loading requests `?limit=0` on paginated targets — a server\nconvention meaning \"return all records\" (implement it, e.g. in the list\nhandler's pagination helper).\n\n## Validation rules (spec-validator.ts, in order)\n\n1. `x-primary-key` present. 2. `x-display-format` present.\n3. `x-list-columns` is an array of existing property names. 4. Every\nproperty has `x-label`. 5. Every property has `x-order`. 6. `$ref` without\n`x-fk` → info (read-only inline). 7. `x-fk.resource` matches some schema's\n`x-resource` and that target has `x-display-format` + `x-primary-key`.\n8. The `x-resource` path exists in `paths`. 9. Collection path has GET and\nPOST. 10. Item path has GET, PUT (or PATCH) and DELETE. 11. Paginated\ncollections declare `schema.default` on `limit`. Errors block rendering of\nthe affected resource; warnings/infos render alongside.\n\n## Index\n\nThe array value of this export is the machine-readable index (name, level,\nrequired, value shape, example) of the extensions documented above." }, "Admin": { "name": "Admin", diff --git a/standards/mcp/templates/app/openapi.yaml b/standards/mcp/templates/app/openapi.yaml index 13704c1..edcf577 100644 --- a/standards/mcp/templates/app/openapi.yaml +++ b/standards/mcp/templates/app/openapi.yaml @@ -4,8 +4,8 @@ info: title: Veterinary Clinic API version: 0.1.0 description: | - Veterinary clinic management API — the reference backend pairing with the - react/vet frontend and the react-openapi admin panel renderer. Every + Veterinary clinic management API — the standards reference backend pairing + with the client template and the react-openapi admin panel renderer. Every resource is driven by OpenAPI x- extension fields; auth is bearer JWT introspected against the auth-server. diff --git a/standards/src/templates/app/openapi.yaml b/standards/src/templates/app/openapi.yaml index 13704c1..edcf577 100644 --- a/standards/src/templates/app/openapi.yaml +++ b/standards/src/templates/app/openapi.yaml @@ -4,8 +4,8 @@ info: title: Veterinary Clinic API version: 0.1.0 description: | - Veterinary clinic management API — the reference backend pairing with the - react/vet frontend and the react-openapi admin panel renderer. Every + Veterinary clinic management API — the standards reference backend pairing + with the client template and the react-openapi admin panel renderer. Every resource is driven by OpenAPI x- extension fields; auth is bearer JWT introspected against the auth-server.