de69f88e29
14 routes: Order (single key, full CRUD + order-details sub-resource) and Orderdetail (composite key ordernumber+productcode, own top-level resource, mirrors backend's own URL structure). MCP layer built with the corrected single-route pattern from the start (STATUS.md section 18) — 7 tools, list/get read-only for all 5 roles, create-order/create-orderdetail for admin+customer+support (verified against OrderPermission/OrderScopedPermission.check() — support gets an unconditional class-level pass, the status-only restriction is object-level and doesn't apply to create). Keycloak (local): sales-api-audience + mcp-sales-audience client scopes, sales-api + mcp-sales resource clients, attached to the broker and librechat respectively. Deploy key and broker secret reused/mirrored from catalog-api and the live broker client, same pattern as customers-api/payments-api.
64 lines
3.5 KiB
Markdown
64 lines
3.5 KiB
Markdown
# sales-api
|
|
|
|
Kong routing/policy layer for the **sales** slice of `classic-models-api`
|
|
(see `/Users/stephanetailland/git/classic-models-api`), split out per the
|
|
DDD decomposition in `../kong-konnect-deployment-strategy.md`. The backend
|
|
stays a single monolith — only Kong does the domain split. Structure
|
|
mirrors `../payments-api`/`../customers-api` — single MCP route, not
|
|
`../catalog-api`'s original two-route pattern (see `../STATUS.md` section
|
|
18).
|
|
|
|
Two resources, both with a REST surface and MCP tools:
|
|
- **`Order`** (single key `ordernumber`) — full CRUD + an `order-details`
|
|
sub-resource (`GET /sales/v1/orders/{ordernumber}/order-details/`,
|
|
mirrors the backend's own `@action` on `OrderViewSet`).
|
|
- **`Orderdetail`** (**composite key** `ordernumber` + `productcode`,
|
|
exposed as its own top-level resource — the backend does this too, not
|
|
just nested under `Order`).
|
|
|
|
| Route | Method | Backend path |
|
|
|---|---|---|
|
|
| `/sales/v1/orders/` | GET, POST | `/classic-models/api/v1/orders/` |
|
|
| `/sales/v1/orders/{ordernumber}/` | GET, PUT, PATCH, DELETE | `/classic-models/api/v1/orders/{ordernumber}/` |
|
|
| `/sales/v1/orders/{ordernumber}/order-details/` | GET | `/classic-models/api/v1/orders/{ordernumber}/order-details/` |
|
|
| `/sales/v1/orderdetails/` | GET, POST | `/classic-models/api/v1/orderdetails/` |
|
|
| `/sales/v1/orderdetails/{ordernumber}/{productcode}/` | GET, PUT, PATCH, DELETE | `/classic-models/api/v1/orderdetails/{ordernumber}/{productcode}/` |
|
|
| `/sales-mcp` | GET, POST, DELETE | MCP streamable-http (tools call into the REST routes above) |
|
|
|
|
## Auth & MCP tool ACLs
|
|
|
|
`openid-connect` on both surfaces (`sales-api` REST audience, `mcp-sales`
|
|
MCP audience), RFC 8693 exchange chain MCP → `sales-api` → `classic-models-api`,
|
|
same shape as every other domain. IdP: local Keycloak
|
|
(`https://keycloak.sttlab.local/realms/classic-models`).
|
|
|
|
MCP write-tool ACLs (`create-order`, `create-orderdetail`) are **admin +
|
|
customer + support** — deliberately different from `customers-api`'s/
|
|
`payments-api`'s admin-only write tools, because it's what the real
|
|
backend permission classes actually allow, verified directly against
|
|
`authentication/permissions.py` rather than assumed by analogy:
|
|
`OrderPermission.check()`/`OrderScopedPermission.check()` give `support`
|
|
an unconditional pass at the class-level (`has_permission`) check — the
|
|
"status-only" restriction usually associated with `support` is enforced
|
|
at the *object* level (`has_object_permission`), which only applies to
|
|
existing records (update/delete), not `create`. `read_only`/
|
|
`product_manager` are excluded (both classes only pass those roles for
|
|
`SAFE_METHODS`).
|
|
|
|
**Correction to note**: `payments-api`'s `create-payment` tool (built
|
|
earlier this session) restricted writes to `admin` only, described at the
|
|
time as "verified against `PaymentPermission`'s actual logic" — but
|
|
`PaymentPermission` extends this same `OrderScopedPermission` base class,
|
|
so by the same reasoning above, `customer` and `support` should also have
|
|
been included there. Not fixed as part of this domain's build (out of
|
|
scope, and it's *more* restrictive than the backend rather than less, so
|
|
not a safety issue) — flagged here and in `../STATUS.md` for whoever
|
|
revisits `payments-api`'s MCP tool ACLs.
|
|
|
|
## Structure
|
|
|
|
Same `dev/` + `kong/rest/` + `kong/mcp/` layout as `payments-api`. Deploy
|
|
key and broker secret follow the same reused/mirrored pattern (`catalog-api`'s
|
|
deploy key, broker's real secret pulled live from Keycloak and copied to
|
|
`kong-v2/sales-api/*` in Vault).
|