Say your contexts are not separate deployables, which is the common case. The reasoning from last time still leaves a tempting idea standing: declare the API inside each context anyway, because that keeps them autonomous.
It does not, not really. It scatters the definition, and the thing that gets scattered is actually the one thing your callers experience as a single product.
With the left-hand shape, no single file knows what the API looks like - unless you are using API Platform that does a great job aggregating everything under a single OpenAPI definition, and it stops working the day you extract a context. Four contexts each answer for their quarter of it, four teams make four reasonable local decisions, and the result is one document with four “accents”, four slight variation of approaches, one is REST, another is GRPC. One context returns created_at, another createdAt. One paginates with a cursor, another with a page number. Each decision was fine where it was made.
Plenty of things will help to soften that. A design system, a Storybook, a Spectral ruleset in CI, and coordination from a CXO (Chief Experience Officer). They work. They also all cost money, time and people, and I have worked on a lot of projects that had the ambition for all four and usually not allocated the budget for any.
There is an older observation underneath this, which I like.
In 1967 Melvin Conway submitted a paper called How Do Committees Invent? to the Harvard Business Review. They rejected it, on the grounds that he had not proved his thesis. Datamation, the major computing magazine of the day, published it in April 1968. Fred Brooks later cited it in The Mythical Man-Month and called it Conway’s Law, which is how most people meet it.
The thesis is that any system designed by an organisation will copy that organisation’s communication structure. Four teams producing four accents in one API is not a discipline failure. It is that sentence, working exactly as described, in a paper a business magazine turned down for lack of proof.
So the question is not whether your teams are good. It is whether the structure you gave them produces the thing you want.
The UI layer, meanwhile, knows nothing about your contexts and does not need to. It does not know what “User Management” is, or “Billing”. It expresses intentions: somebody wants to do a thing, here is the shape of asking. That vocabulary is the caller’s, not the domain’s, and putting it inside a domain directory is filing it under the wrong name.
So I draw it as the layer on the outside. A request crosses the delivery, then the machinery every context shares. Only then is it inside a context, where it meets that context’s own infrastructure, its own application layer and its own domain.
The delivery sits outside every context. Use Next for the second frame.
An argument I love to use to reinforce this, is: Open some code you wrote three years ago. Measure the distance to what you would write today. Better now, obviously, and that is the problem: context after context, your interfaces will slowly differ exactly that way, and an inconsistent API is worse than an inconsistent service because callers are standing on it. Predictability pays for itself faster in a UI than anywhere else in the system, and predictability comes from having one place where the shape is decided.
In a project with a framework like Symfony, I would have Ui/ sits at the level where you declare the contexts. Wrapping them rather than hiding inside one of them. That way, yes, it stays flat, but nesting the layers as directories with the contexts inside each one helps neither the vertical slice nor anybody trying to see where the decoupling is.
You can still split a context into modules underneath that of course.
One delivery, over all of them
You declare the shape once, where you declare the contexts.
The flat tree, and the same tree once a context is worth splitting into modules.
Next time, of course API is not all there is in a project, what about a web page?. A web page is as much a delivery as the API and the terminal, so where does it go?