feat: add global weather support
All checks were successful
CI / Lint, typecheck and build (push) Successful in 9m54s
All checks were successful
CI / Lint, typecheck and build (push) Successful in 9m54s
This commit is contained in:
@@ -6,10 +6,11 @@ Wszystkie zewnętrzne źródła danych są wywoływane przez route handlery Next
|
||||
|
||||
| Metoda | Endpoint | Przeznaczenie |
|
||||
| --- | --- | --- |
|
||||
| `GET` | `/api/forecast?latitude={lat}&longitude={lon}` | Zwraca 7-dniową prognozę modelową dla współrzędnych. Łączy IMGW ALARO z Open-Meteo. Niepoprawne współrzędne zwracają `400`, awaria źródła `502`. |
|
||||
| `GET` | `/api/current-weather?latitude={lat}&longitude={lon}®ion={PL\|GLOBAL}` | Zwraca znormalizowane bieżące warunki. Dla `PL` używa IMGW Hybrid, dla `GLOBAL` modelowych warunków Open-Meteo. |
|
||||
| `GET` | `/api/forecast?latitude={lat}&longitude={lon}®ion={PL\|GLOBAL}` | Zwraca 7-dniową prognozę modelową dla współrzędnych. Dla `PL` łączy IMGW ALARO z Open-Meteo, dla `GLOBAL` używa Open-Meteo. Niepoprawne współrzędne zwracają `400`, awaria źródła `502`. |
|
||||
| `GET` | `/api/imgw-current?latitude={lat}&longitude={lon}` | Pobiera surową lokalną analizę IMGW Hybrid dla współrzędnych. Niepoprawne współrzędne zwracają `400`, awaria źródła `502`. |
|
||||
| `GET` | `/api/imgw/{path}` | Proxy allowlistowanych endpointów IMGW `danepubliczne.imgw.pl`. Obsługuje kolekcje `synop`, `hydro`, `meteo`, `warningsmeteo`, `warningshydro`, `product` oraz szczegół `synop/id/{id}`. Nieobsługiwana ścieżka zwraca `404`. |
|
||||
| `GET` | `/api/locations/search?query={query}&language={pl\|en}` | Wyszukuje miejscowości w Polsce przez Open-Meteo Geocoding. Zapytania krótsze niż 2 znaki albo dłuższe niż 80 znaków zwracają pustą listę. |
|
||||
| `GET` | `/api/locations/search?query={query}&language={pl\|en}` | Wyszukuje miejscowości globalnie przez Open-Meteo Geocoding. Wyniki zawierają `countryCode`, `admin1`, `admin2`, `timezone` i region `PL` albo `GLOBAL`. Zapytania krótsze niż 2 znaki albo dłuższe niż 80 znaków zwracają pustą listę. |
|
||||
| `GET` | `/api/locations/reverse?latitude={lat}&longitude={lon}&language={pl\|en}` | Ustala nazwę miejsca dla pozycji GPS przez Nominatim / OpenStreetMap. Współrzędne są zaokrąglane do trzech miejsc po przecinku. |
|
||||
|
||||
## Powiadomienia
|
||||
@@ -19,7 +20,7 @@ Endpointy powiadomień działają w runtime Node.js, bo korzystają z `web-push`
|
||||
| Metoda | Endpoint | Przeznaczenie |
|
||||
| --- | --- | --- |
|
||||
| `GET` | `/api/notifications/vapid-key` | Zwraca publiczny klucz VAPID oraz informację, czy Web Push jest skonfigurowany. |
|
||||
| `POST` | `/api/notifications/subscriptions` | Zapisuje lub aktualizuje subskrypcję Web Push dla urządzenia. Przyjmuje preferencje ostrzeżeń, briefu porannego, briefu wieczornego, lokalizację, język, województwo i opcjonalny powiat TERYT. |
|
||||
| `POST` | `/api/notifications/subscriptions` | Zapisuje lub aktualizuje subskrypcję Web Push dla urządzenia. Przyjmuje region `PL`/`GLOBAL`, preferencje ostrzeżeń, briefu porannego, briefu wieczornego, lokalizację, język, województwo dla `PL` i opcjonalny powiat TERYT. |
|
||||
| `DELETE` | `/api/notifications/subscriptions` | Usuwa subskrypcję Web Push po jej endpointcie. |
|
||||
| `POST` | `/api/notifications/test` | Wysyła powiadomienie testowe na wskazany endpoint subskrypcji. |
|
||||
| `GET` | `/api/notifications/check` | Endpoint harmonogramu sprawdzający nowe ostrzeżenia meteorologiczne IMGW i wysyłający Web Push do pasujących subskrypcji. |
|
||||
@@ -48,6 +49,7 @@ Jeśli `NOTIFICATIONS_CRON_SECRET` nie jest ustawiony, endpointy harmonogramu s
|
||||
| Endpoint | Cache |
|
||||
| --- | --- |
|
||||
| `/api/forecast` | `s-maxage=900`, `stale-while-revalidate=1800` |
|
||||
| `/api/current-weather` | `s-maxage=120`, `stale-while-revalidate=300` |
|
||||
| `/api/imgw-current` | `s-maxage=120`, `stale-while-revalidate=300` |
|
||||
| `/api/imgw/{path}` | `s-maxage=300`, `stale-while-revalidate=600` |
|
||||
| `/api/locations/search` | `s-maxage=86400`, `stale-while-revalidate=604800` |
|
||||
|
||||
@@ -54,7 +54,7 @@ Service worker:
|
||||
|
||||
- cache'uje powłokę aplikacji,
|
||||
- obsługuje fallback `/offline` dla nawigacji,
|
||||
- cache'uje wybrane odpowiedzi API: `/api/imgw/*`, `/api/imgw-current`, `/api/forecast`,
|
||||
- cache'uje wybrane odpowiedzi API: `/api/imgw/*`, `/api/imgw-current`, `/api/current-weather`, `/api/forecast`,
|
||||
- obsługuje zdarzenia `push` i kliknięcia w powiadomienia.
|
||||
|
||||
Rejestracja service workera działa w buildzie produkcyjnym.
|
||||
@@ -66,6 +66,7 @@ Interfejs jest dostępny po polsku i angielsku. Teksty są w `lib/i18n.tsx`. Naz
|
||||
## Zasady Integracji
|
||||
|
||||
- Dane zewnętrzne przechodzą przez route handlery Next.js.
|
||||
- IMGW pozostaje źródłem bieżących pomiarów, hydro i ostrzeżeń.
|
||||
- Prognoza modelowa jest opisana oddzielnie i nie jest przedstawiana jako pomiar IMGW.
|
||||
- IMGW pozostaje źródłem bieżących pomiarów, hydro i ostrzeżeń dla Polski.
|
||||
- Poza Polską Open-Meteo jest źródłem modelowych bieżących warunków i prognozy.
|
||||
- Prognoza modelowa jest opisana oddzielnie i nie jest przedstawiana jako pomiar IMGW ani oficjalny alert.
|
||||
- Braki danych są pokazywane jawnie, bez generowania fikcyjnych wartości.
|
||||
|
||||
@@ -18,13 +18,27 @@
|
||||
|
||||
IMGW jest traktowane jako źródło bieżących pomiarów, hydro i ostrzeżeń. Prognoza modelowa jest w interfejsie rozdzielona od pomiarów.
|
||||
|
||||
IMGW jest używane tylko dla lokalizacji w Polsce. Dla lokalizacji globalnych oficjalne ostrzeżenia IMGW, dane hydrologiczne IMGW, TERYT i powiatowe filtrowanie ostrzeżeń są niedostępne.
|
||||
|
||||
## Open-Meteo
|
||||
|
||||
Open-Meteo Forecast API (`https://api.open-meteo.com/v1/forecast`) dostarcza pełny 7-dniowy horyzont prognozy, prawdopodobieństwo opadu i fallback, jeśli IMGW ALARO nie odpowiada.
|
||||
Open-Meteo Forecast API (`https://api.open-meteo.com/v1/forecast`) dostarcza pełny 7-dniowy horyzont prognozy, prawdopodobieństwo opadu i fallback, jeśli IMGW ALARO nie odpowiada. Poza Polską dostarcza także modelowe warunki bieżące dla dashboardu.
|
||||
|
||||
Open-Meteo Geocoding API (`https://geocoding-api.open-meteo.com/v1/search`) służy do wyszukiwania miejscowości w Polsce.
|
||||
Open-Meteo Geocoding API (`https://geocoding-api.open-meteo.com/v1/search`) służy do globalnego wyszukiwania miejscowości. Wynik zawiera m.in. `countryCode`, `admin1`, `admin2`, `timezone` i współrzędne, które aplikacja zapisuje w modelu lokalizacji.
|
||||
|
||||
Przed większym lub komercyjnym wdrożeniem należy sprawdzić aktualne warunki korzystania z Open-Meteo albo zastąpić usługę własnym dostawcą.
|
||||
Przed większym, publicznym lub komercyjnym wdrożeniem należy sprawdzić aktualne warunki korzystania, limity i licencję Open-Meteo albo zastąpić usługę własnym dostawcą.
|
||||
|
||||
## Capabilities per Region
|
||||
|
||||
| Capability | Polska | Global |
|
||||
| --- | --- | --- |
|
||||
| Bieżące warunki | IMGW Hybrid + fallback `synop` | Open-Meteo model |
|
||||
| Prognoza godzinowa | IMGW ALARO + Open-Meteo | Open-Meteo |
|
||||
| Prognoza dzienna | IMGW ALARO/Open-Meteo | Open-Meteo |
|
||||
| Oficjalne ostrzeżenia | IMGW | niedostępne |
|
||||
| Filtrowanie powiatowe | TERYT | niedostępne |
|
||||
| Briefy | tak | tak, bez oficjalnych alertów |
|
||||
| Push alerty oficjalne | IMGW | niedostępne |
|
||||
|
||||
## Nominatim / OpenStreetMap
|
||||
|
||||
@@ -43,12 +57,13 @@ Przed wdrożeniem o większym ruchu należy sprawdzić aktualną politykę użyc
|
||||
| Dane | Cache |
|
||||
| --- | --- |
|
||||
| IMGW Hybrid | 120 sekund, `stale-while-revalidate=300` |
|
||||
| Modelowe warunki bieżące Open-Meteo | 120 sekund, `stale-while-revalidate=300` |
|
||||
| Prognoza modelowa | 900 sekund, `stale-while-revalidate=1800` |
|
||||
| Proxy IMGW `danepubliczne.imgw.pl` | 300 sekund, `stale-while-revalidate=600` |
|
||||
| Wyszukiwanie miejscowości | 24 godziny, `stale-while-revalidate=7 dni` |
|
||||
| Reverse geocoding | 24 godziny, `stale-while-revalidate=7 dni` |
|
||||
|
||||
Service worker dodatkowo może cache'ować odpowiedzi `GET` dla `/api/imgw/*`, `/api/imgw-current` i `/api/forecast`, aby ostatnio pobrane dane były dostępne przy problemach z siecią.
|
||||
Service worker dodatkowo może cache'ować odpowiedzi `GET` dla `/api/imgw/*`, `/api/imgw-current`, `/api/current-weather` i `/api/forecast`, aby ostatnio pobrane dane były dostępne przy problemach z siecią.
|
||||
|
||||
## Ograniczenia Źródeł
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
Powiadomienia obejmują:
|
||||
|
||||
- nowe ostrzeżenia meteorologiczne IMGW,
|
||||
- nowe ostrzeżenia meteorologiczne IMGW dla Polski,
|
||||
- poranny brief dnia,
|
||||
- wieczorny brief z prognozą na jutro,
|
||||
- testowe powiadomienie wysyłane z `/settings`.
|
||||
@@ -44,7 +44,8 @@ Jeśli zmienna nie jest ustawiona, aplikacja używa `./data/wtr.sqlite` względe
|
||||
Subskrypcja Web Push zapisuje:
|
||||
|
||||
- endpoint subskrypcji przeglądarki,
|
||||
- województwo,
|
||||
- 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,
|
||||
@@ -56,6 +57,8 @@ Subskrypcja Web Push zapisuje:
|
||||
|
||||
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:
|
||||
@@ -84,6 +87,7 @@ Domyślna konfiguracja:
|
||||
|
||||
```bash
|
||||
NOTIFICATIONS_WARNING_INTERVAL_MINUTES=5
|
||||
NOTIFICATIONS_BRIEF_INTERVAL_MINUTES=5
|
||||
NOTIFICATIONS_MORNING_BRIEF_TIME=07:00
|
||||
NOTIFICATIONS_TOMORROW_BRIEF_TIME=18:00
|
||||
```
|
||||
@@ -91,8 +95,9 @@ NOTIFICATIONS_TOMORROW_BRIEF_TIME=18:00
|
||||
Worker:
|
||||
|
||||
- sprawdza nowe ostrzeżenia co 5 minut,
|
||||
- po 07:00 czasu `Europe/Warsaw` wywołuje `/api/notifications/daily-brief`,
|
||||
- po 18:00 czasu `Europe/Warsaw` wywołuje `/api/notifications/tomorrow-brief`,
|
||||
- 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.
|
||||
|
||||
@@ -2,9 +2,29 @@
|
||||
|
||||
`wtr.` rozdziela bieżące pomiary, lokalną analizę IMGW Hybrid, prognozę modelową i ostrzeżenia. Prognoza nie jest przedstawiana jako pomiar IMGW.
|
||||
|
||||
## Region i Kontrakt Danych
|
||||
|
||||
Aplikacja rozpoznaje dwa regiony pogodowe:
|
||||
|
||||
- `PL` - lokalizacje w Polsce,
|
||||
- `GLOBAL` - wszystkie pozostałe lokalizacje.
|
||||
|
||||
Region jest częścią modelu lokalizacji i odpowiedzi pogodowych. UI powinien bazować na capabilities i metadanych źródła, a nie rozsiewać własne warunki po kraju.
|
||||
|
||||
Każda znormalizowana odpowiedź bieżących warunków zawiera metadane:
|
||||
|
||||
- `source`, np. `IMGW` albo `OPEN_METEO`,
|
||||
- `sourceLabel` dla UI,
|
||||
- `sourceType`, np. `hybrid` albo `model`,
|
||||
- `isOfficial`,
|
||||
- `region`,
|
||||
- `fetchedAt` i `measuredAt`/czas aktualizacji.
|
||||
|
||||
## Bieżące Warunki
|
||||
|
||||
Dashboard hero korzysta z publicznego endpointu IMGW Hybrid oficjalnego portalu `meteo.imgw.pl` przez `/api/imgw-current`.
|
||||
Dashboard hero korzysta z `/api/current-weather`.
|
||||
|
||||
Dla `PL` endpoint używa publicznego endpointu IMGW Hybrid oficjalnego portalu `meteo.imgw.pl`. Dla `GLOBAL` używa modelowych bieżących warunków Open-Meteo i nie opisuje ich jako pomiaru.
|
||||
|
||||
Normalizacja w `lib/imgw-current-api.ts`:
|
||||
|
||||
@@ -19,13 +39,15 @@ Jeśli Hybrid nie dostarcza pełnych danych, UI jawnie korzysta z fallbacku `syn
|
||||
|
||||
## Prognoza Modelowa
|
||||
|
||||
Route handler `/api/forecast` pobiera równolegle:
|
||||
Route handler `/api/forecast` dla `PL` pobiera równolegle:
|
||||
|
||||
- pełne 7 dni Open-Meteo,
|
||||
- godzinowe IMGW ALARO.
|
||||
|
||||
W godzinach pokrytych przez ALARO parametry IMGW mają pierwszeństwo. Open-Meteo dostarcza prawdopodobieństwo opadu i dalszy horyzont do 7 dni. Awaria ALARO pozostawia działający fallback Open-Meteo.
|
||||
|
||||
Dla `GLOBAL` route handler nie odpytuje IMGW ALARO i używa Open-Meteo z `timezone=auto`.
|
||||
|
||||
Dashboard pokazuje:
|
||||
|
||||
- regułowy brief dnia,
|
||||
@@ -38,6 +60,8 @@ Widok szczegółowy dnia korzysta z pełnego zestawu godzin dla wybranej daty.
|
||||
|
||||
Ostrzeżenia meteorologiczne IMGW zawierają kody powiatów TERYT. Ostrzeżenia hydrologiczne zawierają jawne województwa. Normalizacja odbywa się przez `lib/provinces.ts` i `lib/warning-regions.ts`.
|
||||
|
||||
Ostrzeżenia są capability tylko dla `PL`. Dla `GLOBAL` widok `/warnings` pokazuje stan niedostępności oficjalnych ostrzeżeń i nie traktuje prognozy modelowej jako oficjalnego alertu.
|
||||
|
||||
Zasady UI:
|
||||
|
||||
- lokalny obszar jest priorytetyzowany,
|
||||
@@ -55,6 +79,8 @@ Brief dnia analizuje najbliższe 24 godziny prognozy modelowej oraz aktywne i na
|
||||
|
||||
Brief na jutro analizuje pełny jutrzejszy dzień prognozy. Może informować o burzach na podstawie kodów pogodowych modelu nawet wtedy, gdy IMGW nie opublikowało oficjalnego ostrzeżenia.
|
||||
|
||||
Dla `GLOBAL` briefy korzystają z Open-Meteo i pomijają oficjalne ostrzeżenia IMGW.
|
||||
|
||||
## Opad i Pomiary Synoptyczne
|
||||
|
||||
Pole `synop.suma_opadu` jest akumulowaną sumą opadu. Nie oznacza, że pada w tej chwili, i nie steruje animacją deszczu.
|
||||
|
||||
Reference in New Issue
Block a user