From c454423d4d18488f67c7b313fdd0a8d02cf288f6 Mon Sep 17 00:00:00 2001 From: Keith Smith Date: Sat, 5 Sep 2026 08:36:49 -0600 Subject: [PATCH] Sync offline cache on every page load, not just every 2 minutes Online-side mutations (e.g. deleting a tag) only update the server, not IndexedDB, so a throttled background sync could leave the offline cache stale for up to two minutes. Going offline in that window resurrected deleted/stale data (e.g. a deleted tag reappearing). Removing the throttle so every real page load pulls fresh state keeps the offline cache in sync with whatever was just done online. Co-Authored-By: Claude Sonnet 5 --- static/js/app.js | 12 ++++++++++-- static/js/offline-sync.js | 12 ------------ templates/base.html | 4 ++-- templates/sw.js | 2 +- 4 files changed, 13 insertions(+), 17 deletions(-) diff --git a/static/js/app.js b/static/js/app.js index 2c00011..5bcf08b 100644 --- a/static/js/app.js +++ b/static/js/app.js @@ -3,12 +3,20 @@ * Handles theme toggle, task selection, mobile menus, and AJAX operations */ -document.addEventListener('DOMContentLoaded', function() { +document.addEventListener('DOMContentLoaded', async function() { initTheme(); initTaskSelection(); initTimerDisplays(); registerServiceWorker(); - maybeBackgroundSync(); + // Every real page load is a chance for the online UI to have mutated + // something (a tag delete, a task edit) that IndexedDB doesn't know + // about yet - sync unconditionally (no throttle) so the offline cache + // never lags behind what the user just did while online. The server's + // own rate limit (SyncRateThrottle) is the backstop against excess calls. + const pushedChanges = await runBackgroundSync(); + if (pushedChanges) { + window.location.reload(); + } }); window.addEventListener('online', async function() { diff --git a/static/js/offline-sync.js b/static/js/offline-sync.js index 056641c..32c8866 100644 --- a/static/js/offline-sync.js +++ b/static/js/offline-sync.js @@ -5,8 +5,6 @@ * network-loaded page (never from the cached offline app). */ -const BACKGROUND_SYNC_MIN_INTERVAL_MS = 2 * 60 * 1000; - // Bump this whenever a previously-untracked entity type starts being synced // (e.g. tags/time_entries were added after tasks-only syncing already // shipped). /api/sync/ only returns rows changed since a device's last sync @@ -173,13 +171,3 @@ async function runBackgroundSync() { return hadPendingChanges || forceFullResync; } -async function maybeBackgroundSync() { - const lastSyncAt = await getMeta('last_sync_at'); - if (lastSyncAt && Date.now() - new Date(lastSyncAt).getTime() < BACKGROUND_SYNC_MIN_INTERVAL_MS) { - return; - } - const pushedChanges = await runBackgroundSync(); - if (pushedChanges) { - window.location.reload(); - } -} diff --git a/templates/base.html b/templates/base.html index ad6fdb9..c97f441 100644 --- a/templates/base.html +++ b/templates/base.html @@ -148,8 +148,8 @@ {% endblock %} - - + + {% block extra_js %}{% endblock %} diff --git a/templates/sw.js b/templates/sw.js index b85a8f6..4d173b1 100644 --- a/templates/sw.js +++ b/templates/sw.js @@ -1,4 +1,4 @@ -{% load static %}const CACHE_NAME = 'keepitgoing-shell-v7'; +{% load static %}const CACHE_NAME = 'keepitgoing-shell-v8'; const OFFLINE_URL = '{% url "offline" %}'; const OFFLINE_TASKS_URL = '{% url "offline-tasks" %}';