IAMScouting docs

PWA & offline shell

IAMScouting Network ships as an installable PWA with read-only offline support

for the surfaces a scout most often returns to mid-trip (poor cell coverage in

stadiums, basements, foreign SIMs). Source files:

copies are all unavailable)

/network top nav, surfaces after the 2nd visit when

beforeinstallprompt has fired

Cache strategies (sw.js)

| Pattern | Strategy | TTL | Cache |

|---|---|---|---|

| /_next/static/* | cache-first | 30d | iams-v2-static |

| /icons/, /leaflet/ | cache-first | 7d | iams-v2-static |

| /api/map-tile/* | cache-first | 24h | iams-v2-tiles |

| /api/geocode | cache-first | 24h | iams-v2-api |

| /api/stadiums | cache-first | 1h | iams-v2-api |

| /api/network/{leads,jobs,wanted,trip-match} GET | stale-while-revalidate | 1h | iams-v2-network-api |

| /network, /network/leads, /network/jobs (navigation) | network-first | 5min fallback | iams-v2-pages |

| Other HTML navigations | network-first → /network/offline.html | — | iams-v2-pages |

| Everything else (RSC payloads, JS, CSS, JSON, images) | passthrough | — | browser HTTP cache |

Why stale-while-revalidate for network APIs

/api/network/leads, /jobs, /wanted, /trip-match change throughout the

day but a scout reopening the app at half-time during away travel mainly

wants to see what they last loaded — not wait on a slow GPRS round-trip. SWR

returns the cached payload instantly, then refreshes the cache in the

background so the next view is fresh.

Routes that never get cached

The NETWORK_ONLY_PATTERNS list bypasses the worker entirely for anything

auth-sensitive or write-y:

Any request with an Authorization header is also passed straight to the

network, and non-GET methods are never intercepted.

Offline-supported routes (after first visit)

These pages load read-only when the device is offline, showing the last cached

content. Identity, DM, and Stripe flows are intentionally NOT in this list —

they go straight to the network and surface /offline.html if it fails:

| Route | Behaviour offline |

|---|---|

| /network | last cached HTML; pins + map + DM list shown read-only |

| /network/leads | last cached HTML + last SWR'd /api/network/leads payload |

| /network/jobs | last cached HTML + last SWR'd /api/network/jobs payload |

| /network/wanted | last cached HTML + SWR'd /api/network/wanted payload |

| /network/trip-match (when reachable) | SWR'd payload |

| /offline.html | always available — branded fallback w/ Try again |

Posting a pin, sending a DM, applying to a job, etc. is not supported

offline — those routes are bypassed and will fail at submit time. The UI

already shows a generic error toast in that case; future work could queue

mutations via Background Sync (low-priority).

Install affordances

  1. Bottom banner (PWAInstall.tsx): fixed-position dialog. iOS Safari

gets an "Add to Home Screen" tip; Android/Chromium gets a one-tap install

triggered by the stashed beforeinstallprompt event. Dismiss state

persisted in localStorage (iams-pwa-ios-dismissed,

iams-pwa-android-dismissed).

  1. Inline link (InstallPwaPrompt.tsx): subtle "Install app" button in

the /network top nav. Visible only when ALL of:

- beforeinstallprompt has fired (so iOS — which never fires it — does

not see this link)

- localStorage['iams-install-seen'] ≥ 2 (visit count)

- display-mode: standalone is FALSE (not already installed)

- the bottom banner has not been dismissed

  1. Manifest (manifest.json): start_url: /network, display: standalone,

icons 192/512/1024 maskable, dark theme #0a0a0a / accent #c79015,

shortcuts to World map / My pins / DMs.

Bumping the SW version

SW_VERSION is the cache namespace. Old caches are purged on activate. Bump

the version any time the cache strategy or the offline page shape changes

(otherwise users keep serving stale content from the previous matrix).

Testing offline

  1. First visit: load /network, /network/leads, /network/jobs while

online. This populates the page + SWR caches.

  1. DevTools → Network → Offline → reload /network → expect the cached

page; /api/network/leads should also serve from cache.

  1. Navigate to a URL never visited (e.g. /network/leads/999999) while

offline → expect /offline.html.

  1. Toggle back online → /offline.html triggers window.location.reload()

on the online event so the user lands back on the real page.