Scheduling Complexity
Availability, qualifications, restrictions, validation, breaks, and shift trades all interact with scheduling workflows.
How I used the migration from .NET Framework to .NET 8 as an opportunity to redesign a growing production application around Clean Architecture, CQRS, MediatR, explicit business use cases, and independently evolving presentation and infrastructure layers.
As Week at Work expanded, business logic, data access, UI preparation, and request handling had become increasingly intertwined.
The original ASP.NET MVC architecture had served the platform well during its earlier stages, but the application's growing scheduling and workforce-management workflows made seemingly small changes increasingly difficult to isolate.
Rather than recreate the same architecture on a newer runtime, I used the move to .NET 8 to establish clearer boundaries between domain behavior, application workflows, infrastructure, APIs, and MVC presentation.
Upgrading the runtime and modernizing the architecture were treated as two related—but distinct—engineering problems.
Scheduling had evolved far beyond CRUD and increasingly required coordination across many independent business rules and platform capabilities.
Availability, qualifications, restrictions, validation, breaks, and shift trades all interact with scheduling workflows.
Controllers increasingly coordinated data retrieval, authorization, business rules, persistence, notifications, and UI preparation.
Business workflows often existed because an MVC endpoint existed instead of being independently reusable application capabilities.
MVC, Web API, mobile clients, scheduled jobs, and future interfaces should be able to invoke the same business behavior.
Tightly coupled workflows made individual application behaviors more difficult to exercise independently.
The application was already in production, making a complete rewrite an unnecessarily risky modernization strategy.
The architectural problem was not MVC itself—the problem was allowing application workflows to become defined by MVC endpoints.
Contains core business models, invariants, value objects, and meaningful state transitions.
Defines supported business use cases through commands, queries, handlers, DTOs, validators, and interfaces.
Implements persistence, messaging, notifications, timezone services, and external integrations.
MVC and Web API consume application capabilities without owning the business workflows they initiate.
Publishing a schedule became an application capability that could be invoked from MVC, Web API, background processing, or future clients.
Explicitly represent operations that change application state.
Shape retrieval around what the consuming screen or client actually needs.
Complex screens can use purpose-built queries and multiple result sets without forcing the write-side domain model to resemble the UI.
The write side can prioritize domain correctness while the read side independently prioritizes retrieval performance.
Application queries remain reusable across MVC, Web API, mobile clients, and other consumers because presentation formatting stays outside the Application layer.
Application notification capability.
External communication abstractions.
Persist timestamps consistently while application timezone services convert them into location-local business representations.
Application workflows return stable error identifiers while presentation layers translate them using resource files and the selected culture.
Pipeline behaviors reduce handler boilerplate while creating consistent validation, authorization, logging, and transaction boundaries.
The migration strategy was designed so the platform could continue operating while architectural responsibilities moved incrementally into the new solution.
Create Domain, Application, Infrastructure, Web, API, and test projects with explicit dependency boundaries.
Establish the application patterns needed by future migrated features.
Move functionality as vertical slices instead of attempting a single application-wide rewrite.
As workflows move into commands, queries, and application services, legacy controllers and services progressively become thinner and removable.
A simple feature may now involve a command, handler, validator, DTO, mapping configuration, and tests instead of one controller method and a service call.
As workflows become more complex, those explicit boundaries make dependencies and business intent visible instead of hiding them inside large controllers and general-purpose services.
CQRS was used selectively as an organizational strategy, not as a requirement to make every application operation unnecessarily complex.
Application workflows should exist independently of the HTTP endpoint or client that initiates them.
Commands and queries make the platform's supported business operations immediately visible.
Meaningful entity transitions remain close to the business state and rules they protect.
Query models can use purpose-built SQL without distorting transactional domain models.
Application behavior depends on capabilities while Infrastructure supplies replaceable implementations.
Production systems can evolve feature by feature instead of accepting the risk of a complete rewrite.
The redesign shifts Week at Work from an MVC-centric application toward a platform whose business capabilities exist independently of their presentation layer.
The most important lesson was that upgrading a framework and modernizing an architecture are two different problems.
See additional system design, scheduling, and software architecture case studies.