Skip to content

πŸ“˜ App Structure Documentation

πŸ—‚οΈ Folder Structure

src/
β”œβ”€β”€ routes/                     # Routing structure
β”‚   β”œβ”€β”€ index.tsx              # Root router using createBrowserRouter
β”‚   β”œβ”€β”€ MainRoutes.tsx         # Consolidated module routes
β”‚   β”œβ”€β”€ LoginRoutes.tsx        # Auth routes (login/callback)
β”‚   β”œβ”€β”€ LandingRoutes.tsx      # Public landing pages (about, terms, etc.)
β”‚   └── modules/               # Modular routes split per domain
β”‚       β”œβ”€β”€ community-routes.tsx
β”‚       β”œβ”€β”€ sales-routes.tsx
β”‚       └── ...
β”œβ”€β”€ contexts/                  # Global contexts
β”‚   β”œβ”€β”€ Auth0Context.tsx       # Auth0 provider with SafeAuth0Provider wrapper
β”‚   β”œβ”€β”€ ErrorContext.tsx       # App-level error handling
β”‚   β”œβ”€β”€ ConfigContext.tsx      # Org/Company/FinYear tracking
β”œβ”€β”€ components/                # Shared components
β”‚   β”œβ”€β”€ ErrorBoundary          # Global + auth error boundaries
β”‚   β”œβ”€β”€ Loader.tsx, ScrollTop, Notistack, Snackbar
β”‚   └── logo/ etc.
β”œβ”€β”€ pages/                     # Page screens per feature
β”‚   └── landing.tsx            # Public landing page
β”œβ”€β”€ themes/                    # MUI theme setup
β”œβ”€β”€ hooks/                     # Custom hooks (useAuth, useConfig, useMenuItems)
└── shared/                    # Shared utils & storage helpers

πŸ—οΈ App Wrapping (App.tsx Structure)

<GlobalErrorBoundary>
  <ConfigProvider>
    <ThemeCustomization>
      <Locales>
        <ScrollTop>
          <ErrorProvider>
            <SafeAuth0Provider>
              <Notistack>
                <BackdropProvider>
                  <RouterProvider router={router} />
                  <Snackbar />
                </BackdropProvider>
              </Notistack>
            </SafeAuth0Provider>
          </ErrorProvider>
        </ScrollTop>
      </Locales>
    </ThemeCustomization>
  </ConfigProvider>
</GlobalErrorBoundary>

Each provider layer: - GlobalErrorBoundary: Catch any crash globally. - ConfigProvider: Manage Organization, Company, Financial Year context. - ThemeCustomization: Material UI theme setup. - Locales: Language and RTL support. - ScrollTop: Scrolls page to top on route changes. - ErrorProvider: Manage app-wide caught errors. - SafeAuth0Provider: Wraps Auth0Provider inside AuthErrorBoundary. - Notistack: Snackbar system for notifications. - BackdropProvider: Loader/spinner control. - RouterProvider: React Router DOM routes.


πŸ” Authentication & Permissions

1. Login Flow

  • Wrapped with SafeAuth0Provider β†’ Auth0Provider internally.
  • On login:
  • Auth0 session is validated.
  • User info + token fetched.
  • Service token stored in localStorage.
  • Org/Company/FinYear are restored from localStorage via applyLastSelectedPreferences().

2. Permission Management

  • Permissions fetched using: fetchUserPermissionsApi(orgId, userId).
  • Stored in Redux/context + localStorage.
  • Permission refreshes automatically on org change.
useEffect(() => {
  if (organization?.organizationId && state.isLoggedIn) {
    refreshPermissions();
  }
}, [organization?.organizationId]);

3. Accessing Permissions

  • useAuth() hook gives access to userPermissions.
  • Used for conditional rendering of menus, routes, or UI elements.
  • Permissions follow RBAC model with dynamic policies.

πŸ—‚οΈ Routes Structure

src/routes/index.tsx

createBrowserRouter([
  LandingRoutes, // Public landing pages
  LoginRoutes,   // Login / Callback
  MainRoutes     // Protected /App Routes
]);

src/routes/MainRoutes.tsx

Splits into module-specific routes:

{
  path: '/community',
  element: <MinimalLayout />,
  errorElement: <RouteErrorPage />, // Per module fallback
  children: [...]
}
{
  path: '/sales', children: [...]
}
{
  path: '/purchase', children: [...]
}
...

βœ… Each domain (community, sales, etc.) has its own file. βœ… Every route tree uses an errorElement for route errors.


πŸ” Auth & Permission Lifecycle

Login Flow

- User clicks Login
- Auth0 popup appears
- On success:
    1. Token stored β†’ localStorage
    2. User profile fetched
    3. Restore Last Selected Org/Company/FinYear
    4. Update ConfigContext
    5. Fetch Permissions based on organization
    6. Save Permissions into context + localStorage

