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.
This commit is contained in:
Joseph Doherty
2026-01-02 07:43:29 -05:00
commit 26ff8d9b4f
1761 changed files with 596509 additions and 0 deletions
@@ -0,0 +1,328 @@
# Web UI Specification Delta
## Purpose
This document captures ADDED and MODIFIED requirements for the Blazor WebAssembly user interface specific to the .NET 10 migration. It supplements the base specification at `openspec/specs/web-ui/spec.md`.
## ADDED Requirements
### Requirement: Blazor WebAssembly Hosting Model
The system SHALL use Blazor WebAssembly (WASM) as the client-side hosting model.
#### Business Rules
- The client application SHALL run entirely in the browser via WebAssembly
- The application SHALL communicate with the server exclusively via HTTP APIs and SignalR
- The application SHALL NOT use server-side Blazor (SignalR for DOM updates)
- Initial load SHALL include the .NET runtime and application assemblies
- Subsequent navigation SHALL NOT require page reloads
#### Scenario: Initial application load
- **WHEN** a user navigates to the application URL
- **THEN** the browser downloads the .NET WASM runtime
- **AND** the Blazor application initializes in the browser
- **AND** subsequent interactions do not trigger server-side rendering
---
### Requirement: JWT Token Authentication
The system SHALL use JWT tokens for API authentication stored in browser localStorage.
#### Inputs
- Login credentials (username, password)
- LDAP authentication endpoint
#### Outputs
- JWT token stored in localStorage
- Claims extracted for AuthenticationState
#### Business Rules
- Tokens SHALL be stored in browser localStorage via JS interop
- Tokens SHALL be automatically attached to outgoing HTTP requests
- Token expiration SHALL trigger re-authentication prompt
- Logout SHALL remove token from localStorage and clear auth state
#### Scenario: Login stores JWT token
- **WHEN** user submits valid credentials
- **THEN** the API returns a JWT token
- **AND** the token is stored in localStorage under key "authToken"
- **AND** AuthStateProvider parses claims from the token
- **AND** subsequent API requests include Authorization header
#### Scenario: Token expiration
- **WHEN** a stored token has expired
- **AND** the user attempts an API call
- **THEN** the API returns 401 Unauthorized
- **AND** the user is redirected to the login page
---
### Requirement: Custom AuthenticationStateProvider
The system SHALL implement a custom AuthenticationStateProvider for JWT-based authentication state.
#### Business Rules
- AuthStateProvider SHALL parse JWT claims without server round-trip
- Claims SHALL include username, roles, and expiration
- State changes SHALL notify Blazor components via NotifyAuthenticationStateChanged
- Invalid/expired tokens SHALL result in anonymous state
#### Scenario: Parse claims from JWT
- **WHEN** AuthStateProvider initializes with a stored token
- **THEN** it parses the token payload (base64-decoded JSON)
- **AND** extracts claims into ClaimsPrincipal
- **AND** sets authentication type to "jwt"
---
### Requirement: SignalR Auto-Reconnect
The system SHALL implement automatic reconnection for SignalR connections with exponential backoff.
#### Reconnection Schedule
| Attempt | Delay |
|---------|-------|
| 1 | 0 seconds |
| 2 | 2 seconds |
| 3 | 5 seconds |
| 4 | 10 seconds |
| 5 | 30 seconds |
#### Business Rules
- SignalR client SHALL use WithAutomaticReconnect configuration
- Reconnection attempts SHALL follow exponential backoff schedule
- UI SHALL indicate connection state during reconnection
- Events received during reconnection SHALL be delivered after reconnect
#### Scenario: Network interruption recovery
- **WHEN** the SignalR connection is lost
- **THEN** the client attempts reconnection per the backoff schedule
- **AND** logs reconnection attempts to console
- **AND** upon successful reconnection, resumes receiving events
---
### Requirement: File Download via JS Interop
The system SHALL use JavaScript interop for triggering browser file downloads.
#### Business Rules
- Excel result files SHALL be downloaded via JS interop function
- Template files SHALL be downloaded via direct URL navigation
- Downloaded files SHALL prompt browser save dialog
- File names SHALL be specified by the server response headers
#### JavaScript Functions
| Function | Purpose |
|----------|---------|
| `downloadFileFromStream` | Download file from DotNetStreamReference |
| `downloadFileFromUrl` | Download file from URL with filename |
#### Scenario: Download search results
- **WHEN** user clicks Download Results button
- **THEN** API request fetches file as stream
- **AND** JS interop triggers browser download dialog
- **AND** file is saved with name "Search_{id}_Results.xlsx"
---
### Requirement: Radzen Component Library Integration
The system SHALL use Radzen Blazor (free tier) for UI components.
#### Service Registration
- DialogService SHALL be registered for confirmation dialogs
- NotificationService SHALL be registered for toast notifications
- RadzenComponents SHALL be registered via AddRadzenComponents()
#### CSS and JavaScript
- Radzen CSS SHALL be included in index.html
- No additional Radzen JavaScript required for core components
#### Scenario: Register Radzen services
- **WHEN** the application starts
- **THEN** DialogService is available for injection
- **AND** NotificationService is available for injection
- **AND** Radzen component styles are applied
---
### Requirement: Async-First Service Design
The system SHALL use async methods for all service operations.
#### Business Rules
- All HTTP client calls SHALL use async methods (GetFromJsonAsync, PostAsJsonAsync)
- All service interfaces SHALL return Task or Task<T>
- Cancellation tokens SHALL be accepted on all service methods
- UI SHALL remain responsive during API calls
#### Scenario: Async API call with loading state
- **WHEN** user triggers a data load operation
- **THEN** loading indicator displays immediately
- **AND** API call executes asynchronously
- **AND** UI updates when data arrives
- **AND** loading indicator hides
---
### Requirement: ILogger Client-Side Logging
The system SHALL use Microsoft.Extensions.Logging for client-side logging.
#### Business Rules
- All services SHALL accept ILogger<T> via constructor injection
- Log levels SHALL be configurable in Program.cs
- Logs SHALL output to browser console in development
- Error logs SHALL include exception details
#### Log Levels by Category
| Category | Minimum Level |
|----------|---------------|
| Default | Information |
| Microsoft.AspNetCore | Warning |
| SignalR | Debug (dev) / Information (prod) |
---
### Requirement: Same-Window Navigation
The system SHALL use same-window navigation for all internal links (no popups or new tabs).
#### Business Rules
- All internal navigation SHALL use NavigationManager.NavigateTo
- Search detail links SHALL NOT open new windows
- Queue links SHALL NOT open new tabs
- Only external links MAY open new tabs (if any exist)
#### Scenario: Navigate to search detail
- **WHEN** user clicks View button on search grid row
- **THEN** NavigationManager.NavigateTo("/search/{id}") is called
- **AND** current window navigates to search detail
- **AND** no new window or tab opens
---
## MODIFIED Requirements
### Requirement: Clear Data Confirmation
The system SHALL display confirmation dialogs before clearing filter data.
#### Inputs
- User clicks Clear Data button on any filter panel
#### Outputs
- Confirmation dialog with OK/Cancel buttons
- Data cleared only if user confirms
#### Business Rules
- DialogService.Confirm SHALL be used for confirmation dialogs
- Dialog title SHALL be "Confirm Clear"
- Dialog message SHALL be "Are you sure you want to clear all items?"
- Cancel SHALL leave data unchanged
#### Scenario: Clear filter with confirmation
- **WHEN** user clicks Clear Data button
- **THEN** confirmation dialog appears
- **AND** if user clicks OK, filter list is cleared
- **AND** if user clicks Cancel, filter list is unchanged
---
### Requirement: Operator Filter Display
The system SHALL display Operator filter entries with AddressNumber, UserID, and FullName properties.
#### Display Format
| Column | Property | Width |
|--------|----------|-------|
| Address Number | AddressNumber | 120px |
| User ID | UserID | 100px |
| Full Name | FullName | Auto |
#### Business Rules
- Autocomplete dropdown SHALL display all three properties
- Format: "{AddressNumber} - {UserID} - {FullName}"
- Grid SHALL display all three properties in separate columns
#### Scenario: Select operator from autocomplete
- **WHEN** user types in operator autocomplete
- **THEN** dropdown shows results with format "12345 - JSMITH - John Smith"
- **AND** selecting adds entry with all three properties to grid
---
### Requirement: Error Handling Without Custom Error Pages
The system SHALL use Blazor's built-in error handling instead of custom error pages.
#### Business Rules
- ErrorBoundary component SHALL wrap page content in MainLayout
- Unhandled exceptions SHALL display inline error message
- Error recovery SHALL be automatic on next navigation
- Development mode SHALL show exception details
- Production mode SHALL show generic error message
#### Scenario: Unhandled exception in component
- **WHEN** an unhandled exception occurs in a Blazor component
- **THEN** ErrorBoundary catches the exception
- **AND** error content displays instead of the faulted component
- **AND** other components remain functional
- **AND** navigating away recovers the error boundary
---
## Migration Notes
| Legacy Pattern | New Pattern | Status |
|----------------|-------------|--------|
| Kendo UI Grid | RadzenDataGrid | ADDED |
| Kendo DatePicker | RadzenDatePicker | ADDED |
| Kendo ComboBox | RadzenAutoComplete | ADDED |
| jQuery AJAX | HttpClient | ADDED |
| Forms Authentication | JWT with localStorage | MODIFIED |
| SignalR (jQuery) | SignalR (.NET client) | ADDED |
| New window navigation | Same-window navigation | MODIFIED |
| Custom error pages | ErrorBoundary | MODIFIED |
| Clear without confirm | Clear with DialogService.Confirm | MODIFIED |
---
## Open Questions
None - all design decisions resolved per best practice recommendations.