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.
This commit is contained in:
@@ -1,12 +1,51 @@
|
||||
# workforce-api
|
||||
|
||||
Placeholder component repo for the **workforce** slice of
|
||||
`classic-models-api` (see /Users/stephanetailland/git/classic-models-api),
|
||||
split out per the DDD decomposition documented in
|
||||
`../kong-konnect-deployment-strategy.md`.
|
||||
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).
|
||||
|
||||
This repo does not yet contain migrated application code — only the
|
||||
routing scaffold (layer 3: `HTTPRoute`/`KongPlugin`/`KongConsumer`,
|
||||
alongside the eventual app manifests), targeting the Control Plane(s)
|
||||
provisioned for `workforce` (see `../konnect-platform/domains/workforce/`
|
||||
and `../dataplane-workforce`).
|
||||
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`.
|
||||
|
||||
Reference in New Issue
Block a user