EnterpriseAugust 2026 · 6 min read

.NET Enterprise Architecture for CRM, HRM, and WMS Systems

TL;DR

CRM, HRM, and WMS products are architected the same way in practice: one .NET 10 project organized as vertical slices, Blazor Server with MudBlazor for the UI, a JWT-secured REST API, and EF Core for data — with domain modules that stay strict but independent.

.NET Enterprise Architecture for CRM, HRM, and WMS systems looks remarkably similar from product to product, and that is a good thing. These are business applications with the same underlying shape: authenticated users, master data, workflows, approvals, and reports. When a team builds one from scratch, the architecture decision that matters most is how the modules are separated and how one module talks to another — not which web framework sits on top. This article explains how real products on .NET 10 are structured in practice.

The Product Shape of .NET Enterprise Architecture: Modules, Not Layers

A CRM is not one feature — it is a dozen modules: contacts, leads, opportunities, pipelines, activities, and reports. An HRM adds employees, leave, attendance, payroll, and performance. A WMS adds warehouses, locations, inventory, putaway, picking, and shipping. Every one of those modules is a bounded area of the product, and the architecture should make the boundaries explicit without forcing each module into its own project or service.

The pragmatic answer in 2026 is a single .NET 10 project with strict module folders and vertical slices inside each module. One deployable, one DI container, one database — but with the discipline of bounded contexts at the code level. Teams get the operational simplicity of a monolith and the mental clarity of modules that cannot casually reach into each other.

The Shared .NET Enterprise Architecture Stack Behind CRM, HRM, and WMS

Across the Indotalent product line, every CRM, HRM, and WMS uses the same stack, and it solves the same class of problems each time:

  • Vertical Slice Architecture in a single project — each feature owns its command, validator, handler, and DTO
  • Blazor Server for the interactive UI — real-time updates over SignalR with no JavaScript build chain
  • MudBlazor for the admin interface — data grids, forms, dialogs, and theming out of the box
  • REST API with Swagger — the same handlers power both the Blazor UI and external integrations
  • JWT with ASP.NET Core Identity — one security model protecting the UI, the API, and every module
  • EF Core 10 — one DbContext, migrations, and query filters for tenant or company scoping

The stack stays constant because the problems stay constant. A CRM needs secure role-based screens, an API for the sales app, and a data model that changes often — exactly what this stack does well. An HRM needs audit trails and complex approval workflows. A WMS needs transactional integrity on every stock movement. All three are served by the same vertical slice skeleton with different domain code inside.

Inside the CRM module

The CRM module keeps contacts, accounts, and opportunities in separate slices. Pipelines are just a state machine over opportunities: a lead becomes a qualified lead, then a proposal, then a closed win or loss. The state transitions live in the slice, the history is a simple activity table, and the dashboard is a read-only query over the same data.

Inside the HRM module

The HRM module is where audit discipline matters. Employee records, leave balances, and payroll runs are all audited, so an interceptor stamps who, what, and when on every save. Leave approval is a workflow handled by domain events: when a leave request is submitted, an event triggers the notification to the approver without the leave slice depending on the notification slice.

Inside the WMS module

The WMS module treats stock movement as transactional by definition. Every inbound, outbound, and transfer updates stock levels inside a single transaction; nothing is written outside a command handler. The result is that quantity-on-hand is always derivable from the movement history — an invariant that is trivial to enforce when each movement is a vertical slice:

public record AdjustStockCommand(
    Guid WarehouseId,
    Guid ProductId,
    int Delta) : IRequest<StockLevelDto>;

public sealed class AdjustStockHandler
    : IRequestHandler<AdjustStockCommand, StockLevelDto>
{
    private readonly AppDbContext _db;
    public AdjustStockHandler(AppDbContext db) => _db = db;

    public async Task<StockLevelDto> Handle(
        AdjustStockCommand cmd, CancellationToken ct)
    {
        var stock = await _db.Stocks.SingleAsync(
            s => s.WarehouseId == cmd.WarehouseId
                && s.ProductId == cmd.ProductId, ct);
        stock.Adjust(cmd.Delta);
        await _db.SaveChangesAsync(ct);
        return StockLevelDto.FromEntity(stock);
    }
}

The handler is deliberately tiny. Validation runs in a pipeline behavior, the transaction wraps the whole operation, and the REST endpoint that exposes it is one line that delegates to the same handler the Blazor screen calls. Whether the stock adjustment comes from a warehouse operator, a mobile scanner, or an integration, it goes through the same slice and the same invariants.

Why One Project and One DbContext Works

The most common objection is that a CRM, HRM, or WMS is too big for a single project. In practice the opposite is true: one project means one build, one deployable, one namespace graph, and one source of truth for the schema. The boundaries that protect the modules are drawn with folders, namespaces, and explicit entry points — not with project references. A module exposes handlers and DTOs; everything else is internal. That is a compile-time boundary you can verify with a unit test, and it costs a fraction of what a five-project solution costs to navigate.

Shared infrastructure — the DbContext, the JWT configuration, the audit interceptor, the shared UI shell — lives in one place that all modules reference. Domain events keep the modules decoupled: the order module publishes, the inventory module subscribes, and neither knows the other's internals. This is the shape of .NET Enterprise Architecture that actually ships in production products, and it is the shape every Indotalent codebase demonstrates.

Key Takeaways

  • CRM, HRM, and WMS products share the same architecture shape: modules, not layers
  • One .NET 10 project with vertical slices keeps builds fast and boundaries explicit
  • Blazor Server plus MudBlazor covers the admin UI; the REST API reuses the same handlers
  • JWT with ASP.NET Core Identity gives the UI and the API one security model
  • Domain events let modules communicate without compile-time coupling
  • Indotalent ships complete CRM, HRM, and WMS codebases architected this way — $21 each

Ready to study how a CRM, HRM, or WMS is actually built?

Every Indotalent product is a complete .NET 10 codebase architected with VSA, Blazor Server, MudBlazor, and a JWT-secured REST API. Complete source code — $21 each.

Explore Products