Application – the Domain API for the View
The +State article gave domain logic a clear home: domain-relevant runtime state, business rules, derived state, selections, state transitions, and domain intents all live there.
A concrete view usually needs only a small slice of that:
customersloadingselectCustomer()createCustomer()This is where Application begins.
If this layer becomes complicated, responsibility has usually leaked in from a layer below or above it.
A deliberate departure from classical DDD
Section titled “A deliberate departure from classical DDD”In classical DDD-oriented layering models, the Application layer is often associated with application services, use cases, and their coordination. It drives an application use case without owning the actual business rules itself.
This model narrows that responsibility even further. Domain decisions, state transitions, and projections already exist in +State. Application does not build a second layer of use-case orchestration on top of them.
Application therefore remains deliberately thinner than in many classical DDD architectures. Ideally, this layer consists almost entirely of facades.
That is not a shortcut. It is a deliberate frontend interpretation: a view needs a stable gateway into the domain, but it does not need another place where domain logic is created.
The facade as the gateway to the domain
Section titled “The facade as the gateway to the domain”The Presentation should not need to know that the domain internally consists of CustomerState, OrderState, PermissionState, and SelectionState.
Without a facade, a view might access several internal areas directly:
customerState.customers;customerState.selectedCustomer;orderState.canOrder;permissionState.canEdit;That makes the internal structure of the domain part of what the Presentation has to know.
With a facade, the view only sees:
facade.customers;facade.selectedCustomer;facade.canOrder;facade.canEdit;The facade knows the underlying structure. The view knows only its contract.

