Previous lesson: 🧱 Lesson 2A— Creating the base solution, API project, folder structure, dependency injection, environment configuration
🚀 Introduction
In any Clean Architecture or Domain-Driven Design (DDD) project, the Domain Layer is the heart of the system.
It contains the core business entities, rules, and relationships that define what your system does - independent of how it's implemented (no database, UI, or framework dependencies).
In this lecture, we'll implement the core entities of our E-Commerce System:
Customer - who makes purchases
Product - what is being sold
Order - represents a customer's purchase
OrderItem - the individual items within an order
By the end, we'll have a pure, framework-agnostic model layer ready to connect with our Application and Infrastructure layers later on.
🧱 Clean Architecture Recap
Before we dive into the code, recall the four layers in our solution:

This lecture focuses entirely on ECommerce.Domain.
Domain Folder Structure
Create this structure inside the ECommerce.Domain project:

Entities Overview
We'll define four entities:
Customer represents a buyer or user placing orders
Product represents an item available for sale
Order Represents a transaction made by a customer
OrderItem represents a line item within an order
1. Customer.cs
Path: ECommerce.Domain/Entities/Customer.cs
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace ECommerce.Domain.Entities;
public class Customer
{
[Key]
public Guid Id { get; set; } = Guid.NewGuid();
[Required(ErrorMessage = "First name is required.")]
[MaxLength(50, ErrorMessage = "First name cannot exceed 50 characters.")]
public string FirstName { get; set; } = string.Empty;
[Required(ErrorMessage = "Last name is required.")]
[MaxLength(50, ErrorMessage = "Last name cannot exceed 50 characters.")]
public string LastName { get; set; } = string.Empty;
[Required(ErrorMessage = "Email is required.")]
[EmailAddress(ErrorMessage = "Invalid email address.")]
[MaxLength(100, ErrorMessage = "Email cannot exceed 100 characters.")]
public string Email { get; set; } = string.Empty;
[Phone(ErrorMessage = "Invalid phone number.")]
[MaxLength(20, ErrorMessage = "Phone number cannot exceed 20 characters.")]
public string PhoneNumber { get; set; } = string.Empty;
// Navigation Property
public ICollection<Order> Orders { get; set; } = new List<Order>();
// Computed Property (Not mapped to DB)
[NotMapped]
public string FullName => $"{FirstName} {LastName}";
}2. Product.cs
Path: ECommerce.Domain/Entities/Product.cs
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace ECommerce.Domain.Entities;
public class Product
{
[Key]
public Guid Id { get; set; } = Guid.NewGuid();
[Required(ErrorMessage = "Product name is required.")]
[MaxLength(100, ErrorMessage = "Product name cannot exceed 100 characters.")]
public string Name { get; set; } = string.Empty;
[MaxLength(500, ErrorMessage = "Description cannot exceed 500 characters.")]
public string Description { get; set; } = string.Empty;
[Range(0, double.MaxValue, ErrorMessage = "Price must be a non-negative value.")]
[Column(TypeName = "decimal(18,2)")] // Ensures proper precision in database
public decimal Price { get; set; }
[Range(0, int.MaxValue, ErrorMessage = "Stock cannot be negative.")]
public int Stock { get; set; }
// Domain Logic
public void ReduceStock(int quantity)
{
if (quantity > Stock)
throw new InvalidOperationException("Insufficient stock.");
Stock -= quantity;
}
}3. OrderItem.cs
Path: ECommerce.Domain/Entities/OrderItem.cs


Join the conversation! Your thoughts help the community grow.