Files
ginnoir b89690a9f2 Initial scaffold: tooling, plan, task briefs
- pnpm 10 workspace + TypeScript strict + ESLint flat + Prettier
- CLAUDE.md as canonical brief
- docs/tasks/ — 22 task briefs broken out by phase for sub-sessions
- docs/decisions/ — ADR scaffold

Implements task 01 (repo-init).
2026-05-06 00:05:50 -05:00

1.2 KiB

40 — Web Push (VAPID)

Goal

Subscribe browsers to web push and deliver notifications to them.

Depends on

  • 06 (auth), 50 (PWA shell — needed for iOS to allow push). If 50 isn't done, this task can land but iOS won't fire until then.

Scope

  • pnpm add web-push for server, use built-in PushManager on client.
  • VAPID keys generated once (script: pnpm vapid:generate), stored in .env as VAPID_PUBLIC_KEY / VAPID_PRIVATE_KEY. Document in README.
  • Schema: push_subscriptions (id, user_id, endpoint unique, p256dh, auth, user_agent, created_at).
  • Service worker registers on app load; on user opt-in (button in /settings), prompts permission and stores subscription via server action.
  • Server helper sendPush(userId, { title, body, url }) iterates subscriptions, removes any returning 404/410.

Out of scope

  • Notification preferences per category (defer).
  • ntfy fallback (task 42).

Acceptance criteria

  • Opt-in flow works in Chrome desktop and mobile, plus iOS Safari (when PWA installed).
  • Stale subscriptions are pruned on send failure.
  • Sending a test notification from /settings reaches all of the current user's subscribed devices.