The Domain layer contains all entity models that represent the business domain. These entities are mapped to PostgreSQL database tables using Entity Framework Core annotations.
Entities in the Domain layer are pure POCO (Plain Old CLR Objects) classes with minimal dependencies, ensuring the business logic remains independent of infrastructure concerns.
Passwords are hashed using the IPassword utility from Domain.Utilidades before storage. The Password field stores the hash, never the plain text password.
namespace Domain.Entities.Catalogos{ [Table("prioridades")] public class PrioridadE { [Key] [Column("id_prioridad")] public required int IdPrioridad { get; set; } [Column("nombre")] public required string Nombre { get; set; } [Column("nivel")] public required int Nivel { get; set; } }}
namespace Domain.Entities.Catalogos{ [Table("estados_ticket")] public class EstadoTicketE { [Key] [Column("id_estado")] public required int IdEstado { get; set; } [Column("nombre")] public required string Nombre { get; set; } [Column("es_final")] public required bool Final { get; set; } }}
Purpose: Defines ticket states throughout their lifecycle
Property
Type
Description
IdEstado
int
Unique identifier
Nombre
string
Status name (e.g., “Abierto”, “En Progreso”, “Cerrado”)
Final
bool
Whether this is a terminal state (e.g., Closed, Resolved)
DTOs provide a stable API contract independent of database schema changes. You can modify entities without breaking API consumers.
Security
DTOs prevent exposing sensitive entity properties (like password hashes) in API responses.
public class UsuarioDto{ public Guid IdUsuario { get; set; } public string Nombre { get; set; } public string Correo { get; set; } public string Rol { get; set; } public bool Activo { get; set; } // Password is NOT included! public static UsuarioDto CreateDTO(UsuarioE usuarioE) { return new UsuarioDto { IdUsuario = usuarioE.IdUsuario, Nombre = usuarioE.Nombre, Correo = usuarioE.Correo, Rol = usuarioE.Rol, Activo = usuarioE.Activo // Password intentionally excluded }; }}
Specialized Data Shapes
Different DTOs for different use cases (create, update, read).
// For creating new ticketspublic class CrearticketDto{ public required string Titulo { get; set; } public required string Descripcion { get; set; } public required Guid UsuarioId { get; set; } public required int AreaId { get; set; } public required int PrioridadId { get; set; } public required int EstadoId { get; set; } // No ID or dates - those are set by the system}// For updating ticket statuspublic class ActualizarEstadoTicketDto{ public Guid Id { get; set; } public int EstadoId { get; set; } // Only the fields that can be updated}// For querying with joined datapublic class ConsultarTicketDto{ public Guid? IdTicket { get; set; } public required string Titulo { get; set; } public required string Codigo { get; set; } public required string Descripcion { get; set; } public required string Area { get; set; } // Joined from AreaE public required string Prioridad { get; set; } // Joined from PrioridadE public required string Estado { get; set; } // Joined from EstadoTicketE public DateTime FechaCreacion { get; set; } public DateTime FechaActualizacion { get; set; }}
Performance
DTOs can be optimized for specific queries without affecting the entity model.
While Entity Framework Core can handle relationships via navigation properties, this implementation uses a lightweight approach with foreign keys only.