Phases 3 & 4: Complete data access architecture migration
Phase 3 — eliminated ApplicationDbContext from all non-exempt controllers, routing all data access through IUnitOfWork. Added IPlainRepository<T> for the four platform entities (Announcement, BannedIp, DashboardTip, ReleaseNote) that intentionally don't extend BaseEntity and therefore can't use the constrained IRepository<T>. Added permanent-exception comments to the 18 controllers that legitimately retain direct DbContext access (Identity infra, cross-tenant platform ops, bulk streaming exports). Phase 4 — added EnforceDataAccessArchitecture() to Program.cs, a startup gate that reflects over every Controller subclass and throws at boot if any non-exempt controller injects ApplicationDbContext. The app cannot start with a violation. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -9,7 +9,6 @@ using PowderCoating.Application.Services;
|
||||
using PowderCoating.Core.Entities;
|
||||
using PowderCoating.Core.Enums;
|
||||
using PowderCoating.Core.Interfaces;
|
||||
using PowderCoating.Infrastructure.Data;
|
||||
using PowderCoating.Shared.Constants;
|
||||
using PowderCoating.Web.Hubs;
|
||||
|
||||
@@ -19,7 +18,6 @@ namespace PowderCoating.Web.Controllers;
|
||||
public class JobsPriorityController : Controller
|
||||
{
|
||||
private readonly IUnitOfWork _unitOfWork;
|
||||
private readonly ApplicationDbContext _context;
|
||||
private readonly ILogger<JobsPriorityController> _logger;
|
||||
private readonly UserManager<ApplicationUser> _userManager;
|
||||
private readonly ITenantContext _tenantContext;
|
||||
@@ -27,14 +25,12 @@ public class JobsPriorityController : Controller
|
||||
|
||||
public JobsPriorityController(
|
||||
IUnitOfWork unitOfWork,
|
||||
ApplicationDbContext context,
|
||||
ILogger<JobsPriorityController> logger,
|
||||
UserManager<ApplicationUser> userManager,
|
||||
ITenantContext tenantContext,
|
||||
IHubContext<ShopHub> shopHub)
|
||||
{
|
||||
_unitOfWork = unitOfWork;
|
||||
_context = context;
|
||||
_logger = logger;
|
||||
_userManager = userManager;
|
||||
_tenantContext = tenantContext;
|
||||
@@ -63,13 +59,7 @@ public class JobsPriorityController : Controller
|
||||
var today = date?.Date ?? DateTime.Today;
|
||||
|
||||
// Get all jobs scheduled for today with related data
|
||||
var jobs = await _context.Jobs
|
||||
.Include(j => j.Customer)
|
||||
.Include(j => j.JobStatus)
|
||||
.Include(j => j.JobPriority)
|
||||
.Include(j => j.AssignedUser)
|
||||
.Where(j => j.ScheduledDate.HasValue && j.ScheduledDate.Value.Date == today && !j.IsDeleted)
|
||||
.ToListAsync();
|
||||
var jobs = await _unitOfWork.Jobs.GetScheduledJobsForDateAsync(today);
|
||||
|
||||
// Get existing priority records for today
|
||||
var existingPriorities = await _unitOfWork.JobDailyPriorities
|
||||
@@ -108,15 +98,14 @@ public class JobsPriorityController : Controller
|
||||
.ToListAsync();
|
||||
|
||||
// Get maintenance records scheduled for today (Scheduled or InProgress)
|
||||
var maintenanceItems = await _context.MaintenanceRecords
|
||||
.Include(m => m.Equipment)
|
||||
.Include(m => m.AssignedUser)
|
||||
.Where(m => m.ScheduledDate.Date == today && !m.IsDeleted &&
|
||||
(m.Status == MaintenanceStatus.Scheduled ||
|
||||
m.Status == MaintenanceStatus.InProgress))
|
||||
var maintenanceItems = (await _unitOfWork.MaintenanceRecords.FindAsync(
|
||||
m => m.ScheduledDate.Date == today &&
|
||||
(m.Status == MaintenanceStatus.Scheduled || m.Status == MaintenanceStatus.InProgress),
|
||||
false,
|
||||
m => m.Equipment, m => m.AssignedUser))
|
||||
.OrderByDescending(m => (int)m.Priority)
|
||||
.ThenBy(m => m.ScheduledDate)
|
||||
.ToListAsync();
|
||||
.ToList();
|
||||
|
||||
ViewBag.ScheduledDate = today;
|
||||
ViewBag.MaintenanceItems = maintenanceItems;
|
||||
@@ -378,14 +367,10 @@ public class JobsPriorityController : Controller
|
||||
{
|
||||
try
|
||||
{
|
||||
var record = await _context.MaintenanceRecords.FindAsync(maintenanceId);
|
||||
var record = await _unitOfWork.MaintenanceRecords.GetByIdAsync(maintenanceId);
|
||||
if (record == null || record.IsDeleted)
|
||||
return Json(new { success = false, message = "Maintenance record not found" });
|
||||
|
||||
// FindAsync bypasses global query filters — verify company ownership explicitly
|
||||
if (!_tenantContext.IsSuperAdmin() && record.CompanyId != _tenantContext.GetCurrentCompanyId())
|
||||
return Json(new { success = false, message = "Access denied." });
|
||||
|
||||
string workerName = "Unassigned";
|
||||
if (!string.IsNullOrEmpty(workerId))
|
||||
{
|
||||
@@ -402,7 +387,7 @@ public class JobsPriorityController : Controller
|
||||
}
|
||||
|
||||
record.UpdatedAt = DateTime.UtcNow;
|
||||
await _context.SaveChangesAsync();
|
||||
await _unitOfWork.CompleteAsync();
|
||||
|
||||
return Json(new { success = true, message = "Worker assigned successfully", workerName });
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user