using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; using Tiku.Domain.Catalog; using Tiku.Domain.Identity; namespace Tiku.Infrastructure.Persistence.Configurations; internal sealed class UserConfiguration : IEntityTypeConfiguration { public void Configure(EntityTypeBuilder builder) { builder.ToTable("users"); builder.HasKey(entity => entity.Id); builder.Property(entity => entity.Id).HasDefaultValueSql("gen_random_uuid()"); builder.ConfigureTimestamps(); builder.Property(entity => entity.LegacyId).HasMaxLength(64); builder.Property(entity => entity.UserName).HasMaxLength(100); builder.Property(entity => entity.NormalizedUserName).HasMaxLength(100); builder.Property(entity => entity.Email).HasColumnType("citext").HasMaxLength(320); builder.Property(entity => entity.NormalizedEmail).HasMaxLength(320); builder.Property(entity => entity.Phone).HasMaxLength(32); builder.Property(entity => entity.PhoneNumber).HasMaxLength(32); builder.Property(entity => entity.PasswordHash).HasMaxLength(1024); builder.Property(entity => entity.SecurityStamp).HasMaxLength(64); builder.Property(entity => entity.ConcurrencyStamp).HasMaxLength(64).IsConcurrencyToken(); builder.Property(entity => entity.Name).HasMaxLength(200); builder.Property(entity => entity.AvatarUrl).HasMaxLength(2048); builder.Property(entity => entity.PrimaryRole).HasMaxLength(50); builder.Property(entity => entity.Status).HasSnakeCaseEnum(); builder.Property(entity => entity.RawProfile).IsJson("{}"); builder.HasIndex(entity => entity.LegacyId).IsUnique(); builder.HasIndex(entity => entity.NormalizedUserName).IsUnique(); builder.HasIndex(entity => entity.NormalizedEmail); builder.HasIndex(entity => entity.Phone).IsUnique(); } } internal sealed class UserIdentityConfiguration : IEntityTypeConfiguration { public void Configure(EntityTypeBuilder builder) { builder.ConfigureEntity("user_identities"); builder.ConfigureTimestamps(); builder.Property(entity => entity.Provider).HasMaxLength(50); builder.Property(entity => entity.ProviderSubject).HasMaxLength(255); builder.Property(entity => entity.UnionId).HasMaxLength(255); builder.Property(entity => entity.OpenId).HasMaxLength(255); builder.Property(entity => entity.Phone).HasMaxLength(32); builder.Property(entity => entity.Email).HasColumnType("citext").HasMaxLength(320); builder.HasIndex(entity => new { entity.Provider, entity.ProviderSubject }).IsUnique(); builder.HasOne() .WithMany() .HasForeignKey(entity => entity.UserId) .OnDelete(DeleteBehavior.Cascade); } } internal sealed class StudentProfileConfiguration : IEntityTypeConfiguration { public void Configure(EntityTypeBuilder builder) { builder.ConfigureTenantEntity("student_profiles"); builder.ConfigureTimestamps(); builder.Property(entity => entity.LegacyUserId).HasMaxLength(64); builder.Property(entity => entity.AvatarPreset).HasMaxLength(32).HasDefaultValue("male"); builder.Property(entity => entity.Stats).IsJson("{}"); builder.Property(entity => entity.Progress).IsJson("{}"); builder.Property(entity => entity.ModuleSelections).IsJson("{}"); builder.Property(entity => entity.RecentActivities).IsJson("[]"); builder.HasIndex(entity => new { entity.TenantId, entity.UserId }).IsUnique(); builder.HasOne() .WithMany() .HasForeignKey(entity => entity.UserId) .OnDelete(DeleteBehavior.Cascade); builder.HasOne() .WithMany() .HasForeignKey(entity => new { entity.TenantId, entity.RegionId }) .HasPrincipalKey(entity => new { entity.TenantId, entity.Id }) .OnDelete(DeleteBehavior.Restrict); builder.HasOne() .WithMany() .HasForeignKey(entity => new { entity.TenantId, entity.SelectedSchoolId }) .HasPrincipalKey(entity => new { entity.TenantId, entity.Id }) .OnDelete(DeleteBehavior.Restrict); builder.HasOne() .WithMany() .HasForeignKey(entity => new { entity.TenantId, entity.SelectedMajorId }) .HasPrincipalKey(entity => new { entity.TenantId, entity.Id }) .OnDelete(DeleteBehavior.Restrict); } }