Files
tabungin/docs/features/maintenance-mode.md
dwindown 89f881e7cf feat: reorganize admin settings with tabbed interface and documentation
- Reorganized admin settings into tabbed interface (General, Security, Payment Methods)
- Vertical tabs on desktop, horizontal scrollable on mobile
- Moved Payment Methods from separate menu to Settings tab
- Fixed admin profile reuse and dashboard blocking
- Fixed maintenance mode guard to use AppConfig model
- Added admin auto-redirect after login (admins → /admin, users → /)
- Reorganized documentation into docs/ folder structure
- Created comprehensive README and documentation index
- Added PWA and Web Push notifications to to-do list
2025-10-13 09:28:12 +07:00

20 KiB

Maintenance Mode - Visual Flow Diagram

🎯 Where Does the Maintenance Page Appear?

Answer: It appears AFTER successful login, when trying to access protected routes


📊 Complete User Journey

Scenario 1: Non-Logged-In User (Maintenance ON)

┌─────────────────────────────────────────────────────────────┐
│ User opens: http://localhost:5174                           │
└─────────────────────────────────────────────────────────────┘
                          ↓
┌─────────────────────────────────────────────────────────────┐
│ App.tsx checks: Is user logged in?                          │
│ Answer: NO                                                   │
└─────────────────────────────────────────────────────────────┘
                          ↓
┌─────────────────────────────────────────────────────────────┐
│ Redirect to: /auth/login                                    │
│ (Login page loads normally - @SkipMaintenance)              │
└─────────────────────────────────────────────────────────────┘
                          ↓
┌─────────────────────────────────────────────────────────────┐
│ User enters credentials and clicks Login                    │
└─────────────────────────────────────────────────────────────┘
                          ↓
┌─────────────────────────────────────────────────────────────┐
│ POST /auth/login (Works - @SkipMaintenance)                 │
│ Returns: { token: "...", user: {...} }                      │
└─────────────────────────────────────────────────────────────┘
                          ↓
┌─────────────────────────────────────────────────────────────┐
│ Token saved to localStorage                                 │
│ Redirect to: /                                              │
└─────────────────────────────────────────────────────────────┘
                          ↓
┌─────────────────────────────────────────────────────────────┐
│ Dashboard tries to load                                     │
│ Makes API call: GET /api/users/me                           │
└─────────────────────────────────────────────────────────────┘
                          ↓
┌─────────────────────────────────────────────────────────────┐
│ MaintenanceGuard intercepts request                         │
│ - Checks: Is maintenance ON? YES                            │
│ - Checks: Is user admin? NO (role: 'user')                  │
│ - Returns: 503 Service Unavailable                          │
└─────────────────────────────────────────────────────────────┘
                          ↓
┌─────────────────────────────────────────────────────────────┐
│ Axios interceptor catches 503 error                         │
│ Calls: setMaintenanceMode(true)                             │
└─────────────────────────────────────────────────────────────┘
                          ↓
┌─────────────────────────────────────────────────────────────┐
│ ⚠️  MAINTENANCE PAGE DISPLAYED                              │
│                                                              │
│     🔧 Under Maintenance                                    │
│     Your custom message here                                │
│     [Refresh Page]                                          │
└─────────────────────────────────────────────────────────────┘

Scenario 2: Logged-In User (Maintenance Turns ON)

┌─────────────────────────────────────────────────────────────┐
│ User is already logged in, using the app normally          │
│ Currently on: /wallets                                      │
└─────────────────────────────────────────────────────────────┘
                          ↓
┌─────────────────────────────────────────────────────────────┐
│ Admin enables maintenance mode in /admin/settings          │
└─────────────────────────────────────────────────────────────┘
                          ↓
┌─────────────────────────────────────────────────────────────┐
│ User clicks on "Transactions" menu                         │
│ OR tries to create a new transaction                        │
│ OR any action that makes an API call                        │
└─────────────────────────────────────────────────────────────┘
                          ↓
┌─────────────────────────────────────────────────────────────┐
│ API call: POST /api/transactions                            │
└─────────────────────────────────────────────────────────────┘
                          ↓
┌─────────────────────────────────────────────────────────────┐
│ MaintenanceGuard intercepts                                 │
│ - Maintenance is ON                                         │
│ - User is not admin                                         │
│ - Returns: 503                                              │
└─────────────────────────────────────────────────────────────┘
                          ↓
┌─────────────────────────────────────────────────────────────┐
│ Axios interceptor triggers                                  │
│ setMaintenanceMode(true)                                    │
└─────────────────────────────────────────────────────────────┘
                          ↓
┌─────────────────────────────────────────────────────────────┐
│ ⚠️  MAINTENANCE PAGE REPLACES CURRENT VIEW                  │
│                                                              │
│     🔧 Under Maintenance                                    │
│     System is being upgraded...                             │
│     [Refresh Page]                                          │
└─────────────────────────────────────────────────────────────┘

Scenario 3: Admin User (Maintenance ON)

┌─────────────────────────────────────────────────────────────┐
│ Admin logs in at: /auth/login                               │
└─────────────────────────────────────────────────────────────┘
                          ↓
┌─────────────────────────────────────────────────────────────┐
│ Redirected to: /                                            │
│ Makes API call: GET /api/users/me                           │
└─────────────────────────────────────────────────────────────┘
                          ↓
