Stéphane Tailland be1c4fb974 Reconcile this repo's Flux entrypoints instead of applying them by hand
dev/ declares this repo's GitRepository, the Kustomization that deploys
./kong, and its ExternalSecrets — but nothing watched dev/, so those files
were applied once by hand and never re-read. Editing them in git changed
nothing until someone remembered to kubectl apply, which is what silently
swallowed the CONTROL_PLANE_REF_NAME rollout: correct in git for hours
while the cluster still held the old value.

Add the bootstrap Kustomization that watches ./dev and, living in ./dev,
manages itself. This is what `flux bootstrap` would have created;
flux-operator installs the controllers and no root.

It sits in the domain namespace rather than flux-system, because sourceRef
resolves in the Kustomization's own namespace and because this is the
team's to own.

Needs one kubectl apply to exist. That is the last one this repo needs.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-27 14:33:06 +02:00

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.

S
Description
No description provided
Readme 69 KiB