Files
kong-workforce-api/README.md
T
Stéphane Tailland 2880e21ef1 Build workforce-api REST + MCP layers (Layer 3), full build in one pass
16 routes: Office (single key, full CRUD + employees sub-resource)
and Employee (single key, full CRUD + reports + customers
sub-resources). MCP layer built with the single-route pattern from
the start.

Only domain where customer role has zero access — verified against
ReferenceDataPermission.check(): read_only/product_manager/support
get reads, writes are admin-only, customer isn't in the allow-list
at all. All 9 MCP tool ACLs reflect this exactly.

Keycloak (local): workforce-api-audience + mcp-workforce-audience
client scopes, resource clients, broker/librechat attachments.
Deploy key and broker secret reused/mirrored, same pattern as every
domain since payments-api.
2026-08-23 17:13:45 +02:00

2.9 KiB

workforce-api

Kong routing/policy layer for the workforce 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 ../sales-api/../payments-api — single MCP route from the start, not ../catalog-api's original two-route pattern (see ../STATUS.md section 18).

Two resources, both with a REST surface and MCP tools:

  • Office (single key officecode) — full CRUD + an employees sub-resource.
  • Employee (single key employeenumber) — full CRUD + reports (direct reports, self-referential FK) and customers (assigned sales rep's customers) sub-resources.
Route Method Backend path
/workforce/v1/offices/ GET, POST /classic-models/api/v1/offices/
/workforce/v1/offices/{officecode}/ GET, PUT, PATCH, DELETE /classic-models/api/v1/offices/{officecode}/
/workforce/v1/offices/{officecode}/employees/ GET /classic-models/api/v1/offices/{officecode}/employees/
/workforce/v1/employees/ GET, POST /classic-models/api/v1/employees/
/workforce/v1/employees/{employeenumber}/ GET, PUT, PATCH, DELETE /classic-models/api/v1/employees/{employeenumber}/
/workforce/v1/employees/{employeenumber}/reports/ GET /classic-models/api/v1/employees/{employeenumber}/reports/
/workforce/v1/employees/{employeenumber}/customers/ GET /classic-models/api/v1/employees/{employeenumber}/customers/
/workforce-mcp GET, POST, DELETE MCP streamable-http

Auth & MCP tool ACLs — the one domain where customer gets zero access

Both viewsets use ReferenceDataPermission (authentication/permissions.py): read_only/product_manager/support get read access, writes are admin-only, and — unlike every other domain built this session — customer is not in the allow-list at all, not even for reads. Verified directly against the permission class, not assumed: this is genuinely internal staff/organizational data, and the backend enforces that explicitly. All 7 read tools (list-offices, get-office, get-office-employees, list-employees, get-employee, get-employee-reports, get-employee-customers) have ACL [admin, read_only, product_manager, support] — no customer. Both write tools (create-office, create-employee) are admin only.

openid-connect on both surfaces (workforce-api REST audience, mcp-workforce MCP audience), RFC 8693 exchange chain MCP → workforce-api → classic-models-api. IdP: local Keycloak.

Structure

Same dev/ + kong/rest/ + kong/mcp/ layout as sales-api. Deploy key and broker secret reused/mirrored from catalog-api and the live broker client, same pattern as every domain since payments-api.