Set up repository with legacy .NET Framework 4.8 source (OLD/), new .NET 10 Blazor solution (NEW/), OpenSpec specifications, documentation, and project configuration.
12 KiB
JdeScopingTool Architecture Review
Date: January 1, 2026 Reviewer: Claude + Codex MCP Scope: Clean Architecture compliance of NEW/ .NET 10 solution
Executive Summary
The current architecture has several critical and high-severity Clean Architecture violations that need to be addressed. The most pressing issues are:
- Duplicate interfaces in different namespaces - causes DI resolution failures
- Infrastructure code in Core layer - violates the dependency rule
- DI composition leaking into Core - composition should be in Host only
Current Project Structure
NEW/src/
├── JdeScoping.Core # Domain layer (BUT contains infrastructure)
├── JdeScoping.DataAccess # Data access layer
├── JdeScoping.DataSync # Data synchronization service
├── JdeScoping.SearchProcessing # Search query processing
├── JdeScoping.ExcelExport # Excel file generation
├── JdeScoping.Api # Web API controllers
├── JdeScoping.Host # Composition root (ASP.NET host)
├── JdeScoping.Client # Blazor WebAssembly UI
└── JdeScoping.Database # Database migrations (DbUp)
Dependency Graph (Current)
Host → Api, Core, Database, DataAccess, DataSync, SearchProcessing
Api → Core
DataAccess → Core
DataSync → Core, DataAccess
SearchProcessing → Core, DataAccess
ExcelExport → Core
Database → (standalone)
Client → (standalone WASM)
Critical Issues
1. Duplicate ILotFinderRepository Interfaces (CRITICAL)
Problem: Two separate ILotFinderRepository interfaces exist in different namespaces:
| Location | Namespace | Partials |
|---|---|---|
Core/Interfaces/ |
JdeScoping.Core.Interfaces |
ILotFinderRepository.cs, .SearchOperations.cs, .Lookups.cs |
DataAccess/Interfaces/ |
JdeScoping.DataAccess.Interfaces |
ILotFinderRepository.cs, .DataSync.cs, .Lookups.cs, .SearchManagement.cs |
Impact:
SearchController(Api/Controllers/SearchController.cs:23) depends onJdeScoping.Core.Interfaces.ILotFinderRepository- DI registration in DataAccess registers
JdeScoping.DataAccess.Interfaces.ILotFinderRepository - These are completely different interfaces - partial interfaces only merge within the same namespace/assembly
- Runtime DI will fail because the Core interface is never registered
Fix:
- Consolidate ALL
ILotFinderRepositorypartials intoJdeScoping.Core.Interfaces - Have
LotFinderRepositoryimplementation in DataAccess implement the Core interface - Remove duplicate interface files from DataAccess
2. Infrastructure Code in Core Layer (HIGH)
Problem: Core contains concrete implementations that depend on infrastructure packages.
Files in Core that violate this:
Core/Repositories/Jde/JdeOracleDataSource.cs- usesOracle.ManagedDataAccess.Client,DapperCore/Repositories/Jde/JdeFileDataSource.cs- file system accessCore/Repositories/Cms/CmsOracleDataSource.cs- usesOracle.ManagedDataAccess.Client,DapperCore/Repositories/Cms/CmsFileDataSource.cs- file system accessCore/Auth/LdapAuthService.cs- usesSystem.DirectoryServices.Protocols
Package references in Core.csproj that should not be there:
<PackageReference Include="Dapper" Version="2.1.66" />
<PackageReference Include="Microsoft.Data.SqlClient" Version="6.1.3" />
<PackageReference Include="Oracle.ManagedDataAccess.Core" Version="23.26.0" />
<PackageReference Include="ClosedXML" Version="0.105.0" />
<PackageReference Include="System.DirectoryServices.Protocols" Version="10.0.1" />
Fix:
- Move
JdeOracleDataSource,CmsOracleDataSourcetoJdeScoping.DataAccess/Sources/or newJdeScoping.Infrastructure - Move
JdeFileDataSource,CmsFileDataSourcealongside the Oracle implementations - Move
LdapAuthServicetoJdeScoping.Api/Auth/or newJdeScoping.Infrastructure - Remove infrastructure package references from Core.csproj
- Keep only interfaces (
IJdeDataSource,ICmsDataSource,IAuthService) in Core
3. DI Registration Extensions in Core (HIGH)
Problem: Core contains service registration extensions, which is composition logic that belongs in Host.
Files:
Core/Extensions/DataSourceServiceExtensions.csCore/Extensions/AuthServiceExtensions.csCore/Extensions/DataSyncServiceExtensions.csCore/Extensions/ExcelExportServiceExtensions.csCore/Extensions/SearchProcessingServiceExtensions.cs
Fix:
- Move these to
JdeScoping.Host/Extensions/or to each respective project's own extension class - Each infrastructure project should expose an
AddXxx(IServiceCollection)method - Host calls these methods in composition root
Medium Issues
4. ViewModels in Core Layer (MEDIUM)
Problem: Core contains ViewModels that are UI-shaped DTOs.
Files:
Core/ViewModels/WorkOrderViewModel.csCore/ViewModels/LotViewModel.csCore/ViewModels/ItemViewModel.csCore/ViewModels/WorkCenterViewModel.csCore/ViewModels/ProfitCenterViewModel.csCore/ViewModels/PartOperationViewModel.cs
Impact: Core should contain domain models, not presentation layer DTOs.
Fix Options:
- If ViewModels are shared between API and Client: Move to a shared
JdeScoping.ContractsorJdeScoping.Sharedproject - If ViewModels are API-only: Move to
JdeScoping.Api/Models/ - Alternative: Keep in Core but rename to
*Dtoto clarify they are data transfer objects, not UI-specific
5. SearchProcessing Uses Dapper/SqlClient Directly (MEDIUM)
Problem: SearchProcessing/Services/SearchProcessor.cs uses Dapper and SqlClient directly.
Impact: This puts data access logic inside what should be a use-case/application layer.
Fix Options:
- Move SearchProcessing data access into DataAccess (define ports like
ISearchQueryExecutorin Core, implement in DataAccess) - Or accept that SearchProcessing is infrastructure and treat it as such
6. Duplicate/Unused Excel Export Abstractions (LOW)
Problem: Excel export has split abstractions:
Core/Interfaces/IExcelWriter.cs- Core defines interfaceCore/Extensions/ExcelExportServiceExtensions.cs- Core has registrationExcelExport/Interfaces/IExcelExportService.cs- ExcelExport defines different interfaceExcelExport/ServiceCollectionExtensions.cs- ExcelExport has registration
Fix:
- Decide on one interface (keep
IExcelWriterin Core) - Have ExcelExport implement the Core interface
- Remove duplicate interface/registration from ExcelExport
Recommended Target Architecture
Clean Architecture Layers
┌─────────────────────────────────────────────────────────────┐
│ HOST │
│ JdeScoping.Host (Composition Root, Program.cs) │
└─────────────────────────────────────────────────────────────┘
│
┌──────────────────────┼──────────────────────┐
▼ ▼ ▼
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ PRESENTATION │ │ APPLICATION │ │ INFRASTRUCTURE │
│ JdeScoping.Api │ │ (Use Cases) │ │ │
│ JdeScoping. │ │ │ │ DataAccess │
│ Client │ │ │ │ DataSync │
└─────────────────┘ └─────────────────┘ │ ExcelExport │
│ │ │ Infrastructure* │
└──────────────────────┼───────────┴─────────────────┘
▼
┌─────────────────┐
│ DOMAIN │
│ JdeScoping.Core │
│ (Pure, no deps) │
└─────────────────┘
*New project for Oracle/LDAP implementations
Dependency Direction (Target)
All dependencies point inward toward Core:
- Host → All projects
- Api → Core only
- DataAccess → Core only
- DataSync → Core, DataAccess
- SearchProcessing → Core, DataAccess
- ExcelExport → Core only
- Infrastructure → Core only
- Client → (standalone, calls Api)
Refactoring Plan
Phase 1: Fix Critical Issues
-
Consolidate ILotFinderRepository (Day 1)
- Move all partial interface files to
Core/Interfaces/ - Update DataAccess implementation to use Core interface
- Update DI registration
- Verify all consumers use
JdeScoping.Core.Interfaces
- Move all partial interface files to
-
Move Infrastructure from Core (Day 1-2)
- Create
JdeScoping.Infrastructureproject (or use DataAccess) - Move
JdeOracleDataSource,CmsOracleDataSourceimplementations - Move
JdeFileDataSource,CmsFileDataSourceimplementations - Move
LdapAuthService - Remove infrastructure packages from Core.csproj
- Create
Phase 2: Fix High Issues
- Move DI Extensions (Day 2)
- Move service registration extensions to respective infrastructure projects
- Update Host to call each project's
AddXxx()method
Phase 3: Fix Medium Issues
-
Organize ViewModels (Day 3)
- Decide on placement (Shared, Api, or keep in Core)
- Move and update references
-
Clean up SearchProcessing (Day 3)
- Define ports in Core if needed
- Ensure data access goes through DataAccess layer
-
Unify Excel Export (Day 3)
- Single interface in Core
- Single implementation/registration in ExcelExport
Verification Checklist
After refactoring, verify:
dotnet buildsucceeds- All tests pass
- Core.csproj has NO infrastructure package references (only abstractions)
- Core contains ONLY: Models, Interfaces, Options, Helpers, pure domain logic
- No circular dependencies
- DI resolves all interfaces correctly at runtime
- API endpoints work end-to-end
Files to Move/Change
| Current Location | Target Location | Action |
|---|---|---|
Core/Repositories/Jde/* |
Infrastructure/Sources/Jde/ |
Move |
Core/Repositories/Cms/* |
Infrastructure/Sources/Cms/ |
Move |
Core/Auth/LdapAuthService.cs |
Infrastructure/Auth/ |
Move |
DataAccess/Interfaces/ILotFinderRepository*.cs |
Core/Interfaces/ |
Consolidate |
Core/Extensions/*ServiceExtensions.cs |
Host/Extensions/ or respective projects |
Move |
Core/ViewModels/* |
Decision needed | TBD |
Questions to Resolve
- Should ViewModels be shared with Blazor Client? If yes, create
JdeScoping.Sharedproject. - Should SearchProcessing be treated as application layer or infrastructure?
- Prefer single
Infrastructureproject or keep separate (DataAccess,DataSync, etc.)?