Use one feature to understand the architecture
WMS Vertical Slice Architecture organizes code around a business feature so that a developer can follow a use case without beginning in several separate layer projects. In Indotalent’s Blazor WMS Source Code, Warehouse is a useful first slice: it includes components, a service, endpoint mappings, request and response types, handlers, and validators in one feature area.
This article traces the create operation. It describes the actual single-project structure rather than presenting a generic architecture diagram and assuming that the product follows it. The project still has shared infrastructure, and inventory operations can depend on other business data.
Locate the feature boundary
Features/Inventory/Warehouse/
Components/
WarehousePage.razor
_WarehouseCreateForm.razor
_WarehouseDataTable.razor
_WarehouseUpdateForm.razor
Cqrs/
CreateWarehouseHandler.cs
CreateWarehouseValidator.cs
GetWarehouseListHandler.cs
...
WarehouseService.cs
WarehouseEndpoint.cs
The folder groups related operations around Warehouse rather than giving every individual command a completely independent project. CreateWarehouseHandler.cs contains its request DTO, response DTO, command record, and handler. Reading that file provides the local contract and implementation together.
Step 1: collect input in the Blazor component
_WarehouseCreateForm.razor binds a CreateWarehouseRequest to MudBlazor fields. It validates the form, manages a processing state, and invokes WarehouseService.CreateWarehouseAsync. Success produces a notification and a callback. The component owns these interface concerns; it does not contain the EF entity creation logic.
Step 2: cross the service and endpoint boundary
WarehouseService creates a RestRequest for api/warehouse, adds the DTO as JSON, and executes it through BaseService. That shared code handles available bearer-token headers and response processing. WarehouseEndpoint maps the POST action and sends a CreateWarehouseCommand through IMediator.
// Actual command contract
public record CreateWarehouseCommand(CreateWarehouseRequest Data)
: IRequest<CreateWarehouseResponse>;
The complete route includes the /api group mapped in Program.cs. This is an HTTP boundary even though the UI and API are part of the same application project. The warehouse API guide explains methods, response status, and direct-client behavior.
Step 3: perform the use case in the handler
CreateWarehouseHandler receives AppDbContext through its constructor. It checks whether a warehouse already has the requested name with AnyAsync. If so, it throws AlreadyExistsException. Otherwise it creates a Warehouse with Name, Description, and SystemWarehouse, adds the entity, and awaits SaveChangesAsync before returning Id and Name.
That handler is a clear place to locate a business change such as a new warehouse attribute. The change may still require editing the request, response, component, entity, and schema. Proximity helps navigation; it does not eliminate the need to keep those contracts aligned.
Step 4: account for shared behavior
AppDbContext supplies audit and soft-delete handling, plus asynchronous automatic numbering for participating entity types. The response helper wraps the returned DTO. Authentication is configured outside the handler. These shared paths affect more than Warehouse, so changing them warrants checks across their consumers.
Inventory calculation is another shared responsibility. Movement features call InventoryTransactionHelper to derive direction and signed stock. A new movement type may require work both in its feature and in that helper. The architecture should therefore be described as feature-oriented organization with shared infrastructure, not as proof of zero coupling.
Place validation at an enforced boundary
CreateWarehouseValidator validates CreateWarehouseRequest, while the dispatched MediatR message is CreateWarehouseCommand. The generic validation behavior looks for validators of the dispatched type. The form explicitly uses the DTO validator; automatic command-pipeline validation of that payload is not established by the DTO validator alone.
If you extend server validation, make the relationship explicit with a command validator or an explicit DTO-validation call. Test the API without the Blazor form as well. This example shows why tracing the complete slice is more useful than assuming that a folder named Cqrs guarantees every cross-cutting behavior.
Extend a slice without losing the operational result
For a warehouse field, identify the UI input and reload behavior, update the DTO mappings, and plan persistence changes. For a movement feature, additionally define document status, transaction creation, signed quantity, and report inclusion. Reuse the existing structure where it fits, while keeping the new business rule visible in the relevant handler or shared calculation code.
Keep verification tied to outcomes: successful creation and reload, duplicate-name handling, invalid direct API input, and deletion of a system warehouse. For stock changes, reconcile the resulting confirmed balance. These scenarios cover the public behavior of the slice more effectively than checking only that a new folder exists.
Move from architecture study to a working codebase
The Blazor UI guide examines the screen and service in more detail, and the EF Core guide explains the persistence path. All of these views lead to the same Blazor WMS source-code product, where you can review the complete application available for customization.