Commit Graph
3 Commits
Author SHA1 Message Date
Keith SmithandClaude Sonnet 5 922d4d1bf2 Add offline task CRUD, phase 1 (PWA)
Lets users create, edit, and complete tasks with no network connection,
queued locally in IndexedDB and replayed via the existing /api/sync/
protocol once back online -- the same protocol the native Android app
already uses, with zero backend changes. The service worker now routes
the dashboard's offline fallback to a small client-rendered task app
instead of the generic "you're offline" page; every other route keeps
the generic fallback.

Conflicts (server row touched elsewhere since last sync) auto-resolve
as "local wins" rather than surfacing a resolution UI. Scope is title/
status/priority/due-date only -- tags, subtasks, time tracking, and
recurrence editing offline are out of scope for this phase.

Also adds the first real test coverage for sync/views.py (previously
untested): new-item creation, soft-delete-bypasses-conflict-check,
conflict detection/discarding, and both resolve_conflict paths.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-04 23:01:47 -06:00
Keith SmithandClaude Sonnet 5 7e905a0566 Add Web Push notifications (PWA)
Wires up the previously-scaffolded VAPID/DeviceToken infrastructure end
to end: browser subscription flow on the Profile page's existing "Push
Notifications" toggle, a service worker push/notificationclick handler,
and server-side sending from the daily task digest. Also broadens that
digest's eligibility query so push-only users (email notifications off)
aren't silently skipped, and adds `generate_vapid_keys` since the pinned
py-vapid's own key generator is broken against current cryptography.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-04 22:30:56 -06:00
Keith SmithandClaude Sonnet 5 30c61351de Make the web app installable as a PWA (Tier 1: app shell + offline fallback)
Adds a manifest, service worker, and branded icons so the site can be
installed to a home screen/desktop, plus an offline fallback page so a
dropped connection shows something friendlier than the browser's default
error. Icons are rasterized from the existing favicon.svg mark via
rsvg-convert. The manifest and service worker are served through small
Django views (not raw static files) so their asset URLs pick up
WhiteNoise's content-hashed filenames in prod/selfhosted, and the service
worker is served from the site root so its scope covers the whole app.

Does not include true offline task data or Web Push notifications --
those are tracked separately as larger follow-up projects.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-04 22:03:12 -06:00