Stéphane Tailland a2bf84eb22 Let a caller learn what a product commits to, and by when
Orderdetail now carries requireddate and order_status, denormalised from the
order the line belongs to — filtering by product and status already answers
the question this used to need a second call per order for.

list_orders also gained a status filter, matching the backend capability that
list_order_details already exposes.

Regenerated with generate-mcp-tools.py.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-31 15:42:36 +02:00

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).

S
Description
No description provided
Readme 82 KiB