Skip to content

Frontend Architecture Changelog

Paulo Gomes da Cruz Junior edited this page Oct 23, 2026 · 9 revisions

Architecture Changelog — Waste Plus Frontend

2026-10-22 — Migrate to the file-based TanStack Router

  • What: Replaced the hand-built route registry with file-based routing. Routes are now files under src/routes/ (29 files, 19 URLs); the TanStack Router Vite plugin (tanstackRouter, autoCodeSplitting: true, test files ignored) generates src/routeTree.gen.ts, which is committed because the build runs tsc before vite build. Added router.tsx (createAppRouter factory + browser-history singleton + the single Register augmentation), routerContext.ts (AppRouterContext = { queryClient }, isolated to avoid import cycles), and shared helpers in src/routing/ (auth.ts pure redirect decisions, safeRedirect.ts, redirectStorage.ts, searchParams.ts with the Zod /search schema and router-level searchParamCodec, staticData.ts augmenting @tanstack/router-core's StaticDataRouteOption, and nav/useNavEntries.ts projecting the side nav from route staticData). Deleted: routePaths.tsx (RouteDescription[] registry), hand-built routeTree.tsx and applyGuards, AppRouter.tsx, all five guard HOCs (withProtected, withPublicOnly, withOfflineSupport, withPersistentRedirect, withFeatureFlag), the navigateInTree/InTreePath shim, and the useSyncFiltersToSearchParams hook merged from main (#1238). Access control became structural: the pathless _authenticated layout gates auth/status, _admin/_client-access layouts gate roles, feature flags are checked in beforeLoad with throw notFound(), and the _authenticated/$ catch-all renders one-shell 404s.
  • Why: The registry duplicated bookkeeping — routes, menus, and guard wiring were three hand-maintained lists describing one URL space. In the file-based tree the folder structure is the source of truth, and each check lives where its data lives: auth in a React layout (because auth state is React context; a beforeLoad hook would need a duplicated non-React snapshot), flags in beforeLoad (synchronous env values; running before the auth gate is the accepted fail-closed trade-off — disabled means absent, for everyone). The side nav is projected from route metadata so the menu can never drift from the routes. /search filter state became route-owned URL state (validateSearch), making the bidirectional sync hook redundant.
  • Impact: src/routes/ restructured to route files only (helpers in src/routing/); routeTree.gen.ts committed; navigation fully typed through a single Register (a second one collapses the to union to never); redirect-preservation and no-flash timing preserved exactly (useLayoutEffect, primitive effect deps — an object dep caused an infinite navigate/cancel loop caught by the new access-matrix tests). Full record with the decision reasoning: [File-Based Router Migration 20261022](File-Based Router Migration 20261022). Wiki updated: Routing.md, RouteGuards.md, RoutesIndex.md rewrites; stale references fixed across Feature-Flags.md, Authentication.md, Roles.md, Frontend Structure.md, Frontend Architecture Overview.md, ReportingUnitBlockDetails.md, FormulaConfigurationList.md, FormulaConfigurationDetail.md, LayoutSideNav.md, and the useSyncFiltersToSearchParams hook page (now a removal record).

2026-05-11 — Migrate from react-router-dom to TanStack Router v1

  • What: Replaced react-router-dom entirely with @tanstack/react-router v1. The routing model shifted from a runtime-switched dual tree (public vs protected) to a single static route tree with composable HOC guards. Deleted: AppRoutes.tsx, ProtectedRoute.tsx, DashboardRedirect.tsx. Added: routeTree.tsx (router singleton, applyGuards, module augmentation), AppRouter.tsx (thin RouterProvider wrapper), and four guard HOCs (withProtected, withPublicOnly, withOfflineSupport, withPersistentRedirect) in src/routes/guards/. The RouteDescription type in routePaths.tsx was updated to carry component: ComponentType and a guards?: RouteGuard[] array in place of the former element: ReactNode field. redirectStorage.ts was simplified from four keys across both sessionStorage and localStorage to a single sessionStorage key (redirectAfterLogin). TanStack Router DevTools (@tanstack/react-router-devtools) was also installed and mounted alongside the existing ReactQueryDevtools in App.tsx. All unit test files across 14 test modules were migrated to use a new createTestRouter / createRouterWrapper test utility in src/config/tests/routerTestHelper.tsx. The full test suite (94 files) passes with zero TypeScript errors.
  • Why: react-router-dom required rebuilding the entire browser router on every auth state change (including the 3-minute silent token refresh), causing measurable re-render churn. TanStack Router's static tree with guard-based rendering eliminates the rebuild cycle, provides first-class TypeScript inference for useNavigate / Link to / useRouterState across the app without additional type imports, and aligns the routing library with the already-present TanStack Query stack.
  • Impact: src/routes/ restructured — AppRoutes.tsx, ProtectedRoute.tsx, DashboardRedirect.tsx deleted; routeTree.tsx, AppRouter.tsx, and guards/ directory added. routePaths.tsx legacy section removed (deprecated getPublicRoutes, getProtectedRoutes, _LegacyRoute, _GLOBAL_ROUTES). react-router-dom removed from package.json. Architecture wiki pages updated: Routing.md (complete rewrite), Authentication.md (redirect storage and route guard sections), Frontend Architecture Overview.md (stack table, component hierarchy diagram, routing structure section, error boundary and suspense notes), Frontend Structure Guidelines.md (error handling, suspense, memoization, and Vite chunk entries).

2026-05-05 — FormulaInput — Monaco-powered billing formula editor

  • What: Added FormulaInput, a new Form-layer component that combines Monaco Editor with mathjs BigNumber evaluation. The component provides live formula parsing, variable autocomplete, precision drift detection, Carbon Design System styling (field appearance, error/warning borders, helper-text), and native <form> integration via a hidden input. Supporting files: useFormulaEngine (AST-shared evaluation hook), useMonacoFormula (Monaco language registration with completions, hover providers, and squiggle markers), DependencyGraph, VariablePanel, types.ts, utils.ts, and a 61-test unit suite.
  • Why: Provide a reusable, accessible billing-formula editor for forms where formulas (e.g. rate * hours + bonus) are authored by users, stored in the database, and re-evaluated on the Java backend with exp4j. BigNumber mode ensures 64-digit precision with a drift-detection warning when results diverge from IEEE 754 doubles.
  • Impact: components/Form/FormulaInput/ added to the Form layer. Frontend Structure tree updated. Wiki pages created: codes/frontend/Form/FormulaInput.md. No changes to the provider hierarchy, routing, or TanStack Query layer.

2026-04-21 — Add bookmarking UI and feature flag

  • What: Introduced user bookmarking for reporting units. Frontend changes include a new bookmark-ru-enabled feature flag in src/env.ts, UI row actions and checkbox filter in the Waste Search feature (WasteSearchTable and WasteSearchFiltersAdvanced), and unit/e2e tests for bookmark flows. New stubs were added for bookmarked search responses.
  • Why: Enable users to mark reporting units for quick access and to support offline availability for bookmarked items. Rollout will be controlled via the new feature flag.
  • Impact: Update frontend architecture docs (component hierarchy and query flow), add the flag to the Feature Flags registry in the wiki, add tests for disabled/undefined flag states, and coordinate with backend migration and API changes.

Chronological log of architectural changes inferred from git history, file structure evolution, dependency changes, and design decisions.


2026-04-16 — Global API Failure Middleware and Metadata-Aware Query Notifications

  • What: Moved problemDetailsMiddleware and the new failureNotificationMiddleware into the shared BackendApiConfig.MIDDLEWARE chain so backend services no longer register problemDetailsMiddleware() per request. Added metadata-aware service calls and query keys using notificationTarget, introduced the batched useWasteSearchFilterOptionsQueries hook for Waste Search reference data, and updated shared query hooks to notify from stable error timestamps rather than volatile useQueries() array references.
  • Why: Remove duplicated middleware work in the Axios request pipeline, make scoped notification routing part of cache identity, reduce Waste Search filter query overhead, and prevent repeated inline notifications while the same query error persists across renders.
  • Impact: src/services/APIs.ts now owns the global API middleware stack. Service methods conditionally spread meta only when defined. src/config/react-query/queryKeys.ts includes notification metadata in relevant keys, and src/config/react-query/hooks.ts uses errorUpdatedAt-based deduplication for scoped query errors. Architecture guidelines now describe global middleware registration and stable notification-effect dependencies.

2026-04-15 — Explicit Notification Display Mode and Convenience Helpers

  • What: Added a displayMode: 'toast' | 'inline' field to GlobalEvent. NotificationProvider now uses this field to route an event to a Carbon toast or to inline listeners, with a fallback to the original implicit rule (eventTarget present → inline, absent → toast) for backward compatibility. Two convenience helpers were added — sendToastEvent and sendInlineEvent — on both the useNotificationEvents hook and the eventHandler module. clearEvents now routes through sendInlineEvent internally. PWA service worker lifecycle calls were migrated to sendToastEvent.
  • Why: The previous routing rule was implicit and not visible at call sites, making it easy to accidentally send a scoped event as a toast or vice versa. Explicit mode lifts intent to the notification author without removing the flexible sendEvent escape hatch.
  • Impact: GlobalEvent now supports displayMode. All call sites with fixed presentation requirements should use sendToastEvent or sendInlineEvent instead of sendEvent. useScopedNotification ignores events with displayMode: 'toast' even when eventTarget matches. No behavior change for events that do not set displayMode.

2026-04-15 — Notification Event Pipeline Renamed and React-Scoped

  • What: Replaced the old useSendEvent hook family with useNotificationEvents and useScopedNotification, removed the legacy hook folder, and aligned supporting types/helpers with notification-specific naming. The notification flow now remains fully React-managed through NotificationProvider and eventBridge.ts, while shared TanStack Query hooks emit scoped user-facing errors through a notificationTarget option instead of component-level useEffect translation.
  • Why: Reduce architectural ambiguity left over from the prior event-bus naming, remove the appearance of a generic global bus, and keep notification publishing closer to the data-fetching layer that owns the failure state.
  • Impact: src/hooks/useNotificationEvents/ is now the single frontend notification event surface. Page components no longer manage manual subscribe/unsubscribe blocks for scoped banners. Shared query hooks own error-to-notification publication for Waste Search and My Client List. Architecture documentation and hook documentation now describe the notification flow as a React context pipeline instead of an event-bus abstraction.

2026-04-14 — Centralized TanStack Query Hook Layer and Security Hardening

  • What: Introduced src/config/react-query/hooks.ts (shared query hooks) and src/config/react-query/queryKeys.ts (typed key factory). All inline useQuery calls in production components were migrated to these shared hooks. Separately, BackendApiConfig.TOKEN was changed from a synchronous getUserTokenFromCookie() initializer to undefined, with token resolution deferred entirely to the existing async resolver. Redirect storage was simplified from four storage keys across sessionStorage + localStorage to a single sessionStorage key with try/catch error handling. Follow-up hardening also removed duplicate query input type definitions by reusing ReportingUnitsQueryParams across key-builder and hook. The FAM Amplify config was also reorganized into clearer environment, redirect, logout, and OAuth sections with inline JSDoc for maintainability.
  • Why: Eliminate duplicated query keys scattered across components (AP-1), remove a dead synchronous token snapshot at startup that could produce stale tokens before the async resolver fired (SEC-2), and reduce routing complexity introduced for "resilience" that added no real benefit (DL-1).
  • Impact: src/config/react-query/ now owns all query key definitions and shared hooks. Components no longer import useQuery directly for data-fetching queries. BackendApiConfig initialisation is cleaner and free of synchronous cookie reads. REDIRECT_STORAGE_KEYS export removed; redirectStorage.ts now exports only the three public functions with no internal key constants exposed. Query-key input contracts now have a single source of truth, reducing cache-key drift risk. src/config/fam/config.ts is easier to navigate without changing the FAM auth flow.

2026-04-10 — Runtime Config Validation and Typed Feature Flags

  • What: Hardened env.ts to validate runtime window.config with a strict Zod allowlist, added typed VITE_FEATURE_FLAGS parsing, and updated frontend deployment overrides to extend window.config instead of writing flags to localStorage.
  • Why: Close a runtime configuration security gap, prevent unexpected injected keys, and make feature flags explicit and type-safe.
  • Impact: Deploy-time frontend config now has a single validated contract. Feature flag consumers read typed booleans, and new flags must be added intentionally in schema, deployment config, and tests.

2026-04-10 — Architecture Documentation Suite Created

  • What: Generated full architecture documentation: overview, structure tree, guidelines, Copilot skill, instructions, changelog, and refactor opportunities.
  • Why: Establish a self-maintaining architecture system for the frontend.
  • Impact: Baseline documentation created; drift detection now possible.

2026-04 — My Client List Navigation Enhancement (v0.4.x)

  • What: MyClientListing refactored to use RedirectLinkTag for client links with renderCell pattern. Client numbers now link to waste search with pre-populated filters.
  • Why: Improve cross-feature navigation between My Clients and Waste Search.
  • Impact: New component RedirectLinkTag added to components/waste/. TableResource extended with renderCell column customization.
  • Commits: c3383ca, 6af4e61, c8681a7

2026-03 — Vite 7 Major Upgrade

  • What: Upgraded Vite from v6 to v7 (major).
  • Why: Stay current with build tooling, gain performance improvements.
  • Impact: Build pipeline updated. Manual chunks and PWA plugin remain compatible.
  • Commit: e4acd49

2026-03 — Help Menu Feature (v0.3.0)

  • What: Added help menu to the application header.
  • Why: Provide in-app guidance and documentation links.
  • Impact: New UI element in LayoutHeader.
  • Commit: 62e183f

2026-03 — Enhanced App Packaging (v0.4.0)

  • What: Improved application packaging and deployment configuration.
  • Why: Streamline production builds and deployment pipeline.
  • Impact: Updated Dockerfile, OpenShift config, and Caddyfile.
  • Commit: 47137f1

2026-02 — CSS Variable Emission (v0.2.0)

  • What: Added SCSS mixins for emitting CSS variables and override tokens.
  • Why: Enable dynamic theming and Carbon Design System token overrides.
  • Impact: New styles/ mixins. Theme system enhanced.
  • Commits: c45a2dc, 0b0949c, 53e4884, 6a851d6

2026-02 — Client Management Link Removal

  • What: Removed link to Client Management System in My Clients page.
  • Why: Feature deprecated; external CMS no longer used.
  • Impact: Simplified MyClientListing component.
  • Commit: d82e1b9

2026-02 — Strict Role Rules Implementation

  • What: Implemented strict IDIR multi-role restrictions and BCeID forbidden role validation. Added /unauthorized?reason=... redirects.
  • Why: Security compliance — enforce FAM role assignment constraints.
  • Impact: userAccessValidation.ts created. ProtectedRoute enhanced. New RoleError page with reason codes.
  • Commits: a975846, 2d61635, 40f2f04

2026-02 — Search Parameter Sharing (v0.1.x)

  • What: Implemented URL-based search parameter sharing via useSyncFiltersToSearchParams with bidirectional sync and per-key transforms.
  • Why: Allow users to share and bookmark search results via URL.
  • Impact: New hook useSyncFiltersToSearchParams. Filter state now hydrates from URL params and updates them on change.
  • Commit: 4342038

2026-02 — Environment Label Feature

  • What: Added environment label (DEV, TEST, PROD) to the application header.
  • Why: Help users distinguish between environments during testing.
  • Impact: LayoutHeader displays env badge from runtime config.
  • Commit: eaad9ba

2026-01 — User State Refresh Fix

  • What: Improved user state refresh logic to handle silent Cognito updates without forcing re-renders.
  • Why: Fix stale user data after token refresh.
  • Impact: AuthProvider token refresh logic refined.
  • Commit: f7c510c

2026-01 — WireMock Login Setup

  • What: Set up WireMock-based login mocking for local development and E2E tests.
  • Why: Enable offline development and reliable test authentication.
  • Impact: New stub/ directory with WireMock mappings. New npm scripts stub and stub:login.
  • Commit: 643d24a

2026-01 — Production Deployment (v0.1.0)

  • What: Initial production deployment configuration.
  • Why: Launch the application to production.
  • Impact: Complete CI/CD pipeline established. OpenShift deployment manifests finalized.
  • Commits: 952950e, 6f1026f

Pre-2026 — Foundation Architecture

  • What: Established the core architecture:
    • React 19 + TypeScript + Vite
    • Carbon Design System
    • AWS Amplify + Cognito authentication
    • TanStack Query for server state
    • Custom Axios-based HTTP client with middleware
    • PWA scaffolding with Workbox
    • Vitest + Playwright testing pyramid
    • Context-based client state (auth, layout, theme, preferences, notifications, page title)
  • Impact: The architectural foundations documented in architecture-overview.md were established during this period.

Dependency Evolution

Date Change Version
2026-04 Axios security update 1.15.0
2026-03 Vite major upgrade 7.x
2026-03 Carbon libraries upgrade 1.103.0+
2026-03 Sass library upgrade 1.98.0
2026-02 Lodash security update 4.18.1
2026-01 Initial dependency set React 19, TS 5.9

Testing Strategy Evolution

Date Change
2026-03 Added accessibility testing (Playwright + Axe)
2026-02 Added WireMock-based auth mocking for E2E
2026-01 Established Vitest unit + Playwright E2E pyramid
2026-01 Coverage thresholds set to 80% across all metrics

Waste Plus Wiki

Home

Architecture

Codes

Decisions

Knowledge Base

Development

Changes

Clone this wiki locally