Files
jdescopingtool/openspec/changes/archive/2026-01-01-implement-web-api/tasks.md
T
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

330 lines
13 KiB
Markdown

# Tasks: Implement Web API
## Phase 1: Project Setup
- [x] 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
- [x] 002: Add project reference to JdeScoping.Host
- Location: `NEW/src/JdeScoping.Host/JdeScoping.Host.csproj`
- Validation: Solution builds with new reference
- [x] 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
- [x] 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
- [x] 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
- [x] 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
- [x] 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
- [x] 008: Create AuthResult record
- Location: `NEW/src/JdeScoping.Api/Models/AuthResult.cs`
- Properties: Success, User, ErrorMessage
- Validation: Record compiles
- [x] 009: Create FileUploadResult<T> model
- Location: `NEW/src/JdeScoping.Api/Models/FileUploadResult.cs`
- Source: `OLD/WebInterface/Models/FileUploadResult.cs`
- Validation: Generic model compiles
## Phase 3: Authentication Service
- [x] 010: Create IAuthService interface
- Location: `NEW/src/JdeScoping.Api/Services/IAuthService.cs`
- Methods: AuthenticateAsync, GetUserInfoAsync
- Include CancellationToken parameters
- Validation: Interface compiles
- [x] 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
- [x] 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
- [x] 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
- [x] 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
- [x] 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
- [x] 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
- [x] 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<StatusHub> for SignalR notifications
- Validation: Controller compiles, endpoints respond correctly
## Phase 8: Lookup Controller
- [x] 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
- [x] 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
- [x] 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
- [x] 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
- [x] 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
- [x] 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
- [x] 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
- [x] 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
- [x] 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
- [x] 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
- [x] 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
- [x] 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
- [x] 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
- [x] 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
- [x] 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
- [x] 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
- [x] 034: Create integration test project
- Location: `NEW/tests/JdeScoping.Api.IntegrationTests/JdeScoping.Api.IntegrationTests.csproj`
- Use WebApplicationFactory for testing
- Validation: Test project builds
- [x] 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
- [x] 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
- [x] 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)
- [x] 038: Verify solution builds
- Command: `dotnet build NEW/JdeScoping.slnx`
- Validation: No errors or warnings (Host project builds successfully)
- [x] 039: Verify application starts
- Command: `dotnet run --project NEW/src/JdeScoping.Host`
- Validation: Application starts, Swagger UI accessible at /swagger
- [x] 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
- [x] 041: Run OpenSpec validation
- Command: `openspec validate implement-web-api --strict`
- Validation: No validation errors
- [x] 042: Codex MCP review of controller implementations
- Compare controller actions against legacy
- Verify all endpoints match legacy behavior
- Validation: No significant behavioral differences