App-Start ohne Wartezeit + vollstaendige Offline-Nutzung (lokale Daten auf dem Telefon, laufende Synchronisation) #220

Closed
opened 2026-09-29 08:48:50 +02:00 by lena · 3 comments
Collaborator

Story: Listen sofort sehen - auch ohne Netz

As a Nutzer der App auf dem Telefon,
I want to dass meine Listen beim Oeffnen der App sofort da sind, ohne Ladezeit, und dass ich die App auch komplett offline nutzen kann, waehrend sich die Daten im Hintergrund laufend mit dem Server abgleichen,
so that ich z. B. im Supermarkt ohne Empfang oder bei langsamem Netz nicht warten muss, bevor ich meine Einkaufsliste sehe.

Wortlaut des Nutzers: "Die Ladezeit am Anfang von der App ist mir zu lang. Ausserdem moechte ich die App offline nutzen koennen. Gibt es eine Moeglichkeit die Daten lokal auf dem Telefon zu haben (ggf. lightweight ohne das LLM) und diese konstant zu synchronisieren. Ich meine, das wurde bereits eingebaut? Ich haette gerne keine Ladezeit, bevor ich meine Listen sehe"

Ist-Stand (PO-Recherche im Code, 2026-09-29): Teilweise vorhanden, aber nicht vollstaendig:

  • #97 / #102 haben einen lokalen Lese-Cache (IndexedDB) und eine Offline-Warteschlange fuer Aenderungen gebaut - allerdings nur fuer Einkaufslisten- und Vorratsschrank-Produkte und deren Kategorien (ReactUi/src/offline/offlineReadCache.ts). To-Do-Listen, Masterpacklisten, priorisierte Listen und die Listenuebersicht selbst werden nicht lokal vorgehalten.
  • Der Cache wird nur als Rueckfall genutzt, wenn der Server nicht erreichbar ist - bei langsamem, aber vorhandenem Netz wartet die App trotzdem auf den Server, bevor etwas angezeigt wird.
  • Der Service Worker (ReactUi/public/sw.js) cached bewusst nichts (kein fetch-Handler, nur Push/Installierbarkeit). Ohne Netz startet die App deshalb gar nicht erst; der lokale Cache hilft nur, wenn die App schon offen war.
  • Die KI-Funktionen (Smart-Add-Modell im Web Worker) sollen laut Nutzerwunsch den Start nicht verzoegern - zu pruefen, ob sie das aktuell tun.

Acceptance criteria:

  • Die App-Oberflaeche (HTML/JS/CSS, Icons, Uebersetzungen) wird lokal auf dem Geraet vorgehalten; die App startet auch komplett ohne Netz (z. B. im Flugmodus) und zeigt die zuletzt bekannten Daten.
  • Beim Start werden Listenuebersicht und die zuletzt geoeffnete Liste sofort aus den lokalen Daten angezeigt ("stale-while-revalidate"), ohne auf den Server zu warten; frische Serverdaten ersetzen die Anzeige unauffaellig, sobald sie da sind.
  • Lokal vorgehalten werden alle Listentypen (To-Do, Einkaufsliste, Vorratsschrank, Masterpackliste, priorisierte Liste) inkl. Listenuebersicht, jeweils mit den Daten, die man zum Anzeigen braucht.
  • Aenderungen offline werden wie bisher in der Warteschlange gesammelt und bei Wiederverbindung automatisch uebertragen; Listentypen, deren Aenderungen noch nicht offline-faehig sind, zeigen offline einen klaren Hinweis statt eines Fehlers.
  • Die lokalen Daten werden bei bestehender Verbindung laufend aktualisiert (z. B. beim Zurueckkehren in die App und in regelmaessigen Abstaenden), sodass beim naechsten Oeffnen moeglichst aktuelle Daten da sind.
  • Das KI-/LLM-Modell wird nicht fuer die Startanzeige benoetigt und blockiert sie nicht (spaet bzw. nur bei Bedarf laden); ohne Modell funktioniert alles ausser den KI-Vorschlaegen.
  • Beim Abmelden werden die lokalen Daten des Nutzers vom Geraet entfernt (kein Datenleck bei geteilten Geraeten).
  • Nach einem App-Update laedt der Service Worker die neue Version zuverlaessig (kein "haengen gebliebenes" altes Frontend).

Out of scope for this story:

  • Konfliktaufloesung ueber das bestehende "letzte Aenderung gewinnt"-Verhalten aus #97 hinaus.
  • Echtzeit-Synchronisation zwischen mehreren Geraeten per Push/WebSocket.

