Fix: Offline-Pfote — Step 2+3 tolerant, mehr Prefetch, SW by-v1088

Steps wurden nicht grün weil Probes zu strikt waren (alle 7 Module
bzw. 3 URL-Patterns erforderlich) — Cache-Inhalt zum Refresh-
Zeitpunkt oft unvollständig.

- Step 2 toleriert 1 fehlendes Page-Modul (have >= want-1)
- Step 3 verlangt nur noch Profil ODER welcome-dashboard PLUS Diary
  ODER Health (nicht beides)
- Neuer _prefetchPages() lädt alle 10 Page-Module proaktiv beim
  App-Start — unabhängig von SW-Install-Status
- _prefetchData() wird jetzt mehrmals retried (2s, 5s, 10s, 20s),
  damit hund-spezifische Daten geholt werden sobald
  _appState.activeDog gesetzt ist
This commit is contained in:
rene 2026-05-26 15:52:20 +02:00
parent 87462cb2fe
commit 03725d6682
5 changed files with 39 additions and 24 deletions

View file

@ -410,7 +410,7 @@ async def serve_media(path: str, request: _Request):
raise _HE(404, "Nicht gefunden.")
return _media_response(filepath)
APP_VER = "1087" # muss mit APP_VER in app.js übereinstimmen
APP_VER = "1088" # muss mit APP_VER in app.js übereinstimmen
@app.get("/.well-known/assetlinks.json")
async def assetlinks():

View file

@ -101,9 +101,9 @@
</script>
<!-- CSS: Reihenfolge ist wichtig — ?v= zwingt Browser zur Neuladung -->
<link rel="stylesheet" href="/css/design-system.css?v=1087">
<link rel="stylesheet" href="/css/layout.css?v=1087">
<link rel="stylesheet" href="/css/components.css?v=1087">
<link rel="stylesheet" href="/css/design-system.css?v=1088">
<link rel="stylesheet" href="/css/layout.css?v=1088">
<link rel="stylesheet" href="/css/components.css?v=1088">
</head>
<body>
@ -625,11 +625,11 @@
<div id="modal-container"></div>
<!-- JS: Reihenfolge ist wichtig — erst Basis, dann Features -->
<script src="/js/api.js?v=1087"></script>
<script src="/js/ui.js?v=1087"></script>
<script src="/js/app.js?v=1087"></script>
<script src="/js/worlds.js?v=1087"></script>
<script src="/js/offline-indicator.js?v=1087"></script>
<script src="/js/api.js?v=1088"></script>
<script src="/js/ui.js?v=1088"></script>
<script src="/js/app.js?v=1088"></script>
<script src="/js/worlds.js?v=1088"></script>
<script src="/js/offline-indicator.js?v=1088"></script>
<!-- Feature-Seiten werden lazy geladen -->

View file

@ -3,7 +3,7 @@
Router, State-Management, Navigation, Initialisierung.
============================================================ */
const APP_VER = '1087'; // ← bei jedem Deploy mit Frontend-Änderungen erhöhen
const APP_VER = '1088'; // ← bei jedem Deploy mit Frontend-Änderungen erhöhen
const APP_VERSION = '1.6.0'; // ← semantische Version, wird bei make release gesetzt
window.APP_VER = APP_VER; // global verfügbar für andere Module (z.B. offline-indicator)
window.APP_VERSION = APP_VERSION;

View file