┌─────────────────────────────────────────────────────────────┐
│ MaintenanceGuard intercepts                                 │
│ - Maintenance is ON                                         │
│ - Extracts JWT token                                        │
│ - Checks role: 'admin'                                      │
│ - Returns: 503 (Even for admin on main app!)               │
└─────────────────────────────────────────────────────────────┘
                          ↓
┌─────────────────────────────────────────────────────────────┐
│ ⚠️  MAINTENANCE PAGE SHOWN                                  │
│                                                              │
│ (Admin sees maintenance on main app)                        │
└─────────────────────────────────────────────────────────────┘
                          ↓
┌─────────────────────────────────────────────────────────────┐
│ Admin navigates to: /admin                                  │
└─────────────────────────────────────────────────────────────┘
                          ↓
┌─────────────────────────────────────────────────────────────┐
│ Makes API call: GET /api/admin/users/stats                  │
└─────────────────────────────────────────────────────────────┘
                          ↓
┌─────────────────────────────────────────────────────────────┐
│ MaintenanceGuard intercepts                                 │
│ - Route has @SkipMaintenance decorator                      │
│ - Returns: ALLOW (200 OK)                                   │
└─────────────────────────────────────────────────────────────┘
                          ↓
┌─────────────────────────────────────────────────────────────┐
│ ✅ ADMIN PANEL WORKS NORMALLY                               │
│                                                              │
│ Admin can:                                                  │
│ - View dashboard                                            │
│ - Manage users                                              │
│ - Disable maintenance mode                                  │
└─────────────────────────────────────────────────────────────┘

🎨 Visual Representation

App Structure During Maintenance:

┌─────────────────────────────────────────────────────────────┐
│                    TABUNGIN APP                              │
├─────────────────────────────────────────────────────────────┤
│                                                              │
│  PUBLIC ROUTES (Always Work)                                │
│  ✅ /auth/login                                             │
│  ✅ /auth/register                                          │
│  ✅ /auth/otp                                               │
│  ✅ /health                                                 │
│                                                              │
├─────────────────────────────────────────────────────────────┤
│                                                              │
│  ADMIN ROUTES (Work for Admins Only)                        │
│  ✅ /admin/*                                                │
│  ✅ /api/admin/*                                            │
│                                                              │
├─────────────────────────────────────────────────────────────┤
│                                                              │
│  MAIN APP ROUTES (BLOCKED - Shows Maintenance)              │
│  ❌ /                                                        │
│  ❌ /wallets                                                │
│  ❌ /transactions                                           │
│  ❌ /api/users/me                                           │
│  ❌ /api/wallets                                            │
│  ❌ /api/transactions                                       │
│                                                              │
│  👉 All show: MAINTENANCE PAGE                              │
│                                                              │
└─────────────────────────────────────────────────────────────┘

🔍 Code Flow in App.tsx

export default function App() {
  const [maintenanceMode, setMaintenanceMode] = useState(false)
  const [maintenanceMessage, setMaintenanceMessage] = useState('')

  useEffect(() => {
    // Setup interceptor on app load
    setupAxiosInterceptors((message) => {
      setMaintenanceMessage(message)
      setMaintenanceMode(true)  // 👈 This triggers maintenance page
    })
  }, [])

  // 👇 When maintenance mode is true, show maintenance page
  if (maintenanceMode) {
    return (
      <ThemeProvider>
        <MaintenancePage message={maintenanceMessage} />
      </ThemeProvider>
    )
  }

  // 👇 Otherwise, show normal app
  return (
    <BrowserRouter>
      <ThemeProvider>
        <LanguageProvider>
          <AuthProvider>
            <Routes>
              {/* All routes here */}
            </Routes>
          </AuthProvider>
        </LanguageProvider>
      </ThemeProvider>
    </BrowserRouter>
  )
}

🎯 Key Points

1. Maintenance Page is NOT a Route

  • It's not /maintenance or any URL
  • It's a state-based replacement of the entire app
  • When maintenanceMode state is true, it replaces everything

2. Trigger is API Response

  • Maintenance page appears when any API call returns 503
  • The axios interceptor catches this and sets state
  • This can happen on:
    • Initial page load (GET /api/users/me)
    • Any user action (creating transaction, loading wallets, etc.)
    • Navigation between pages

3. Admin Panel is Separate

  • Admin routes (/admin/*) have @SkipMaintenance
  • API calls to /api/admin/* bypass the guard
  • Admins can still manage the system
  • But if admin tries to access main app (/), they also see maintenance

4. Login Always Works

  • /auth/login has @SkipMaintenance
  • Users can still login during maintenance
  • But after login, they immediately see maintenance page

📝 Summary

Where does maintenance page appear?

  • After any API call that returns 503
  • For regular users trying to access protected routes
  • Even for admins trying to access main app (not admin panel)
  • Replaces the entire app UI (not a specific route)

Where does it NOT appear?

  • On login/register pages (before API calls)
  • On admin panel routes (for admins)
  • On health check endpoints

How to see it?

  1. Enable maintenance mode as admin
  2. Login as regular user (or stay logged in)
  3. Try to access any page or make any action
  4. Maintenance page will appear immediately