Separate intent, not infrastructure by default

A command expresses a requested state change. A query reads a projection and should not mutate business state. Keeping the two paths explicit makes authorization, validation, transaction boundaries, and response shape easier to follow.

Organize around use cases

A feature can group its query or command with its handler and related result types. Controllers translate HTTP contracts into requests and send them through a mediator. Handlers coordinate business rules and call feature ports; Infrastructure implements persistence.

A mediator does not require microservices

MediatR dispatches in-process requests. It does not create a network boundary, separate deployment, or independent database. A single application can use this organization while sharing a database transaction where consistency requires it.

Keep the read path proportionate

A query can project directly to a screen-specific result when that makes the use case clearer. Avoid generic repositories, duplicate databases, or a pipeline of abstractions without a concrete need.

Interview takeaway

Walk through one request from controller to handler to persistence and back. Identify where the transaction begins and which part owns each validation rule.