Repository navigation
Frontend Structure
Paulo Gomes da Cruz Junior edited this page Oct 23, 2026
·
10 revisions
frontend/
├── index.html # HTML entry point (preloads fonts, gov logos, runtime config)
├── vite.config.ts # Vite + Vitest + PWA plugin configuration
├── eslint.config.js # Flat ESLint config (TS, React Hooks, TanStack Query, Prettier)
├── playwright.config.ts # Playwright E2E + a11y multi-browser config
├── tsconfig.json # Project references root
├── tsconfig.app.json # App source (strict, ES2022, react-jsx)
├── tsconfig.node.json # Node/build scripts (ES2023)
├── tsconfig.test.json # Test-specific overrides
├── package.json # Dependencies, scripts, overrides, engines
├── Caddyfile # Caddy web server config (production)
├── Dockerfile # Container build
├── openshift.deploy.yml # OpenShift deployment manifest
│
├── public/ # Static assets served as-is
│ ├── robots.txt
│ ├── data/
│ │ ├── config.js # Runtime environment injection (window.config)
│ │ └── params.js # Runtime parameters injection
│ ├── fonts/ # BCSans font files (woff2)
│ ├── icons/ # Favicons, app icons, site.webmanifest
│ ├── img/ # BC gov logos, landing images
│ └── screenshots/ # PWA install screenshots
│
├── src/ # Application source
│ ├── main.tsx # React root — providers, Amplify init, SW registration
│ ├── App.tsx # Root component — routes + devtools
│ ├── env.ts # Merged Vite + runtime env accessor
│ ├── registerServiceWorker.ts # PWA service worker registration
│ ├── service-worker.ts # Workbox SW with precaching + background sync
│ ├── vite-env.d.ts # Vite client type declarations
│ │
│ ├── assets/ # Static imports (images, SVG, etc.)
│ │
│ ├── styles/ # Global SCSS
│ │ └── _fonts.scss # Font-face declarations
│ │
│ ├── router.tsx # createAppRouter factory + router singleton + single Register
│ ├── routerContext.ts # AppRouterContext type ({ queryClient })
│ ├── routeTree.gen.ts # Generated route tree (committed; tsc runs before vite build)
│ │
│ ├── routes/ # File-based routes — one file per route, folder = URL
│ │ ├── __root.tsx # Root route: title sync, auth-aware not-found, error component
│ │ ├── index.tsx # / — public-only landing
│ │ ├── dashboard.tsx # /dashboard — post-login redirect resolver
│ │ ├── no-role.tsx # /no-role — status page (outside the shell)
│ │ ├── unauthorized.tsx # /unauthorized — status page (outside the shell)
│ │ └── _authenticated/ # Auth-gated subtree (pathless layout in _authenticated.tsx)
│ │ ├── _admin.tsx # ADMIN role-tier layout
│ │ ├── _admin/ # /configuration subtree (flag-gated in configuration.tsx)
│ │ ├── _client-access.tsx # VIEWER/SUBMITTER role-tier layout
│ │ ├── _client-access/clients.tsx # /clients
│ │ ├── search.tsx # /search (owns filter state via validateSearch)
│ │ ├── reporting-units/ # /reporting-units/* (flag-gated routes + loader)
│ │ └── $.tsx # Catch-all 404 inside the shell
│ │
│ ├── routing/ # Shared routing helpers (route files only in routes/)
│ │ ├── auth.ts # computeAuthRedirect, hasAnyRole (pure logic)
│ │ ├── redirectStorage.ts # Single-key session storage for post-login redirect URL
│ │ ├── safeRedirect.ts # Open-redirect protection + OAuth callback detection
│ │ ├── searchParams.ts # Zod /search schema + router-level searchParamCodec
│ │ ├── staticData.ts # StaticDataRouteOption augmentation + NavTarget union
│ │ └── nav/ # Side-nav projection from route staticData
│ │ ├── useNavEntries.ts # Filters/sorts nav entries (roles, flags, connectivity)
│ │ └── routeMetadata.ts # collectRouteGates (gate inheritance), resolveRouteTitle
│ │
│ ├── context/ # React Context providers
│ │ ├── auth/ # Authentication context
│ │ │ ├── AuthContext.tsx # Context definition (user, isLoggedIn, actions)
│ │ │ ├── AuthProvider.tsx # Amplify session, token refresh, mock support
│ │ │ ├── authUtils.ts # JWT parsing, role/privilege extraction
│ │ │ ├── userAccessValidation.ts # Role validation rules engine
│ │ │ ├── useAuth.ts # Consumer hook
│ │ │ └── types.ts # Role, FamLoginUser, IdpProvider types
│ │ │
│ │ ├── layout/ # Layout state context
│ │ │ ├── LayoutContext.tsx # Side nav, header panel toggle state
│ │ │ ├── LayoutProvider.tsx # Responsive breakpoint-aware provider
│ │ │ └── useLayout.ts # Consumer hook
│ │ │
│ │ ├── theme/ # Carbon theme context
│ │ │ ├── ThemeContext.tsx # Theme state (g10/g100 toggle)
│ │ │ ├── ThemeProvider.tsx # Syncs with preference context
│ │ │ └── useTheme.ts # Consumer hook
│ │ │
│ │ ├── preference/ # User preferences context
│ │ │ ├── PreferenceContext.tsx # Preference state + loading
│ │ │ ├── PreferenceProvider.tsx # API load/save lifecycle
│ │ │ ├── usePreference.ts # Consumer hook
│ │ │ ├── utils.ts # Backend preference read/write
│ │ │ └── types.ts # CarbonTheme, UserPreference
│ │ │
│ │ ├── notification/ # Toast notification context
│ │ │ ├── NotificationContext.tsx # Toast display + notification event contract
│ │ │ ├── NotificationProvider.tsx # Carbon toast rendering, queueing, and listener registry
│ │ │ ├── eventBridge.ts # Outside-React adapter for notification publishers
│ │ │ └── useNotification.ts # Consumer hook
│ │ │
│ │ └── pageTitle/ # Page title context
│ │ ├── PageTitleContext.tsx # Hierarchical title management
│ │ ├── PageTitleProvider.tsx # Document title sync
│ │ └── usePageTitle.ts # Consumer hook
│ │
│ ├── hooks/ # Custom React hooks
│ │ ├── useBreakpoint/ # Carbon breakpoint tracking
│ │ │ ├── index.tsx # Resize listener, breakpoint detection
│ │ │ └── types.ts # Breakpoint type definitions
│ │ │
│ │ ├── useDebounce/ # Generic debounce
│ │ │ └── index.tsx
│ │ │
│ │ ├── useOfflineMode/ # Online/offline detection
│ │ │ ├── index.tsx # Hook exposing online status
│ │ │ └── onlineStatusStore.ts # Singleton store with feature flag
│ │ │
│ │ ├── useOutsideClick/ # Click-outside detection
│ │ │ └── index.ts
│ │ │
│ │ ├── useNotificationEvents/ # Notification event publishing and scoped listeners
│ │ │ ├── index.tsx # Hook: sendEvent, subscribe, unsubscribe, clearEvents
│ │ │ ├── eventHandler.ts # Notification event helpers for internal and external publishers
│ │ │ ├── useScopedNotification.ts # Page-scoped inline notification hook
│ │ │ ├── types.ts # Notification event types and payload shape
│ │ │ └── useNotificationEvents.unit.test.tsx # Hook contract tests
│ │ │
│ │ └── useSyncPreferencesToFilters/ # Preference → filter sync
│ │ └── index.tsx
│ │
│ ├── config/ # Infrastructure configuration
│ │ ├── api/ # HTTP client layer
│ │ │ ├── types.ts # HttpClient, APIConfig, ApiError, ProblemDetails
│ │ │ ├── request.ts # Axios request pipeline
│ │ │ ├── CancelablePromise.ts # Cancellable async wrapper
│ │ │ ├── problemDetailsMiddleware.ts # RFC 7807 error normalization
│ │ │ └── failureNotificationMiddleware.ts # Global toast emission for unscoped API failures
│ │ │
│ │ ├── fam/ # AWS Amplify / Cognito config
│ │ │ └── config.ts # Amplify auth config grouped by environment, redirect, and logout concerns
│ │ │
│ │ ├── pwa/ # Progressive Web App config
│ │ │ ├── middleware.ts # Offline data + mutation queue middleware
│ │ │ ├── syncHandlers.ts # Background sync placeholders
│ │ │ ├── types.ts # PwaDB, CachedValue, IdbMiddlewareOptions
│ │ │ ├── utils.ts # Periodic/background sync registration
│ │ │ └── idb/
│ │ │ └── config.ts # IndexedDB setup and CRUD utilities
│ │ │
│ │ ├── react-query/ # TanStack Query config
│ │ │ ├── config.ts # QueryClientConfig (3h stale, no retry)
│ │ │ ├── hooks.ts # Shared query hooks, batched filter queries, scoped error notifications
│ │ │ ├── queryKeys.ts # Typed query-key factory with metadata-aware cache keys
│ │ │ ├── retry.ts # noRetry stub
│ │ │ └── TimeUnits.ts # Time constants
│ │ │
│ │ └── tests/ # Test infrastructure
│ │ ├── setup-env.ts # Vitest global mocks (Amplify, APIs, DOM)
│ │ ├── custom-matchers.ts # toContainText, toBeEmptyDOMElement
│ │ ├── auth.helper.ts # E2E auth mocking / real login
│ │ ├── auth.setup.ts # Playwright auth setup fixture
│ │ ├── e2e.helper.ts # API route mocking utilities
│ │ ├── a11y.helper.ts # Axe accessibility helpers
│ │ ├── coverage.setup.ts # Coverage instrumentation setup
│ │ ├── browser.setup.ts # Browser test setup
│ │ ├── browser.teardown.ts # Browser test teardown
│ │ └── MockPromise.ts # Controllable promise for testing
│ │
│ ├── services/ # Backend service clients
│ │ ├── APIs.ts # Service registry (user, search, codes, forestclient)
│ │ ├── search.service.ts # Reporting unit search API
│ │ ├── search.types.ts # Search DTOs
│ │ ├── search.utils.ts # View-model ↔ DTO converters
│ │ ├── codes.service.ts # Reference data API
│ │ ├── users.service.ts # User preferences API
│ │ ├── forestclient.service.ts # Forest client lookup API
│ │ ├── forestclient.types.ts # Forest client DTOs
│ │ ├── pagination.types.ts # PageableRequest, sorting utilities
│ │ ├── types.ts # Re-exported shared service types
│ │ ├── utils.ts # removeEmpty, B3 headers, DTO converters
│ │ └── utils.types.ts # Override, DefinedValue, ArrayKey
│ │
│ ├── components/ # Reusable UI components
│ │ ├── Layout/ # Application shell
│ │ │ ├── index.tsx # Shell wrapper (header + content + sidenav)
│ │ │ ├── LayoutHeader/ # Global header bar
│ │ │ │ ├── index.tsx
│ │ │ │ ├── LayoutHeaderGlobalBar.tsx
│ │ │ │ └── utils.ts
│ │ │ ├── LayoutHeaderPanel/ # Right-side header panel
│ │ │ │ └── index.tsx
│ │ │ ├── LayoutSideNav/ # Side navigation
│ │ │ │ └── index.tsx
│ │ │ ├── HeaderPanelProfile/ # User profile in header panel
│ │ │ │ └── index.tsx
│ │ │ ├── HeaderDistrictDisplay/ # District/client display in header
│ │ │ │ ├── index.tsx
│ │ │ │ ├── ClientDisplay/
│ │ │ │ └── DistrictDisplay/
│ │ │ ├── AvatarImage/ # User avatar component
│ │ │ │ └── index.tsx
│ │ │ └── ThemeToggle/ # Dark/light theme switch
│ │ │ └── index.tsx
│ │ │
│ │ ├── core/ # Domain-agnostic reusable components
│ │ │ ├── PageTitle/ # Page header with breadcrumbs
│ │ │ │ ├── index.tsx
│ │ │ │ └── types.ts
│ │ │ ├── EmptySection/ # Empty state display
│ │ │ │ └── index.tsx
│ │ │ ├── Subtitle/ # Section subtitle
│ │ │ │ └── index.tsx
│ │ │ ├── DistrictSelection/ # District picker panel
│ │ │ │ ├── index.tsx
│ │ │ │ ├── DistrictListing/
│ │ │ │ ├── DistrictItem/
│ │ │ │ ├── ClientListing/
│ │ │ │ ├── constants.ts
│ │ │ │ ├── types.ts
│ │ │ │ └── utils.ts
│ │ │ └── Tags/ # Utility tag components
│ │ │ ├── ColorTag/
│ │ │ ├── DateTag/
│ │ │ ├── EmptyValueTag/
│ │ │ ├── UnderConstructionTag/
│ │ │ └── YesNoTag/
│ │ │
│ │ ├── Form/ # Form and data display components
│ │ │ ├── FormulaInput/ # Monaco-powered formula editor with BigNumber evaluation
│ │ │ │ ├── index.tsx # Root component + FormulaInputProps interface
│ │ │ │ ├── index.scss # BEM styles + Carbon token bindings
│ │ │ │ ├── index.unit.test.tsx # 61-test suite (Vitest + Testing Library)
│ │ │ │ ├── useFormulaEngine.ts # Evaluation, variable resolution, precision drift check
│ │ │ │ ├── useMonacoFormula.ts # Monaco language registration, completions, hover, markers
│ │ │ │ ├── DependencyGraph.tsx # Variable dependency visualisation (Carbon Tags)
│ │ │ │ ├── VariablePanel.tsx # Available-variable list (fixed / dynamic)
│ │ │ │ ├── types.ts # FormulaError, EvaluationResult, PositionedToken, DriftCheckResult
│ │ │ │ └── utils.ts # Pure helpers: parseFormula, evaluateFormula, tokenize, checkDrift
│ │ │ ├── TableResource/ # Generic paginated data table
│ │ │ │ ├── index.tsx
│ │ │ │ ├── types.ts
│ │ │ │ ├── useTableToolbar.ts
│ │ │ │ ├── ColumnCustomizationMenu/
│ │ │ │ ├── TableResourceActions/
│ │ │ │ ├── TableResourceExpandRow/
│ │ │ │ └── TableResourceRow/
│ │ │ ├── ActiveMultiSelect/ # Multi-select with active state
│ │ │ │ └── index.tsx
│ │ │ ├── AutoCompleteInput/ # Autocomplete text input
│ │ │ │ └── index.tsx
│ │ │ ├── ReadonlyInput/ # Read-only display field
│ │ │ │ ├── index.tsx
│ │ │ │ ├── constants.ts
│ │ │ │ └── utils.ts
│ │ │ └── SearchInput/ # Search text input
│ │ │ └── index.tsx
│ │ │
│ │ └── waste/ # Domain-specific components
│ │ ├── WasteSearch/ # Waste search feature
│ │ │ ├── index.tsx
│ │ │ ├── WasteSearchTable/
│ │ │ │ ├── index.tsx
│ │ │ │ ├── rowActions.tsx
│ │ │ │ ├── index.unit.test.tsx
│ │ │ │ ├── rowActions.unit.test.tsx
│ │ │ │ └── constants.tsx
│ │ │ ├── WasteSearchFilters/
│ │ │ │ ├── index.tsx
│ │ │ │ ├── useWasteSearchFilters.ts
│ │ │ │ ├── useWasteSearchFilterOptions.ts
│ │ │ │ └── utils.ts
│ │ │ ├── WasteSearchFiltersActive/
│ │ │ │ ├── index.tsx
│ │ │ │ └── utils.ts
│ │ │ ├── WasteSearchFiltersAdvanced/
│ │ │ │ ├── index.tsx
│ │ │ │ ├── AdvancedFilterClientInput.tsx
│ │ │ │ ├── AdvancedFilterDateRange.tsx
│ │ │ │ ├── useAdvancedFilterHandlers.ts
│ │ │ │ ├── useClientLookup.ts
│ │ │ │ └── utils.ts
│ │ │ └── WasteSearchTableExpandContent/
│ │ │ └── index.tsx
│ │ ├── MyClientListing/ # Client list table
│ │ │ ├── index.tsx
│ │ │ └── constants.tsx
│ │ ├── CodeDescriptionTag/ # Code + description badge
│ │ │ └── index.tsx
│ │ ├── RedirectLinkTag/ # Clickable redirect link
│ │ │ └── index.tsx
│ │ ├── RoleBasedRedirectLinkTag/ # Role-gated link
│ │ │ └── index.tsx
│ │ ├── TooltipRedirectLinkTag/ # Link with tooltip
│ │ │ └── index.tsx
│ │ └── TooltipRoleBasedRedirectLinkTag/ # Role-gated link + tooltip
│ │ └── index.tsx
│ │
│ └── pages/ # Route-level page components
│ ├── Landing/ # Public landing page
│ │ └── index.tsx
│ ├── MyClientList/ # My clients page
│ │ └── index.tsx
│ ├── WasteSearch/ # Waste search page
│ │ └── index.tsx
│ ├── GlobalError/ # Route error boundary fallback
│ │ └── index.tsx
│ ├── NoRole/ # No FAM roles assigned
│ │ └── index.tsx
│ ├── NotFound/ # 404 page
│ │ └── index.tsx
│ └── RoleError/ # Unauthorized / role violation
│ └── index.tsx
│
├── stub/ # WireMock stubs for local dev
│ ├── __files/ # Response body files
│ └── mappings/ # Request/response mappings
│
├── build/ # Production build output
├── coverage/ # Test coverage reports
├── test-reports/ # JUnit test reports
└── test-results/ # Playwright test artifacts
Three-tier organization:
| Tier | Folder | Purpose |
|---|---|---|
| Shell | Layout/ |
Application frame: header, sidenav, panels |
| Reusable | core/ |
Domain-agnostic components: PageTitle, Tags, EmptySection |
| Domain | waste/ |
Feature-specific components: WasteSearch, MyClientListing |
| Forms | Form/ |
Generic form controls: TableResource, inputs, selects |
Each context follows a consistent pattern:
-
<Name>Context.tsx—createContext()with typed state -
<Name>Provider.tsx— side-effects, API calls, lifecycle -
use<Name>.ts— consumer hook with null-check -
types.ts— type definitions (when needed)
Cross-cutting utilities organized by concern. Each hook gets its own directory with:
-
index.tsx— the hook implementation -
types.ts— type definitions (optional) -
*.unit.test.tsx— co-located test
Service-per-domain pattern where each service:
- Extends
HttpClientbase class - Has its own
*.types.tsfor DTOs - Returns
CancelablePromise<T> - Applies
problemDetailsMiddleware()per-request
Infrastructure concerns separated by tool:
-
api/— HTTP client infrastructure -
fam/— AWS Amplify/Cognito config -
pwa/— Offline and service worker config -
react-query/— TanStack Query client config -
tests/— Test setup and helpers
-
No— Resolved. A centralized query hook layer now lives insrc/queries/directorysrc/config/react-query/hooks.tswith a typed key factory insrc/config/react-query/queryKeys.ts. All productionuseQuerycalls are routed through these shared hooks. -
No— Resolved. Shared types and Zod 4 wire schemas now live insrc/types/directorysrc/types/, one*.types.tsmodule per domain, with anindex.tsbarrel re-exporting them as@/types(branchchore/tech-debt-types, commits2da3794d..0c3f4fcc).src/services/types.tsremains as a back-compat re-export barrel. See the Frontend Type Boundary pattern. -
No
src/constants/directory — Constants are co-located per component. A shared constants directory would help with app-wide values. -
Test helpers in
config/tests/— E2E and unit helpers cohabit. Separating would clarify ownership.
src/
├── queries/ # NEW: TanStack Query hooks
│ ├── useSearchQuery.ts # Wraps SearchService.searchReportingUnit
│ ├── useCodesQuery.ts # Wraps CodesService methods
│ └── useForestClientQuery.ts # Wraps ForestClientService methods
│
├── types/ # DONE: Shared domain types + Zod 4 wire schemas
│ ├── index.ts # Barrel: export type * from each *.types.ts
│ ├── pagination.types.ts # PageType, PageableResponse (extracted from services/)
│ ├── search.types.ts # Search DTOs + codeDescriptionSchema
│ └── … # audit, forestclient, speciesComposition, tableResource, utils
│
├── constants/ # NEW: App-wide constants
│ └── roles.ts # Role enums (extracted from auth/types)
│
├── config/tests/ # SPLIT into:
│ ├── unit/ # Vitest setup, mocks, matchers
│ └── e2e/ # Playwright helpers, auth, stubs
-
Feature folders — As the app grows beyond waste search, consider grouping by feature (
src/features/waste-search/,src/features/client-management/) to co-locate routes, components, queries, and types. -
Barrel exports— Partially resolved.src/types/index.tsbarrels all shared types as@/types, andsrc/services/types.tsre-exports them for back-compat. Barrels forcontext/andhooks/remain open ideas. -
Query key factory— Resolved.src/config/react-query/queryKeys.tscentralizes all query keys in a typedqueryKeysfactory organized by domain (codes,search,forestClient,preference,autocomplete). - Error boundary components — Add component-level error boundaries for resilient feature isolation.
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