The recent branch work has been less visible than the first Licenses screenshots, but it is important for the shape of Foundry.
The question was not whether another endpoint could be made to return JSON. It was where FOLIO-era utility behavior should live when Foundry is deliberately trying not to recreate FOLIO’s service-boundary mistakes.
The problem with FOLIO utility services
FOLIO grew a lot of module-to-module dependencies around things that are not really bounded contexts. Some of those APIs are platform utilities: settings, tags, acquisition units, and similar support functions.
That creates the developer problem Foundry is trying to avoid. To run one meaningful business capability, a developer can end up needing a long tail of supporting services. Even if each service is individually reasonable, the aggregate stops fitting comfortably on a laptop.
Foundry’s answer is not to hide those calls with gateway stubs. The answer is to give platform support APIs a real owner.
That owner is foundry-platform-services.
Sovereign as vocabulary, not another default process
There was a parallel idea called Sovereign: a pluggable docking layer for downstream library systems such as FOLIO, Koha, TIND, or local Foundry implementations.
The idea is still useful. The separate sovereign-svc executable is not currently useful.
For now, Foundry keeps the provider contract inside foundry-platform-services. A standalone workspace can use local providers. A workspace extending an external system can later use a remote provider for the same platform interface.
That keeps the local developer substrate smaller without losing the important abstraction.
A 20,000-foot package view. Foundry keeps the FOLIO-compatible REST shape in foundry-platform-services, while Loom and Envoy decide which compatibility interfaces are present in a workspace. Dashed packages show future provider bindings, not current runtime dependencies.
The first refactor: settings and tags
The first platform-services code was intentionally minimal. It served the settings and tags calls needed by the Licenses UI.
The problem was that the controllers owned too much. They exposed the FOLIO-compatible REST shape and also embodied the local behavior.
That is now split:
- controllers own compatibility paths, headers, DTOs, and mapping;
- provider interfaces own behavior;
- the resolver selects the provider for the request context;
- local Foundry providers supply the current standalone behavior.
The default resolver still returns local providers. The important change is that the controller no longer assumes local implementation forever.
The internal shape is intentionally simple: controllers own compatibility REST contracts, the resolver owns provider selection, provider interfaces own behavior, and concrete local providers own storage and CQL details. Dashed classes are plausible future bindings, not classes that exist today.
Why acquisition units matter
The next pressure came from Licenses access control.
FOLIO acquisition units are exposed by mod-orders, but the concept is platform-wide. They control who can see or mutate records across acquisition-related areas. Foundry should not run Orders just to provide this utility surface to Licenses.
The new backlog item therefore treats acquisition units as a provider-backed platform compatibility interface:
- visible FOLIO paths remain
/acquisitions-units/unitsand/acquisitions-units/memberships; - internal implementation paths are versioned under
/acquisitions-units/v1; - the local provider stores data per tenant through
ki-mt-mn; - local data starts empty;
- CRUD is supported so bootstrap or admin flows can write real data later.
This is not a Licenses route shim. It is a platform support API with a local provider.
Okapi compatibility without Okapi as the control plane
There is one more FOLIO-era behavior to support: interface discovery.
access-control-grails checks whether the tenant provides acquisitions-units before enabling the acquisition-unit policy engine. In Okapi this is discovered through paths such as:
/_/proxy/tenants/{tenant}/interfaces
Foundry now models that as a narrow compatibility API, not as a recreation of Okapi. Loom decides whether acquisition-units platform support is selected for the workspace. Envoy exposes the compatibility path. foundry-platform-services returns the interface descriptor shape that the existing FOLIO client expects.
The control plane still remains Loom. The data plane still remains Envoy.
Identity remains explicit
Acquisition-unit memberships involve user ids, and FOLIO APIs tend to assume UUID-shaped identifiers.
Foundry’s native local identity is the OIDC issuer plus subject. That should stay native. For FOLIO compatibility, the local default can derive a stable UUID-shaped X-Okapi-User-Id using UUIDv5 over issuer and subject.
That mapping is deliberately documented as compatibility state. It is not the Foundry user id. A later external FOLIO, Koha, or TIND provider may replace it with a persisted or delegated mapping.
What this branch prepares for
This branch prepares Foundry for the next merge by making the docking layer concrete:
sovereign-svchas been removed from the workspace for now;foundry-platform-servicesis documented as the provider-backed platform support boundary;- settings and tags now delegate through provider interfaces;
- acquisition units have a real local provider-backed implementation path;
- interface discovery is treated as compatibility behavior, not as a general Okapi clone;
- local Licenses can enable acquisition-unit access-control integration against real platform routes.
The runtime proof now exists. The clean developer install shows that the local kernel still comes up, Licenses still activates explicitly, and the Licenses policy path reaches the acquisition-units compatibility API rather than failing because the support interface is missing.
That changes the question. It is no longer a question of where the boundary should be, or whether the boundary can hold under a real local run. The next pressure is making the same provider boundary useful for real external bindings without reintroducing the dependency weight Foundry is trying to remove.