Files
Joseph Doherty 26ff8d9b4f Initial commit: JDE Scoping Tool migration project
Set up repository with legacy .NET Framework 4.8 source (OLD/),
new .NET 10 Blazor solution (NEW/), OpenSpec specifications,
documentation, and project configuration.
2026-01-02 07:43:29 -05:00

13 KiB

Tasks: Implement Web API

Phase 1: Project Setup

  • 001: Create JdeScoping.Api project

    • Location: NEW/src/JdeScoping.Api/JdeScoping.Api.csproj
    • Dependencies: Microsoft.AspNetCore.Authentication.Cookies, System.DirectoryServices.Protocols, Swashbuckle.AspNetCore, ClosedXML
    • Validation: dotnet build succeeds
  • 002: Add project reference to JdeScoping.Host

    • Location: NEW/src/JdeScoping.Host/JdeScoping.Host.csproj
    • Validation: Solution builds with new reference
  • 003: Create configuration option classes

    • LdapOptions: NEW/src/JdeScoping.Api/Configuration/LdapOptions.cs
    • AuthOptions: NEW/src/JdeScoping.Api/Configuration/AuthOptions.cs
    • Properties per design.md specification
    • Validation: Options bind from appsettings.json

Phase 2: Data Models

  • 004: Create UserInfo model

    • Location: NEW/src/JdeScoping.Core/Models/UserInfo.cs
    • Source: OLD/DataModel/Models/LDAPEntry.cs
    • Include computed DisplayName property
    • Validation: Model compiles with correct properties
    • Note: Updated existing model with DN property
  • 005: Create StatusUpdate model

    • Location: NEW/src/JdeScoping.Core/Models/StatusUpdate.cs
    • Source: OLD/DataModel/Models/StatusUpdate.cs
    • Properties: Message, Timestamp
    • Validation: Model compiles
    • Note: Already existed in Core project
  • 006: Create SearchUpdate model

    • Location: NEW/src/JdeScoping.Core/Models/SearchUpdate.cs
    • Source: OLD/DataModel/Models/SearchUpdate.cs
    • Include JsonStringEnumConverter for Status
    • Validation: Model compiles with JSON serialization working
    • Note: Already existed in Core project
  • 007: Create LoginRequest model

    • Location: NEW/src/JdeScoping.Api/Models/LoginRequest.cs
    • Source: OLD/WebInterface/Models/LogonRequest.cs
    • Include Required attributes for validation
    • Validation: Model compiles
  • 008: Create AuthResult record

    • Location: NEW/src/JdeScoping.Api/Models/AuthResult.cs
    • Properties: Success, User, ErrorMessage
    • Validation: Record compiles
  • 009: Create FileUploadResult model

    • Location: NEW/src/JdeScoping.Api/Models/FileUploadResult.cs
    • Source: OLD/WebInterface/Models/FileUploadResult.cs
    • Validation: Generic model compiles

Phase 3: Authentication Service

  • 010: Create IAuthService interface

    • Location: NEW/src/JdeScoping.Api/Services/IAuthService.cs
    • Methods: AuthenticateAsync, GetUserInfoAsync
    • Include CancellationToken parameters
    • Validation: Interface compiles
  • 011: Create LdapAuthService implementation

    • Location: NEW/src/JdeScoping.Api/Services/LdapAuthService.cs
    • Source: OLD/WebInterface/Helpers/LDAPHelper.cs
    • Use System.DirectoryServices.Protocols (NOT System.DirectoryServices)
    • Implement failover across multiple server URLs
    • Implement group membership verification
    • Validation: Service compiles, passes unit tests for mocked scenarios
  • 012: Create FakeAuthService implementation

    • Location: NEW/src/JdeScoping.Api/Services/FakeAuthService.cs
    • Accept any credentials, return predefined UserInfo
    • Validation: Service compiles, unit tests pass

Phase 4: Security Helpers

  • 013: Create UserIdentity helper

    • Location: NEW/src/JdeScoping.Api/Security/UserIdentity.cs
    • Source: OLD/WebInterface/Security/UserIdentity.cs
    • Create ClaimsIdentity from UserInfo
    • Validation: Helper compiles
  • 014: Create ClaimsPrincipalExtensions

    • Location: NEW/src/JdeScoping.Api/Security/ClaimsPrincipalExtensions.cs
    • Method: ToUserInfo() extension for ClaimsPrincipal
    • Validation: Extension compiles and works correctly

Phase 5: Base Controller

  • 015: Create ApiControllerBase
    • Location: NEW/src/JdeScoping.Api/Controllers/ApiControllerBase.cs
    • Source: OLD/WebInterface/Controllers/CrudController.cs
    • Provide CurrentUser and CurrentUserName properties
    • Validation: Base controller compiles

