using System.Diagnostics; using LctMonolith.Models; using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Identity.EntityFrameworkCore; using Microsoft.EntityFrameworkCore; using EventLog = LctMonolith.Models.EventLog; namespace LctMonolith.Database.Data; /// /// Main EF Core database context for gamification module (PostgreSQL provider expected). /// public class AppDbContext : IdentityDbContext, Guid> { public AppDbContext(DbContextOptions options) : base(options) { } public DbSet Ranks => Set(); public DbSet RankRequiredMissions => Set(); public DbSet RankRequiredCompetencies => Set(); public DbSet Missions => Set(); public DbSet UserMissions => Set(); public DbSet MissionCompetencyRewards => Set(); public DbSet MissionArtifactRewards => Set(); public DbSet Competencies => Set(); public DbSet UserCompetencies => Set(); public DbSet Artifacts => Set(); public DbSet UserArtifacts => Set(); public DbSet StoreItems => Set(); public DbSet UserInventoryItems => Set(); public DbSet Transactions => Set(); public DbSet EventLogs => Set(); public DbSet RefreshTokens => Set(); public DbSet Notifications => Set(); protected override void OnModelCreating(ModelBuilder b) { base.OnModelCreating(b); // Rank required mission composite key b.Entity().HasKey(x => new { x.RankId, x.MissionId }); b.Entity() .HasOne(x => x.Rank).WithMany(r => r.RequiredMissions).HasForeignKey(x => x.RankId); b.Entity() .HasOne(x => x.Mission).WithMany(m => m.RanksRequiring).HasForeignKey(x => x.MissionId); // Rank required competency composite key b.Entity().HasKey(x => new { x.RankId, x.CompetencyId }); b.Entity() .HasOne(x => x.Rank).WithMany(r => r.RequiredCompetencies).HasForeignKey(x => x.RankId); b.Entity() .HasOne(x => x.Competency).WithMany(c => c.RankRequirements).HasForeignKey(x => x.CompetencyId); // UserMission composite key b.Entity().HasKey(x => new { x.UserId, x.MissionId }); b.Entity() .HasOne(x => x.User).WithMany(u => u.Missions).HasForeignKey(x => x.UserId); b.Entity() .HasOne(x => x.Mission).WithMany(m => m.UserMissions).HasForeignKey(x => x.MissionId); // UserCompetency composite key b.Entity().HasKey(x => new { x.UserId, x.CompetencyId }); b.Entity() .HasOne(x => x.User).WithMany(u => u.Competencies).HasForeignKey(x => x.UserId); b.Entity() .HasOne(x => x.Competency).WithMany(c => c.UserCompetencies).HasForeignKey(x => x.CompetencyId); // Mission competency reward composite key b.Entity().HasKey(x => new { x.MissionId, x.CompetencyId }); // Mission artifact reward composite key b.Entity().HasKey(x => new { x.MissionId, x.ArtifactId }); // UserArtifact composite key b.Entity().HasKey(x => new { x.UserId, x.ArtifactId }); // UserInventory composite key b.Entity().HasKey(x => new { x.UserId, x.StoreItemId }); // Refresh token index unique b.Entity().HasIndex(x => x.Token).IsUnique(); // ---------- Added performance indexes ---------- b.Entity().HasIndex(u => u.RankId); b.Entity().HasIndex(m => m.MinRankId); b.Entity().HasIndex(um => new { um.UserId, um.Status }); b.Entity().HasIndex(uc => uc.CompetencyId); // for querying all users by competency b.Entity().HasIndex(e => new { e.UserId, e.Type, e.CreatedAt }); b.Entity().HasIndex(i => i.IsActive); b.Entity().HasIndex(t => new { t.UserId, t.CreatedAt }); b.Entity().HasIndex(n => new { n.UserId, n.IsRead, n.CreatedAt }); } }