Files
Joseph Doherty 604bfe919c refactor: address code review findings across all projects
Apply comprehensive fixes from code reviews including:
- Extract shared utilities (SqlFormatHelper, CellValueConverter, DbDestinationBase)
- Add interface abstractions (IAuthenticationService, IDatabaseMigrator, IMisQueryBuilder)
- Implement SecureStore for encrypted secrets storage
- Fix error handling with proper HTTP status codes and logging
- Optimize double enumeration in DevEtlRegistry
- Add DataSync.Dev README for developer onboarding
- Extract filter panel base classes to reduce duplication
- Update code review docs to mark all issues as fixed
2026-01-19 11:05:36 -05:00

6.1 KiB

Code Review: JdeScoping.Client

Project Path: NEW/src/JdeScoping.Client Layer: Presentation Purpose: Blazor WebAssembly client


Executive Summary

The JdeScoping.Client project is a Blazor WebAssembly application serving as the presentation layer. The codebase demonstrates good architectural patterns with clear separation between services, components, and models.

Overall Assessment: Good with Room for Improvement

Category Rating Notes
SOLID Principles Good Some SRP concerns in SearchEdit.razor
Clean Architecture Excellent Clear layer separation
Code Organization Good Well-organized folder structure
Error Handling Good Consistent ApiResult pattern
Testability Good Interface-based design enables mocking
Code Duplication Needs Improvement Good DRY violations in filter panels FIXED
Async Patterns Good Proper async/await usage
Null Safety Good Nullable enabled with proper handling
Documentation Good XML docs on interfaces and services

1. SOLID Principles

Single Responsibility Principle (SRP)

Positive Observations:

  • API clients properly separated by domain
  • Authentication concerns separated into dedicated services
  • Base class ApiClientBase handles HTTP concerns separately

Areas for Improvement:

Issue: SearchEdit.razor has multiple responsibilities

The component handles:

  • Search loading and state management
  • Form validation
  • Search type detection
  • SignalR event handling
  • File download operations

Recommendation: Extract search type detection into a dedicated service.

Dependency Inversion Principle (DIP)

Issue: Concrete dependency on AuthStateProvider

Recommendation: Create an IAuthStateProvider interface.


2. Clean Architecture

Layer Separation

Positive Observations:

  • Clear folder structure separating Pages, Components, Services, Models
  • Core contracts defined in separate JdeScoping.Core project
  • ViewModels properly isolated in Models folder

3. Code Organization

Naming Conventions

Positive: Consistent PascalCase for public members, underscore prefix for private fields.

Issue: Inconsistent parameter naming in TimeSpanFilterPanel (MinimumDT vs MinimumDt).


4. Error Handling

Positive: Consistent use of ApiResult<T> discriminated union

Standard pattern:

result.Switch(
    success => { /* handle success */ },
    notFound => { _errorMessage = "Not found."; },
    validation => { _errorMessage = FormatValidationErrors(validation.FieldErrors); },
    // ...
);

Issues

Issue: Silent exception swallowing in AuthStateProvider FIXED

Resolution: Exceptions are now logged at Warning level with the message "Session validation failed, treating as unauthenticated".

Issue: RefreshStatusService uses Console.WriteLine

Recommendation: Use proper logging abstraction.


5. Testability

Positive Aspects

  • All services properly registered in DI
  • Interface-based design for API clients
  • Comprehensive test coverage in ApiClientBaseTests

6. Code Duplication (DRY Violations)

Critical Duplications

Issue: FormatSql method duplicated

Found in both PipelineScheduleSection.razor and SqlQueryModal.razor.

Recommendation: Extract to a shared utility class like SqlFormatHelper.cs.

Issue: Duplicated API result handling in filter panels FIXED

Issue: Similar autocomplete search patterns FIXED

Multiple filter panels have nearly identical OnSearchAsync, OnItemSelected, AddItemAsync, DeleteItem, ClearDataAsync methods.

Resolution: Created two base component classes:

  • AutocompleteFilterPanelBase<TItem> - for panels with autocomplete search (WorkCenter, ProfitCenter, Operator)
  • FileUploadFilterPanelBase<TItem> - for panels with file upload (WorkOrder, ComponentLot, PartOperation)

Derived components now inherit from these bases and only override abstract methods for panel-specific API calls and configuration.


7. Async Patterns

Positive Observations

  • Consistent async/await usage
  • CancellationToken support in all API client methods
  • Proper use of Task.WhenAll for parallel requests

Issues

Issue: Fire-and-forget tasks without error handling

_ = JSRuntime.InvokeVoidAsync("downloadFile", "template.xlsx", bytes);

Recommendation: Consider awaiting these calls or using a try-catch wrapper.

Positive: Good thread-safe caching in CryptoService with SemaphoreSlim.

Issue: SemaphoreSlim not disposed FIXED - Implemented IAsyncDisposable on CryptoService.


8. Null Safety

Positive: Nullable reference types enabled

Issues:

Issue: Nullable parameters not validated in ViewModelMappingExtensions

Recommendation: Add null checks or use null-conditional operator.


9. Security Considerations

Positive Practices

  • Good credential encryption pattern using RSA-OAEP

Issues

Issue: Potential XSS via JavaScript eval

await JSRuntime.InvokeVoidAsync("eval", "document.getElementById('workOrderFileInput').click()");

Recommendation: Create a dedicated JavaScript interop function instead.


Recommendations Summary

Critical Priority

  1. Extract FormatSql method to shared utility class
  2. Replace eval usage with dedicated JS interop function

High Priority

  1. Extract business logic from SearchEdit.razor into services
  2. Create generic base for autocomplete filter panels FIXED
  3. Add logging to catch blocks FIXED - Added Warning-level logging to AuthStateProvider
  4. Implement IAsyncDisposable on CryptoService FIXED

Medium Priority

  1. Create interface for AuthStateProvider
  2. Standardize API result error notification handling
  3. Use IAuthApiClient in CryptoService instead of direct HTTP
  4. Add XML documentation to Razor components