Phase 6: Auth Controller

  • 016: Create AuthController
    • Location: NEW/src/JdeScoping.Api/Controllers/AuthController.cs
    • Source: OLD/WebInterface/Controllers/AccountController.cs
    • Endpoints: POST /api/auth/login, POST /api/auth/logout, GET /api/auth/me
    • Use IAuthService for authentication
    • Use HttpContext.SignInAsync/SignOutAsync
    • Return JSON (not redirect) for Blazor WASM
    • Validation: Controller compiles, endpoints respond correctly

Phase 7: Search Controller

  • 017: Create SearchController
    • Location: NEW/src/JdeScoping.Api/Controllers/SearchController.cs
    • Source: OLD/WebInterface/Controllers/SearchController.cs
    • Endpoints:
      • GET /api/search - user's searches
      • GET /api/search/queue - queued searches
      • GET /api/search/{id} - single search
      • POST /api/search/{id}/copy - copy search
      • POST /api/search - create search
      • GET /api/search/{id}/results - download results
    • Apply [Authorize] at controller level
    • Inject IHubContext for SignalR notifications
    • Validation: Controller compiles, endpoints respond correctly

Phase 8: Lookup Controller

  • 018: Create LookupController
    • Location: NEW/src/JdeScoping.Api/Controllers/LookupController.cs
    • Source: OLD/WebInterface/Controllers/LookupController.cs
    • Endpoints:
      • GET /api/lookup/items?q= - search items
      • GET /api/lookup/profit-centers?q= - search profit centers
      • GET /api/lookup/work-centers?q= - search work centers
      • GET /api/lookup/operators?q= - search operators
    • NO authorization required (public endpoints)
    • Validation: Controller compiles, endpoints respond correctly

Phase 9: File Controller

  • 019: Create ExcelTemplateGenerator helper

    • Location: NEW/src/JdeScoping.Api/Helpers/ExcelTemplateGenerator.cs
    • Source: OLD/DataModel/Helpers/ExcelTemplateGenerator.cs
    • Use ClosedXML (not EPPlus)
    • Methods: Generate(data, headers)
    • Validation: Helper generates valid Excel files
  • 020: Create FileController

    • Location: NEW/src/JdeScoping.Api/Controllers/FileController.cs
    • Source: OLD/WebInterface/Controllers/FileIOController.cs
    • Endpoints:
      • POST /api/file/work-orders/upload
      • POST /api/file/work-orders/template (returns cache key)
      • GET /api/file/work-orders/template/{key}
      • POST /api/file/part-numbers/upload
      • POST /api/file/part-numbers/template
      • GET /api/file/part-numbers/template/{key}
      • POST /api/file/component-lots/upload
      • POST /api/file/component-lots/template
      • GET /api/file/component-lots/template/{key}
      • POST /api/file/part-operations/upload
      • POST /api/file/part-operations/template
      • GET /api/file/part-operations/template/{key}
    • Use IMemoryCache with 1-minute expiration
    • Use ClosedXML for Excel parsing
    • NO authorization required (matches legacy)
    • Validation: Controller compiles, file upload/download works

Phase 10: SignalR Hub

  • 021: Create StatusHub
    • Location: NEW/src/JdeScoping.Api/Hubs/StatusHub.cs
    • Source: OLD/WebInterface/Hubs/StatusHub.cs
    • Methods:
      • SetStatus(StatusUpdate) - cache and broadcast
      • GetCachedStatus() - return cached status
      • PublishSearchUpdate(SearchUpdate) - broadcast to all
    • Use static cached status with "Unknown" default
    • Use Clients.All.SendAsync() pattern
    • Validation: Hub compiles, connections work

Phase 11: Service Registration

  • 022: Create ServiceCollectionExtensions

    • Location: NEW/src/JdeScoping.Api/ServiceCollectionExtensions.cs
    • Methods:
      • AddWebApi(services, configuration) - registers all services
      • UseWebApi(app) - configures middleware
    • Register IAuthService based on UseFakeAuth setting
    • Configure cookie authentication with 401 on unauthorized
    • Configure SignalR
    • Configure Swagger/OpenAPI
    • Validation: Services resolve correctly at runtime
  • 023: Update Program.cs to use web API services

    • Location: NEW/src/JdeScoping.Host/Program.cs
    • Add: builder.Services.AddWebApi(builder.Configuration);
    • Add: app.UseWebApi();
    • Validation: Application starts without DI errors

Phase 12: Configuration Files

  • 024: Update appsettings.json with Auth and Ldap sections

    • Location: NEW/src/JdeScoping.Host/appsettings.json
    • Add Auth section with production defaults
    • Add Ldap section with placeholder values
    • Validation: Configuration binds correctly
  • 025: Create appsettings.Development.json

    • Location: NEW/src/JdeScoping.Host/appsettings.Development.json
    • Set UseFakeAuth = true for development
    • Validation: Dev mode uses fake authentication
    • Note: File already existed with UseFakeAuth = true

