Oficiální meteo výstrahy správně: CAP, atribuce a rozšiřitelnost
Vládní výstrahy jsou zadarmo a veřejné — „prostě je zobrazit" je ale past: různé zdroje, různé severity škály, povinná atribuce, expirace, lokální časové zóny.

Proč „jen zobrazit výstrahy" nestačí
Oficiální meteorologické výstrahy jsou z logiky věci veřejné a bezplatné. Státní instituce je publikují s cílem chránit životy a majetek, což z nich dělá ideální datový zdroj pro jakoukoli meteorologickou platformu. Na první pohled se zdá, že implementace je triviální záležitost: stačí najít API, stáhnout JSON nebo XML, uložit ho do databáze a vykreslit uživateli na mapu nebo do detailu předpovědi.
Tento naivní přístup je však spolehlivou cestou k nepřehlednému, chybovému a dlouhodobě neudržitelnému kódu. Jakmile se pokusíte integrovat oficiální výstrahy počasí v aplikaci, která má ambici fungovat globálně nebo alespoň na úrovni více států, narazíte na sérii architektonických a UX překážek.
Prvním problémem je nejednotnost formátů a klasifikací. Každá národní meteorologická služba používá vlastní metodiku pro určování závažnosti jevů. Co je pro jednoho „střední nebezpečí“, to jiný označuje žlutou barvou nebo stupněm 2 z 5. Bez jednotné normalizační vrstvy nelze v uživatelském rozhraní nabídnout konzistentní zážitek.
Druhým úskalím je správa životního cyklu výstrah. Výstrahy nejsou statická data. Jsou průběžně aktualizovány, doplňovány, rušeny nebo přirozeně expirují. Pokud vaše aplikace nedokáže spolehlivě detekovat, že platnost výstrahy již skončila, nebo že nová zpráva plně nahrazuje tu předchozí, riskujete, že uživatele zahltíte neaktuálními informacemi, což v kritických situacích podkopává důvěru v celou platformu.
K tomu se přidávají přísné licenční podmínky vyžadující přesnou atribuci zdroje, nutnost správné práce s časovými zónami v místě dopadu události a potřeba překladu odborných textů do jazyka uživatele. To vše ukazuje, že integrace výstrah vyžaduje robustní softwarovou architekturu, nikoli pouze jednoduchý skript pro stahování dat.
CAP: společný jazyk výstrah
Abychom nemuseli pro každou zemi vyvíjet zcela unikátní parser, existuje mezinárodní standard CAP (Common Alerting Protocol). Jedná se o XML formát (případně jeho JSON variantu), který definuje univerzální strukturu pro šíření nouzových zpráv a varování před nebezpečnými jevy.
Standard CAP rozděluje výstrahu do několika klíčových segmentů:
- Event (Událost): Konkrétní typ nebezpečí (např. silný vítr, povodeň, extrémní horka).
- Severity (Závažnost): Míra dopadu na životy a majetek (Extreme, Severe, Moderate, Minor, Unknown).
- Urgency (Urgence): Časový rámec, ve kterém je nutné jednat (Immediate, Expected, Future, Past, Unknown).
- Certainty (Jistota): Pravděpodobnost, že jev skutečně nastane (Observed, Likely, Possible, Unlikely, Unknown).
- Description a Instruction (Popis a instrukce): Textové informace popisující povahu hrozby a doporučené chování pro minimalizaci rizik.
- Area (Oblast): Geografická specifikace zasaženého území, nejčastěji definovaná polygonem nebo sadou geokódů (např. FIPS kódy v USA).
- Validity (Platnost): Časová okna definující začátek (
onset), okamžik účinnosti (effective) a konec platnosti (expires).
Ačkoli CAP představuje obrovský krok vpřed k unifikaci, v praxi se stále setkáte s drobnými odchylkami. Různé meteorologické služby implementují standard s drobnými nuancemi, využívají vlastní XML jmenné prostory nebo specifickým způsobem interpretují kombinace polí severity, urgency a certainty. Naše aplikace proto musí s CAP pracovat jako s výchozím bodem, nad kterým staví vlastní validační a normalizační logiku.
První zdroj: NWS a geografický gate
Jako první produkční zdroj pro oficiální výstrahy počasí v aplikaci byla zvolena americká služba NWS (National Weather Service). NWS poskytuje robustní a bezplatné API, které pokrývá území Spojených států amerických, Aljašku, Havaj a Portoriko.
Volání externího API pro každé uživatelské vyžádání předpovědi je však neefektivní. Pokud uživatel vyhledává počasí v Praze, je zcela zbytečné dotazovat servery NWS v USA. Z tohoto důvodu je před samotné volání adaptéru předsazen takzvaný geografický gate.
Každý adaptér pro konkrétní zdroj výstrah implementuje metodu, která na základě zeměpisných souřadnic (šířky a délky) rozhodne, zda má smysl daný zdroj vůbec dotazovat.
interface AlertSource {
readonly id: string;
readonly attribution: string;
covers(latitude: number, longitude: number): boolean;
fetchAlerts(latitude: number, longitude: number): Promise<RawAlert[]>;
}
export class NwsAlertSource implements AlertSource {
readonly id = 'nws';
readonly attribution = 'National Weather Service (NWS)';
covers(latitude: number, longitude: number): boolean {
// Geografický gate omezující dotazy pouze na území USA a přidružených oblastí
const isWithinUS = latitude >= 24.396308 && latitude <= 49.384358
&& longitude >= -125.00165 && longitude <= -66.93457;
const isAlaska = latitude >= 51.214183 && latitude <= 71.3895
&& longitude >= -179.148909 && longitude <= -129.9795;
const isHawaii = latitude >= 18.910361 && latitude <= 28.402123
&& longitude >= -178.334698 && longitude <= -154.806773;
const isPuertoRico = latitude >= 17.926822 && latitude <= 18.520556
&& longitude >= -67.271444 && longitude <= -65.244111;
return isWithinUS || isAlaska || isHawaii || isPuertoRico;
}
async fetchAlerts(latitude: number, longitude: number): Promise<RawAlert[]> {
// Volání API NWS a stažení dat pro dané souřadnice
}
}
Díky tomuto mechanismu jádro aplikace okamžitě ví, které adaptéry má pro danou lokalitu aktivovat. Pokud se uživatel dotáže na lokalitu mimo pokrytí NWS, adaptér je okamžitě vyřazen z exekučního řetězce, což šetří síťovou kapacitu i výpočetní čas.
Normalizace: jedna škála závažnosti pro všechny
Jakmile získáme surová data z jednotlivých adaptérů, nastává klíčová fáze: normalizace. Cílem je převést specifické datové struktury různých poskytovatelů na jednotný interní model, se kterým dokáže pracovat zbytek aplikace a frontend.
Normalizační proces řeší několik zásadních úkolů:
- Sjednocení škály závažnosti: CAP rozlišuje pět úrovní závažnosti, ale různé služby je interpretují odlišně. V našem interním modelu mapujeme tyto stavy na jednotnou čtyřstupňovou škálu:
Informational,Moderate,SevereaExtreme. - Deduplikace výstrah: Stejná výstraha může být publikována ve více zprávách (např. původní varování, aktualizace popisu, upřesnění polygonu). Normalizační vrstva porovnává unikátní identifikátory výstrah a zajišťuje, že uživateli se zobrazí vždy pouze nejnovější verze dané události.
- Filtrace neaktivních výstrah: Výstrahy, jejichž časový údaj
expiresjiž nastal v minulosti vzhledem k aktuálnímu času na serveru, jsou automaticky zahozeny. - Třídění podle priorit: Pokud pro jedno místo platí více výstrah současně (např. silný vítr a zároveň povodňová bdělost), jsou seřazeny sestupně podle závažnosti, aby ty nejkritičtější byly uživateli prezentovány na prvním místě.
export enum AlertSeverity {
Informational = 'informational',
Moderate = 'moderate',
Severe = 'severe',
Extreme = 'extreme'
}
export interface NormalizedAlert {
id: string;
sourceId: string;
event: string;
severity: AlertSeverity;
headline: string;
description: string;
instruction?: string;
startsAt: Date;
expiresAt: Date;
attribution: string;
}
Tato striktní typovost zaručuje, že zbytek aplikačního kódu nemusí řešit, odkud výstraha pochází. Všechny výstrahy bez ohledu na původní formát splňují stejný kontrakt.
Port-based architektura: přidat zdroj bez sahání do jádra
Aby byla platforma dlouhodobě udržitelná, je navržena podle principů port-based architektury (známé také jako Hexagonal Architecture). Jádro aplikace definuje rozhraní (porty), přes která komunikuje s vnějším světem. Konkrétní implementace těchto rozhraní (adaptéry) pak žijí na okraji systému.
Tento přístup je detailněji popsán v článku o tom, jak je platforma poskládaná. V kontextu výstrah je portem právě rozhraní AlertSource.
┌────────────────────────────────────────────────────────┐
│ JÁDRO SLUŽBY │
│ (WeatherAlertService - NestJS + MongoDB + Redis) │
│ │
│ Definuje port: AlertSource │
└──────────────────────────┬─────────────────────────────┘
│
┌─────────────────┴─────────────────┐
▼ ▼
┌─────────────────┐ ┌─────────────────┐
│ NwsAdapter │ │MeteoAlarmAdapter│
│ (USA) │ │(Evropa - plán) │
│ │ │ │
│ Implementuje │ │ Implementuje │
│ AlertSource │ │ AlertSource │
└─────────────────┘ └─────────────────┘
Pokud se v budoucnu rozhodneme přidat podporu pro evropský systém MeteoAlarm nebo český ČHMÚ, nebudeme muset upravovat ani řádek v jádru služby WeatherAlertService. Vytvoříme pouze nový adaptér (např. MeteoAlarmAdapter), který implementuje rozhraní AlertSource, zaregistrujeme jej do DI kontejneru a systém začne automaticky stahovat, normalizovat a zobrazovat výstrahy pro evropské lokality.
Tato volná vazba výrazně usnadňuje testování. Při psaní unit a integračních testů pro jádro služby nemusíme provádět reálná síťová volání na servery NWS. Stačí nám podhodit mockovací adaptér, který vrací předem definovaná testovací data.
Povinná atribuce a lokální časové zóny
Při zobrazování oficiálních výstrah nelze opomenout legislativní a UX požadavky. Většina poskytovatelů dat (včetně těch veřejných) vyžaduje v rámci licencí (např. CC BY) jasné uvedení zdroje informací.
V uživatelském rozhraní platformy je proto u každé zobrazené výstrahy striktně vyžadována atribuce. Uživatel musí na první pohled vidět, která autorita výstrahu vydala. V databázi i v API odpovědích je proto pole attribution povinnou součástí každého normalizovaného záznamu.
Druhým, technicky mnohem náročnějším oříškem, je správná interpretace časových údajů. Představte si uživatele, který sedí v Praze (středoevropský čas, CET) a plánuje cestu do Miami na Floridě (východní čas, EST). Pokud si v aplikaci zobrazí detail počasí pro Miami a uvidí varování před hurikánem s platností „do 22:00“, v jakém časovém pásmu tento údaj je?
Zobrazení v čase uživatele (CET) je matoucí, protože uživatel se snaží pochopit situaci na místě dopadu. Zobrazení v UTC je pro běžného člověka nepoužitelné. Správným řešením je zobrazit čas v lokální časové zóně místa, pro které je výstraha vydána.
Při zpracování souřadnic dotazované lokality proto aplikace nejprve zjistí příslušné IANA časové pásmo (např. America/New_York). Časové údaje o platnosti výstrahy jsou sice interně ukládány v UTC, ale při formátování pro uživatelské rozhraní jsou transformovány do cílové časové zóny dané lokality. Uživatel v Praze tak vidí, že výstraha v Miami platí do 16:00 místního času (EDT), což přesně odpovídá reálné situaci na místě.
Když je výstraha v cizím jazyce
Oficiální výstrahy jsou národními autoritami vydávány primárně v úředním jazyce dané země. NWS publikuje zprávy v angličtině, španělská AEMET ve španělštině a ČHMÚ v češtině. Pro globální platformu to představuje vážný UX problém. Pokud uživatel z Česka cestuje po Španělsku a obdrží kritickou výstrahu před bleskovými povodněmi, potřebuje porozumět instrukcím okamžitě, bez nutnosti kopírovat texty do externích překladačů.
Pro vyřešení tohoto problému byl do platformy integrován systém on-demand AI překladů. Vzhledem k tomu, že překlady generované velkými jazykovými modely jsou zpoplatněné, celý proces podléhá přísné optimalizaci:
- On-demand spuštění: Překlad textu výstrahy (titulek, popis a instrukce) se nespouští automaticky při stažení výstrahy na server. Aktivuje se až ve chvíli, kdy si konkrétní uživatel vyžádá detail výstrahy v jazyce, který se neshoduje s originálním jazykem zprávy.
- Cachování výsledků: Jakmile je překlad pro danou kombinaci ID výstrahy a cílového jazyka jednou vygenerován, uloží se do databáze. Všichni další uživatelé, kteří si zobrazí stejnou výstrahu ve stejném jazyce, již dostávají nacachovaný výsledek. Vzhledem k tomu, že stejné varování často čtou tisíce lidí v dané oblasti, je efektivita této cache velmi vysoká.
- Integrace Gemini: Pro samotný překlad je využíváno API modelu Gemini. Model dostává jako kontext informaci, že se jedná o meteorologické varování, což zajišťuje přesné zachování odborné terminologie a tónu instrukcí.
- Graceful degradation: Pokud překladové API selže (např. z důvodu překročení rychlostních limitů nebo výpadku služby), aplikace nesmí spadnout. V takovém případě tiše degraduje a uživateli zobrazí původní text v originálním jazyce s informací, že překlad nebyl dočasně dostupný. Pokud se během procesu překladu vyskytne neočekávaná chyba, interní systém pro správu kvót zajistí, že se neúspěšný pokus nezapočítá do limitů spotřeby.
Je důležité zdůraznit, že v současné fázi vývoje se jedná výhradně o pasivní zobrazování a překlad oficiálních výstrah vydaných státními autoritami. Uživatelsky definované hlídače počasí (např. „upozorni mě, pokud rychlost větru v mé lokalitě překročí 15 m/s“), které by vyžadovaly neustálé vyhodnocování personalizovaných pravidel na pozadí, jsou v současnosti předmětem budoucího plánování a nejsou v systému implementovány.
Robustní integrace oficiálních výstrah počasí v aplikaci ukazuje, že i zdánlivě jednoduchá integrace veřejných dat vyžaduje promyšlenou architekturu. Použití standardu CAP, geografických bran, port-based návrhu a efektivního cachování překladů umožňuje platformě škálovat a snadno se rozšiřovat o další globální zdroje. Pokud vás zajímá, jak jsou tyto principy aplikovány v praxi, navštivte stránku popisující celý projekt Weather InTouch.

