Skip to content

Android PWA: installable SPA with manifest, hand-rolled service worker, cache-on-logout #86

@MartinCastroAlvarez

Description

@MartinCastroAlvarez

Summary

When a user visits the SPA on Android, the browser should prompt to install it as a Progressive Web App. After install, the app loads from a service-worker-cached shell — near-instant on subsequent visits, and the read paths keep working when the network is flaky.

Why this matters

For mobile-heavy admin users (oncall, ops staff), the cold-start cost of "open browser → type URL → wait for cookie + bundle" is the difference between "I'll do that later" and "I'll do that now." A 200-KB cached shell + a service worker collapses repeat-visit latency to near-zero. The HTML admin doesn't and can't do this.

What I expect as a consumer

  • A manifest served at <mount>/web.manifest (one Django view; start_url / scope / name resolved from the consumer-chosen mount + AdminSite.site_header at request time). Theme colour resolved server-side from Sec-CH-Prefers-Color-Scheme (pair with the dark-mode issue #84).
  • A hand-rolled service worker at <mount>/sw.js with Service-Worker-Allowed: <mount> header. No vite-plugin-pwa / Workbox — the SW JS stays auditable and the dependency surface stays small.
  • Cache policy:
    • SPA shell (index.html, JS, CSS) → stale-while-revalidate, versioned cache.
    • Static icons / fonts → cache-first, immutable.
    • /api/v1/registry/, /api/v1/<app>/<model>/, /api/v1/<app>/<model>/<pk>/ → network-first, last-good cache.
    • Action invocations / writes → no caching, no replay.
    • Anything outside the SPA mount → pass through.
    • Server Cache-Control: no-store responses → skip caching (honour the existing security middleware).
  • Install prompt UX: browser's beforeinstallprompt event captured; SPA renders an "Install this admin" affordance in the user menu (with the Lucide Download icon). User clicks → SPA calls prompt(). Native dialog renders. 14-day cooldown on dismiss. iOS Safari (no API) gets a one-line "Add to Home Screen" tip in the user menu.
  • Offline behaviour: read paths keep working from the SW cache; write paths show a sticky banner ("You're offline. Changes will save when you reconnect."); mutations queue and flush on online.
  • Cache purge on logout (Security ask): the logout flow runs caches.delete(...) for the SPA caches so cached API payloads don't outlive the session.

Out of scope for a first cut

  • Background sync for writes (post-v1).
  • Push notifications.
  • Periodic background sync (Chrome's "Periodic Background Sync API").
  • Wear OS / tablet-only variants.

Acceptance signal

A staff user opens the SPA on Android Chrome, gets the install prompt, accepts; the installed app launches in standalone mode, first paint < 200 ms on the second cold start, reads work for ≥5 minutes after killing wifi, mutations queue and flush on reconnect.

Workaround today

None — there is no manifest, no service worker, no install affordance.

CSP additions needed

worker-src 'self' must be added to the package's recommended CSP sample. Security lane will sign off on this when the issue is picked up.

— PM/UX-owned issue, opened from the lane that ran the 2026-05-26 directive cycle.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions