Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.encoreos.io/llms.txt

Use this file to discover all available pages before exploring further.

Status: Proposed (becomes Accepted on Phase 3 activation per MICROFRONTENDS_RUNBOOK.md) Date: 2026-04-22 Participants: Platform Architecture (cloud agent draft, Jeremy Bloom approval at activation) Related: ADR-013 (amended by this ADR), ADR-008, Phase 3 of docs/recommendations/DEV_VELOCITY_AND_ARCHITECTURE_PLAN_2026-04-22.md (PR #137)

Context

ADR-013 established the platform’s PWA strategy: a single Workbox service worker registered at scope /, with CacheFirst for static assets, NetworkFirst for REST, and NetworkOnly for auth. That ADR assumes a single app generating one sw.js and one precache manifest. Phase 3 (docs/development/MICROFRONTENDS_RUNBOOK.md) introduces a second Vercel project (encoreos-public) that handles /auth, /employee-setup, /pending-activation, /pm/kiosk/:siteId/*, /portal/*, /p/:token, /packet/:token, /gr/whistleblower-report, /chatbot/widget. Both projects use vite-plugin-pwa today, so each will independently generate a sw.js. The problem: only one service worker can claim scope / per origin. If both Vercel projects emit sw.js at the root with scope: '/', whichever one installs second will fail (or, worse, supersede the first and start serving cached chunks from the wrong project). This is a real, known issue with Vite + microfrontends and is the headline reason the recommendations doc (§ 3.5) flagged the PWA scope problem as a “non-trivial migration cost”.

Options Considered

Option A: Keep encoreos-app SW at scope /; disable SW on encoreos-public

  • encoreos-app continues to emit sw.js at scope: '/' exactly as today.
  • encoreos-public removes vite-plugin-pwa (or sets registerType: 'none').
  • Result: the public zone has no offline support, no PWA install prompt, no precache. That is acceptable for the public zone because:
    • Auth pages are short-lived and use NetworkOnly for the auth endpoint anyway.
    • The kiosk hardware is wall-powered, on a known network, and reloads on tap — offline is not a real requirement.
    • Public form portals (/p/*, /packet/*, /portal/*) need server reachability to submit anyway.
Pros: Zero risk to the existing PWA install base. ADR-013 is preserved verbatim for the authenticated zone (the only place users actually use PWA features). Smallest possible delta. Cons: Public-zone users cannot install the public zone as a PWA on its own. (No real demand for this today.)

Option B: Each zone owns a sub-scope SW

  • encoreos-app keeps scope: '/'.
  • encoreos-public registers sw.js at scope: '/auth/', scope: '/portal/', etc. — one SW registration per route family.
  • Vercel’s microfrontends asset prefix machinery handles routing the SW file requests correctly per zone.
Pros: Each zone can have a tailored offline experience. Cons: Browsers limit the number of active SW registrations per origin. Multiple sub-scope SWs is a non-standard pattern and historically has produced inconsistent behavior across Chrome / Safari / Firefox. The kiosk path (/pm/kiosk/...) is awkward — the literal scope must match the kiosk route, which today is /pm/kiosk/:siteId, so the scope would be /pm/kiosk/ (which is fine, but a single missing trailing slash breaks it). High testing surface for low value.

Option C: A single shared SW lives in encoreos-app; precaches both zones’ assets

  • Only encoreos-app generates a SW. It precaches its own chunks AND fetches and precaches encoreos-public’s critical chunks via the Vercel asset-prefix URLs.
  • Requires custom Workbox plugin work to discover encoreos-public’s manifest at build time.
Pros: One SW; full offline support across both zones. Cons: Tight build-time coupling between two Vercel projects (the whole point of microfrontends is to decouple them). Custom Workbox config is fragile. We’d own a one-off integration that doesn’t appear elsewhere in the ecosystem.

Decision

Adopt Option A. At Phase 3 activation, the wiring PR will:
  1. Leave encoreos-app’s vite.config.ts PWA configuration unchanged. It continues to register sw.js at scope / exactly as documented in ADR-013.
  2. In encoreos-public’s build config (when that project is created with its own vite.config.ts or a shared config gated on VERCEL_PROJECT_ID), disable vite-plugin-pwa entirely. Concretely: skip the VitePWA({...}) plugin invocation when the build target is encoreos-public.
  3. The encoreos-public index.html does NOT include <link rel="manifest"> and does NOT register a service worker.
  4. The Workbox runtimeCaching rule already in place that excludes /auth/* from caching becomes redundant (the SW does not run on those routes anymore once encoreos-public owns them) but stays in place as defense-in-depth.
Upgrade path: if a future requirement demands offline behavior in the public zone (e.g., a kiosk that must remain functional when the network drops mid-session), revisit Option B for just that one sub-path. Do not preemptively adopt Option B for all public-zone routes.

Consequences

Positive

  • ADR-013’s behavior in the authenticated zone (which is where ~100% of PWA usage actually happens today) is preserved unchanged. Zero risk to existing PWA install base.
  • No multi-SW complexity. Only one origin-level SW exists at any time.
  • The smallest possible delta between today’s behavior and Phase 3 activation.

Negative

  • Users cannot install encoreos-public as a standalone PWA. (Not a stated requirement; revisit if it becomes one.)
  • The kiosk experience loses the precache and offline behavior that ADR-013 provides for the authenticated app. Since kiosks are wall-powered and on a known network, this is acceptable. If a specific kiosk deployment ever needs offline, that’s a future ADR amendment scoped to that one route.

Mitigations

  • Add a startup-time assertion in encoreos-public’s entry script that warns if a SW is somehow already registered for the origin (e.g., a stale install from before activation) and unregisters it. Keeps users from getting stuck on stale chunks during the rollout window.
  • The Phase 3 cutover plan (MICROFRONTENDS_RUNBOOK.md step 4) explicitly soaks the preview deployment for ≥24 hours to surface any cross-zone SW interactions before production cutover.