using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using ColaFlow.Modules.ProjectManagement.Domain.Aggregates.ProjectAggregate;
using ColaFlow.Modules.ProjectManagement.Domain.ValueObjects;
using ColaFlow.Shared.Kernel.Common;
namespace ColaFlow.Modules.ProjectManagement.Infrastructure.Persistence.Configurations;
///
/// Entity configuration for Project aggregate root
///
public class ProjectConfiguration : IEntityTypeConfiguration
{
public void Configure(EntityTypeBuilder builder)
{
builder.ToTable("Projects");
// Primary key
builder.HasKey(p => p.Id);
// Id conversion (StronglyTypedId to Guid)
builder.Property(p => p.Id)
.HasConversion(
id => id.Value,
value => ProjectId.From(value))
.IsRequired()
.ValueGeneratedNever();
// TenantId conversion
builder.Property(p => p.TenantId)
.HasConversion(
id => id.Value,
value => TenantId.From(value))
.IsRequired();
// Basic properties
builder.Property(p => p.Name)
.HasMaxLength(200)
.IsRequired();
builder.Property(p => p.Description)
.HasMaxLength(2000);
// ProjectKey as owned value object
builder.OwnsOne(p => p.Key, kb =>
{
kb.Property(k => k.Value)
.HasColumnName("Key")
.HasMaxLength(20)
.IsRequired();
kb.HasIndex(k => k.Value).IsUnique();
});
// Status enumeration (stored as string)
builder.Property(p => p.Status)
.HasConversion(
s => s.Name,
name => Enumeration.FromDisplayName(name))
.HasMaxLength(50)
.IsRequired();
// OwnerId conversion
builder.Property(p => p.OwnerId)
.HasConversion(
id => id.Value,
value => UserId.From(value))
.IsRequired();
// Timestamps
builder.Property(p => p.CreatedAt)
.IsRequired();
builder.Property(p => p.UpdatedAt);
// Relationships - Epics collection (owned by aggregate)
// Configure the one-to-many relationship with Epic
// Use string-based FK name because ProjectId is a value object with conversion configured in EpicConfiguration
builder.HasMany("Epics")
.WithOne()
.HasForeignKey("ProjectId")
.OnDelete(DeleteBehavior.Cascade);
// Indexes for performance
builder.HasIndex(p => p.CreatedAt);
builder.HasIndex(p => p.OwnerId);
builder.HasIndex(p => p.TenantId);
// Ignore DomainEvents (handled separately)
builder.Ignore(p => p.DomainEvents);
}
}