# Common Bugs & Pitfalls ## Auth redirect loop (index.html ↔ dashboard.html) **Symptom**: Page constantly refreshes between index.html and dashboard.html. **Root cause**: `index.html` line 131 blindly checks `localStorage.getItem('pocketbase_auth')` — any truthy value (including stale/expired tokens) triggers a redirect to dashboard.html. Dashboard's `onAuthStateChanged` then detects the invalid token and bounces back to index.html, but the stale token is never cleared from localStorage. **Fix**: In every file that redirects unauthenticated users back to index.html, clear the stale token first: ```javascript localStorage.removeItem('pocketbase_auth'); window.location.href = 'index.html'; ``` Files that need this: `dashboard.js` (line 122), `appointments.js` (line 50), `repair-orders.js` (line 58). ## PocketBase auto-cancellation ("request was auto-cancelled") **Symptom**: Creating/updating records fails with "The request was auto-cancelled" or similar abort error. **Root cause**: PocketBase SDK auto-cancels requests that share the same `requestKey`. By default, all `create`/`update` calls to the same collection share the same key — a rapid double-click fires two identical requests and the first is aborted. **Fix — two parts**: 1. Disable auto-cancellation in `pocketbase.js` by passing `{ requestKey: null }` to all mutating PocketBase calls: - `addDoc`: `pb.collection(collName).create(pbData, { requestKey: null })` - `updateDoc`: `pb.collection(collName).update(docId, pbData, { requestKey: null })` - `setDoc`: both internal `update` and `create` calls need it 2. Add double-submission guard to form submit handlers — disable the button on first click: ```javascript const submitBtn = document.getElementById('submit-create-ro'); if (submitBtn && submitBtn.disabled) return; if (submitBtn) { submitBtn.disabled = true; submitBtn.textContent = 'Creating...'; } ``` Re-enable the button in BOTH the success path (after form clear/collapse) AND the catch block on error. Forgetting the success path leaves the button permanently disabled after a successful submission. ## DuckDNS DNS stale / site unreachable **Symptom**: "This site can't be reached" when accessing grajmedia.duckdns.org. **Check order**: 1. `dig +short grajmedia.duckdns.org` — if returns `127.0.0.1`, run the DuckDNS updater manually: `bash /opt/duckdns/update.sh` 2. The cron job runs every 5 min: `*/5 * * * * /opt/duckdns/update.sh` 3. `/etc/hosts` has `127.0.0.1 grajmedia.duckdns.org` for local hairpin NAT — this is intentional, not a bug ## Dashboard Completed counter shows 0 (`ro.status` vs `ro.workStatus`) **Symptom**: "Completed: 0" on the dashboard Repair Orders Today card, despite having completed orders today. **Root causes (usually BOTH apply)**: 1. **Wrong field**: Code filters by `ro.status === 'completed'` but `status` only stores `waiter`/`drop-off`. Must use `ro.workStatus === 'completed'`. 2. **Completed orders filtered out at source**: `loadRepairOrders()` in dashboard.js removes all completed orders from `dashboardData.repairOrders` before any counter can see them. **Fix checklist**: - Replace ALL `ro.status === 'completed'` with `ro.workStatus === 'completed'` - Replace ALL `ro.status === 'picked-up'` with `ro.workStatus === 'waiting-for-pickup'` - Remove the completed-filter from `loadRepairOrders()` so `dashboardData.repairOrders` contains ALL orders - Each consumer then filters by `ro.workStatus` as needed - See `references/status-field-confusion.md` for the full reference