Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/Andrespeerez/porfolio-blog/llms.txt

Use this file to discover all available pages before exploring further.

User is the only domain entity in the application. It lives in the Domain layer with no framework dependencies. Password hashing is delegated to IPasswordHasher via the factory method, keeping the entity clean.

Properties

Id
int
Auto-increment primary key. This value is 0 until the entity is persisted — EF Core sets it after SaveChangesAsync() completes.
Email
string
The user’s email address. Initialized to string.Empty by default. A unique index is enforced at the database level by AppDbContext.OnModelCreating.
PasswordHash
string
Stores the hashed representation of the user’s password. Declared with private set, meaning it cannot be assigned from outside the User class. The only way to populate this property is through the User.Create factory method.

Factory method: User.Create

The static factory User.Create is the single entry point for constructing a valid User instance. It accepts a plain-text password, delegates hashing to the provided IPasswordHasher, and returns a fully initialised entity ready to be persisted. Signature
static User Create(string email, string rawPassword, IPasswordHasher hasher)
Parameters
email
string
required
The user’s email address. Stored directly on the entity — no normalisation or validation is applied at the domain layer.
rawPassword
string
required
The plain-text password supplied by the caller. It is hashed immediately inside Create and is never stored on the entity.
hasher
IPasswordHasher
required
The hasher abstraction used to compute PasswordHash. In production this is satisfied by IdentityPasswordHasher, but any implementation of IPasswordHasher may be substituted (e.g., a test double).
Full source
Domain/Entities/User.cs
public class User
{
    public int Id { get; set; }
    public string Email { get; set; } = string.Empty;
    public string PasswordHash { get; private set; } = string.Empty;

    public static User Create(string email, string rawPassword, IPasswordHasher hasher)
    {
        return new User() { Email = email, PasswordHash = hasher.Hash(rawPassword) };
    }
}
PasswordHash has a private set accessor, meaning it can only be assigned inside the User class — enforcing that all hashing goes through User.Create. There is no public setter and no other constructor parameter for the hash, making it impossible to accidentally store a plain-text password on the entity.

EF Core mapping

AppDbContext maps User to a Users table through EF Core’s convention-based mapping. There are no explicit [Table], [Column], or [Key] attributes on the entity — EF Core infers the table name from the DbSet<User> Users property name and treats Id as the primary key by convention. The one non-default configuration applied in OnModelCreating is a unique index on the Email column:
Infrastructure/Persistence/Context/AppDbContext.cs
modelBuilder.Entity<User>().HasIndex(u => u.Email).IsUnique();
This means attempting to persist two User records with the same email address will throw a DbUpdateException at the database level, regardless of any application-layer validation.

Build docs developers (and LLMs) love