Skip to content

Frontend Infrastructure - Deep Dive Documentation

Generated: 2026-03-26 Scope: Sass-boilerplate-frontend-v1/src/ (store, hooks, providers, context, lib, services, actions, hocs, constants, interceptors, middleware, root layout) Files Analyzed: 45 (41 core infra + 4 app router layouts) Lines of Code: ~2,100 Workflow Mode: Exhaustive Deep-Dive


Overview

The frontend infrastructure layer provides the foundational wiring for a Next.js 15 + React 19 SaaS dashboard application. It encompasses state management (Redux Toolkit + React Query + React Context), HTTP communication (Axios interceptor), route protection (Next.js middleware), theming (next-themes + custom context), utility libraries, and server actions.

Purpose: Cross-cutting application plumbing — everything between the UI components and the backend API.

Key Responsibilities: - Authentication state lifecycle (cookie-based JWT, no refresh mechanism) - Permission-gated route access (middleware + hooks) - HTTP request/response pipeline (interceptor, token injection, error handling) - Theme management (dark/light with custom font loading) - Reusable utilities (formatting, icons, uploads, debounce, media queries) - React Query caching configuration - Server-side revalidation (ISR cache tags)

Integration Points: Consumed by 69+ component/page files. Connects to Express.js backend via 34 API hook modules. Bridges SSR (middleware, server actions, layouts) and CSR (providers, hooks, interceptors).


Consolidated Issue Summary

Total Issues Found: ~179 (deduplicated across 6 analysis passes)

Severity Count Description
Critical 16 Security holes, broken auth flow, dead code, data corruption
High 22 Logic bugs, UX breakage, performance, dead code
Medium ~63 Anti-patterns, missing guards, inconsistencies
Low ~62 Style, naming, minor improvements
Systemic 8 Cross-cutting architectural issues

Known Issues - Critical (16)

ID Severity File(s) Issue Impact
C1 CRITICAL store/slices/authSlice.js Side effects in Redux reducers — getCookie()/deleteCookie() called synchronously inside reducers Violates Redux principles; breaks SSR, time-travel debugging, and middleware
C2 CRITICAL middleware.js No JWT validation — only checks cookie existence, not token validity. token=anything passes Any fabricated cookie bypasses middleware
C3 CRITICAL interceptors/axiosInstance.js 403 responses trigger full logout + cookie deletion — permission-denied destroys session Any RBAC check failure forces re-authentication
C4 CRITICAL interceptors/axiosInstance.js No token refresh mechanism — 401 immediately logs out, no silent refresh attempt Users logged out the instant JWT expires
C5 CRITICAL api/auth/index.js refreshToken API sends no refresh token in request body — endpoint is non-functional Token refresh can never work even if interceptor called it
C6 CRITICAL components/providers/protected-route.jsx 100% dead code — never imported anywhere in the codebase False sense of security; entire protection relies on middleware.js only
C7 CRITICAL theme-provider.jsx, theme-context.jsx Theme state desync — next-themes and custom ThemeContext communicate via one-way CustomEvent that only fires on mount. Post-mount changes never propagate Components using useThemeContext().theme show stale theme
C8 CRITICAL components/providers/theme-provider.jsx Console.log left in production (lines 59-68) — logs all theme configuration on every mount Leaks configuration details; performance noise
C9 CRITICAL app/layout.js, dashboard/layout.js Settings dispatched to Redux from two competing sources — root layout (server fetch) and dashboard layout (React Query) both dispatch to same slice Race condition; potentially overwrites with differently-shaped data
C10 CRITICAL hooks/useDashboardData.js Error swallowing — try/catch in queryFn makes isError permanently false Consumers can never detect API failures; dashboard shows empty without explanation
C11 CRITICAL lib/uploadFile.js No file validation — accepts ANY file type (exe, php, etc.) with zero type/size/extension checks Unrestricted file upload vulnerability
C12 CRITICAL lib/uploadFile.js No authentication — uses raw fetch() bypassing axiosInstance, uploads go without auth tokens Unauthenticated upload endpoint if backend doesn't independently verify
C13 CRITICAL lib/utils.js Full Lucide library import — import * as LucideIcons from "lucide-react" dumps ~1,000+ icons into client bundle Adds hundreds of KB to bundle size
C14 CRITICAL services/, lib/, hooks/ 617 LOC dead code — menuService.js (94), menuItemService.js (145), dummyMenuData.js (282), useMenus.js (96) all have zero consumers Dead weight; confuses future developers
C15 CRITICAL services/, api/menu/, api/menu-builder/ Three competing menu implementations with identically-named hooks (useCreateMenu, useUpdateMenu, useDeleteMenu) Import confusion; wrong implementation silently used
C16 CRITICAL hooks/useCheckPermission.js + store/slices/authSlice.js Permission split-brain after page refresh — initializeAuth() sets isAuthenticated=true but user=null. Permission checks read from Redux (null), not React Query (has data) All permission-gated UI disappears after refresh until profile loads

