Repository navigation
Frontend Architecture Changelog
Paulo Gomes da Cruz Junior edited this page Oct 23, 2026
·
9 revisions
-
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) generatessrc/routeTree.gen.ts, which is committed because the build runstscbeforevite build. Addedrouter.tsx(createAppRouterfactory + browser-history singleton + the singleRegisteraugmentation),routerContext.ts(AppRouterContext = { queryClient }, isolated to avoid import cycles), and shared helpers insrc/routing/(auth.tspure redirect decisions,safeRedirect.ts,redirectStorage.ts,searchParams.tswith the Zod/searchschema and router-levelsearchParamCodec,staticData.tsaugmenting@tanstack/router-core'sStaticDataRouteOption, andnav/useNavEntries.tsprojecting the side nav from routestaticData). Deleted:routePaths.tsx(RouteDescription[]registry), hand-builtrouteTree.tsxandapplyGuards,AppRouter.tsx, all five guard HOCs (withProtected,withPublicOnly,withOfflineSupport,withPersistentRedirect,withFeatureFlag), thenavigateInTree/InTreePathshim, and theuseSyncFiltersToSearchParamshook merged from main (#1238). Access control became structural: the pathless_authenticatedlayout gates auth/status,_admin/_client-accesslayouts gate roles, feature flags are checked inbeforeLoadwiththrow 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
beforeLoadhook would need a duplicated non-React snapshot), flags inbeforeLoad(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./searchfilter state became route-owned URL state (validateSearch), making the bidirectional sync hook redundant. -
Impact:
src/routes/restructured to route files only (helpers insrc/routing/);routeTree.gen.tscommitted; navigation fully typed through a singleRegister(a second one collapses thetounion tonever); 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.mdrewrites; stale references fixed acrossFeature-Flags.md,Authentication.md,Roles.md,Frontend Structure.md,Frontend Architecture Overview.md,ReportingUnitBlockDetails.md,FormulaConfigurationList.md,FormulaConfigurationDetail.md,LayoutSideNav.md, and theuseSyncFiltersToSearchParamshook page (now a removal record).
-
What: Replaced
react-router-domentirely with@tanstack/react-routerv1. 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(thinRouterProviderwrapper), and four guard HOCs (withProtected,withPublicOnly,withOfflineSupport,withPersistentRedirect) insrc/routes/guards/. TheRouteDescriptiontype inroutePaths.tsxwas updated to carrycomponent: ComponentTypeand aguards?: RouteGuard[]array in place of the formerelement: ReactNodefield.redirectStorage.tswas simplified from four keys across bothsessionStorageandlocalStorageto a singlesessionStoragekey (redirectAfterLogin). TanStack Router DevTools (@tanstack/react-router-devtools) was also installed and mounted alongside the existing ReactQueryDevtools inApp.tsx. All unit test files across 14 test modules were migrated to use a newcreateTestRouter/createRouterWrappertest utility insrc/config/tests/routerTestHelper.tsx. The full test suite (94 files) passes with zero TypeScript errors. -
Why:
react-router-domrequired 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 foruseNavigate/Link to/useRouterStateacross 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.tsxdeleted;routeTree.tsx,AppRouter.tsx, andguards/directory added.routePaths.tsxlegacy section removed (deprecatedgetPublicRoutes,getProtectedRoutes,_LegacyRoute,_GLOBAL_ROUTES).react-router-domremoved frompackage.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).
-
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.
-
What: Introduced user bookmarking for reporting units. Frontend changes include a new
bookmark-ru-enabledfeature flag insrc/env.ts, UI row actions and checkbox filter in the Waste Search feature (WasteSearchTableandWasteSearchFiltersAdvanced), 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.
-
What: Moved
problemDetailsMiddlewareand the newfailureNotificationMiddlewareinto the sharedBackendApiConfig.MIDDLEWAREchain so backend services no longer registerproblemDetailsMiddleware()per request. Added metadata-aware service calls and query keys usingnotificationTarget, introduced the batcheduseWasteSearchFilterOptionsQuerieshook for Waste Search reference data, and updated shared query hooks to notify from stable error timestamps rather than volatileuseQueries()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.tsnow owns the global API middleware stack. Service methods conditionally spreadmetaonly when defined.src/config/react-query/queryKeys.tsincludes notification metadata in relevant keys, andsrc/config/react-query/hooks.tsuseserrorUpdatedAt-based deduplication for scoped query errors. Architecture guidelines now describe global middleware registration and stable notification-effect dependencies.
-
What: Added a
displayMode: 'toast' | 'inline'field toGlobalEvent.NotificationProvidernow uses this field to route an event to a Carbon toast or to inline listeners, with a fallback to the original implicit rule (eventTargetpresent → inline, absent → toast) for backward compatibility. Two convenience helpers were added —sendToastEventandsendInlineEvent— on both theuseNotificationEventshook and theeventHandlermodule.clearEventsnow routes throughsendInlineEventinternally. PWA service worker lifecycle calls were migrated tosendToastEvent. -
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
sendEventescape hatch. -
Impact:
GlobalEventnow supportsdisplayMode. All call sites with fixed presentation requirements should usesendToastEventorsendInlineEventinstead ofsendEvent.useScopedNotificationignores events withdisplayMode: 'toast'even wheneventTargetmatches. No behavior change for events that do not setdisplayMode.
-
What: Replaced the old
useSendEventhook family withuseNotificationEventsanduseScopedNotification, removed the legacy hook folder, and aligned supporting types/helpers with notification-specific naming. The notification flow now remains fully React-managed throughNotificationProviderandeventBridge.ts, while shared TanStack Query hooks emit scoped user-facing errors through anotificationTargetoption instead of component-leveluseEffecttranslation. - 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.
-
What: Introduced
src/config/react-query/hooks.ts(shared query hooks) andsrc/config/react-query/queryKeys.ts(typed key factory). All inlineuseQuerycalls in production components were migrated to these shared hooks. Separately,BackendApiConfig.TOKENwas changed from a synchronousgetUserTokenFromCookie()initializer toundefined, with token resolution deferred entirely to the existing async resolver. Redirect storage was simplified from four storage keys acrosssessionStorage+localStorageto a singlesessionStoragekey withtry/catcherror handling. Follow-up hardening also removed duplicate query input type definitions by reusingReportingUnitsQueryParamsacross 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 importuseQuerydirectly for data-fetching queries.BackendApiConfiginitialisation is cleaner and free of synchronous cookie reads.REDIRECT_STORAGE_KEYSexport removed;redirectStorage.tsnow 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.tsis easier to navigate without changing the FAM auth flow.
-
What: Hardened
env.tsto validate runtimewindow.configwith a strict Zod allowlist, added typedVITE_FEATURE_FLAGSparsing, and updated frontend deployment overrides to extendwindow.configinstead of writing flags tolocalStorage. - 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.
- 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.
-
What:
MyClientListingrefactored to useRedirectLinkTagfor client links withrenderCellpattern. 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
RedirectLinkTagadded tocomponents/waste/.TableResourceextended withrenderCellcolumn customization. -
Commits:
c3383ca,6af4e61,c8681a7
- 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
- What: Added help menu to the application header.
- Why: Provide in-app guidance and documentation links.
-
Impact: New UI element in
LayoutHeader. -
Commit:
62e183f
- What: Improved application packaging and deployment configuration.
- Why: Streamline production builds and deployment pipeline.
- Impact: Updated Dockerfile, OpenShift config, and Caddyfile.
-
Commit:
47137f1
- 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
- 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
-
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.tscreated.ProtectedRouteenhanced. NewRoleErrorpage with reason codes. -
Commits:
a975846,2d61635,40f2f04
-
What: Implemented URL-based search parameter sharing via
useSyncFiltersToSearchParamswith 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
- What: Added environment label (DEV, TEST, PROD) to the application header.
- Why: Help users distinguish between environments during testing.
-
Impact:
LayoutHeaderdisplays env badge from runtime config. -
Commit:
eaad9ba
- What: Improved user state refresh logic to handle silent Cognito updates without forcing re-renders.
- Why: Fix stale user data after token refresh.
-
Impact:
AuthProvidertoken refresh logic refined. -
Commit:
f7c510c
- 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 scriptsstubandstub:login. -
Commit:
643d24a
- What: Initial production deployment configuration.
- Why: Launch the application to production.
- Impact: Complete CI/CD pipeline established. OpenShift deployment manifests finalized.
-
Commits:
952950e,6f1026f
-
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.mdwere established during this period.
| 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 |
| 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 |
This wiki documents NR Waste Plus for users and developers. Verify security and deployment guidance against the current application configuration before applying it elsewhere.
- Report an issue or ask a question in the GitHub repository.
- Follow the Contributing Guidelines to propose an update.
- Read the Code of Conduct.
Collection indexes support human browsing and machine retrieval. Keep both current when adding or moving wiki pages.
NR Waste Plus Wiki | GitHub Repository