Creating our Core Domain Entities
It can be challenging to choose our models.
You should consider the long-term effects before committing and making a decision. Initially, I made the decision to include numerous other options, like payment, shopping cart, product variant, product image, and so forth. However, I am aware that the project will take more than six months to complete, and as I am a lone developer, I may not be able to finish it.
Core/Entities and their relationship
> - Category
- > Contains products
- > Navigation: Products collection
- > Used by seller/admin to organize items
- > Self-referencing for subcategories
> - Product
- > Belongs to Category
- > Navigation: OrderItems, Reviews
- > Shown in shop menu to customers
- > Can be added/updated by seller
> - Order
- > Created when a customer buys items
- > Contains multiple OrderItems
- > Status tracks the overall order (Pending, Confirmed, Shipped, Delivered, Cancelled)
- > TotalAmount = sum of OrderItem.UnitPrice * Quantity
- > Managed mostly by backend (seller/admin)
> - OrderItem
- > Snapshot of a product at the time of order
- > Contains UnitPrice, Quantity
- > Navigation to Order and Product
> - Review
- > Written by customer
- > Only creation is needed (no update)
- > Linked to Product and User`
Now that our model and entities are completed
We go on to our Dto. Data Transfer Object (DTO)
Planning is necessary in various ways.
//our Dtos category for httpPost
public record CategoryRequestDto
{
public string Name { get; init; } = string.Empty;
public string? Description { get; init; }
}
Why are records being used here?
Because we are striving for immutability, which classes do not have
PS: We also need to put Enums in Shared, Why? same reason for Dtos: Dependency Management.
Also, Enums often represent fundamental, non-changing data points that are used across multiple layers.
Validation
We're setting a standard here: Fluent Validation is our primary validation tool. While the built-in Data Annotations are fine for quick setups, we're phasing them out for consistency and enterprise readiness.
In the world of real-deal, production-level applications—especially larger ones—Fluent Validation is the industry favorite. Getting comfortable with its clear, code-based approach now is a huge win for future projects.
Sample code:
internal class CategoryRequestValidation : AbstractValidator<CategoryRequestDto>
{
protected CategoryRequestValidation()
{
RuleFor(x => x.Name)
.NotEmpty().WithMessage("Category name is required.")
.MaximumLength(100).WithMessage("Category name must not exceed 100 characters.");
RuleFor(x => x.Description)
.MaximumLength(500).WithMessage("Category description must not exceed 500 characters.");
}
}
Lastly we just register it in our Dependency Injection
/// <summary>
/// Creates extension methods for registering services in the Infrastructure layer.
/// </summary>
public static class DependencyInjection
{
public static IServiceCollection AddInfrastructure(this IServiceCollection services)
{
#region
//Category Validation
services.AddValidatorsFromAssemblyContaining<CategoryRequestValidation>();
services.AddValidatorsFromAssemblyContaining<CategoryUpdateValidation>();
//The rest of Codes
What's Next?
In Part 3, I'll dive into implementing the base architecture with:
- Creating DbContext
- Configuring Secret User
- Registering services in Program.cs
- Prepare for Identity



Top comments (0)