Open questions: (escalate to human if unanswered)

  • Gibt es eine Obergrenze, wie viel Speicher die App lokal belegen darf? Vorschlag PO: nur eigene Listen, keine Fotos/Avatare in Originalgroesse.
  • Soll die Story in Phasen geteilt werden (Phase 1: App-Shell-Caching + sofortige Anzeige aus dem Cache fuer die bestehenden Listentypen; Phase 2: alle weiteren Listentypen offline)? Entscheidung beim Architect/PO im Loop.

Als Backlog-Item vom Nutzer eingereicht (per Chat, nicht im laufenden Loop-Zyklus geclaimt).

## Story: Listen sofort sehen - auch ohne Netz **As a** Nutzer der App auf dem Telefon, **I want to** dass meine Listen beim Oeffnen der App sofort da sind, ohne Ladezeit, und dass ich die App auch komplett offline nutzen kann, waehrend sich die Daten im Hintergrund laufend mit dem Server abgleichen, **so that** ich z. B. im Supermarkt ohne Empfang oder bei langsamem Netz nicht warten muss, bevor ich meine Einkaufsliste sehe. Wortlaut des Nutzers: "Die Ladezeit am Anfang von der App ist mir zu lang. Ausserdem moechte ich die App offline nutzen koennen. Gibt es eine Moeglichkeit die Daten lokal auf dem Telefon zu haben (ggf. lightweight ohne das LLM) und diese konstant zu synchronisieren. Ich meine, das wurde bereits eingebaut? Ich haette gerne keine Ladezeit, bevor ich meine Listen sehe" **Ist-Stand (PO-Recherche im Code, 2026-09-29):** Teilweise vorhanden, aber nicht vollstaendig: - #97 / #102 haben einen lokalen Lese-Cache (IndexedDB) und eine Offline-Warteschlange fuer Aenderungen gebaut - allerdings nur fuer **Einkaufslisten- und Vorratsschrank-Produkte und deren Kategorien** (`ReactUi/src/offline/offlineReadCache.ts`). To-Do-Listen, Masterpacklisten, priorisierte Listen und die Listenuebersicht selbst werden nicht lokal vorgehalten. - Der Cache wird nur als Rueckfall genutzt, wenn der Server nicht erreichbar ist - bei langsamem, aber vorhandenem Netz wartet die App trotzdem auf den Server, bevor etwas angezeigt wird. - Der Service Worker (`ReactUi/public/sw.js`) cached bewusst **nichts** (kein fetch-Handler, nur Push/Installierbarkeit). Ohne Netz startet die App deshalb gar nicht erst; der lokale Cache hilft nur, wenn die App schon offen war. - Die KI-Funktionen (Smart-Add-Modell im Web Worker) sollen laut Nutzerwunsch den Start nicht verzoegern - zu pruefen, ob sie das aktuell tun. **Acceptance criteria:** - [ ] Die App-Oberflaeche (HTML/JS/CSS, Icons, Uebersetzungen) wird lokal auf dem Geraet vorgehalten; die App startet auch komplett ohne Netz (z. B. im Flugmodus) und zeigt die zuletzt bekannten Daten. - [ ] Beim Start werden Listenuebersicht und die zuletzt geoeffnete Liste sofort aus den lokalen Daten angezeigt ("stale-while-revalidate"), ohne auf den Server zu warten; frische Serverdaten ersetzen die Anzeige unauffaellig, sobald sie da sind. - [ ] Lokal vorgehalten werden alle Listentypen (To-Do, Einkaufsliste, Vorratsschrank, Masterpackliste, priorisierte Liste) inkl. Listenuebersicht, jeweils mit den Daten, die man zum Anzeigen braucht. - [ ] Aenderungen offline werden wie bisher in der Warteschlange gesammelt und bei Wiederverbindung automatisch uebertragen; Listentypen, deren Aenderungen noch nicht offline-faehig sind, zeigen offline einen klaren Hinweis statt eines Fehlers. - [ ] Die lokalen Daten werden bei bestehender Verbindung laufend aktualisiert (z. B. beim Zurueckkehren in die App und in regelmaessigen Abstaenden), sodass beim naechsten Oeffnen moeglichst aktuelle Daten da sind. - [ ] Das KI-/LLM-Modell wird nicht fuer die Startanzeige benoetigt und blockiert sie nicht (spaet bzw. nur bei Bedarf laden); ohne Modell funktioniert alles ausser den KI-Vorschlaegen. - [ ] Beim Abmelden werden die lokalen Daten des Nutzers vom Geraet entfernt (kein Datenleck bei geteilten Geraeten). - [ ] Nach einem App-Update laedt der Service Worker die neue Version zuverlaessig (kein "haengen gebliebenes" altes Frontend). **Out of scope for this story:** - Konfliktaufloesung ueber das bestehende "letzte Aenderung gewinnt"-Verhalten aus #97 hinaus. - Echtzeit-Synchronisation zwischen mehreren Geraeten per Push/WebSocket. **Open questions:** (escalate to human if unanswered) - Gibt es eine Obergrenze, wie viel Speicher die App lokal belegen darf? Vorschlag PO: nur eigene Listen, keine Fotos/Avatare in Originalgroesse. - Soll die Story in Phasen geteilt werden (Phase 1: App-Shell-Caching + sofortige Anzeige aus dem Cache fuer die bestehenden Listentypen; Phase 2: alle weiteren Listentypen offline)? Entscheidung beim Architect/PO im Loop. --- Als Backlog-Item vom Nutzer eingereicht (per Chat, nicht im laufenden Loop-Zyklus geclaimt).
lena self-assigned this 2026-09-29 19:20:44 +02:00
Author
Collaborator

