Files
bea-edit/plan/pwa-plan.md
rehlert f09384d2e6 pwa / offline mode
- @vite-pwa/sveltekit: workbox precache (incl. pdfjs worker), generated manifest, prompt-style updates via PwaUpdatePrompt toast
- prerendered routes for offline navigation, PWA icons, theme-color + apple-touch-icon
- pwa offline/update e2e suite (pnpm test:pwa, playwright.pwa.config.ts)
- datenschutz: offline/install section; prettier cleanup of shadcn components
2026-10-04 12:55:46 +02:00

147 lines
5.9 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Plan: PWA / Offline-Fähigkeit
## Goal
The app already processes everything locally — but the browser still has to fetch the app shell
from the server on every load. Making **beA-Edit an installable, offline-capable PWA** reinforces
the privacy story ("works without internet after first load"), enables home-screen/desktop
installation, and is essentially free given there are no network calls to cache-around.
---
## Open decisions (defaults marked ✅)
### D1 — Implementation approach
- ✅ **A. `@vite-pwa/sveltekit`** (new **dev** dependency). Mature integration: precaching of the
built assets via Workbox, generated manifest, virtual `RegisterSW` module, works with
`adapter-node` builds. The dependency is justified (agents.md allows deps when the task cannot
reasonably be done without) — hand-rolling a correct service worker + update flow is
error-prone.
- B. Hand-written minimal `sw.js` in `static/` + manual manifest. Zero deps but custom update
logic, manual asset hashing, more long-term maintenance.
### D2 — Update UX
- ✅ **A. Auto-update with a toast.** New versions activate on next navigation; a small toast
"Neue Version verfügbar – Seite neu laden" appears when an update is waiting (Workbox
`onNeedRefresh`/`onOfflineReady` hooks). Never force-reload mid-work (users may have unsaved
archive state).
- B. Silent auto-reload. Rejected: could interrupt an in-progress merge.
### D3 — Legal pages
- ✅ **Review required, not auto-edited.** A service worker + install prompt is client-side
storage/behavior; `datenschutz/+page.svelte` should likely gain a sentence. Flag for the user;
do not rewrite legal copy unilaterally (project constraint).
---
## Technical approach
### Vite config
```ts
// vite.config.ts
import { SvelteKitPWA } from '@vite-pwa/sveltekit';
export default defineConfig({
plugins: [
sveltekit(),
tailwindcss(),
SvelteKitPWA({
registerType: 'prompt',
manifest: {
name: 'beA-Edit',
short_name: 'beA-Edit',
description: 'PDF-Werkzeuge für die beA-Kanzlei – 100 % lokal im Browser.',
lang: 'de',
start_url: '/',
display: 'standalone',
background_color: '#f2f5f8', // align with theme background token
theme_color: '#…', // align with primary token
icons: [
/* 192 + 512 + maskable, derived from static logo */
]
},
workbox: {
globPatterns: ['**/*.{js,css,html,svg,woff2}'],
navigateFallback: '/' // SPA-style offline fallback for app routes
},
devOptions: { enabled: false }
})
]
});
```
Notes:
- pdfjs worker chunk (`pdf.worker.mjs?url`) is part of the built assets → precached by glob.
- Legal routes (`/impressum`, `/datenschutz`) precache like any route; offline navigation works
via the fallback.
- No runtime caching strategies needed: the app makes **no** network requests by design.
### Registration UI
- Root `+layout.svelte`: import the virtual `virtual:pwa-register` module (SSR-guarded), wire
`onNeedRefresh` → toast state; render a small dismissible toast component (build with existing
card/button styling; no new UI dep) with "Neu laden" / "Später".
- `onOfflineReady` → optional one-time hint "beA-Edit funktioniert jetzt offline." (keep subtle).
- Install prompt: rely on the browser's native install affordance (manifest makes it appear);
optionally an "Installieren" hint on the start page later — out of scope for v1.
### Icons
- Generate 192/512/maskable PNGs from the existing logo (`static/` logo asset) once, committed
to `static/icons/`. Use an offline tool/imagemagick during implementation; no runtime dep.
### Docker / adapter-node
- Service worker + manifest are static build output → served by `node build/index.js` without
changes. Verify `Cache-Control` headers don't block SW updates (adapter-node defaults are fine;
the SW itself must not be cached aggressively — Vite PWA emits the right filenames).
## Files changed
- `vite.config.ts` — SvelteKitPWA plugin + manifest.
- `package.json` / lockfile — `@vite-pwa/sveltekit` dev dependency (via pnpm only).
- `src/routes/+layout.svelte` — registration + update toast.
- `static/icons/*` — generated icons; `static/manifest.webmanifest` handled by plugin.
- `src/app.html` — `theme-color` meta if plugin doesn't inject.
- `agents.md` — document PWA setup + update behavior.
- `datenschutz/+page.svelte` — only after explicit user approval (D3).
## Implementation phases
1. Add dependency, configure plugin + manifest + icons.
2. Registration + update toast in root layout.
3. Build + `pnpm preview`: verify `/` loads, then devtools → Application → service worker
registered; toggle "Offline" → reload → app still works.
4. Production image smoke test (Docker build, offline reload).
5. Update `agents.md`; flag datenschutz review.
## Verification
- Fresh load registers the SW (devtools), `onOfflineReady` path reachable.
- Offline reload after precache: start page + all tool routes render; dropping a ZIP still works
fully (entire processing chain offline).
- New build deployed → toast offers reload; choosing it loads the new version; declining does
not interrupt current state.
- No console errors on iOS Safari (manifest parsing quirks) — best-effort check.
- `pnpm check`, `pnpm lint`, `pnpm build` pass.
## Risks
- **Stale cache confusion** during development: keep `devOptions.enabled: false`; document in
agents.md that preview/production test the SW, not dev mode.
- **Large precache manifest**: the pdfjs worker + fonts add a few MB to the first precache —
acceptable for an installable tool; monitor build output stats.
- **SW + SvelteKit hydration edge cases** on first offline visit are known upstream; pin a
current stable plugin version and test the exact offline-reload sequence.
## Out of scope
- Background sync (nothing to sync — no network by design).
- App-store packaging.
- Custom install button UI beyond the native affordance.