The core idea follows the classic Facade pattern: a facade provides a simplified interface to a more complex subsystem (Design Patterns: Elements of Reusable Object-Oriented Software, Gamma/Helm/Johnson/Vlissides, 1994). Here, that principle is applied to the boundary between Presentation and Domain.
If you come from classic MVC architectures, the position can be compared loosely to a view-oriented controller: there is a defined access point between the UI and the model. The responsibility of the facade here is much narrower, though – it does not develop application logic or domain logic of its own.
Facades expose and delegate
Section titled “Facades expose and delegate”A facade may collect existing values and data flows from +State and expose them through a suitable contract:
export class CustomerDetailFacade { readonly customer = this.customerState.selectedCustomer; readonly canDelete = this.customerState.canDelete; readonly loading = this.customerState.loading;
deleteCustomer(): void { this.customerState.deleteSelected(); }}That is a good facade. It exposes, delegates, and hides internal structure. It does not create new domain meaning.
Several existing streams or reactive values may also appear side by side in the same contract. What the facade should not do is derive a new domain statement from them:
readonly canOrder = combineLatest([ this.customerState.customer$, this.orderState.orders$, this.permissionState.permissions$,]).pipe( map(([customer, orders, permissions]) => { // domain decision is created here }),);If several data sources together produce a domain statement, that statement already belongs in +State.
Application only exposes the result:
readonly canOrder = this.orderState.canOrder;A facade may collect several data flows. It does not combine them into new domain logic.
No logic. Period.
Section titled “No logic. Period.”The facade does not make decisions.
A business rule does not belong here:
save(): void { if (this.customerState.customer().status === CustomerStatus.Active) { // ... }}Nor does a domain derivation:
readonly visibleCustomers = computed(() => this.customerState.customers() .filter(...) .sort(...),);if filtering and sorting are part of the state or a domain-relevant projection.
And UI responsibility does not belong here either:
delete(): void { if (confirm('Really delete?')) { // ... }}A facade may simply delegate:
deleteCustomer(): void { this.customerState.deleteSelected();}or expose existing state:
readonly canDelete = this.customerState.canDelete;The triviality of these methods is intentional. If a facade starts becoming interesting, it is worth checking whether responsibility from another layer is creeping in.
Why have a facade at all?
Section titled “Why have a facade at all?”If the facade only exposes and delegates, the Presentation could access +State directly.
That would also mean learning the internal structure of the domain.
Today, perhaps only:
CustomerListComponent ↓CustomerStateA new requirement can quickly add more dependencies:
CustomerListComponent ├── CustomerState ├── PermissionState ├── SelectionState └── OrderStateThe internal structure of the domain becomes part of the view contract.
With a facade, there is still one entry point:
CustomerListView ↓CustomerListFacade ↓internal domain structureThe domain can be restructured underneath without forcing the Presentation to follow every change.
That is where the value of this seemingly trivial layer lies: it reduces structural coupling.
One view – one facade
Section titled “One view – one facade”The rule in this model is refreshingly simple:
A view has exactly one matching facade.
CustomerListView ↔ CustomerListFacadeCustomerDetailView ↔ CustomerDetailFacadeCustomerEditView ↔ CustomerEditFacadeA generic CustomerFacade for every Customer-related view looks attractive at first:
CustomerListCustomerDetailCustomerEditor ↓CustomerFacadeBut every additional view expands its contract:
CustomerListCustomerDetailCustomerEditorCustomerHistoryCustomerSearchCustomerAdminCustomerExport ↓CustomerFacadeWhat starts with customers and selectedCustomer eventually grows into history, orders, permissions, search, filter, sort, create, update, delete, archive, export, and more – even though each consumer needs only part of it.
The facade turns into a god service.
The real problem is the absence of a natural boundary. Three, five, or ten views are not architectural thresholds. A certain percentage of shared properties does not create a stable rule either.
The 1:1 relationship solves that question deliberately and trivially:
A facade’s responsibility ends where its view’s responsibility ends.
No size heuristic. No debate about a maximum number of properties. The view itself defines the boundary.

Duplication is deliberately allowed
Section titled “Duplication is deliberately allowed”The 1:1 rule inevitably creates places where two facades look similar or even identical:
export class CustomerListFacade { readonly customers = this.customerState.customers;}export class CustomerSearchFacade { readonly customers = this.customerState.customers;}That duplication is intentional.
Both contracts can evolve independently. The fact that they expose the same projection today is not a reason to couple their responsibilities.
Duplicated delegation is cheap. Coupled responsibilities are expensive.
This is not a free pass to ignore DRY. The deciding factor is the reason for change. CustomerListFacade changes when the Customer List contract changes. CustomerSearchFacade changes when the Search View contract changes.
The facade therefore does not answer:
What can our application do with Customers?
It answers:
What does this particular view need from our domain?
Names such as CustomerListFacade, CustomerDetailFacade, and CustomerEditFacade make that responsibility visible. The facade forms a view-specific domain API and exposes only what that view is allowed to consume.
What Application should and should not do
Section titled “What Application should and should not do”Application and its facades may:
- consume
+State - expose existing state and projection values
- collect already existing streams
- delegate intents and commands to
+State - provide a view-specific contract
- hide internal domain structures from the Presentation
- encapsulate several internal domain sources behind a single view contract
- expose already created ViewModels or projections
Application and its facades should not:
- implement business rules
- make domain decisions
- create domain-derived state
- combine streams into new domain logic
- model state transitions of their own
- parse DTOs
- call HTTP APIs or external SDKs
- interpret technical contracts
- control the router
- trigger dialogs, toasts, or snackbars
- know DOM or UI-framework details
- make Material-, Ionic-, or Bootstrap-specific decisions
- combine several views into one god facade for the sake of reuse
The benefits live in the boundary, not in the code
Section titled “The benefits live in the boundary, not in the code”A view gets exactly one entry point into the domain. It does not need to know where individual values come from or how many stores or projections sit behind its contract. The domain can therefore be restructured internally without forcing every Presentation to follow those changes.
Reasons for change also stay local. A new feature in the Customer Editor does not automatically expand the contract of the Customer List. Each facade remains as small as the view it exists for. Some duplicated delegation is the price of independent contracts – and it is a low one.
The actual benefit therefore does not come from sophisticated code in the Application layer. It comes from the boundary that this code makes explicit.
No artificial complexity
Section titled “No artificial complexity”A realistic Application layer may consist almost entirely of classes like this:
export class CustomerListFacade { readonly customers = this.customerState.customers; readonly loading = this.customerState.loading;
selectCustomer(id: CustomerId): void { this.customerState.select(id); }
createCustomer(): void { this.customerState.create(); }}That is not a sign that the layer is unnecessary. Its value lies in the contract and the decoupled structure, not in the amount of code.
A good facade is boring. It creates no new domain logic; it only makes existing domain logic accessible to exactly one view.
+State owns the domain logic. Application provides a suitable contract to a concrete view. The domain does not know the view. The facade knows both sides without creating any new domain meaning.
Presentation begins on the other side of that contract.