pwa-platform
PWA plumbing for apps/pwa: web app manifest, vite-plugin-pwa / Workbox strategy, update prompt, offline behaviour, iOS and Android install quirks, safe areas, Vercel headers and rewrites, demo state p
SKILL.md.claude/skills/pwa-platform/SKILL.md
GitHubPWA platform
Owner: the pwa-engineer agent. The jury opens a link on an unknown phone, possibly on poor conference Wi-Fi.
The prototype must load fast, survive a flaky network, and install cleanly.
Manifest (vite-plugin-pwa manifest option)
| Field | Value |
|---|---|
name, short_name |
our working name (never "mObywatel" alone; the prototype-guardrails skill) |
lang, dir |
pl, ltr |
start_url, scope |
/, / (keep ?osoba= params working, see below) |
display |
standalone |
orientation |
portrait |
theme_color, background_color |
from @mobywatel/brand tokens (import in vite.config.ts, no literals) |
icons |
192 and 512 PNG, plus a 512 purpose: "maskable"; files in public/icons/ (the brand-designer agent) |
description |
one plain-Polish sentence including "nieoficjalny prototyp" |
Service worker strategy
registerType: 'prompt': never swap code under a user mid-matter. Show an "Nowa wersja – odśwież" toast (useRegisterSWfromvirtual:pwa-register/react) insrc/pwa/.workbox.globPatterns: the app shell, fonts, icons and all content JSON, so every persona and scenario works offline after the first load.navigateFallback: '/index.html'for SPA routes. Exclude/api/from the fallback.- Runtime caching only for the optional LLM proxy:
NetworkOnly(never cache conversations). devOptions.enabled: falseby default.pnpm devnever proves SW or offline behaviour.- When offline and the user asks the live assistant, fall back to scripted mode and say so in plain Polish.
Offline test procedure
pnpm run build && pnpm preview, then open the app and wait for "ready to work offline" (log or toast).- DevTools › Application: manifest has no errors, the SW is activated, and the precache lists the content.
- Network › Offline, then reload and walk one full matter.
- Automated: a Playwright flow loads
/, waits fornavigator.serviceWorker.ready, thencontext.setOffline(true), reloads, and completes a scenario. It lives inapps/pwa/e2e/offline.spec.ts(owner: theqa-engineeragent). - Update flow: build, load, change a string, rebuild, then reload once and expect the update toast.
iOS (Safari) specifics
- No install prompt event. Show an "Add to Home Screen" instruction sheet (Share › Do ekranu początkowego)
when
navigator.standaloneis false on iOS. Show it once, and it can be dismissed. apple-touch-icon(180 px) and<meta name="apple-mobile-web-app-capable" content="yes">,apple-mobile-web-app-status-bar-style,apple-mobile-web-app-title.- Layout:
viewport-fit=cover,env(safe-area-inset-*)paddings,100dvhnot100vh. - An installed app has its own storage, separate from Safari. The demo state starts fresh after install.
- Speech recognition support differs (the
ai-assistantskill), so always offer text.
Android / Chromium
- Capture
beforeinstallprompt, show our own "Zainstaluj" button in settings and after the first completed matter. Never show it on first paint.
Demo state
- Persona via URL:
/?osoba=martaselects the persona and stores it. A persona switcher in settings and on the start screen lets the jury try others. - State (completed matters, reminders, settings) in IndexedDB via
src/platform/storage, versioned with a schema number. Reset on mismatch. - "Zresetuj demo" in settings clears state and returns to the start screen. The jury will poke at it, so make reset easy to find.
- Settings (senior mode, text size, language) persist separately from demo state and survive reset.
Vercel
apps/pwa/vercel.json:
- SPA rewrite: everything except files and
/api/*→/index.html. - Headers:
sw.jsandmanifest.webmanifestwithCache-Control: no-cache; hashed assetsimmutable. AddX-Content-Type-Options: nosniff,Referrer-Policy: strict-origin-when-cross-originand a CSP that allows only self (plus the proxy if used). - Deploying and production: the
competition-submissionskill.
Checks
- Lighthouse (mobile) on the preview or deployed URL: performance ≥ 90, accessibility 100, best practices ≥
95, installable. The
web-vitals-a11y-auditskill helps when available. - JS budget: initial route under ~200 kB gzip. Lazy-load the assistant and each matter.
- Verify with the
verify-changeskill, using a build and not the dev server.