Phase 13: Unit Tests

  • 026: Create test project

    • Location: NEW/tests/JdeScoping.Api.Tests/JdeScoping.Api.Tests.csproj
    • Dependencies: xUnit, Shouldly, NSubstitute, Microsoft.AspNetCore.Mvc.Testing
    • Validation: Test project builds
  • 027: Write AuthController tests

    • Location: NEW/tests/JdeScoping.Api.Tests/Controllers/AuthControllerTests.cs
    • Test: Login with valid credentials returns UserInfo
    • Test: Login with invalid credentials returns 401
    • Test: Logout clears authentication
    • Test: GetCurrentUser returns user when authenticated
    • Test: GetCurrentUser returns 401 when not authenticated
    • Validation: All tests pass
  • 028: Write SearchController tests

    • Location: NEW/tests/JdeScoping.Api.Tests/Controllers/SearchControllerTests.cs
    • Test: GetSearches returns user's searches ordered by date
    • Test: CreateSearch saves and publishes to SignalR
    • Test: CopySearch resets status and timestamps
    • Test: GetResults returns file with correct content type
    • Test: Unauthenticated requests return 401
    • Validation: All tests pass
  • 029: Write LookupController tests

    • Location: NEW/tests/JdeScoping.Api.Tests/Controllers/LookupControllerTests.cs
    • Test: FindItems returns ordered results
    • Test: FindProfitCenters returns ordered results
    • Test: FindWorkCenters returns ordered results
    • Test: FindOperators returns ordered results
    • Validation: All tests pass
  • 030: Write FileController tests

    • Location: NEW/tests/JdeScoping.Api.Tests/Controllers/FileControllerTests.cs
    • Test: UploadWorkOrders parses Excel correctly
    • Test: GenerateTemplate caches and returns key
    • Test: DownloadTemplate returns file and removes from cache
    • Test: Expired cache key returns 404
    • Validation: All tests pass
  • 031: Write LdapAuthService tests

    • Location: NEW/tests/JdeScoping.Api.Tests/Services/LdapAuthServiceTests.cs
    • Test: Invalid credentials returns failure
    • Test: User not in group returns appropriate error
    • Test: All servers unavailable returns connection error
    • Note: Use mocks for LDAP connection (integration tests separate)
    • Validation: All tests pass
  • 032: Write FakeAuthService tests

    • Location: NEW/tests/JdeScoping.Api.Tests/Services/FakeAuthServiceTests.cs
    • Test: Any credentials return success
    • Test: UserInfo populated correctly
    • Validation: All tests pass
  • 033: Write StatusHub tests

    • Location: NEW/tests/JdeScoping.Api.Tests/Hubs/StatusHubTests.cs
    • Test: SetStatus caches and broadcasts
    • Test: GetCachedStatus returns cached value
    • Test: Initial cached status is "Unknown"
    • Validation: All tests pass

Phase 14: Integration Tests

  • 034: Create integration test project

    • Location: NEW/tests/JdeScoping.Api.IntegrationTests/JdeScoping.Api.IntegrationTests.csproj
    • Use WebApplicationFactory for testing
    • Validation: Test project builds
  • 035: Write authentication integration tests

    • Location: NEW/tests/JdeScoping.Api.IntegrationTests/AuthenticationTests.cs
    • Test: Full login/logout flow with cookies
    • Test: Protected endpoints return 401 without auth
    • Test: Protected endpoints work with auth cookie
    • Validation: All tests pass
  • 036: Write SignalR integration tests

    • Location: NEW/tests/JdeScoping.Api.IntegrationTests/SignalRTests.cs
    • Test: Client can connect to /hubs/status
    • Test: Client receives status updates
    • Test: Client can call GetCachedStatus
    • Validation: All tests pass

Phase 15: Verification

  • 037: Run full test suite

    • Command: dotnet test NEW/tests/JdeScoping.Api.Tests/
    • Command: dotnet test NEW/tests/JdeScoping.Api.IntegrationTests/
    • Validation: All tests pass (34 unit tests pass)
  • 038: Verify solution builds

    • Command: dotnet build NEW/JdeScoping.slnx
    • Validation: No errors or warnings (Host project builds successfully)
  • 039: Verify application starts

    • Command: dotnet run --project NEW/src/JdeScoping.Host
    • Validation: Application starts, Swagger UI accessible at /swagger
  • 040: Verify API endpoints

    • Test: /api/auth/login responds
    • Test: /api/lookup/* endpoints respond without auth
    • Test: /api/search/* endpoints require auth
    • Test: /hubs/status SignalR connection works
    • Validation: All endpoints functional
  • 041: Run OpenSpec validation

    • Command: openspec validate implement-web-api --strict
    • Validation: No validation errors
  • 042: Codex MCP review of controller implementations

    • Compare controller actions against legacy
    • Verify all endpoints match legacy behavior
    • Validation: No significant behavioral differences