# SPQ Page Architecture & Auth Flow ## Page layout ``` / (index.html) — login page (NO redirect — root lands here directly) dashboard.html — main dashboard (auth-guarded: no user → redirects to /) appointments.html, customers.html, repair-orders.html — sub-pages (auth-guarded) ``` ## Why index.html = login page When `index.html` was the dashboard and `login.html` was a separate page, stale/expired PocketBase tokens in localStorage caused an infinite redirect loop: 1. User visits `/` → `index.html` (dashboard) → `onAuthStateChanged` → SDK sees stale token as valid → stays 2. First PocketBase API call fails (401) → SDK clears auth → `onChange(null)` fires → redirect to `login.html` 3. `login.html` loads → SDK reads token from localStorage again (still there, client-side JWT expiry check says valid) → `onAuthStateChanged(user)` → redirect to `index.html` 4. Loop! Making `index.html` the login page eliminates the bounce: unauthorized users see the login form directly, authorized users get one clean redirect to `dashboard.html`. ## Auth guard pattern (in every page JS) ```js onAuthStateChanged(auth, (user) => { if (user) { // initialize page } else { window.location.href = 'index.html'; // redirect to login } }); ``` **login.js** (login page): ```js onAuthStateChanged(auth, (user) => { if (user) { window.location.href = 'dashboard.html'; // already logged in → dashboard } // If no user, stay on login page }); ``` ## PocketBase auth flow The `pocketbase.js` adapter: - Creates PocketBase client pointed at `window.location.origin` (same-origin, through nginx `/api/` proxy) - `onAuthStateChanged` fires initial state synchronously via `auth.currentUser` getter (reads from `pb.authStore`) - Then registers `pb.authStore.onChange` for future changes - `authStore` reads from localStorage key `pocketbase_auth` ## When renaming/moving pages All references are relative (`dashboard.html`, not absolute paths). Files to update: | File | What to change | |------|---------------| | `login.js` | Login success redirect → `dashboard.html` | | `dashboard.js`, `main.js`, `appointments.js`, `customers.js`, `repair-orders.js` | Auth fail redirect → `index.html` | | `shared/header-functionality.js` | Logout redirect → `index.html` | | `index.html` (login page body) | Post-login redirects → `dashboard.html?cb=...` | | `appointments.html`, `repair-orders.html`, `customers.html` | Nav links → `dashboard.html` | | `dashboard.html` | Nav self-links → `dashboard.html` | | `customers.js` | Quote links → `dashboard.html?quoteId=...` | Total: ~28 references across 13 files. ## nginx note Home nginx `server_name` must include the domain the VPS sends in `Host` header. If the VPS proxies `shopproquote.graj-media.com` with `Host: graj-media.com`, add it as an alias: ``` server_name grajmedia.duckdns.org graj-media.com shopproquote.graj-media.com; ```