π 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βAuth0Providerinternally. - On login:
- Auth0 session is validated.
- User info + token fetched.
- Service token stored in
localStorage. - Org/Company/FinYear are restored from
localStorageviaapplyLastSelectedPreferences().
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 touserPermissions.- 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.
π§© Menu Generation and Permissions¶
Menu is Generated Dynamically via useMenuItems¶
const menuItems = useMenuItems();
Internal working:
const getMenuItemsImpl = ({ permissions, company, user }) => {
if (!Array.isArray(permissions)) return [];
return permissions.map(p => generateMenuItemFromPermission(p));
};
β 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: [...]
}
π§ Menu Generation¶
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 β
βββββββββββββββββββββββββββββ
¶
ββββββββββββββ
β 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.