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:
@@ -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.
|
||||
Reference in New Issue
Block a user