Files
wtr/docs/notifications.md
zv f15ebd28dc
All checks were successful
CI / Lint, test, typecheck and build (push) Successful in 10m45s
fix: preserve brief notification preferences
2026-07-04 15:28:58 +02:00

4.5 KiB

Powiadomienia Web Push

Powiadomienia obejmują:

  • nowe ostrzeżenia meteorologiczne IMGW dla Polski,
  • poranny brief dnia,
  • wieczorny brief z prognozą na jutro,
  • testowe powiadomienie wysyłane z /settings.

Konfiguracja użytkownika znajduje się w widoku /settings.

Wymagania

Do wysyłki Web Push potrzebne są klucze VAPID:

WEB_PUSH_VAPID_PUBLIC_KEY=
WEB_PUSH_VAPID_PRIVATE_KEY=
WEB_PUSH_VAPID_SUBJECT=mailto:admin@example.com

Klucze można wygenerować poleceniem:

npx web-push generate-vapid-keys

Endpointy harmonogramu wymagają też sekretu crona w produkcji:

NOTIFICATIONS_CRON_SECRET=

Subskrypcje Web Push i historia wysyłek są zapisywane w SQLite:

WTR_DATABASE_PATH=./data/wtr.sqlite

Jeśli zmienna nie jest ustawiona, aplikacja używa ./data/wtr.sqlite względem katalogu projektu.

Preferencje Subskrypcji

Subskrypcja Web Push zapisuje:

  • endpoint subskrypcji przeglądarki,
  • region pogodowy PL albo GLOBAL,
  • województwo dla oficjalnych ostrzeżeń IMGW w Polsce,
  • język interfejsu,
  • czy ostrzeżenia są aktywne,
  • czy aktywny jest brief poranny,
  • czy aktywny jest brief na jutro,
  • współrzędne i nazwę lokalizacji,
  • opcjonalny powiat TERYT,
  • wybraną jednostkę temperatury dla briefów wysyłanych z serwera,
  • wybraną jednostkę wiatru dla briefów wysyłanych z serwera.

Ostrzeżenia meteo są filtrowane po powiecie TERYT, jeśli lokalizacja go dostarcza. W przeciwnym razie używany jest fallback wojewódzki.

Dla subskrypcji GLOBAL oficjalne ostrzeżenia IMGW są wyłączone, province może być puste, a powiadomienia mogą obejmować brief poranny i brief na jutro oparte o prognozę modelową Open-Meteo.

Worker Self-Hosted

Worker powiadomień uruchamia się osobno od aplikacji:

npm run notifications:worker

Wymaga równolegle działającej aplikacji Next.js. Domyślnie odpytuje:

http://127.0.0.1:3000

Jeśli aplikacja działa pod innym adresem albo portem, ustaw:

WTR_APP_URL=http://127.0.0.1:4000

Worker wczytuje .env i .env.local. Zmienne ustawione bezpośrednio w shellu mają pierwszeństwo.

Harmonogram

Domyślna konfiguracja:

NOTIFICATIONS_WARNING_INTERVAL_MINUTES=5
NOTIFICATIONS_BRIEF_INTERVAL_MINUTES=5
NOTIFICATIONS_MORNING_BRIEF_TIME=07:00
NOTIFICATIONS_TOMORROW_BRIEF_TIME=18:00

Worker:

  • sprawdza nowe ostrzeżenia co 5 minut,
  • co 5 minut odpytuje endpointy briefów,
  • endpoint /api/notifications/daily-brief wysyła po 07:00 lokalnego czasu zapisanego w subskrypcji,
  • endpoint /api/notifications/tomorrow-brief wysyła po 18:00 lokalnego czasu zapisanego w subskrypcji,
  • nie blokuje jednego harmonogramu błędem drugiego.

Endpointy harmonogramu nie uruchamiają się same bez workera albo zewnętrznego crona.

Endpointy briefów zwracają diagnostykę JSON z polami subscriptions, eligibleSubscriptions, sent, skipped, failed oraz skippedReasons. Dla problemów z harmonogramem najważniejsze powody to:

  • disabled - subskrypcja istnieje, ale dany brief nie jest włączony w zapisanym stanie serwera,
  • missingLocation - brief jest włączony, ale subskrypcja nie ma współrzędnych,
  • beforeTime - lokalny czas subskrypcji jest jeszcze przed skonfigurowaną godziną,
  • alreadySent - brief dla tej lokalnej daty został już oznaczony jako wysłany,
  • noBrief - prognoza nie pozwoliła zbudować treści briefu.

Zewnętrzny Cron

Jeśli nie używasz npm run notifications:worker, zewnętrzny cron powinien wywoływać:

GET /api/notifications/check
GET /api/notifications/daily-brief
GET /api/notifications/tomorrow-brief

W produkcji dodaj jeden z nagłówków:

Authorization: Bearer <NOTIFICATIONS_CRON_SECRET>
x-cron-secret: <NOTIFICATIONS_CRON_SECRET>

Platformy

  • iOS/iPadOS wymaga dodania PWA do ekranu początkowego i uruchomienia aplikacji z ikony.
  • Android i desktop nie są blokowane wymogiem standalone, jeśli przeglądarka obsługuje Web Push.
  • GPS i powiadomienia wymagają bezpiecznego kontekstu HTTPS poza wyjątkami typu localhost.

Ograniczenia

lib/push-store.ts przechowuje subskrypcje i historię wysyłek w lokalnym SQLite przez better-sqlite3. Dane przetrwają restart procesu, jeśli plik wskazany przez WTR_DATABASE_PATH znajduje się w trwałym katalogu. Na self-hostingu warto backupować plik bazy razem z plikami -wal i -shm, jeśli istnieją.

Powiadomienie testowe jest wysyłane na konkretny endpoint subskrypcji przekazany z /settings, a nie broadcastowane do wszystkich urządzeń.