Known Issues - High (22)

ID Severity File(s) Issue
H1 HIGH store/slices/authSlice.js user=null while isAuthenticated=true — temporal gap between cookie check and profile fetch
H2 HIGH store/slices/authSlice.js Dead state.auth.token — Redux token field written but never read by any consumer
H3 HIGH store/slices/settingSlice.js Name collision — getAllSettings/getSettingByGroup exist as both Redux selectors AND API hook names
H4 HIGH interceptors/axiosInstance.js Hard window.location.href = "/login" redirect on logout — destroys all client state; not a React transition
H5 HIGH interceptors/axiosInstance.js Dynamic import in error handler — import('@/store') in catch block; if this fails, error is silently swallowed
H6 HIGH interceptors/axiosInstance.js Concurrent 401 race condition — multiple simultaneous 401 responses trigger parallel logouts
H7 HIGH hooks/useCheckPermission.js Fail-open design — returns true when requiredPermissions is empty or undefined
H8 HIGH hooks/useFormSubmit.js Brittle error detection — checks error messages with string.includes("validation")
H9 HIGH hooks/useFormSubmit.js Unconditional useRouter() — always called even when redirect not needed
H10 HIGH hooks/useMediaQuery.jsx SSR crash risk — window.matchMedia called without SSR guard
H11 HIGH hooks/useRedux.js 100% dead code — typed Redux hooks wrapper with zero imports anywhere
H12 HIGH lib/pricing-data.js All pricing hardcoded in frontend — should come from backend/Stripe
H13 HIGH lib/uploadFile.js Redundant if/else — video and image branches are 100% identical code
H14 HIGH lib/utils.js handleDownloadJson is dead code — never imported anywhere
H15 HIGH hocs/createIcon.js Missing Next.js Image width/height or fill prop — build warning/error risk
H16 HIGH dashboard/layout.js isOpen localStorage parsing bug — !!"false" evaluates to true, sidebar can never persist as closed
H17 HIGH store/slices/authSlice.js initializeAuth doesn't fetch user profile — state.user stays null until useProfile() runs
H18 HIGH theme-provider.jsx, theme-context.jsx Google Font loading logic duplicated in both files
H19 HIGH services/authService.js Architectural anomaly — only module using services/ abstraction; all 30+ other modules call axiosInstance directly
H20 HIGH services/authService.js getProfile() returns response.data.data while others return response.data — inconsistent response shape
H21 HIGH api/menu-builder/menu-label.js Doubles base URL — constructs ${NEXT_PUBLIC_API_URL}/menu-labels but axiosInstance already has baseURL set
H22 HIGH 14 files across api/ keepPreviousData: true is deprecated in React Query v5 — should use placeholderData: keepPreviousData

Known Issues - Systemic (8)

ID Issue Scope
SYS1 Zero useMemo/useCallback across all 10 custom hooks — every returned function recreated every render All hooks/
SYS2 9 of 10 hooks missing 'use client' directive — rely on parent component's directive All hooks/
SYS3 Inconsistent error handling — some hooks swallow, some throw, some return error objects All hooks/
SYS4 4 coexisting state management approaches (Redux, React Query, Context, localStorage) with weak coordination Entire frontend
SYS5 Settings triple-cached — ISR (24h), React Query (1h staleTime), Redux (on component mount) — can desync Settings flow
SYS6 Zero test coverage — no test files exist for any infrastructure file All infra
SYS7 13+ dead exports across 6 files — functions exported but never imported lib/, services/, hooks/
SYS8 Inconsistent extension conventions — .jsx vs .js for files containing JSX hooks/, providers/

Complete File Inventory

1. Store — Redux State Management (3 files, ~120 LOC)

store/index.js

Purpose: Configures Redux store with Redux Toolkit. Single configureStore call combining auth and setting slices. Exports: store (configured Redux store), RootState type (implicit) Dependencies: @reduxjs/toolkit, ./slices/authSlice, ./slices/settingSlice Used By: components/providers/redux-provider.jsx, interceptors/axiosInstance.js (dynamic import) Key Detail: No custom middleware, no Redux DevTools configuration, no persistence. Contributor Note: Adding a new slice requires import here + adding to the reducer map. No middleware pipeline to worry about.

store/slices/authSlice.js

Purpose: Manages authentication state — token presence, user object, authenticated flag. Includes initializeAuth (reads cookie) and logout (deletes cookie + clears state). Exports: authSlice, initializeAuth, setUser, setToken, logout, selectAuth, selectUser (implicit via useSelector) State Shape: { isAuthenticated: boolean, user: object|null, token: string|null } Dependencies: @reduxjs/toolkit, cookies-next (getCookie, deleteCookie) Used By: 9 direct importers + 10 useSelector(state => state.auth) consumers Issues: C1, C16, H1, H2, H17 — side effects in reducers, user null gap, dead token field Contributor Note: initializeAuth only checks cookie existence — it does NOT fetch user profile. The user object is populated later by useProfile() in dashboard layout. There is a temporal gap where isAuthenticated=true but user=null.