Core Files

  • contexts/Auth0Context.tsx β†’ Handles login, token, user, permissions.
  • hooks/useAuth.ts β†’ Custom hook to access auth.
  • hooks/useConfig.ts β†’ Custom hook to access org/company/fin year.

const menuItems = useMenuItems();

Internal working:

const getMenuItemsImpl = ({ permissions, company, user }) => {
  if (!Array.isArray(permissions)) return [];
  return permissions.map(p => generateMenuItemFromPermission(p));
};
- Menu options are based on permissions. - No hardcoded menu. - Hides features if permission missing.

βœ… Safe fallbacks if permissions are missing.

Example:

If user has Sales.Invoice.View, they see Invoices menu. If not, it won't even render that menu item.


🚨 Error Handling in the App

  • GlobalErrorBoundary: Any React error at the App level.
  • AuthErrorBoundary: If Auth0 provider crashes.
  • RouteErrorPage: Per route crash fallback.

Sample Route Usage:

{
  path: '/sales',
  element: <MinimalLayout />,
  errorElement: <RouteErrorPage />,
  children: [...]
}


useMenuItems()

  • Generates dynamic menus based on user permissions + current company/org.
  • Reads from centralized permissions list.
  • Organized in a modular structure, e.g.:
    const getMenuItemsImpl = ({ permissions, company, user }) => {
      if (!Array.isArray(permissions)) return [];
      return permissions.map(p => generateMenuItemFromPermission(p));
    };
    
  • Resilient to null/undefined using fallback checks.

🧩 Routing

  • Each domain (community, sales, inventory, payroll, etc.) has its own file under routes/modules/
  • Combined in MainRoutes.tsx.
  • Public routes (about, terms) in LandingRoutes.tsx
  • Error boundary per route via:
    {
      path: '/app',
      element: <MinimalLayout />,
      errorElement: <RouteErrorPage />, // dynamically catches per route
      children: [...]
    }
    

🚨 Error Boundaries

1. GlobalErrorBoundary

Wraps App.tsx β€” catches unexpected React errors.

2. AuthErrorBoundary

Handles failures inside the auth layer.

3. RouteErrorPage

Used in routing errorElement. Displays fallback UI for route crashes (e.g. failed loaders, permissions map errors).


πŸ”„ Full Login & Preference Restoration Flow

[Login Success]
  β†’ Get user via Auth0
  β†’ Save token to localStorage
  β†’ Fetch org/company/finYear from localStorage or defaults
  β†’ Call `applyLastSelectedPreferences`
      ↳ Triggers ConfigContext update
  β†’ Fetch permissions
      ↳ Save to context + localStorage
  β†’ Render components conditionally based on permissions

🧠 Key Learnings / Best Practices

  • Modular route files scale better.
  • SafeAuth0Provider with AuthErrorBoundary gives graceful auth fallback.
  • Global error handling ensures better UX under failure.
  • useConfig + localStorage drives organization/company/fin year persistence.
  • Centralized permission fetch avoids redundancy and ensures proper UI visibility.
  • Menu is dynamically derived and not hardcoded.

βœ… Refactoring completed successfully. πŸ“¦ Future Enhancements: - Add lazy loading + suspense fallback per route chunk - Implement role-based menu grouping - Add loader guards while permission fetch is pending


πŸ“Š Suggested Diagram

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Login Page β”‚
β””β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”˜
      ↓
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”     β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Auth0 Login Flow │────▢ Save Token     β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜     β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                               ↓
                     β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                     β”‚ Restore Preferences        β”‚
                     β”‚ - Org                      β”‚
                     β”‚ - Company                  β”‚
                     β”‚ - Fin Year                 β”‚
                     β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                ↓
                      β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                      β”‚ Fetch Permissions    β”‚
                      β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                 ↓
                      β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                      β”‚ Update Auth Context    β”‚
                      β”‚ + localStorage         β”‚
                      β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                 ↓
                      β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                      β”‚ useMenuItems builds Menu  β”‚
                      β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

πŸ”„ Full App Lifecycle Diagram

[User Lands]
  ↓
[Auth0 Check Session]
  ↓
Is Logged In? 
 |        
No        Yes
 |           ↓
Show Login   Fetch Token
               ↓
           Fetch User Profile
               ↓
           Restore Org/Company/FinYear
               ↓
           Fetch Permissions
               ↓
           Update Auth Context
               ↓
           Render Menu Items Dynamically

πŸ“¦ Summary

  • App wrapping is deeply layered but clean.
  • Dynamic routing with modular approach.
  • Permission-driven UI visibility (RBAC).
  • Error boundaries at App, Auth, and Route levels.
  • Use of centralized hooks (useAuth, useConfig, useMenuItems).
  • Minimal hardcoding β†’ Everything reactive.