# Auth Redirect Anti-Loop Pattern

## The Problem

When BOTH the login page and the dashboard have `onAuthStateChanged` listeners that redirect to each other, any auth-state instability creates an infinite loop:

```
dashboard.js: onAuthStateChanged(null) → redirect to login page
login.js: onAuthStateChanged(user) → redirect to dashboard
→ LOOP
```

This fires when PocketBase auth is unstable — stale token in localStorage that passes JWT expiry check but gets 401 on first API call, Host header mismatch causing API calls to fail, etc.

## The Fix (Three Parts)

### 1. login.js — onAuthStateChanged is UI-only, NO redirect

```js
onAuthStateChanged(auth, (user) => {
    if (user) {
        // Show logged-in UI, hide form
        // DO NOT redirect
    } else {
        // Show login form, hide loading
        // DO NOT redirect
    }
});
```

Only explicit login/signup button handlers redirect:
```js
loginBtn.addEventListener('click', async () => {
    await signInWithEmailAndPassword(...);
    window.location.href = 'dashboard.html';
});
```

### 2. index.html — inline localStorage check for "already logged in"

```html
<script>if(localStorage.getItem('pocketbase_auth')){location.replace('dashboard.html?cb='+Date.now())}</script>
```

This fires BEFORE any ES modules load. No auth-state dependency. Cannot cause a loop. The `cb=` parameter busts browser cache.

### 3. dashboard.js and all protected pages — redirect to login on null

```js
onAuthStateChanged(auth, (user) => {
    if (user) {
        initializeApp();
    } else {
        window.location.href = 'index.html';
    }
});
```

This is correct and should remain. It's the login page's auto-redirect that creates the loop, not the dashboard's.

## File Architecture

| File | Role | Redirects? |
|------|------|-----------|
| `index.html` | Login page | Inline script: localStorage check → dashboard |
| `login.js` | Login logic | Only on explicit button click → dashboard |
| `dashboard.js` | Dashboard | onAuthStateChanged(null) → index.html |
| `repair-orders.js` | Protected page | onAuthStateChanged(null) → index.html |
| `appointments.js` | Protected page | onAuthStateChanged(null) → index.html |
| `customers.js` | Protected page | onAuthStateChanged(null) → index.html |
| `main.js` | Protected page | onAuthStateChanged(null) → index.html |
| `shared/header-functionality.js` | Logout handler | signOut → index.html |

## Verification Checklist

After any auth or routing change:
1. Visit root with NO auth token → login form shows, no redirect
2. Log in → redirects to dashboard, one hop
3. Visit root with VALID auth token → auto-redirect to dashboard, one hop
4. Visit `/dashboard.html` with NO auth → redirect to login, one hop
5. Log out → redirect to login, one hop
6. **No double-bounce under any scenario**
