Public Processes API — credentialed access for partners (v2)
What it takes to let partner systems create and query processes (case phases such as Abertura and Inquérito Prévio) from outside, authenticated with an API key instead of the browser's HttpOnly session — without opening a second public network boundary. This is the direction, not a shipped feature; see System overview v2 for how it fits into the rest of the proposed architecture.
The idea
Reuse the gateway shape that already exists for the system's AI gateway boundary — one public origin, Traefik in front, nothing else exposed — but not the "same process" part of it, because the trust boundary here is different:
- Browser keeps using the HttpOnly session against the internal API, inside the backend instance.
- Partner systems authenticate with an API key against a separate public API service
(
:8020), reached at/api/public/processesthrough the same Traefik origin. API key, not OAuth2 client-credentials: partners are provisioned individually and don't need token refresh machinery for what's initially a low-volume integration surface — this can grow into OAuth2 later without changing the route shape. - The public API is its own deployable, not a route inside the backend instance. It's the one surface built to accept credentials from untrusted external parties, unlike the internal API (trusts the SPA's session) or the MCP server (only ever reached by ai-service, a trusted first-party service, over the private network). It holds its own API-key secrets, never connects to Postgres, and calls the internal API over the private network with a short-lived, scoped internal token — mirroring the Traefik-ForwardAuth-then-JWT pattern already used for ai-service, so Core still enforces domain logic and tenancy for every request no matter which surface it arrived through.
Each process type is exposed as an individual resource. Abertura and Inquérito Prévio already
exist as case-workflow phases in MyLegalTeam.Domain/Cases; a new process type would land as one more
resource under the same prefix, without touching the authentication boundary.
Open questions
- Resource naming. The domain calls this a processo; the existing controller for the underlying
aggregate is
CasesController(MyLegalTeam.Api/Controllers/CasesController.cs), i.e. the code already says "Case" in English. A real implementation should decide whether the public route says/api/public/processes(product language) or/api/public/cases(existing code language) before partners start integrating against it. - Internal token issuance. Who mints the scoped token the public API presents to Core, and how — a private, network-restricted endpoint on Core (mirroring ForwardAuth), or a shared internal secret? Either way it must be a distinct credential from the session-signing and JWKS keys, so a compromise of the public API can't forge internal or ai-service tokens.
- Network exposure. The public API's own port must only be reachable from Traefik and Core on the private network, never directly from the internet — Traefik stays the only public origin.
- Key issuance and rotation. Where API keys are minted, stored (hashed, in the public API's own store rather than the backend's identity tables — least privilege cuts both ways), and rotated, and what happens to in-flight partner requests during a rotation.
- Scope model. ai-service's gateway token uses a single
ai:draftscope. A partner-facing API handling multiple process types over multiple companies almost certainly needs per-partner, per-resource scopes — closer toAuthorizerole checks than to the current all-or-nothing ForwardAuth grant. - Rate limiting and quotas per partner. Being a separate deployable makes this easier than the per-replica problem ai-service's gateway token has today (see the production notes in the AI gateway auth spec), but the limiter still needs to key on the partner's API key, not just the replica.
- Versioning — see Response envelope & versioning for the existing convention this would need to follow.
Nothing here is built. If this graduates from exploration to commitment, it should get its own PRD and
a contracts pass before any endpoint ships.