Post http-log to /sales instead of /logs. Fluent Bit's http input derives the record tag from the request URI, so the path is what identifies this domain in the collector and becomes the Loki label domain=sales. The collector keeps writing every domain to the on-disk audit trail as well, so this is reversible by restoring the previous path. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
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 keyordernumber) — full CRUD + anorder-detailssub-resource (GET /sales/v1/orders/{ordernumber}/order-details/, mirrors the backend's own@actiononOrderViewSet).Orderdetail(composite keyordernumber+productcode, exposed as its own top-level resource — the backend does this too, not just nested underOrder).
| 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).