store/slices/settingSlice.js

Purpose: Stores global site settings (logo, site name, etc.) fetched from backend. Simple set/get pattern. Exports: settingSlice, setSettings, getAllSettings, getSettingByGroup State Shape: { settings: Array<{key, value, group}> } Dependencies: @reduxjs/toolkit Used By: 5 importers (root layout, dashboard layout, theme components) Issues: H3 (name collision with API hooks), C9 (dual dispatch), settinReducer typo in store config Contributor Note: Settings are dispatched from TWO places — root layout (server fetch + dispatch) and dashboard layout (React Query + dispatch). These can race.


2. Interceptors — HTTP Layer (1 file, ~50 LOC)

interceptors/axiosInstance.js

Purpose: Central Axios instance with baseURL from env, request interceptor (attaches JWT from cookie), response error interceptor (handles 401/403). Exports: axiosInstance (default export) Dependencies: axios, cookies-next, @/store (dynamic import in error handler) Used By: 35 active consumers (all api/ hook modules) Issues: C3, C4, H4, H5, H6 — 403 logout, no refresh, hard redirect, dynamic import in error, race condition Contributor Note: This is the single most impactful infrastructure file — 35 modules depend on it. The error interceptor dynamically imports the store to dispatch logout, avoiding a circular dependency. The JWT cookie is non-httpOnly (documented security concern in project memory). No request queuing during token refresh (because refresh doesn't exist).


3. Custom Hooks (10 files, ~330 LOC)

hooks/useCheckPermission.js

Purpose: Checks if current user has required permission(s). Reads user.role.permissions from Redux. Exports: useCheckPermission(requiredPermissions: string[]): boolean Used By: 14 files (permission-wrapper, nav-permission-wrapper, page components) Issues: H7 (fail-open), C16 (split-brain after refresh — reads from Redux where user is null) Contributor Note: This hook returns true when requiredPermissions is empty — any component without explicit permissions is accessible to everyone. After page refresh, it reads user from Redux (null) not React Query (has data), so all permission checks fail until profile re-fetches.

hooks/useCheckSlug.js

Purpose: Validates slug uniqueness against backend API with debounce. Exports: useCheckSlug(slug, type): { isAvailable, isChecking } Used By: 5 files (blog, page, product forms) Issues: M — no error handling for API failure, returns undefined on error

hooks/useClientPathName.jsx

Purpose: Returns current pathname on client side using Next.js usePathname. Exports: useClientPathName(): string Used By: 3 files (layout components for active link highlighting) Issues: L — trivially thin wrapper, could be replaced by direct usePathname() call

hooks/useDashboardData.js

Purpose: Fetches dashboard analytics data via React Query. Exports: useDashboardData(): { data, isLoading, isError } Used By: 2 files (dashboard page, welcome section) Issues: C10 — try/catch in queryFn swallows all errors; isError is always false

hooks/useDebounce.jsx

Purpose: Debounces a value by specified delay using setTimeout. Exports: useDebounce(value, delay): debouncedValue Used By: 16 files (most-consumed hook — search inputs, slug checks, filters) Issues: L — no cleanup race condition guard, but generally correct pattern

hooks/useFormSubmit.js

Purpose: Generic form submission handler with toast notifications and optional redirect. Exports: useFormSubmit(mutationFn, options): { handleSubmit, isLoading } Used By: 4 files Issues: H8 (brittle string matching for validation errors), H9 (unconditional useRouter)

hooks/useMediaQuery.jsx

Purpose: Evaluates CSS media query and returns boolean match. Exports: useMediaQuery(query): boolean Used By: 3 files (responsive layout decisions) Issues: H10 — window.matchMedia without SSR guard; will throw during server render

hooks/useMenus.js

Purpose: CRUD operations for menus via React Query mutations. Exports: useMenus, useMenu, useCreateMenu, useUpdateMenu, useDeleteMenu, useCreateMenuItem, useUpdateMenuItem, useDeleteMenuItem, useReorderMenuItems Used By: 0 files — COMPLETELY DEAD CODE (confirmed via grep) Issues: C14 — 96 LOC of dead code. Consumers use api/menu/ hooks instead. Contributor Note: This hook uses the dead services/menuService.js and services/menuItemService.js. The live menu system uses api/menu/index.js and api/menu/menu-item.js directly.

hooks/useRedux.js

Purpose: Typed wrappers for useSelector and useDispatch. Exports: useAppSelector, useAppDispatch Used By: 0 files — COMPLETELY DEAD CODE Issues: H11 — zero consumers. All components use useSelector/useDispatch directly.

hooks/useTableActions.js

Purpose: Reusable CRUD action handlers for data tables (delete, soft-delete, restore, bulk operations). Exports: useTableActions(config): { handleDelete, handleRestore, handleBulkDelete, ... } Used By: 9 files (all dashboard table pages) Issues: M — no memoization on returned handlers; new function objects every render


4. Providers & Context (6 files, ~310 LOC)

components/providers/auth-initializer.jsx

Purpose: Runs initializeAuth() on mount to read JWT cookie and set Redux auth state. Exports: AuthInitializer (wraps children) Dependencies: Redux initializeAuth action Used By: app/layout.js (root layout) Issues: H17 — only reads cookie, doesn't fetch user profile. Temporal gap where authenticated but user=null.

components/providers/protected-route.jsx

Purpose: Client-side route guard checking isAuthenticated from Redux. Exports: ProtectedRoute (wraps children, redirects if unauthenticated) Used By: ZERO FILES — 100% DEAD CODE Issues: C6 — never imported anywhere. Route protection is handled entirely by middleware.js. Contributor Note: This file gives a false sense of security in the codebase. Delete it or wire it into the dashboard layout.

components/providers/query-provider.jsx

Purpose: Wraps app in QueryClientProvider with configured React Query client. Exports: QueryProvider (wraps children) Configuration: staleTime: 5 * 60 * 1000 (5 min), retry: 1, refetchOnWindowFocus: false Used By: app/layout.js (root layout) Issues: M — keepPreviousData deprecated in RQ v5 (but this file is fine; the issue is in consumers)

components/providers/redux-provider.jsx

Purpose: Wraps app in Redux Provider with store. Exports: ReduxProvider (wraps children) Dependencies: react-redux, @/store Used By: app/layout.js (root layout) Issues: None — minimal correct implementation

components/providers/theme-provider.jsx

Purpose: Integrates next-themes ThemeProvider + custom ThemeContext initialization + Google Font loading. Exports: ThemeProvider (wraps children) Dependencies: next-themes, @/context/theme-context, Redux settings Used By: app/layout.js (root layout) Issues: C7 (theme desync), C8 (console.log in production), H18 (duplicate font loading logic) Contributor Note: This is the most complex provider. It fires a CustomEvent('theme-loaded') on mount that ThemeContext listens to, but post-mount theme changes via next-themes never fire this event. Components using useThemeContext().theme see stale data after user toggles theme.

context/theme-context.jsx

Purpose: Custom React Context storing theme state (mode, primary color, font family) with localStorage persistence. Exports: ThemeContext, ThemeProvider (context provider), useThemeContext() Used By: 8 files (theme controls, chart components for theming) Issues: C7 (desync with next-themes), H18 (duplicate font logic) Contributor Note: This context is a SECOND theme system alongside next-themes. The intent was to extend next-themes with custom properties (primary color, font), but the two systems don't stay synchronized.


5. Middleware (1 file, ~50 LOC)

middleware.js

Purpose: Next.js edge middleware — checks for token cookie on protected routes, redirects unauthenticated users to /login. Exports: middleware function, config (route matcher) Protected Routes: /dashboard/* paths Public Routes: /, /login, /register, /forgot-password, /blogs/*, etc. Issues: C2 — only checks request.cookies.get('token') existence. Does NOT validate JWT signature, expiry, or structure. Contributor Note: This is the ONLY active route protection mechanism (since protected-route.jsx is dead code). It runs on the edge, so it can't do full JWT validation without a secret. Consider calling a lightweight /auth/verify endpoint or using jose for edge-compatible JWT validation.


6. Root Layout & App Router Layouts (4 files, ~200 LOC)

app/layout.js

Purpose: Root layout — wraps entire app in provider hierarchy. Fetches settings server-side and passes to Redux. Provider Nesting Order (outermost → innermost): 1. ReduxProvider 2. QueryProvider 3. AuthInitializer 4. ThemeProvider 5. {children}

Issues: C9 — dispatches settings to Redux from server-side fetch. Dashboard layout ALSO dispatches settings from React Query. Contributor Note: Provider order matters for dependencies. Redux must be outermost (Query hooks need it). Auth must be before Theme (theme reads auth state). This order is correct.

app/(auth)/layout.js

Purpose: Auth pages layout (login, register, forgot-password). Minimal wrapper.

app/(main-layout)/layout.js

Purpose: Public pages layout (landing, blogs, contact). Includes header/footer.

app/(dashboard-layout)/dashboard/layout.js

Purpose: Dashboard layout — fetches user profile, navigation links, settings via React Query. Renders sidebar + header + content. Issues: H16 (isOpen localStorage parsing bug), C9 (re-dispatches settings to Redux) Contributor Note: This layout makes 3 parallel API calls on mount: useProfile(), useNavigationLinks(), useSettings(). All must succeed for the dashboard to render. No error boundaries exist.


7. Lib Utilities (10 files, ~600 LOC)

lib/utils.js

Purpose: General utilities — cn() (className merger), formatText(), generateAvatar(), getIconComponent(), handleDownloadJson(). Used By: 69 files (most-imported utility file — primarily for cn()) Issues: C13 (full Lucide import), H14 (handleDownloadJson dead), iconNameToPascalCase exported but only used internally Contributor Note: cn() uses clsx + tailwind-merge. This is the standard shadcn pattern. The Lucide wildcard import is the #1 bundle size issue.

lib/helper.js

Purpose: Data table helpers — getSortIcon(), handleMasterCheckboxChange(), getMasterCheckboxState(). Used By: 7 files (all table pages) Issues: M — permission logic inconsistency between handleMasterCheckboxChange and getMasterCheckboxState

lib/uploadFile.js

Purpose: File upload utility — sends file to backend via fetch(). Used By: 4 files (image upload components) Issues: C11 (no validation), C12 (no auth), H13 (redundant if/else) Contributor Note: This bypasses the entire axios infrastructure. It uses raw fetch() with no token, no error handling, no file type/size checks.

lib/editor.js

Purpose: BlockNote rich text editor configuration — custom slash menu items, toolbar groups, block types. Used By: 3 files (blog editor components) Issues: M — several unused imports from BlockNote packages

lib/icons.js

Purpose: Icon mapping — maps string icon names to Lucide React components using createIcon HOC. Used By: 5 files (sidebar, menu builder) Issues: L — relies on createIcon HOC which has H15 issue

lib/constant.js

Purpose: Global constants — API base URL, asset paths, default values. Used By: 8 files Issues: L — minimal file, no significant issues

lib/customMenuItems.js

Purpose: Custom BlockNote editor menu items (e.g., "Insert Image", "Insert Video"). Used By: 1 file (lib/editor.js) Issues: M — several unused imports

lib/dummyMenuData.js

Purpose: Mock menu data — hardcoded nested menu tree structure. Used By: ZERO FILES — DEAD CODE (282 LOC) Issues: C14 — completely unused. Uses MongoDB-style ObjectIds despite PostgreSQL backend.

lib/menuHelpers.js

Purpose: Tree manipulation utilities — flattenTree(), buildTree(), findNode(), moveNode(). Used By: 4 files (menu builder components) Issues: L — correct tree utilities, well-structured

lib/pricing-data.js

Purpose: Hardcoded pricing plans — 3 tiers with features, prices, billing cycles. Used By: 2 files (pricing section, package page) Issues: H12 — pricing should come from backend, not hardcoded in frontend. Uses "annually" while constants/package.js uses "yearly".


8. Services (3 files, ~280 LOC)

services/authService.js

Purpose: Auth API abstraction — login(), register(), logout(), getProfile(), verifyEmail(). Used By: api/auth/index.js (sole consumer) Issues: H19 (only service file used), H20 (inconsistent response shape) Contributor Note: This is the only active service file. It's consumed by api/auth/index.js which wraps it in React Query hooks. Every other module (30+) skips the service layer and calls axiosInstance directly.

services/menuService.js

Purpose: Menu CRUD operations via dummy data (not API calls). Used By: ZERO FILES — DEAD CODE (94 LOC) Issues: C14 — returns hardcoded data from dummyMenuData.js, never calls backend

services/menuItemService.js

Purpose: Menu item CRUD operations via dummy data. Used By: ZERO FILES — DEAD CODE (145 LOC) Issues: C14 — returns hardcoded data, never calls backend


9. Server Actions (2 files, ~40 LOC)

actions/revalidate.js

Purpose: Server action to revalidate Next.js ISR cache tags via revalidateTag(). Exports: revalidate(tag), revalidateBulk(tags), revalidateAll() Used By: 10 files (all CRUD operations that need cache invalidation) Issues: L — revalidateAll() hardcodes a list of known tags; new features require manual addition

actions/navigation-links.js

Purpose: Server action to revalidate the navigation-links cache tag specifically. Exports: revalidateNavigationLinks() Used By: 2 files Issues: M — redundant with revalidate('navigation-links') from revalidate.js


10. HOCs (1 file, ~25 LOC)

hocs/createIcon.js

Purpose: Higher-order component that wraps an image source into a Next.js Image component with standardized props. Exports: createIcon(src): React.Component Used By: 1 file (lib/icons.js) Issues: H15 — missing width/height or fill prop on Next.js Image component


11. Constants (3 files, ~250 LOC)

constants/landing-page-data.js

Purpose: Static data for landing page sections — hero text, features, testimonials, pricing plans, stats, FAQ. Used By: 5 files (landing page section components) Issues: M — contains gaming-template remnants ("Total Games Listed" stat, game categories). pricingPlans array is completely unused (superseded by lib/pricing-data.js).

constants/metadata.js

Purpose: Default Next.js metadata — title, description, OpenGraph, categories. Used By: 3 files Issues: M — contains gaming categories ("Action", "Adventure", "Strategy") in a SaaS boilerplate

constants/package.js

Purpose: Package/subscription constants — billing cycle options, plan type mappings. Used By: 2 files (package pages) Issues: M — uses "yearly" while lib/pricing-data.js uses "annually"


User Flow Analysis

Flow 1: App Bootstrap

Browser loads any page
  → Next.js SSR: middleware.js checks cookie existence
    → If /dashboard/* and no cookie → redirect /login
    → If cookie exists (any value) → allow through
  → Server render: app/layout.js
    → Fetches settings via server-side fetch (ISR cached 24h)
    → Passes settings to client
  → Client hydration:
    → ReduxProvider wraps app
    → QueryProvider configures React Query (5min staleTime)
    → AuthInitializer runs initializeAuth()
      → Reads 'token' cookie via getCookie()
      → Sets isAuthenticated=true, token=cookieValue
      → Does NOT fetch user profile (user remains null)
    → ThemeProvider initializes
      → Reads settings from Redux
      → Fires CustomEvent('theme-loaded')
      → ThemeContext picks up event, stores theme config
    → Page component renders

Gap: Between AuthInitializer completing and useProfile() running in dashboard layout, state.auth.user is null. Any permission check during this window fails.

Flow 2: Login → Dashboard

User submits login form
  → api/auth/useLogin mutation fires
    → authService.login(credentials) → POST /auth/login
    → On success:
      → Sets JWT cookie (non-httpOnly)
      → Dispatches setUser(user) to Redux
      → Dispatches setToken(token) to Redux
      → React Query cache: queryClient.setQueryData(['profile'], user)
      → window.location.href = '/dashboard' (FULL PAGE RELOAD)
  → Full reload triggers:
    → middleware.js: cookie exists → allow
    → app/layout.js: server-side settings fetch
    → AuthInitializer: reads cookie → isAuthenticated=true, user=null
    → dashboard/layout.js:
      → useProfile() → GET /auth/profile → populates user
      → useNavigationLinks() → fetches nav
      → useSettings() → fetches settings, RE-DISPATCHES to Redux
    → Dashboard renders with all data

Issue: Login sets user in Redux, then immediately does window.location.href which destroys that state. The dashboard re-fetches everything from scratch. The setUser dispatch before reload is wasted work.

Flow 3: Permission Check

Component wrapped in <PermissionWrapper requiredPermissions={['user.view']}>
  → useCheckPermission(['user.view']) called
    → Reads state.auth.user from Redux
    → If user is null (after refresh): returns false → component hidden
    → If user exists: checks user.role.permissions.includes('user.view')
    → Returns boolean
  → PermissionWrapper renders children or nothing

AFTER PAGE REFRESH:
  → AuthInitializer sets isAuthenticated=true, user=null
  → Permission checks all return false
  → Entire dashboard UI is permission-gated → shows empty
  → useProfile() fires → user populated → re-render → UI appears
  → FLASH OF EMPTY CONTENT

Critical Bug (C16): Permission checks depend on Redux user which is null after refresh. React Query has the profile data (via useProfile), but useCheckPermission reads from Redux. This creates a split-brain where the auth system says "authenticated" but the permission system says "no access."

Flow 4: Theme Switch

User clicks dark mode toggle (DarkModeControl component)
  → Uses next-themes setTheme('dark')
  → next-themes updates:
    → document.documentElement class
    → localStorage
  → BUT: ThemeContext is NOT notified
    → CustomEvent('theme-loaded') was only fired on mount
    → ThemeContext still has stale theme value
  → Components using useThemeContext().theme see stale data
  → Components using next-themes useTheme() see correct data
  → Chart components (using ThemeContext for chart colors) show wrong colors

Issue (C7): Two theme systems exist — next-themes (the standard) and ThemeContext (the custom extension). They don't stay synchronized after initial mount.

Flow 5: Data Fetching

Component needs data:
  → Uses React Query hook from api/ (e.g., useUsers())
    → Hook calls axiosInstance.get('/users')
    → axiosInstance request interceptor:
      → Reads 'token' cookie
      → Attaches as Authorization: Bearer header
    → Response:
      → 200: data returned, cached by React Query (5min stale)
      → 401: interceptor catches
        → Dynamic import('@/store')
        → Dispatches logout()
        → Deletes cookie
        → window.location.href = '/login'
        → NO TOKEN REFRESH ATTEMPT
      → 403: interceptor catches
        → SAME AS 401 — full logout (BUG: C3)
      → Other errors: thrown to React Query error boundary

Issue: There is no token refresh flow. The useRefreshToken hook exists in api/auth/index.js but has zero consumers. The authService.refreshToken endpoint doesn't even send a refresh token in the request body (C5).


Dependency Graph

Provider Nesting Order (verified correct)

<ReduxProvider>           ← Redux store available everywhere
  <QueryProvider>         ← React Query available everywhere
    <AuthInitializer>     ← Reads cookie, sets Redux auth state
      <ThemeProvider>     ← Reads Redux settings for theme config
        {children}        ← App content
      </ThemeProvider>
    </AuthInitializer>
  </QueryProvider>
</ReduxProvider>

Entry Points (not imported by other infra files)

  • middleware.js — Next.js edge middleware (entry point for server-side routing)
  • app/layout.js — Root layout (entry point for React tree)
  • actions/revalidate.js — Server actions (entry point for ISR invalidation)
  • actions/navigation-links.js — Server action

Leaf Nodes (don't import other infra files)

  • hooks/useDebounce.jsx — Pure utility, no infra dependencies
  • hooks/useMediaQuery.jsx — Pure utility
  • hooks/useClientPathName.jsx — Only depends on Next.js
  • lib/menuHelpers.js — Pure tree utilities
  • lib/dummyMenuData.js — Static data (dead code)
  • constants/* — All static data files

Key Dependency Chains

axiosInstance → (used by) → api/* hooks → (used by) → page components
     ↑                                                       |
     |                                                        ↓
     ← ← ← ← ← store/authSlice (dynamic import on error) ← ←

theme-context ← ← theme-provider → next-themes
                     ↓                    ↓
                 Redux settings      DOM + localStorage

Circular Dependencies

  • No actual circular dependencies detected
  • axiosInstance.jsstore/index.js uses dynamic import() to break the potential cycle
  • Provider nesting order avoids all dependency conflicts

Dead Code Inventory

File LOC Evidence Action
services/menuService.js 94 0 imports (grep verified) Delete
services/menuItemService.js 145 0 imports (grep verified) Delete
lib/dummyMenuData.js 282 0 imports (grep verified) Delete
hooks/useMenus.js 96 0 imports (grep verified) Delete
hooks/useRedux.js ~20 0 imports (grep verified) Delete
components/providers/protected-route.jsx ~40 0 imports (grep verified) Delete or wire in
lib/utils.jshandleDownloadJson ~15 0 imports of this function Remove export
lib/utils.jsiconNameToPascalCase ~5 Only used internally Remove export
constants/landing-page-data.jspricingPlans ~30 Superseded by lib/pricing-data.js Remove
Total Dead Code ~727 LOC

Testing Analysis

Test Coverage: 0%

No test files exist for any frontend infrastructure file. Zero statements, branches, functions, or lines covered.

Testing Gaps (Priority Order)

  1. interceptors/axiosInstance.js — Most critical to test: token attachment, 401/403 handling, concurrent request behavior
  2. hooks/useCheckPermission.js — Security-critical: test fail-open behavior, null user handling, permission matching
  3. store/slices/authSlice.js — Test reducers (side effect behavior), initializeAuth, logout
  4. middleware.js — Test route protection: cookie present/absent, protected vs public routes
  5. hooks/useFormSubmit.js — Test error parsing, success/failure flows, redirect behavior
  6. lib/uploadFile.js — Test file validation (once added), auth token attachment (once added)
  7. context/theme-context.jsx — Test theme switching, localStorage persistence, event handling
  8. actions/revalidate.js — Test tag invalidation, bulk invalidation

Suggested Test Stack

  • Unit tests: Vitest + React Testing Library (matches Next.js 15 ecosystem)
  • Hook tests: @testing-library/react-hooks or renderHook from RTL
  • Integration tests: MSW (Mock Service Worker) for API mocking
  • E2E: Playwright (already available as MCP plugin)

Architecture & Design Patterns

State Management Strategy (4 Systems)

System Purpose Scope Sync Mechanism
Redux (Toolkit) Auth state, settings Global, persists across routes dispatch() from providers/layouts
React Query Server data cache Per-query, 5min stale Automatic refetch on stale/focus
React Context Theme configuration Global CustomEvent (fragile)
localStorage Theme persistence, sidebar state Browser-local Manual read/write

Conflict: Settings exist in all 4 systems simultaneously. Auth user exists in Redux AND React Query. Theme exists in Context AND localStorage AND next-themes (DOM).

Error Handling Philosophy

Inconsistent. Three patterns coexist: 1. Swallow silentlyuseDashboardData try/catch, BrevoService (backend) 2. Throw to boundary — React Query default for most api/ hooks 3. Intercept and redirect — axiosInstance catches 401/403 globally

No error boundaries exist anywhere in the frontend. API failures in layout-level fetches crash the entire page tree.

Code Organization

The frontend follows a feature-by-type organization: - api/ — React Query hooks grouped by backend module - hooks/ — Reusable custom hooks (flat directory) - components/ — UI (by type: ui/, custom/, pages/, providers/, layout/, editor/) - lib/ — Utility functions (flat directory) - services/ — Mostly dead; only authService active - store/ — Redux slices - constants/ — Static data - actions/ — Server actions


Duplicate Functionality

Pattern Location 1 Location 2 Resolution
Menu CRUD hooks api/menu/ api/menu-builder/ Delete menu-builder (9/11 hooks broken)
Theme font loading theme-provider.jsx theme-context.jsx Consolidate to one location
Settings dispatch app/layout.js dashboard/layout.js Remove one; root layout covers all
Pricing data lib/pricing-data.js constants/landing-page-data.js Delete from constants
Permission check hooks/useCheckPermission.js lib/helper.js (checkbox perms) Different concerns; keep both

Best-Practice Reference Files

  • hooks/useMenus.js — Despite being dead code, uses query key factory pattern correctly with proper cache invalidation. Template for other CRUD hooks.
  • components/providers/redux-provider.jsx — Minimal correct provider implementation. Template for new providers.
  • actions/revalidate.js — Clean server action pattern with proper 'use server' directive.

Modification Guidance

To Add New Functionality

Adding a new Redux slice: 1. Create slice in store/slices/newSlice.js 2. Import and add to reducer map in store/index.js 3. Export selectors and actions from slice file 4. Use useSelector/useDispatch directly (not useRedux.js)

Adding a new custom hook: 1. Create in hooks/useNewHook.js 2. Add 'use client' directive at top 3. Use useCallback for returned functions 4. Follow useMenus.js pattern for React Query hooks 5. Handle error states explicitly (don't swallow)

Adding a new provider: 1. Create in components/providers/new-provider.jsx 2. Add to provider nesting in app/layout.js 3. Respect dependency order (Redux → Query → Auth → Theme → new)

To Modify Existing Functionality

Fixing the auth flow: 1. Implement token refresh in axiosInstance.js response interceptor 2. Call useRefreshToken API (fix to actually send refresh token) 3. Queue concurrent 401s to prevent parallel logouts 4. Change 403 handling to show error, not logout

Fixing the theme system: 1. Remove ThemeContext custom event bridge 2. Have ThemeContext read directly from next-themes via useTheme() 3. Or: fire CustomEvent on every theme change, not just mount

To Remove/Deprecate

Safe deletions (zero consumers): - services/menuService.js — delete - services/menuItemService.js — delete - lib/dummyMenuData.js — delete - hooks/useMenus.js — delete - hooks/useRedux.js — delete - components/providers/protected-route.jsx — delete

Requires migration first: - services/authService.js — inline into api/auth/index.js, then delete services/ - lib/pricing-data.js — replace with backend API, then delete - actions/navigation-links.js — replace with revalidate('navigation-links'), then delete

Testing Checklist for Changes

  • Verify auth state after page refresh (user should not be null)
  • Verify permission-gated UI appears immediately (no flash of empty)
  • Verify theme toggle updates ALL theme-dependent components
  • Verify 403 response shows error message, not logout
  • Verify file upload sends auth token and validates file type
  • Verify no console.log in production build
  • Verify bundle size doesn't include full Lucide library
  • Verify settings are consistent across Redux, React Query, and ISR cache
  • Verify sidebar open/close state persists across page loads
  • Verify dashboard shows error state when API fails (not empty)

Contributor Checklist

Risks & Gotchas

  • axiosInstance is imported by 35 modules — changes here affect the entire app
  • Redux authSlice has side effects in reducers — don't assume pure reducers
  • middleware.js runs on the edge — no Node.js APIs, no secrets access
  • lib/utils.js is imported by 69 files — bundle impact of any addition is high
  • Theme system has two independent implementations that must stay in sync
  • Settings are dispatched from 2 places — changes to settings shape affect both

Pre-change Verification Steps

  1. grep -r "from.*<module>" src/ to find all consumers before modifying any infra file
  2. Check both api/menu/ AND api/menu-builder/ when touching menu functionality
  3. Verify provider nesting order if adding/removing providers
  4. Test with cleared localStorage and cookies to catch initialization bugs
  5. Test both authenticated and unauthenticated states

Suggested Tests Before PR

  1. Login → navigate dashboard → refresh page → verify UI renders correctly
  2. Let JWT expire → make API call → verify graceful handling (currently: forced logout)
  3. Toggle theme → navigate pages → verify theme persists
  4. Upload file → verify it's authenticated and validated
  5. Remove permissions from user → verify 403 shows error (not logout)

Generated by document-project workflow (deep-dive mode) Base Documentation: docs/index.md Scan Date: 2026-03-26 Analysis Mode: Exhaustive Subagent Reports: 6 parallel analysis agents + 1 discovery agent