Refactor provider composition and ESLint configuration
- Add new provider composition system with validation - Create providerComposition.tsx for centralized provider management - Implement providerOrderValidator.tsx to ensure correct provider order - Add comprehensive tests for provider composition - Create custom ESLint rules in frontend/eslint-rules/ - Update ESLint configuration - Update architecture and tasks documentation Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
@@ -949,11 +949,57 @@ Shared TypeScript interfaces and type aliases. Purely declarative — no runtime
|
||||
|
||||
React context providers for application-wide concerns.
|
||||
|
||||
**Provider Ordering and Compile-Time Validation**
|
||||
|
||||
Provider order is **order-sensitive** and enforced at compile-time through TypeScript discriminated unions. The required order (outermost to innermost) is:
|
||||
|
||||
1. `ThemeProvider` — must be outermost; provides theme context to `AppContents`
|
||||
2. `FluentProvider` — supplies Fluent UI theme and design tokens to all Fluent UI consumers
|
||||
3. `NotificationProvider` — provides notification service; must wrap error boundaries
|
||||
4. `ErrorBoundary` — catches catastrophic errors at the top level
|
||||
5. `BrowserRouter` — enables client-side routing
|
||||
6. `NavigationCancellationProvider` — manages route-aware request cancellation using `useLocation()`
|
||||
7. `AuthProvider` — validates session on mount; must be inside BrowserRouter (uses `useNavigate()`)
|
||||
8. `TimezoneProvider` — fetches timezone after auth; wraps protected routes only
|
||||
|
||||
**Compile-Time Validation:**
|
||||
|
||||
A type-safe builder pattern (`ProviderCompositionBuilder`) in `providerComposition.tsx` enforces this order using TypeScript's discriminated unions. The builder prevents adding providers out of order at compile-time:
|
||||
|
||||
```tsx
|
||||
const tree = createProviderComposition()
|
||||
.withTheme({ children })
|
||||
.withFluent(theme) // ✓ Must come after withTheme
|
||||
.withNotification() // ✓ Must come after withFluent
|
||||
.withErrorBoundary() // ✓ Correct order enforced
|
||||
.withBrowserRouter()
|
||||
.withNavigationCancellation()
|
||||
.withAuth()
|
||||
.build(routes);
|
||||
```
|
||||
|
||||
Attempting to add providers out of order results in TypeScript errors (no runtime overhead).
|
||||
|
||||
**Runtime Validation (Development):**
|
||||
|
||||
A runtime validator (`providerOrderValidator.tsx`) provides fallback validation for development:
|
||||
|
||||
- `validateProviderPosition()` — checks if a provider is correctly nested
|
||||
- `validateProvidersExist()` — ensures required providers are in the tree
|
||||
- `hasProvider()` — queries provider presence
|
||||
- `useProviderValidation()` — development-only hook that warns if required providers are missing
|
||||
|
||||
See `src/providers/PROVIDER_ORDER.md` for detailed dependency rationale.
|
||||
|
||||
**Provider Reference:**
|
||||
|
||||
| Provider | Purpose |
|
||||
|---|---|
|
||||
| `AuthProvider` | Holds authentication state; exposes `isAuthenticated`, `login()`, and `logout()` via `useAuth()`. Synchronizes logout events across browser tabs in real-time using the BroadcastChannel API (with storage event fallback for older browsers). When a user logs out in any tab, all other open tabs immediately reflect the logout state without requiring a page refresh. |
|
||||
| `TimezoneProvider` | Reads the configured IANA timezone from the backend and supplies it to all children via `useTimezone()` |
|
||||
| `ThemeProvider` | Manages light/dark theme selection, supplies the active Fluent UI theme to `FluentProvider` |
|
||||
| `NotificationProvider` | Provides notification service via `useNotification()` hook; must wrap error boundaries so they can display error notifications |
|
||||
| `NavigationCancellationProvider` | Detects route changes and automatically aborts pending API requests; call `useNavigationAbortSignal()` to get an `AbortSignal` that lives for the current route |
|
||||
|
||||
#### Theme (`src/theme/`)
|
||||
|
||||
|
||||
@@ -1,52 +1,3 @@
|
||||
## [IMPORTANT] Error response schema inconsistent
|
||||
|
||||
**Where found**
|
||||
|
||||
- Different handlers return different response shapes
|
||||
- Fail2Ban errors: `{ "error_code": "...", "detail": "..." }`
|
||||
- Validation errors: `{ "detail": [...] }`
|
||||
- Not found errors: `{ "detail": "...", "error_code": "..." }`
|
||||
|
||||
**Why this is needed**
|
||||
|
||||
Frontend must normalize multiple shapes, making error handling fragile and error-prone.
|
||||
|
||||
**Goal**
|
||||
|
||||
Unify all error responses to single schema.
|
||||
|
||||
**What to do**
|
||||
|
||||
1. Define canonical error response:
|
||||
```python
|
||||
class ErrorResponse(BaseModel):
|
||||
error_code: str
|
||||
message: str
|
||||
status: int
|
||||
details: dict | None = None
|
||||
```
|
||||
|
||||
2. Update all handlers to return this format
|
||||
3. Update frontend to expect unified schema
|
||||
|
||||
**Possible traps and issues**
|
||||
|
||||
- Backward compatibility with old clients
|
||||
- FastAPI's built-in handlers may override custom
|
||||
- Rich detail structures need accommodation
|
||||
|
||||
**Docs changes needed**
|
||||
|
||||
- Update API documentation with unified error schema
|
||||
- Add error code reference table
|
||||
|
||||
**Doc references**
|
||||
|
||||
- `Docs/API.md` (error codes)
|
||||
- `backend/app/main.py` (exception handlers)
|
||||
|
||||
---
|
||||
|
||||
## [IMPORTANT] Provider ordering fragility (Frontend)
|
||||
|
||||
**Where found**
|
||||
|
||||
Reference in New Issue
Block a user