Claimed by the go loop (2026-09-29). Start: Architect design for the offline shell caching, instant start from local data and caching all list types. Progress follows as commits on master.

Claimed by the go loop (2026-09-29). Start: Architect design for the offline shell caching, instant start from local data and caching all list types. Progress follows as commits on master.
Author
Collaborator

Architect design (go loop, 2026-09-29) - one pass, no phase split:

  1. Local read cache (existing localStorage store from #97) extended from shopping/pantry products to every query needed to render: list overview (todo/shopping/pantry/master-pack lists, list order, group headings, default list), account gate (admin flag, password-change flag), todos + todo categories/labels (todo list and priority matrix), master-pack items/labels, pantry labels, due overview. Cache is scoped to the logged-in user (owner id stored next to it; a different user id clears it) and wiped on every transition to logged out. Writes are quota-safe (a full storage never breaks a request).
  2. Stale-while-revalidate: new callApiCached(name, request, apply) shows the cached value immediately and then the server answer. The cached value is only used for the first load of that query in this app session, so a refetch after an edit never flashes the older cached state.
  3. App shell offline: the service worker caches index.html (stale-while-revalidate), hashed /assets (cache-first), icons and manifest. /api is never touched, and .wasm/model files are not cached (the AI stays online-only). When a background check finds a new index.html, the page shows an "update available - reload" toast. Caching is only enabled for the production build (sw.js?shell=1).
  4. Continuous sync: an app:refresh event on return to the app (visibilitychange) and every 5 minutes while visible and online; the overview and list pages refetch on it.
  5. Offline hints: uncached reads fail silently while the browser is offline (the banner explains it). Changes that are not offline-capable (everything except shopping/pantry) show a clear "not possible offline" toast instead of the generic network error, and the offline banner text says which lists stay editable.
  6. AI: the embedding worker starts only on the first smart-add input or after a short idle delay, never during initial rendering.

Security pre-review: no new endpoints. Cached data is only a mirror of what the server already returned to this user; the server still authorizes everything. Cached admin/password-change flags are UI hints only (an admin password reset revokes all sessions -> 401 -> cache wiped). The service worker never caches /api responses or anything cookie-bound, only the public static shell. Cache wiped on logout / session loss (AC 7).

Architect design (go loop, 2026-09-29) - one pass, no phase split: 1. Local read cache (existing localStorage store from #97) extended from shopping/pantry products to every query needed to render: list overview (todo/shopping/pantry/master-pack lists, list order, group headings, default list), account gate (admin flag, password-change flag), todos + todo categories/labels (todo list and priority matrix), master-pack items/labels, pantry labels, due overview. Cache is scoped to the logged-in user (owner id stored next to it; a different user id clears it) and wiped on every transition to logged out. Writes are quota-safe (a full storage never breaks a request). 2. Stale-while-revalidate: new callApiCached(name, request, apply) shows the cached value immediately and then the server answer. The cached value is only used for the first load of that query in this app session, so a refetch after an edit never flashes the older cached state. 3. App shell offline: the service worker caches index.html (stale-while-revalidate), hashed /assets (cache-first), icons and manifest. /api is never touched, and .wasm/model files are not cached (the AI stays online-only). When a background check finds a new index.html, the page shows an "update available - reload" toast. Caching is only enabled for the production build (sw.js?shell=1). 4. Continuous sync: an app:refresh event on return to the app (visibilitychange) and every 5 minutes while visible and online; the overview and list pages refetch on it. 5. Offline hints: uncached reads fail silently while the browser is offline (the banner explains it). Changes that are not offline-capable (everything except shopping/pantry) show a clear "not possible offline" toast instead of the generic network error, and the offline banner text says which lists stay editable. 6. AI: the embedding worker starts only on the first smart-add input or after a short idle delay, never during initial rendering. Security pre-review: no new endpoints. Cached data is only a mirror of what the server already returned to this user; the server still authorizes everything. Cached admin/password-change flags are UI hints only (an admin password reset revokes all sessions -> 401 -> cache wiped). The service worker never caches /api responses or anything cookie-bound, only the public static shell. Cache wiped on logout / session loss (AC 7).
Author
Collaborator

Done (go loop, 2026-09-29). Commits on master: a75a27c9, 6204cd28, e0653187 (plus memory 918688b7).

Scope:

  • App shell on the device: in production builds the service worker serves index.html stale-while-revalidate and the hashed assets cache-first. It never caches /api, /health or the AI .wasm. Once a new build has been fetched in the background, a toast offers "Reload".
  • Instant start: the account gate (admin and password-change flags), default list, list overview (all 4 list types, list order, group headings) and the main content of every list type (todos + categories/labels, priority matrix, shopping, pantry incl. labels, master pack items/labels, due overview) are cached locally. They are shown immediately and then replaced by the server answer (callApiCached; the cache is used only on the first load per session, so a refetch after an edit never flashes older data).
  • Continuous sync: refresh on return to the app (after >= 30 s away), every 5 min while visible, and on reconnect.
  • Offline: uncached reads fail quietly. Changes that can't be queued (everything except shopping/pantry) show "This change needs an internet connection ...". The todo, priority, master pack and due pages show a read-only offline banner.
  • AI: the embedding worker starts on the first smart-add input or 4 s after the page opens, never during start-up.
  • Privacy: the cache is scoped to the logged-in user (a different user id wipes it) and wiped on every logout or session loss. Writes are quota-safe.

Tests: +30 unit tests (callApiCached, offlineDb owner/quota, store logout wipe, offline toasts, appRefresh, SW registration/update toast, lazy worker, banner). Full suite 1526 passing, build green. Verified live with Playwright against the production review container: SW controls the page and caches the shell (no .wasm); with the server delayed by 4 s the list overview appeared after ~300 ms; a cold start of a list URL in offline mode showed the overview and the list with the read-only banner.

Decisions / not done: no phase split. Storage limit: only the user's own list data in localStorage (no photos/avatars). "Last opened list": the app reopens the URL it was on, or the configured default list. It does not additionally remember the last list when no default is set. Security review: no findings. The cached admin/password flags are UI hints only (the server authorizes everything, and an admin reset revokes sessions -> cache wiped).

Done (go loop, 2026-09-29). Commits on master: a75a27c9, 6204cd28, e0653187 (plus memory 918688b7). Scope: - App shell on the device: in production builds the service worker serves index.html stale-while-revalidate and the hashed assets cache-first. It never caches /api, /health or the AI .wasm. Once a new build has been fetched in the background, a toast offers "Reload". - Instant start: the account gate (admin and password-change flags), default list, list overview (all 4 list types, list order, group headings) and the main content of every list type (todos + categories/labels, priority matrix, shopping, pantry incl. labels, master pack items/labels, due overview) are cached locally. They are shown immediately and then replaced by the server answer (callApiCached; the cache is used only on the first load per session, so a refetch after an edit never flashes older data). - Continuous sync: refresh on return to the app (after >= 30 s away), every 5 min while visible, and on reconnect. - Offline: uncached reads fail quietly. Changes that can't be queued (everything except shopping/pantry) show "This change needs an internet connection ...". The todo, priority, master pack and due pages show a read-only offline banner. - AI: the embedding worker starts on the first smart-add input or 4 s after the page opens, never during start-up. - Privacy: the cache is scoped to the logged-in user (a different user id wipes it) and wiped on every logout or session loss. Writes are quota-safe. Tests: +30 unit tests (callApiCached, offlineDb owner/quota, store logout wipe, offline toasts, appRefresh, SW registration/update toast, lazy worker, banner). Full suite 1526 passing, build green. Verified live with Playwright against the production review container: SW controls the page and caches the shell (no .wasm); with the server delayed by 4 s the list overview appeared after ~300 ms; a cold start of a list URL in offline mode showed the overview and the list with the read-only banner. Decisions / not done: no phase split. Storage limit: only the user's own list data in localStorage (no photos/avatars). "Last opened list": the app reopens the URL it was on, or the configured default list. It does not additionally remember the last list when no default is set. Security review: no findings. The cached admin/password flags are UI hints only (the server authorizes everything, and an admin reset revokes sessions -> cache wiped).
lena closed this issue 2026-09-29 20:16:23 +02:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
robert/todo#220
No description provided.