# SPQ Auth Flow & Page Structure ## File roles | File | Role | |------|------| | `index.html` | **Login/signup page** — the root page. No auth redirect on load. | | `dashboard.html` | **Dashboard** — the main app (was previously `index.html`). | | `appointments.html`, `repair-orders.html`, `customers.html` | Sub-pages with shared header/nav pointing to `dashboard.html`. | ## Auth redirects ``` Not logged in: / → index.html (login form, NO redirect) /dashboard.html → auth guard → redirects to /index.html Logged in: / → detects token in localStorage → redirects to /dashboard.html /dashboard.html → stays Logout → redirects to /index.html ``` ## Why index.html is the login page Originally `index.html` was the dashboard and `login.html` was the login page. This caused a **redirect loop**: when PocketBase auth state was unstable (stale/expired token), `onAuthStateChanged` on the dashboard saw no user and redirected to `login.html`, whose own `onAuthStateChanged` saw the stored token and redirected back to `index.html` — creating a flip-flop between the two URLs. **Fix**: Made `index.html` the login page and moved the dashboard to `dashboard.html`. Now visiting the root (`/`) shows the login form directly with zero redirects. The dashboard only redirects when it detects no user (→ `/`), and the login only redirects when it detects a user (→ `/dashboard.html`). No more reciprocal bounce. ## Reference: all redirect targets When renaming or restructuring pages, update these files: ### Auth failure → `index.html` (login) - `dashboard.js:122` — `window.location.href = 'index.html'` - `main.js:44` — `window.location.href = 'index.html'` - `appointments.js:50` — `window.location.href = 'index.html'` - `customers.js:78` — `window.location.href = 'index.html'` - `repair-orders.js:58` — `window.location.href = 'index.html'` - `shared/header-functionality.js:318` — logout handler → `'index.html'` ### Login success → `dashboard.html` - `login.js:33` — `window.location.href = 'dashboard.html'` - `index.html:131` — inline script: `location.replace('dashboard.html?cb='+Date.now())` - `index.html:577` — login success handler - `index.html:1035` — signup success handler ### Nav links → `dashboard.html` All `href="dashboard.html"` in: `appointments.html`, `repair-orders.html`, `customers.html`, `dashboard.html` - `dashboard.html` nav has `active-page` class on its own link ### Quote deep-link → `dashboard.html?quoteId=...` - `customers.js:676` — `href="dashboard.html?quoteId=${escapeHtml(quote.id)}"` ### Keyboard shortcut → `dashboard.html` - `dashboard.js:2144` — case 'q' keyboard shortcut ## Dual-VPS config Host header note The VPS has two ShopProQuote nginx configs: - `shopproquote-duckdns` (for `grajmedia.duckdns.org`) — `Host: grajmedia.duckdns.org` ✓ correct - `shopproquote` (for `shopproquote.graj-media.com`) — `Host: graj-media.com` — **may not match home nginx** which only has `server_name grajmedia.duckdns.org`. See `vps-reverse-proxy` skill's "Host header mismatch → SPA redirect loop" pitfall.