# AGENTS.md ## Projekt `wtr.` to mobilna PWA pogodowa dla Polski. Pokazuje bieżącą analizę IMGW Hybrid, pomiary synoptyczne, dane hydrologiczne i ostrzeżenia z publicznych API IMGW oraz prognozę modelową łączącą IMGW ALARO z Open-Meteo. Open-Meteo Geocoding służy także do wyszukiwania miejscowości, a Nominatim / OpenStreetMap do opcjonalnego reverse geocodingu po zgodzie GPS użytkownika. Stack: Next.js App Router, React, TypeScript, Tailwind CSS, TanStack Query, Zustand, Framer Motion, Recharts, Lucide React i `web-push`. PWA korzysta z manifestu oraz własnego service workera. Najważniejsze katalogi: - `app/` - routing, layout, globalne style i route handlery proxy. - `components/` - komponenty pogody, prognozy, hydro, ostrzeżeń, layoutu, UI i stanów ekranu. - `hooks/` - hooki TanStack Query. - `lib/` - fetchery, normalizacja danych, tłumaczenia, helpery, Web Push i store Zustand. - `types/` - typy danych IMGW, prognozy, lokalizacji oraz powiadomień. - `public/` - manifest, service worker i ikony PWA. ## Komendy Wymagany jest Node.js 20.9 lub nowszy. ```bash npm install npm run dev npm run lint npm run typecheck npm run build npm run start npm run notifications:worker ``` Repozytorium nie ma obecnie skryptu testów ani formattera. `npm run typecheck` uruchamia `tsc --noEmit`, a `npm run build` uruchamia produkcyjny build Next.js. `npm run notifications:worker` uruchamia osobny proces Node do cyklicznego wywoływania endpointów Web Push na self-hostingu; wczytuje `.env` i `.env.local`, ale nadal wymaga równolegle działającego `npm run start` albo poprawnego `WTR_APP_URL`. Nie opisuj ani nie uruchamiaj nieistniejących komend jako standardowego workflow. ## Konwencje kodu - Używaj TypeScript konsekwentnie i importów absolutnych `@/...`. - Komponenty i typy nazywaj `PascalCase`, funkcje oraz hooki `camelCase`; hooki zaczynają się od `use`. - Trzymaj routing w `app/`, komponenty funkcjonalne w odpowiednim podkatalogu `components/`, zapytania Query w `hooks/`, fetchery i normalizację w `lib/`, a typy danych w `types/`. - Dodawaj `"use client"` tylko tam, gdzie komponent lub moduł korzysta z hooków, stanu przeglądarki albo interakcji. - Dane zewnętrzne pobieraj przez route handlery Next.js. Nie omijaj allowlisty w `app/api/imgw/[...path]/route.ts`. - Traktuj IMGW jako źródło bieżących pomiarów, hydro i ostrzeżeń. Prognozę pokazuj oddzielnie jako prognozę modelową preferującą IMGW ALARO i jawnie uzupełnioną przez Open-Meteo. Nie generuj fikcyjnych danych ani nie przedstawiaj prognozy jako pomiaru IMGW. - Dashboard hero korzysta z publicznego endpointu Hybrid oficjalnego portalu IMGW przez `app/api/imgw-current/route.ts`, z fallbackiem do godzinowego `synop`. Hybrid ma krótki cache i dostarcza m.in. opad 10-minutowy; nie przedstawiaj go jako akumulowanej sumy opadu stacji. - Hybrid wybieraj z pierwszego pełnego rekordu analizy zwracanego przez endpoint dla lokalizacji, preferując `Type_Ten_Minutes`, a potem `Type_Hour`. Wymagaj realnych wartości liczbowych; nie traktuj `null` jako pełnego pola i nie opieraj wyboru na zegarze przeglądarki. Jeśli pełny `Type_Ten_Minutes` jest o ponad 2 godziny starszy od pełnego `Type_Hour` z tej samej odpowiedzi, użyj świeższego `Type_Hour`, żeby nie nadpisywać aktualnego fallbacku starym rekordem Hybrid. Jeśli IMGW zwraca wyłącznie lokalny opad MERGE bez pełnych parametrów, zachowuj go jako częściową analizę lokalną, a pozostałe parametry uzupełniaj jawnym fallbackiem `synop`. - W UI rozdzielaj lokalną analizę Hybrid dla współrzędnych miejscowości od kontekstowej informacji o najbliższej stacji pomiarowej. Fallback `synop` oznaczaj jawnie; dla stacji oddalonej o co najmniej 30 km zachowuj ostrzeżenie o możliwej różnicy warunków lokalnych. - Route handler prognozy pobiera pełne 7 dni Open-Meteo oraz godzinowe IMGW ALARO. W godzinach pokrytych przez ALARO parametry IMGW mają pierwszeństwo, Open-Meteo dostarcza prawdopodobieństwo opadu i dalszy horyzont, a awaria ALARO pozostawia działający fallback Open-Meteo. Dashboard pokazuje regułowy brief dnia, najbliższe 24 przyszłe godziny oraz wykresy pełnego bieżącego dnia, a widok szczegółowy dnia korzysta z pełnego zestawu godzin dla wybranej daty. - `synop.suma_opadu` jest akumulowaną sumą opadu. Nie używaj jej jako sygnału, że pada w tej chwili, ani do sterowania animacją deszczu. - Ostrzeżenia hydro zawierają jawne województwa, a ostrzeżenia meteo kody powiatów TERYT. Normalizuj oba warianty przez `lib/provinces.ts` i `lib/warning-regions.ts`; nie filtruj ostrzeżeń wyłącznie po opisach tekstowych. - HTTP `404` z IMGW dla ostrzeżeń z JSON `{"status":false,"message":"No products were found"}` oznacza brak produktów i ma być normalizowany do pustej listy, nie do błędu UI ani błędu workera. - Listy ostrzeżeń zachowują priorytet lokalnego obszaru, a wewnątrz każdej grupy pokazują ostrzeżenia meteorologiczne przed hydrologicznymi. Jeśli lokalizacja ma rozpoznany powiat TERYT, ostrzeżenia meteo filtruj po tym powiecie; w przeciwnym razie stosuj fallback wojewódzki. W obrębie rodzaju zachowuj kolejność publikacji od najnowszych. - Dashboard pokazuje kompaktowo wyłącznie aktywne i nadchodzące ostrzeżenia meteo dla wybranego obszaru. Filtruj je po `validTo` względem czasu przeglądarki i automatycznie usuwaj wygasłe komunikaty bez przeładowania strony. - Brief dnia i brief na jutro generuj deterministycznie w `lib/weather-brief.ts` z prognozy modelowej i ostrzeżeń IMGW. Nie traktuj ich jako odpowiedzi modelu AI i nie wymagaj klucza OpenAI API. Brief na jutro korzysta z pełnego jutrzejszego dnia prognozy i może informować o burzach na podstawie kodów modelu także bez oficjalnego ostrzeżenia IMGW. - Powiadomienia Web Push o ostrzeżeniach meteo, porannym briefie i wieczornym briefie na jutro konfiguruj przez `/settings`, `public/sw.js`, route handlery `app/api/notifications/*`, w tym testowy `/api/notifications/test`, oraz self-hostowany worker `scripts/notification-worker.mjs`. Endpointy harmonogramu nie uruchamiają się same bez workera albo zewnętrznego crona. Wymagają kluczy VAPID w zmiennych środowiskowych. iOS/iPadOS wymaga PWA z ekranu początkowego, ale Android i desktop nie powinny być blokowane wymogiem `standalone`. Obecny `lib/push-store.ts` jest pamięciowy i przed produkcją musi zostać zastąpiony trwałym magazynem subskrypcji. - GPS wymaga świadomej zgody użytkownika i HTTPS. Zaokrąglaj współrzędne przed użyciem i utrzymuj widoczną atrybucję OpenStreetMap dla reverse geocodingu Nominatim. - Normalizuj zewnętrzne odpowiedzi i obsługuj `null`, puste pola oraz błędne wartości. Brak danych pokazuj jawnie zamiast uzupełniać estymacją. - Dla pobierania danych używaj TanStack Query z sensownym `queryKey`, cache i retry. W UI zachowuj loading, error, retry oraz empty states. - Teksty interfejsu dodawaj równolegle po polsku i angielsku w `lib/i18n.tsx`. Nazw stacji i treści IMGW nie tłumacz automatycznie. - Trwałe preferencje użytkownika zapisuj przez istniejący store Zustand w `lib/store.ts` lub istniejące klucze `localStorage`. - Zachowuj mobile-first UI, dostępność klawiatury, `aria-label`, focus states oraz spokojny styl glassmorphism. - Pełnoekranowe warstwy interaktywne zamykaj przyciskiem i klawiszem `Escape`, blokuj przewijanie tła oraz przywracaj fokus po zamknięciu. - Nie edytuj ręcznie `next-env.d.ts`; plik jest generowany przez Next.js. Obsługa błędów: - Route handlery zwracają kontrolowane odpowiedzi JSON z kodem HTTP. - Fetchery w `lib/` rzucają `Error`, a komponenty prezentują czytelny stan błędu i retry. - Projekt nie ma warstwy logowania aplikacyjnego. Nie dodawaj przypadkowych `console.log`. ## Zmiany frontendowe To jest istniejąca aplikacja produktowa. Nie przebudowuj frontendu od zera, jeśli celem jest poprawa wyglądu. Zachowuj routing, przepływ danych, strukturę komponentów i logikę biznesową. Restyle powinien najpierw przechodzić przez globalne style, theme, tokeny, layout oraz komponenty współdzielone, a dopiero później przez pojedyncze widoki. Docelowy kierunek wizualny: - spokojny, praktyczny i produktowy; - nowoczesny, ale bez efektów modnych na siłę; - neutralna baza kolorystyczna i jeden konsekwentny kolor akcentu; - czytelna hierarchia, przewidywalne odstępy i spójne karty; - wygląd nudny w dobrym sensie: dopracowany, czytelny, bez dekoracyjnego szumu. Unikaj: - neonowych kolorów, fioletowo-cyjanowych gradientów i świecących cieni; - losowych dekoracyjnych blobów, nadmiaru blurów i efektów bez funkcji; - przesadnie dużych zaokrągleń oraz niespójnych radiusów między sekcjami; - generycznych sekcji typu SaaS landing page; - arbitralnych kolorów `bg-[#...]`, `text-[#...]`, `border-[#...]` w komponentach; - lokalnych wyjątków stylistycznych, które powodują inny wygląd `/`, `/warnings`, `/hydro` i modali. Przy zmianach UI: - nie dodawaj nowych zależności bez wyraźnego powodu; - nie zmieniaj UX ani przepływu interakcji, chyba że problem jest oczywisty i opiszesz go przed zmianą; - preferuj tokeny Tailwind/theme, klasy użytkowe z `app/globals.css`, `Card`, `Button` i komponenty współdzielone; - ogranicz zakres do najmniejszego zestawu plików potrzebnych do poprawy spójności; - po zmianie sprawdź, czy nie pojawiły się hardcodowane kolory, nowe gradienty, neonowe akcenty, niespójne karty ani zmiany logiki biznesowej; - sprawdź responsywność co najmniej mentalnie dla mobile, tablet i desktop, a przy większych zmianach uruchom aplikację lokalnie. ## Instrukcje dla agenta - Przed zmianą przeczytaj pliki w obszarze funkcji i sprawdź `git status`. - Utrzymuj mały zakres zmian. Nie refaktoruj niezwiązanych modułów i nie cofaj cudzych zmian. - Nie dodawaj mocków jako źródła danych pogodowych. Przy zmianie źródeł API zaktualizuj route handler, typy, normalizację, UI i README. - Przy zmianach PWA sprawdź spójność `public/manifest.json`, `public/sw.js` i rejestracji service workera. - Przed zakończeniem uruchom co najmniej `npm run lint` i `npm run build`. Jeśli dodano testy, uruchom także ich skrypt. - Sprawdź `git diff --check` oraz `git status`. Nie commituj wygenerowanego churnu w `next-env.d.ts`. - Po każdej zmianie rób commit i używaj formatu Conventional Commits, np. `fix: correct warning filtering`. - Ważne decyzje o źródłach danych, ograniczeniach API, uruchamianiu i wdrożeniu dokumentuj krótko w `README.md`. ## Utrzymywanie pliku Aktualizuj `AGENTS.md` w tej samej zmianie, gdy zmieniają się: struktura projektu, komendy, konwencje, zależności, sposób uruchamiania, testowania lub istotne decyzje architektoniczne. Jeśli ten plik jest nieaktualny, niepełny albo sprzeczny z kodem, popraw go zamiast ślepo go przestrzegać. Zachowuj go krótkim i praktycznym: bez historii czatu, dziennika zmian i ogólnych porad niezwiązanych z repozytorium.