using Collaboration.Domain.Entities; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; namespace Collaboration.Infrastructure.Persistence; /// /// DbContext for the Collaboration module. /// Designed to be registered as a separate context or merged into your /// main application DbContext — your choice based on deployment preference. /// public class CollabDbContext : DbContext { public CollabDbContext(DbContextOptions options) : base(options) { } public DbSet Sessions => Set(); public DbSet Participants => Set(); public DbSet Invites => Set(); public DbSet SessionEvents => Set(); public DbSet Configs => Set(); protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.HasDefaultSchema("collab"); modelBuilder.ApplyConfiguration(new CollabSessionConfiguration()); modelBuilder.ApplyConfiguration(new CollabParticipantConfiguration()); modelBuilder.ApplyConfiguration(new CollabSessionInviteConfiguration()); modelBuilder.ApplyConfiguration(new CollabSessionEventConfiguration()); modelBuilder.ApplyConfiguration(new CollabConfigConfiguration()); } } // ── Entity Configurations ──────────────────────────────────────────────────── internal class CollabSessionConfiguration : IEntityTypeConfiguration { public void Configure(EntityTypeBuilder b) { b.ToTable("Sessions"); b.HasKey(x => x.SessionId); b.Property(x => x.SessionCode).HasMaxLength(10).IsRequired(); b.HasIndex(x => x.SessionCode).IsUnique(); b.Property(x => x.Title).HasMaxLength(200).IsRequired(); b.Property(x => x.SessionType).HasConversion().HasMaxLength(20); b.Property(x => x.Status).HasConversion().HasMaxLength(20); b.Property(x => x.Mode).HasConversion().HasMaxLength(20); b.Property(x => x.ContextModuleCode).HasMaxLength(50); b.Property(x => x.ContextRecordId).HasMaxLength(100); b.Property(x => x.ContextRecordLabel).HasMaxLength(300); b.Property(x => x.ContextRouteUrl).HasMaxLength(1000); b.Property(x => x.SettingsJson).HasColumnType("nvarchar(max)"); // Indexes for common query patterns b.HasIndex(x => new { x.OrgId, x.Status }); b.HasIndex(x => new { x.CreatedBy, x.Status }); b.HasIndex(x => x.ScheduledAt); b.HasMany(x => x.Participants) .WithOne(x => x.Session) .HasForeignKey(x => x.SessionId) .OnDelete(DeleteBehavior.Cascade); b.HasMany(x => x.Invites) .WithOne(x => x.Session) .HasForeignKey(x => x.SessionId) .OnDelete(DeleteBehavior.Cascade); b.HasMany(x => x.Events) .WithOne(x => x.Session) .HasForeignKey(x => x.SessionId) .OnDelete(DeleteBehavior.Cascade); } } internal class CollabParticipantConfiguration : IEntityTypeConfiguration { public void Configure(EntityTypeBuilder b) { b.ToTable("Participants"); b.HasKey(x => x.ParticipantId); b.Property(x => x.DisplayName).HasMaxLength(150).IsRequired(); b.Property(x => x.Role).HasConversion().HasMaxLength(20); b.Property(x => x.CursorColor).HasMaxLength(7); // hex #RRGGBB b.Property(x => x.SignalRConnectionId).HasMaxLength(200); b.HasIndex(x => new { x.SessionId, x.UserId }); b.HasIndex(x => x.SignalRConnectionId); // Needed for disconnect lookup } } internal class CollabSessionInviteConfiguration : IEntityTypeConfiguration { public void Configure(EntityTypeBuilder b) { b.ToTable("Invites"); b.HasKey(x => x.InviteId); b.Property(x => x.InviteToken).HasMaxLength(100).IsRequired(); b.HasIndex(x => x.InviteToken).IsUnique(); b.Property(x => x.OfferedRole).HasConversion().HasMaxLength(20); b.Property(x => x.Status).HasConversion().HasMaxLength(20); b.HasIndex(x => new { x.SessionId, x.InvitedUserId }); b.HasIndex(x => x.ExpiresAt); // For expiry cleanup job } } internal class CollabSessionEventConfiguration : IEntityTypeConfiguration { public void Configure(EntityTypeBuilder b) { b.ToTable("SessionEvents"); b.HasKey(x => x.EventId); b.Property(x => x.EventId).UseIdentityColumn(); b.Property(x => x.EventType).HasConversion().HasMaxLength(50); b.Property(x => x.Payload).HasColumnType("nvarchar(max)"); b.HasIndex(x => new { x.SessionId, x.Timestamp }); b.HasIndex(x => new { x.EventType, x.Timestamp }); // Audit queries } } internal class CollabConfigConfiguration : IEntityTypeConfiguration { public void Configure(EntityTypeBuilder b) { b.ToTable("Configs"); b.HasKey(x => x.OrgId); b.Property(x => x.ControlConsentMode).HasConversion().HasMaxLength(30); b.Property(x => x.AllowedModulesJson).HasColumnType("nvarchar(max)"); } }