Files
wtr/docs/weather-logic.md
zv 2182297adc
All checks were successful
CI / Lint, typecheck and build (push) Successful in 9m54s
feat: add global weather support
2026-06-14 15:59:14 +02:00

152 lines
6.2 KiB
Markdown

# Logika Pogody i Fallbacki
`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 `/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`:
- bierze pod uwagę tylko rekordy `Type_Ten_Minutes` i `Type_Hour`,
- wymaga realnych wartości liczbowych dla pełnego rekordu pogodowego,
- nie traktuje `null` jako kompletnej wartości,
- preferuje pełny rekord 10-minutowy,
- jeśli pełny rekord 10-minutowy jest o ponad 2 godziny starszy od pełnego rekordu godzinowego, wybiera świeższy rekord godzinowy,
- zachowuje lokalny opad MERGE jako częściową analizę, jeśli nie ma pełnych parametrów.
Jeśli Hybrid nie dostarcza pełnych danych, UI jawnie korzysta z fallbacku `synop`. Gdy najbliższa stacja jest oddalona o co najmniej 30 km, aplikacja ostrzega, że lokalne warunki mogą się różnić.
## Prognoza Modelowa
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,
- najbliższe 24 przyszłe godziny,
- wykresy pełnego bieżącego dnia.
Widok szczegółowy dnia korzysta z pełnego zestawu godzin dla wybranej daty.
## Ostrzeżenia
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,
- ostrzeżenia meteo są pokazywane przed hydrologicznymi,
- jeśli lokalizacja ma powiat TERYT, meteo jest filtrowane po powiecie,
- jeśli powiat nie jest znany, stosowany jest fallback wojewódzki,
- dashboard pokazuje kompaktowo tylko aktywne i nadchodzące ostrzeżenia meteo dla wybranego obszaru,
- wygasłe ostrzeżenia są filtrowane po `validTo` względem czasu przeglądarki.
## Briefy
Brief dnia i brief na jutro są generowane deterministycznie w `lib/weather-brief.ts`. Nie są odpowiedzią modelu AI i nie wymagają klucza OpenAI API.
Brief dnia analizuje najbliższe 24 godziny prognozy modelowej oraz aktywne i nadchodzące ostrzeżenia meteo dla obszaru użytkownika.
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.
IMGW Hybrid dostarcza m.in. opad 10-minutowy. Ten parametr jest prezentowany oddzielnie od akumulowanej sumy opadu stacji.
## Stany Pogody
Prognoza godzinowa i dzienna rozpoznaje:
| Stan | Opis w interfejsie |
| --- | --- |
| `clear` | Bezchmurnie |
| `partlyCloudy` | Częściowe zachmurzenie |
| `cloudy` | Pochmurno |
| `fog` | Mgła |
| `drizzle` | Mżawka |
| `rain` | Opady deszczu |
| `snow` | Opady śniegu |
| `thunderstorm` | Burza |
| `unknown` | Brak opisu |
Bieżąca analiza IMGW Hybrid rozpoznaje bezpośrednio opad deszczu, śnieg i burzę. Dashboard hero używa opisu warunków w następującym priorytecie:
1. bieżące zjawisko z IMGW Hybrid: `Burza`, `Opady śniegu`, `Opady deszczu`,
2. silny wiatr od `8 m/s`: `Silny wiatr`,
3. bieżący kod pogody i zachmurzenie z IMGW Hybrid,
4. najbliższa godzina prognozy modelowej, jeśli Hybrid nie daje opisu nieba,
5. wysoka wilgotność od `90%`: `Wilgotno`,
6. fallback: `Pogodnie`.
Pole `Cloud` z IMGW Hybrid jest używane jako opis nieba:
| Cloud | Opis w hero |
| --- | --- |
| `>= 75` | Pochmurno |
| `>= 25` | Częściowe zachmurzenie |
| `< 25` | brak osobnego opisu zachmurzenia |
Jednostki temperatury i wiatru wybierane w `/settings` dotyczą prezentacji w UI, briefach i powiadomieniach. Dane źródłowe oraz progi logiki pogody pozostają liczone w `°C` i `m/s`.
## Mood i Efekty Wizualne
Hero aktualnej pogody używa uproszczonego moodu do wyboru ikony, tekstu i małego akcentu stanu.
| Mood | Reguła |
| --- | --- |
| `night` | godzina przed `06:00` lub od `21:00` |
| `wind` | wiatr od `8 m/s` |
| `cold` | temperatura do `3°C` |
| `cloudy` | wilgotność od `80%` |
| `warm` | temperatura od `20°C` |
| `mild` | pozostałe przypadki |
Warstwa efektów wizualnych jest ograniczona do subtelnych efektów informacyjnych: kropli przy lokalnym opadzie oraz błysku przy burzy. Mood hero jest heurystyką, a nie pełną klasyfikacją sterowaną kodem warunków IMGW Hybrid.
## Podgląd Efektów w Development
W trybie deweloperskim można wymusić samą nakładkę efektu na karcie pogody przez parametr URL. Nie zmienia to danych pogodowych, temperatury, opisu ani ikon.
```text
/?effect=rain
/?effect=thunderstorm
/?effect=storm
/?effect=none
```
Ten mechanizm działa tylko przy `NODE_ENV=development`, np. podczas `npm run dev`. Produkcyjny build ignoruje te parametry i używa wyłącznie rzeczywistych danych pogodowych.