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