@ -31,13 +31,15 @@ window.OfflineIndicator = (() => {
} },
{ step: 2, title: 'Wichtige Seiten',
detail: 'Tagebuch, Karte, Gassi, Erste Hilfe, Notizblock, Ausgaben, Routen',
detail: 'Tagebuch, Gesundheit, Karte, Gassi, Erste Hilfe, Notizen, Ausgaben, Routen',
probe: async () => {
const c = await _staticCache();
if (!c) return false;
const must = ['diary.js','map.js','walks.js','erste-hilfe.js','notes.js','expenses.js','routes.js'];
const want = ['diary.js','health.js','map.js','walks.js','erste-hilfe.js',
'notes.js','expenses.js','routes.js'];
const urls = (await c.keys()).map(r => r.url);
return must.every(name => urls.some(u => u.includes('/js/pages/' + name)));
const have = want.filter(name => urls.some(u => u.includes('/js/pages/' + name)));
return have.length >= want.length - 1; // 1 Toleranz (falls einzelner Fetch fehlschlug)
} },
{ step: 3, title: 'Hund-Daten',
@ -46,9 +48,12 @@ window.OfflineIndicator = (() => {
const c = await caches.open(CACHE_API).catch(() => null);
if (!c) return false;
const urls = (await c.keys()).map(r => r.url);
return urls.some(u => /\/api\/dogs\/\d+(\?|$)/.test(u))
&& urls.some(u => /\/api\/dogs\/\d+\/diary/.test(u))
&& urls.some(u => /\/api\/dogs\/\d+\/health/.test(u));
const hasProfile = urls.some(u => /\/api\/dogs\/\d+(\?|$)/.test(u))
|| urls.some(u => /\/api\/dogs\/\d+\/welcome-dashboard/.test(u));
const hasDiary = urls.some(u => /\/api\/dogs\/\d+\/diary/.test(u));
const hasHealth = urls.some(u => /\/api\/dogs\/\d+\/health/.test(u));
// Profil + mindestens eine Datenquelle (Tagebuch oder Gesundheit)
return hasProfile && (hasDiary || hasHealth);
} },
{ step: 4, title: 'Weitere Listen',
@ -207,15 +212,21 @@ window.OfflineIndicator = (() => {
} catch {}
}
// Daten-Prefetch beim App-Start: Listen die offline brauchbar sein müssen,
// Page-Module proaktiv fetchen — falls SW-Install sie noch nicht alle hatte
function _prefetchPages() {
['diary','health','map','walks','erste-hilfe','notes','expenses','routes','poison','lost']
.forEach(p => fetch(`/js/pages/${p}.js?v=${window.APP_VER}`).catch(() => {}));
}
// Daten-Prefetch: Listen die offline brauchbar sein müssen,
// auch wenn der User die Seiten noch nie geöffnet hat
async function _prefetchData() {
function _prefetchData() {
fetch('/api/expenses').catch(() => {});
fetch('/api/routes').catch(() => {});
fetch('/api/notes').catch(() => {});
// Hund-spezifische Daten nur wenn aktiver Hund bekannt
const dogId = window._appState?.activeDog?.id;
if (dogId) {
fetch(`/api/dogs/${dogId}`).catch(() => {});
fetch(`/api/dogs/${dogId}/health`).catch(() => {});
fetch(`/api/dogs/${dogId}/diary?limit=20`).catch(() => {});
}
@ -223,11 +234,15 @@ window.OfflineIndicator = (() => {
function init() {
refresh();
_prefetchTiles(); // Karten-Tiles (nur wenn GPS schon erlaubt)
_prefetchData(); // Listen-Daten (Expenses, Routes, Notes, Health)
_prefetchPages();
_prefetchTiles();
_prefetchData();
// Wenn der aktive Hund erst nach init() gesetzt wird → nochmal triggern
setTimeout(() => { _prefetchData(); refresh(); }, 3000);
// Mehrere Retries für hund-spezifische Daten — _appState.activeDog wird oft
// erst nach Login/Hunde-Load gesetzt, manchmal mehrere Sekunden nach Init
[2_000, 5_000, 10_000, 20_000].forEach(delay => {
setTimeout(() => { _prefetchData(); refresh(); }, delay);
});
if (navigator.serviceWorker) {
navigator.serviceWorker.addEventListener('message', e => {

View file

@ -4,7 +4,7 @@
============================================================ */
// ← EINZIGE Stelle für die Version — STATIC_ASSETS und CACHE_VERSION leiten sich ab
const VER = '1087';
const VER = '1088';
const CACHE_VERSION = `by-v${VER}`;
const CACHE_STATIC = `${CACHE_VERSION}-static`;
const CACHE_TILES = 'ban-yaro-tiles-v1'; // bleibt über SW-Updates erhalten