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); } }