diff --git a/CLAUDE.md b/CLAUDE.md index 5736f4d..eec9609 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -17,6 +17,8 @@ Selbstgehostete Rezept-PWA für die Familie Siegeln. Erreichbar unter `https://k | **Migrations** | Werden via Vite `import.meta.glob('./migrations/*.sql', {eager, query:'?raw'})` gebundelt. Neue Migration einfach als `00N_name.sql` ablegen, kein Copy-in-Dockerfile nötig. | | **$lib/server in Client** | Svelte-Import aus `$lib/server/*` in einem `.svelte`-Komponenten-Script bricht den Build. Pures JS/TS, das beidseitig funktioniert (z. B. Portionen-Scaler), gehört nach `$lib/`, nicht `$lib/server/`. | | **Preview-Bilder** | `recipe.image_path` kann **absolute URL** (Preview-Modus) oder **lokaler Filename** sein. `RecipeView.svelte` prüft mit `/^https?:\/\//i`. | +| **Service Worker nur ab HTTPS** | `npm run dev` liefert HTTP → SW registriert nicht. Für PWA-Tests `npm run build && npm run preview` (localhost) oder Prod-Docker. | +| **Icon-Rendering** | `npm run render:icons` rendert `icon-192.png` + `icon-512.png` aus `static/icon.svg`. Nur nach SVG-Änderung erneut ausführen + committen. | ## Dateien, die man typischerweise anfasst @@ -27,6 +29,9 @@ Selbstgehostete Rezept-PWA für die Familie Siegeln. Erreichbar unter `https://k - `src/lib/server/search/searxng.ts` — Web-Suche + Thumbnail-Enrichment + SQLite-Cache - `src/lib/server/recipes/importer.ts` — JSON-LD → Recipe, orchestriert Bild-Download - `src/lib/server/db/migrations/*.sql` — Schema; bei Änderung immer **neue** Migration statt bestehende bearbeiten +- `src/service-worker.ts` — Service-Worker-Orchestrator (Shell-Cache + Pre-Cache + SWR) +- `src/lib/sw/` — reine Logik (Cache-Strategy-Entscheider, Diff-Manifest) für Unit-Tests +- `src/lib/client/*.svelte.ts` — Frontend-Stores (Network, Sync-Status, Toast, Install-Prompt) ## Arbeitsweise (wie wir es machen) diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md index e0d80aa..0752fe4 100644 --- a/docs/ARCHITECTURE.md +++ b/docs/ARCHITECTURE.md @@ -106,6 +106,35 @@ Bei Schema-Änderung: - **Keine Svelte-Component-Tests** (bewusst, Aufwand/Nutzen stimmt nicht; UI wird manuell getestet) - **Vor Commit**: `npm test && npm run check` muss grün sein. +### Service Worker (PWA) + +`src/service-worker.ts` ist SvelteKits eingebauter SW-Slot. Er nutzt `$service-worker` (`build`, `files`, `version`) für den App-Shell-Cache und implementiert eigene Logik für: + +- **Pre-Cache** (alle Rezepte + Bilder beim Initial-Sync), über paginierten Fetch von `/api/recipes/all`. +- **Delta-Sync** beim App-Start (diff vs. Cache-Manifest, nur Delta laden). +- **Drei Cache-Strategien** (dispatcht per `resolveStrategy`): Shell = cache-first, Daten = SWR, Bilder = cache-first. +- **Message-Protokoll** (`sync-start`, `sync-progress`, `sync-done`, `sync-error`) zwischen SW und Client. + +Reine Logik-Einheiten (testbar, Unit-Tests in `tests/unit/`): +- `src/lib/sw/cache-strategy.ts` — `resolveStrategy({url, method})` → `'shell' | 'swr' | 'images' | 'network-only'` +- `src/lib/sw/diff-manifest.ts` — `diffManifest(current, cached)` → `{toAdd, toRemove}` + +Client-Stores (SSR-safe via typeof-Guards): +- `src/lib/client/network.svelte.ts` — `navigator.onLine` + Events. +- `src/lib/client/sync-status.svelte.ts` — SW-Message-Spiegel, `lastSynced` in localStorage. +- `src/lib/client/toast.svelte.ts` — Toast-Queue für Offline-Fehler + Sync-Meldungen. +- `src/lib/client/install-prompt.svelte.ts` — fängt `beforeinstallprompt`, erkennt Plattform. +- `src/lib/client/sw-register.ts` — registriert den SW, leitet Messages an den Sync-Status-Store. +- `src/lib/client/require-online.ts` — Helper für Schreib-Aktionen (Toast statt stillem Fail). + +UI-Komponenten: +- `src/lib/components/SyncIndicator.svelte` — Pill unten rechts (Sync-Fortschritt / Offline-Status). +- `src/lib/components/Toast.svelte` — Top-Center-Toast-Renderer. + +Admin-UI: `src/routes/admin/app/+page.svelte` mit Install-Button, manuellem Sync-Trigger, Cache-Reset. + +E2E-Tests: `tests/e2e/offline.spec.ts` — Playwright setzt das Netzwerk offline und prüft Navigation/Toast/Indikator-Verhalten. + ## Was später kommt (laut Spec, aktuell nicht implementiert) - LLM-Fallback für nicht-JSON-LD-Seiten diff --git a/docs/OPERATIONS.md b/docs/OPERATIONS.md index b023705..0adffba 100644 --- a/docs/OPERATIONS.md +++ b/docs/OPERATIONS.md @@ -146,3 +146,28 @@ Siehe `.env.example` im Repo. - **Thumbnail-Cache in SQLite** → `003_thumbnail_cache.sql` + `searxng.ts` Git-Log ist die Wahrheit; diese Datei ist eine Orientierung. + +## PWA / Offline-Modus + +Kochwas ist eine installierbare PWA. Erkennbar an: +- `static/manifest.webmanifest` (Manifest + Icons: SVG + 192×192 + 512×512, alle maskable) +- `src/service-worker.ts` (Cache + Sync) + +Caches im Browser (siehe DevTools → Application → Cache Storage): +- `kochwas-shell-` — App-Shell (JS/CSS/Static-Icons), cache-first +- `kochwas-data-v1` — Rezept-HTMLs + API-JSON (SWR) +- `kochwas-images-v1` — Bilder (cache-first) +- `kochwas-meta` — Cache-Manifest (Liste der gecachten Rezept-IDs unter `/__cache-manifest__`) + +Sync-Verhalten: +- **Initial-Sync** (nach erstem Install): SW lädt alle Rezepte + Bilder im Hintergrund. Fortschritt im `SyncIndicator`-Pill unten rechts. +- **Update-Sync** (bei jedem App-Start online): Diff gegen Cache-Manifest, nur Delta nachladen, gelöschte IDs räumen. +- **Storage-Quota-Check**: < 100 MB frei → abbrechen mit Fehler-Toast. + +Bei SW-Problemen Debug-Pfad: +1. Admin → „App"-Tab → „Offline-Cache leeren" (destructive, zweistufig bestätigt) +2. Alternative: DevTools → Application → Service Workers → Unregister, dann Seite neu laden. + +E2E-Tests (Playwright): `npm run test:e2e`. Setzt `npm run build` voraus (Playwright startet automatisch `npm run preview`). + +Icons einmalig rendern: `npm run render:icons` (schreibt nach `static/icon-*.png`, committen).