# Protokol DatováMapa 0.1

Normativní popis rozhraní mezi poskytovatelem dat a portálem. Při rozporu s jinou dokumentací platí tento dokument a strojová schémata:

- [JSON Schema manifestu](https://datovamapa.cz/schema/0.1/manifest.json) a [JSON Schema dat](https://datovamapa.cz/schema/0.1/data.json) – generované ze zod schémat v `src/lib/protocol/`,
- [OpenAPI kontrakt poskytovatele](https://datovamapa.cz/schema/0.1/poskytovatel-openapi.json).

Postup přípravy dat krok za krokem (zejména pro AI agenty) je v [návodu pro AI agenty](https://datovamapa.cz/dokumentace/pro-ai-agenty.md), srozumitelný úvod v [průvodci pro poskytovatele](https://datovamapa.cz/dokumentace/pro-poskytovatele.md). Platné vzory: [manifest-kompletni.json](https://datovamapa.cz/priklady/manifest-kompletni.json), [data-body.json](https://datovamapa.cz/priklady/data-body.json).

## Přehled

```
Poskytovatel                         Portál DatováMapa                 Prohlížeč
─────────────                        ─────────────────                 ─────────
manifest.json  ◄── GET (cache 10 min) ── registr → katalog ──────────► /api/katalog
data endpoint  ◄── GET ?bbox&zoom&… ──── proxy + validace + cache ───► /api/data/{provider}/{dataset}
rastrové dlaždice ◄───────────────────────────────────────────────────── přímo z prohlížeče
```

## Obecná pravidla

- Formát JSON, kódování UTF-8, souřadnice WGS84 (EPSG:4326) v pořadí `[lon, lat]`.
- Komunikace přes HTTPS (http jen pro `localhost` při vývoji).
- **Neznámá pole se ignorují.** Neznámý typ `presentation` se vykreslí jako `auto`.
- Verze `protocol` ve tvaru `major.minor`. Portál přijme manifest se stejnou hlavní verzí.
- Identifikátory (`provider.id`, `dataset.id`): malá písmena bez diakritiky, číslice, pomlčky, max. 64 znaků. Globální klíč sady je `provider/dataset`.
- Barvy jen v hex zápisu (`#rgb`, `#rrggbb`, `#rrggbbaa`).

## Manifest

| Pole | Povinné | Popis |
|---|---|---|
| `protocol` | ano | Verze protokolu, např. `"0.1"` |
| `provider.id` | ano | Identifikátor; musí odpovídat id v registru portálu |
| `provider.name` | ano | Název zobrazovaný jako zdroj |
| `provider.description`, `homepage`, `logo`, `contact` | ne | |
| `provider.managedBy` | ne | `provider` (výchozí) / `portal` – manifest pro veřejnou službu udržuje DatováMapa |
| `license` | ne | `{ name, url?, attribution }` – výchozí licence všech sad |
| `datasets[]` | ano | 1–200 datových sad s unikátním `id` |

### Datová sada

| Pole | Povinné | Popis |
|---|---|---|
| `id`, `title` | ano | |
| `description` | ne | |
| `category` | ne | `uzemi`, `priroda`, `voda`, `rizika`, `energie`, `doprava`, `spolecnost`, `ekonomika`, `infrastruktura`, `ukazka`, `ostatni`; jiná hodnota → Ostatní |
| `tags`, `keywords` | ne | Pro vyhledávání a budoucího asistenta |
| `useCases` | ne | Účely, pro které se sada hodí: `stavba`, `bydleni`, `koupe-pozemku`, `zemedelstvi`, `investice`… |
| `coverage` | ne | `{ bbox?, area?, minZoom?, maxZoom? }` – pod `minZoom` portál data nenačítá |
| `temporal` | ne | `{ updated?, frequency?, param? }` – `param` = klíč parametru, kterým se volí období (viz [časový filtr](https://datovamapa.cz/dokumentace/protokol.md#casovy-filtr)) |
| `license` | ne | Přepisuje licenci poskytovatele |
| `source` | ano | Odkud data brát (viz níže) |
| `presentation` | ano | Jak data vykreslit (viz níže) |
| `fields[]` | ne | Popis vlastností objektů: `key`, `label`, `type`, `unit`, `decimals`, `description`, `primary` |
| `params[]` | ne | Filtry pro uživatele (viz níže) |
| `cache` | ne | `{ ttl?: sekundy, store?: boolean }` |

### `source`

**`geojson`** – nativní formát.

```json
{ "type": "geojson", "url": "/data/kontejnery", "mode": "bbox", "maxFeatures": 5000 }
```

- `url` může být relativní vůči URL manifestu. Zdrojem může být i **statický soubor** (`lavicky.geojson` vedle `manifest.json` na libovolném webovém hostingu) – v režimu `full` portál žádné query parametry nevyžaduje a soubor je platný endpoint.
- `mode: "full"` – celá sada jedním dotazem (malé sady). `mode: "bbox"` – portál se ptá na výřez mapy.
- `maxFeatures` ≤ 5000.

**`raster`** – hotové dlaždice, prohlížeč je načítá přímo ze zdroje.

```json
{ "type": "raster", "tiles": ["https://…/{z}/{x}/{y}.png"], "tileSize": 256, "minZoom": 0, "maxZoom": 19 }
```

Šablony podporují `{z}/{x}/{y}` i `{bbox-epsg-3857}` (WMS GetMap). Jen https.

### `presentation`

| `type` | Geometrie | Volby |
|---|---|---|
| `circle` | body | `color`, `radius`, `opacity`, `strokeColor`, `strokeWidth`, `label`, `cluster` |
| `heatmap` | body | `weight`, `radius`, `intensity`, `colors[]`, `opacity` |
| `line` | linie | `color`, `width`, `opacity`, `dash[]`, `label` |
| `fill` | plochy | `color`, `opacity`, `outlineColor`, `outlineWidth`, `label` |
| `raster` | dlaždice | `opacity` |
| `auto` | cokoli | `color` |

Všechny typy mají volitelnou `legend: [{ label, color }]` (max. 20 položek). Portál ji ukazuje v legendě přímo v mapě a ve výběru vrstev. U vektorových typů ji umí odvodit z barev, u `raster` ne – barvy jsou zapečené v obrázcích dlaždic, takže legendu rastru uveďte ručně (např. převzetím z legendy WMS / ArcGIS služby).

**Barva** (`color`) je buď hex řetězec, nebo pravidlo podle vlastnosti objektu:

```json
{ "field": "druh", "type": "categorical", "values": { "papír": "#2563eb" }, "default": "#64748b" }
{ "field": "hodnota", "type": "interpolate", "stops": [[0, "#f7fcb9"], [100, "#004529"]] }
{ "field": "hodnota", "type": "step", "default": "#eee", "stops": [[10, "#fc8"], [50, "#e34"]] }
{ "type": "trend" }
```

`trend` barví objekty podle toho, zda jejich hodnota v čase roste, stagnuje, nebo klesá. Počítá ho portál z grafu vývoje `dm.chart` – viz [vývoj v čase a trend](https://datovamapa.cz/dokumentace/protokol.md#vyvoj-v-case-a-trend).

**Číslo** (`radius`, `width`, `weight`) je číslo nebo `{ "field", "type": "interpolate", "stops": [[hodnota, číslo], …] }`.

**Popisek** (`label`): `{ field, minZoom?, color?, size? }`.

### `params`

Filtr, který uživatel nastaví v portálu; portál ho pošle jako query parametr `key=value`.

| `type` | Hodnota v dotazu |
|---|---|
| `enum` | `key=a` (z `options`) |
| `multi-enum` | `key=a,b,c` |
| `number` | `key=42` (v rozsahu `min`–`max`) |
| `range` | `key=od,do` |
| `boolean` | `key=true` / `false` |
| `date` | `key=2026-10-06` |
| `date-range` | `key=2026-01-01,2026-12-31` |
| `text` | `key=…` (max. 200 znaků) |

Klíče `bbox`, `zoom`, `limit`, `cursor`, `lang`, `protocol` jsou rezervované. Portál posílá jen deklarované parametry a hodnoty předem ověří; nevyplněný parametr nahradí `default`.

### Časový filtr

Data v čase (nehody, měření, události) mají jeden parametr pro období a odkazují na něj z `temporal.param`. Portál ho pak neukazuje mezi ostatními filtry, ale jako časovou osu v okně pod legendou: posuvník období a sloupcový graf po letech, ve kterém jde období vybrat kliknutím nebo tažením. Zvolené období je vidět i u vrstvy v legendě.

- Typ `range` s roky – `min` a `max` jsou první a poslední rok dat, hodnota `od,do` (např. `2019,2023`, jeden rok `2023,2023`). Objekty za celé období vracejte dohromady (souhrnně), ne po jednotlivých letech.
- Typ `date-range` – období po dnech, `2026-01-01,2026-06-30`.

```json manifest
{
  "protocol": "0.1",
  "provider": { "id": "mesto-priklad", "name": "Město Příklad" },
  "license": { "name": "CC BY 4.0", "attribution": "© Město Příklad" },
  "datasets": [{
    "id": "nehody",
    "title": "Dopravní nehody",
    "description": "Nehody evidované Policií ČR podle následků.",
    "category": "doprava",
    "keywords": ["nehoda", "dopravní nehoda", "bezpečnost", "zranění", "křižovatka"],
    "useCases": ["doprava", "bydleni"],
    "coverage": { "bbox": [16.43, 49.1, 16.73, 49.3], "minZoom": 12 },
    "temporal": { "frequency": "ročně", "param": "obdobi" },
    "source": { "type": "geojson", "url": "https://data.mesto-priklad.cz/datovamapa/nehody", "mode": "bbox", "maxFeatures": 5000 },
    "presentation": {
      "type": "circle",
      "color": { "field": "nasledky", "type": "categorical", "values": { "zranění": "#dc2626", "hmotná škoda": "#facc15" }, "default": "#facc15" }
    },
    "fields": [
      { "key": "nasledky", "label": "Následky", "type": "string", "primary": true },
      { "key": "datum", "label": "Datum", "type": "date" }
    ],
    "params": [{ "key": "obdobi", "label": "Období", "type": "range", "min": 2015, "max": 2025, "step": 1, "default": "2025,2025" }]
  }]
}
```

Graf kreslí portál z `dm.timeline` v odpovědi (viz [datová odpověď](https://datovamapa.cz/dokumentace/protokol.md#datova-odpoved)). U hodnot v čase, kde počty objektů nedávají smysl (počet obyvatel, cena), pošlete místo něj souhrnný vývoj v `dm.chart` – portál ho u posuvníku ukáže jako čárový graf, viz [vývoj v čase a trend](https://datovamapa.cz/dokumentace/protokol.md#vyvoj-v-case-a-trend). Bez obojího zůstane jen posuvník období.

### Vývoj v čase a trend

Standardní zobrazení dat, jejichž hodnota se u objektu mění v čase – počet obyvatel obce, cena, naměřená koncentrace, návštěvnost. Kdykoli data takovou řadu mají, posílejte ji; portál z ní sám kreslí graf a umí podle ní barvit.

- **Graf vývoje.** Má-li objekt hodnotu za více období, pošlete ji v `feature.dm.chart` (viz [datová odpověď](https://datovamapa.cz/dokumentace/protokol.md#datova-odpoved)). Portál ji ukáže v detailu objektu jako čárový graf s hodnotou za zvolené období a změnou proti jeho začátku. Platí to i pro kartogramy, kde se rok volí parametrem: pošlete řadu za všechny roky a zvolený rok jako `highlight` se stejným `from` a `to`. Když sada barví podle číselné hodnoty, období se volí parametrem a graf chybí, validátor to hlásí jako `chybi_graf_vyvoje`.
- **Souhrnný graf u legendy.** Vývoj za celé území sady nebo za výřez (např. počet obyvatel Česka) pošlete v `dm.chart` odpovědi – stejný tvar jako graf objektu. Portál ho ukáže u časového filtru, dokud uživatel žádný objekt nerozklikne, a zvolené období vyznačí podle `highlight`. Barví-li sada podle trendu, dostane čára barvu trendu celku – je pak vidět, jestli zelené tečky jen nekopírují celostátní vývoj.
- **Barva podle trendu.** Je-li smyslem sady změna („roste, nebo ubývá?“), nastavte `color: { "type": "trend" }`. Portál z grafu každého objektu spočítá průměrnou změnu za jedno období v % počáteční hodnoty – ve zvýrazněném období (`highlight`), jinak za celou řadu. Od `threshold` (výchozí 0,5 %) výš hodnota **roste** (zelená), od −`threshold` níž **klesá** (červená), mezi tím **stagnuje** (šedá). Barvy lze přepsat přes `colors: { up, flat, down }`, třeba když je růst nežádoucí. Legendu portál odvodí sám a graf v detailu obarví stejně jako objekt v mapě. Objekt bez grafu zůstane světle šedý (`trend_bez_grafu`).

Trend vychází z relativní změny, hodí se proto pro kladné veličiny (počty, ceny, koncentrace). Hodnoty kolem nuly, jako saldo stěhování, barvěte přes `interpolate` a vývoj ukažte jen grafem.

```json manifest
{
  "protocol": "0.1",
  "provider": { "id": "kraj-priklad", "name": "Kraj Příklad" },
  "license": { "name": "CC BY 4.0", "attribution": "© Kraj Příklad" },
  "datasets": [{
    "id": "vyvoj-obyvatel",
    "title": "Vývoj počtu obyvatel obcí",
    "description": "Kde obyvatel přibývá a kde ubývá. Barva podle trendu ve zvoleném období, v detailu obce graf po letech.",
    "category": "spolecnost",
    "keywords": ["obyvatelé", "vývoj", "trend", "růst", "vylidňování"],
    "useCases": ["bydleni", "verejna-sprava"],
    "temporal": { "frequency": "ročně", "param": "obdobi" },
    "source": { "type": "geojson", "url": "https://data.kraj-priklad.cz/datovamapa/obyvatele" },
    "presentation": { "type": "circle", "color": { "type": "trend", "threshold": 0.5 }, "radius": 7 },
    "fields": [
      { "key": "nazev", "label": "Obec", "type": "string", "primary": true },
      { "key": "obyvatel", "label": "Obyvatel na konci období", "type": "integer" }
    ],
    "params": [{ "key": "obdobi", "label": "Období", "type": "range", "min": 2015, "max": 2025, "step": 1, "default": "2015,2025" }]
  }]
}
```

Odpověď pak u každé obce posílá řadu za všechny roky a zvolené období v `highlight`, například `{ "from": "2015", "to": "2025" }`.

## Datový dotaz

```
GET {source.url}?bbox=minLon,minLat,maxLon,maxLat&zoom=10&limit=5000&lang=cs&protocol=0.1[&cursor=…][&{params}]
Accept: application/geo+json, application/json
User-Agent: DatovaMapa/0.1 (+https://datovamapa.cz/dokumentace/pro-poskytovatele)
```

- `bbox` a `zoom` jen v režimu `bbox`. Výřez je **zarovnaný na dlaždice** úrovně `zoom` (celé číslo), takže blízké pohledy vedou na stejný dotaz – poskytovatel i portál mohou odpovědi cachovat.
- `limit` = kolik objektů portál nanejvýš zpracuje.
- Časový limit odpovědi 10 s, velikost max. 15 MB.

## Datová odpověď

GeoJSON `FeatureCollection` (RFC 7946). Podporované geometrie: `Point`, `MultiPoint`, `LineString`, `MultiLineString`, `Polygon`, `MultiPolygon`. Objekty s `geometry: null` se přeskočí.

Volitelná rozšíření:

```json
{
  "type": "FeatureCollection",
  "features": [{
    "type": "Feature", "id": 1, "geometry": {…}, "properties": {…},
    "dm": { "title": "…", "description": "…", "url": "https://…", "color": "#e11d48", "chart": {…} }
  }],
  "dm": { "generated": "2026-10-06T08:00:00Z", "ttl": 3600, "total": 1, "truncated": false, "next": "…", "notice": "…", "timeline": […] }
}
```

- `feature.dm` – nadpis a popis v detailu, odkaz na detail u zdroje, přepsání barvy, graf vývoje.
- `feature.dm.chart` – vývoj jedné hodnoty objektu v čase, který portál nakreslí v detailu objektu jako čárový graf s hodnotou za poslední období (např. počet obyvatel obce po letech) a ze kterého počítá barvu podle trendu. `label` říká, co graf ukazuje, nepovinné `unit`, `decimals`, `note` (poznámka pod grafem, např. o změně metodiky) a `highlight: { from, to }` – zvýrazněné období, typicky zvolené v časovém filtru; portál ho podbarví, ukáže hodnotu na jeho konci a změnu i trend počítá od jeho začátku. Stejné `from` a `to` označí jedno období, např. rok zvolený u kartogramu – graf se na něm zastaví. `points` jsou dvojice `{ period, value }` seřazené od nejstaršího období – `period` je rok, měsíc nebo den jako u `dm.timeline`. 2–100 bodů. Posílejte ho vždy, když má objekt hodnotu za více období (viz [vývoj v čase a trend](https://datovamapa.cz/dokumentace/protokol.md#vyvoj-v-case-a-trend)).
- `dm.ttl` – platnost odpovědi (portál použije menší z `cache.ttl` a `dm.ttl`).
- `dm.total`, `dm.truncated` – kolik objektů celkem / zda je odpověď zkrácená.
- `dm.notice` – krátké sdělení pro uživatele (zobrazí se u vrstvy).
- `dm.next` – kurzor na další stránku (portál ho zatím nevyužívá, rezervováno).
- `dm.timeline` – počty objektů **ve výřezu** po obdobích za celou dobu, kterou sada pokrývá, nezávisle na zvoleném období a na `limit` (spočítejte je agregačním dotazem, ne z vrácených objektů). Portál z nich kreslí graf u legendy. `period` je rok (`2023`), měsíc (`2023-05`) nebo den; nepovinné `values` rozdělí počet podle hodnot vlastnosti z `color.field` a graf je obarví jako legendu. Max. 400 období.
- `dm.chart` – souhrnný vývoj hodnoty za celé území sady nebo výřez (např. počet obyvatel Česka), stejný tvar jako `feature.dm.chart`. Portál ho ukáže u časového filtru jako čárový graf, když odpověď neposílá `dm.timeline`.

```json data
{
  "type": "FeatureCollection",
  "features": [],
  "dm": {
    "timeline": [
      { "period": "2024", "count": 2366, "values": { "zranění": 701, "hmotná škoda": 1665 } },
      { "period": "2025", "count": 1894, "values": { "zranění": 652, "hmotná škoda": 1242 } }
    ]
  }
}
```

Souhrnný vývoj za celé území místo počtů objektů (zvolené období 2023–2025):

```json data
{
  "type": "FeatureCollection",
  "features": [],
  "dm": {
    "chart": {
      "label": "Počet obyvatel Česka k 31. 12.",
      "highlight": { "from": "2022", "to": "2025" },
      "points": [
        { "period": "2021", "value": 10516707 },
        { "period": "2022", "value": 10827529 },
        { "period": "2023", "value": 10900555 },
        { "period": "2024", "value": 10909500 },
        { "period": "2025", "value": 10915839 }
      ]
    }
  }
}
```

Objekt s grafem vývoje v detailu:

```json data
{
  "type": "FeatureCollection",
  "features": [{
    "type": "Feature",
    "id": "500496",
    "geometry": { "type": "Point", "coordinates": [17.2731, 49.5957] },
    "properties": { "nazev": "Olomouc", "obyvatel": 105297 },
    "dm": {
      "chart": {
        "label": "Počet obyvatel k 31. 12.",
        "points": [
          { "period": "2023", "value": 102293 },
          { "period": "2024", "value": 103063 },
          { "period": "2025", "value": 105297 }
        ]
      }
    }
  }]
}
```
- Vlastnosti s prefixem `__dm_` jsou rezervované pro portál a z odpovědi se odstraní.

## Cache

- Portál drží odpovědi po dobu `min(cache.ttl, dm.ttl)`, výchozí 300 s. Manifesty 10 min.
- Po vypršení drží záznam ještě 24 h jako zálohu: když zdroj neodpovídá, ukáže poslední data s upozorněním.
- `cache.store: false` – poskytovatel nesouhlasí s trvalým uložením dat do datové vrstvy portálu (krátkodobé cachování odpovědí podle `ttl` platí dál).

## Validace

Shodu s protokolem ověřuje [validátor](https://datovamapa.cz/dokumentace/api.md#validator) (`POST /api/validovat`, živý test `GET /api/validovat?manifestUrl=…`, nebo MCP nástroje `validovat_manifest` a `validovat_data`). Rozlišuje:

- **chyby** (`errors`) – porušení tohoto dokumentu; manifest s chybou portál nepřijme, data s chybou nezobrazí,
- **doporučení** (`warnings`) – data fungují, ale hůř se hledají, zobrazují nebo kombinují.

Každý nález má stabilní `code` ([přehled kódů](https://datovamapa.cz/dokumentace/api.md#kody-nalezu)), cestu `path` a u doporučení radu `hint`. Kódy se mezi minor verzemi nemění, nové mohou přibývat.

## Vývoj protokolu

- Nová volitelná pole a nové typy `presentation` / `source` = nová minor verze (0.2…).
- Změna významu existujících polí = nová major verze; portál po přechodnou dobu podporuje obě.
- Kandidáti na další verze: `symbol` (ikony), `extrusion` (3D), časová dimenze (`time` u objektů + parametr), `vector-tiles` / `pmtiles` / `ogc-features` jako zdroje, stránkování přes `next`, agregace pro malá přiblížení.
