Feature: web push slice 1, VAPID keys + subscription store
The foundation for background notifications (docs/webpush-design.md).
- Dependency (approved): web-push for RFC 8292 VAPID JWTs and RFC 8291
payload encryption. Lazy import so a canary that autofollows before
npm ci never crashes on boot (same pattern as @simplewebauthn/server).
- VAPID keys: env (VAPID_PUBLIC_KEY/VAPID_PRIVATE_KEY/VAPID_SUBJECT) wins,
else auto-generated once into storage/.vapid (0600), never regenerated
while the file exists: new keys would invalidate every subscription.
Subject: PUBLIC_BASE_URL, else mailto from SMTP_FROM.
- push_subscriptions table: one row per device, client keys for encrypted
payloads, per-type alert preferences (follow/reply on, like/boost off,
dm on by default), self-pruning on 404/410 in the send path.
- notifyUser/notifySite: honour alert prefs, cap title/body length,
fire-and-forget at call sites (slice 3 wires the triggers).
Changed files:
package.json, package-lock.json
src/config/database.js
- push_subscriptions table (additive)
src/routes/posts.js
- RESERVED_SLUGS: add 'push' (and the missing 'paid') so a post can't
shadow the mounted routes
New file:
src/services/PushService.js
- VAPID key resolve/persist, subscription CRUD, encrypted send with
pruning, notifyUser/notifySite
test/push.test.js
- key autogen (0600, persists, served=stored), subscription CRUD,
upsert-not-duplicate, refuse incomplete payloads
-robo
Co-Authored-By: Claude Opus 4.8 <noreply@…>