Dependency direction and call rules
Pulsar separates passive type references from behavioral calls. Delivery calls inward to Domain, Infrastructure implements Domain Contracts, and the detailed matrix below decides the permitted behavioral edges.
Passive type reference and behavioral call
A passive type reference only mentions a type in a signature, return value, property, or data construction. It does not transfer workflow control. A behavioral call invokes another type’s behavior. Imports alone never make a prohibited behavioral edge permissible.
Context: paired reference and call — A Controller may carry a Domain DTO but enters behavior through one UseCase.
final class CreateOrderController
{
public function store(CreateOrderData $data, CreateOrder $useCase): OrderResource
{
$order = $useCase->execute($data); // one behavioral call
return OrderResource::make($order);
}
}CreateOrderData is a permitted passive Domain DTO reference. Calling the UseCase is permitted behavior. A Controller must not make a behavioral call to a Query, Operation, or Action. A Contract signature may mention DTOs, Enums, Value Objects, Models, Events, other Contracts, or Laravel contracts. It must not make a behavioral call to a UseCase, Action, Operation, Service, or concrete Infrastructure type.
Domain Contract layer direction
| Origin layer | Behavioral direction |
|---|---|
| Service delivery | Inward to Domain through its documented entry types. |
| Domain | Itself and its own Contracts. |
| Infrastructure | Inward to Domain Contracts it implements. |
Nothing points at Delivery: Domain and Infrastructure do not make behavioral calls to Services. That rule does not turn permitted passive values into a delivery-orchestration loophole.
Dependency matrix for behavioral calls
| Origin | Behavioral target | Decision |
|---|---|---|
| Controller | exactly one UseCase | Allowed. The Controller stays thin and may assemble delivery response after it returns. |
| Controller | Query, Operation, or Action | Prohibited. |
| Job or Command | exactly one UseCase | Allowed. Validate, authorize, and establish context first. |
| Job or Command | Action, Operation, transaction, or branching business logic | Prohibited. |
| UseCase | Action, Operation, Query, Event, or Domain Contract | Allowed within its stated responsibilities. |
| UseCase | another UseCase | Prohibited. Extract reusable workflow to an Operation. |
| Operation | Action, Query, Model, or Contract | Allowed. |
| Operation | another Operation, UseCase, or Event emission | Prohibited. |
| Action | Model or Contract | Allowed. |
| Action | another Action or Query | Prohibited. |
| Query | Model | Allowed. |
| Query | Action or another Query | Prohibited. |
| synchronous Listener | Contract side effect, Notification, or Job | Allowed. It must not call a UseCase. |
| queued Listener | at most one UseCase | Conditional. Only for queued, idempotent form; synchronous Listener to UseCase is prohibited. |
| Contract | UseCase, Action, Operation, Service, or concrete Infrastructure | Prohibited as a behavioral dependency. |
| Infrastructure Adapter | its Domain Contract | Allowed. It implements the consumer-owned port. |
| Infrastructure Adapter | Service, UseCase, Action, or Operation | Prohibited. |
| Service A | Service B | Prohibited. Cross-Service communication uses events, not a Service-to-Service call. |
| Domain or Service | concrete Infrastructure Adapter | Prohibited. Depend on the Domain Contract. |
Keep unspecified details unspecified
The matrix is the exhaustive classified dependency rule set. It does not invent an Adapter-to-Adapter rule. Transaction mechanics, Event delivery tiers, authorization, tenancy, and binding details remain on later architecture pages. Use Placement for paths and Preset for the subset a test can check.