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:
2026-04-28 09:17:29 -04:00
parent 90bc0d965f
commit 1cb7a8ca4a
72 changed files with 9060 additions and 2323 deletions
@@ -1,3 +1,5 @@
using PowderCoating.Core.Entities;
namespace PowderCoating.Application.Interfaces;
/// <summary>
@@ -22,4 +24,25 @@ public interface IOperationalReportService
/// <summary>Returns powder usage (lbs and cost) broken down by color and vendor.</summary>
Task<PowderUsageReport> GetPowderUsageAsync(int companyId, int months);
/// <summary>
/// Returns all active (non-deleted, non-voided) bills with their Vendor and non-deleted
/// Payments navigations loaded. Used by Analytics, ExpensesAp, and AI accounting actions
/// so those controllers do not need a direct ApplicationDbContext reference.
/// </summary>
Task<List<Bill>> GetActiveBillsAsync();
/// <summary>
/// Returns all non-deleted direct expenses with their ExpenseAccount navigation loaded.
/// Used by Analytics, ExpensesAp, and AI accounting actions so those controllers do not
/// need a direct ApplicationDbContext reference.
/// </summary>
Task<List<Expense>> GetAllExpensesAsync();
/// <summary>
/// Returns the full job status history log with FromStatus and ToStatus navigations
/// loaded. Used by Analytics and JobCycleTime so those actions do not need a direct
/// ApplicationDbContext reference.
/// </summary>
Task<List<JobStatusHistory>> GetAllJobStatusHistoryAsync();
}