feat(notify): web push as a notification channel
MindSift CI & Docker Release / Build, Test in Container & Push (push) Successful in 2m15s

- VAPID keys from VAPID_* or generated once (push_keys, migration 9);
  devices in push_subscriptions, forgotten on 404/410 from the push service
- push column for every event (also due tasks) and the daily summary,
  bundles as one notification; /push/key, /devices, /subscribe,
  /unsubscribe, /test
- settings: switch push on per device, test it, see the devices; the
  service worker shows notifications and focuses MindSift on click
- tests decrypt a sent push like a browser (RFC 8291) and check VAPID

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
sandrodachandClaude Opus 5.5 committed 2026-10-30 21:21:55 +01:00
1 parent 1a49e6b304
commit 38b8c92899
27 files changed
+918 -27

No files matched your search

+7
View File
@@ -143,6 +143,9 @@ func (s *Server) startAlarmTicker() {
if set.Events.Due.Webhook {
channels = append(channels, "webhook")
}
if set.Events.Due.Push {
channels = append(channels, "push")
}
if a.AlarmEmail == "" {
a.AlarmEmail = a.UserEmail
}
@@ -166,6 +169,10 @@ func (s *Server) startAlarmTicker() {
sentAny = true
}
}
case "push":
if err := s.sendPush(a.UserID, pushMessage{Title: "⏰ Aufgabe fällig", Body: a.Title + " – " + due, URL: "/", Tag: "task-" + a.TaskID}); err == nil {
sentAny = true
}
case "webhook":
if a.CustomWebhookURL != "" {
if err := s.sendCustomWebhookNotification(a.CustomWebhookURL, "task_due", a.Title, desc, a.DueDate, a.Priority); err == nil {