Stéphane Tailland 14da60f9ec Point the control-plane ref at the stable mirror CR
CONTROL_PLANE_REF_NAME held the random suffix the Gateway operator gives
its auto-created mirror CR, looked up by hand. Replacing the Konnect org
recreated those CRs under new suffixes, so the ref named an object that
no longer existed and the domain's Kong entities sat Programmed=False.

Name the ${NAME}-cp mirror declared in k8s-platform's dataplane-template
instead — derived from NAME, so it stays valid across Gateway
recreations and Konnect org changes.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-26 16:30:15 +02:00

payments-api

Kong routing/policy layer for the payments 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 itself stays a single monolith — only Kong does the domain split. Structure mirrors ../customers-api, not ../catalog-api — see ../STATUS.md section 18 for why (catalog-api's two-route MCP pattern has a latent bug; customers-api's single-route pattern is the corrected one to copy going forward).

Two exposure surfaces, both proxying to the real classic-models-api backend:

  • REST (kong/rest/) — 6 routes over Payment, which uses a composite key (customernumber + checknumber, not a single id like Customer/Product) — both URI segments are captured and passed through to the backend's own composite-key URL pattern.
  • MCP (kong/mcp/) — list-payments/get-payment (all 5 roles) and create-payment (admin only — verified against PaymentPermission's actual logic in authentication/permissions.py, not guessed: writes are admin-only in practice, customer can only write their own via the REST API directly, not exposed as an MCP tool). One KongRoute for all three MCP HTTP methods, one ai-mcp-proxy binding — see ../STATUS.md section 18 for why this matters (a second route + binding for the same plugin creates a duplicate-tool-name bug, found and fixed on customers-mcp, built correctly here from the start).
Route Method Backend path
/payments/v1/payments/ GET, POST /classic-models/api/v1/payments/
/payments/v1/payments/{customernumber}/{checknumber}/ GET, PUT, PATCH, DELETE /classic-models/api/v1/payments/{customernumber}/{checknumber}/
/payments-mcp GET, POST, DELETE MCP streamable-http (tools call into the REST routes above)

Auth

openid-connect on both surfaces, distinct audience each (payments-api for REST, mcp-payments for MCP) with a real RFC 8693 exchange chain: MCP → payments-api → classic-models-api, same pattern as catalog-api/customers-api. IdP is the local Keycloak (https://keycloak.sttlab.local/realms/classic-models) — see ../STATUS.md sections 15/16. payments-api-audience and mcp-payments-audience client scopes + payments-api/mcp-payments resource clients created on the local Keycloak, attached to kong-token-exchange-broker's default scopes (REST audience) and to librechat's optional scopes (MCP audience) respectively — no dedicated protocol mappers on either new client itself, same practice as every other domain built this session. mcp-payments's OAuth callback added to librechat's redirectUris, and a payments-mcp server entry added to LibreChat's librechat.yaml (infra-librechat repo).

Other policies

Per-consumer rate limiting, response caching (GET/HEAD), audit log (http-log, endpoint still a placeholder — no real log collector in this lab, same caveat as the other domains).

Structure

Same dev/ + kong/rest/ layout as customers-api. Deploy key (kong-v2/payments-api/git-deploy-key) is a copy of catalog-api's, not a freshly generated one — per the user's explicit instruction this session ("no reason a working key for catalog-api wouldn't work for customers-api"), the same reused key is used here too rather than minting yet another one per domain.

S
Description
No description provided
Readme 70 KiB