# Changelog

All notable changes to this project will be documented in this file.
Format: [Keep a Changelog](https://keepachangelog.com/en/1.1.0/)

## [Unreleased]

## [v0.0.7] — 2026-06-05

### Fixed
- ET-015 (deployed v0.0.7, PR #30): `docker-compose.yml` healthcheck сервиса `app` переведён с `curl -f`
  (отсутствует в базовом `python:3.12-slim`) на python one-liner через
  `urllib.request` из stdlib — без изменений `Dockerfile` и `src/api/main.py`,
  без ребилда образа (достаточно `docker compose up -d app`). Внутренний
  `urlopen(timeout=3)` меньше внешнего `healthcheck.timeout: 5s` (AC-07);
  добавлен `start_period: 20s` для смягчения окна холодного старта uvicorn.
  Контракт `/api/health` сохранён (HTTP 200 + JSON). Покрытие: 12 static-
  тестов (`tests/static/test_healthcheck_compose.py`) + 6 unit-тестов
  (`tests/unit/test_healthcheck_oneliner.py`, исполняют ровно ту же
  one-liner-команду против мок-сервера). ADR-020. Refs: ET-015.

  `fix(infra): use python urllib for container healthcheck (ET-015)`

### Changed
- ET-012: Слой публичных GPS-треков теперь виден с зума z=5 (раньше — с z=8).
  Калибровка существующей tier-структуры `build_gps_mvt`/`_simplify_coords`
  (ADR-016): для z≤5 фильтр `min_length=10 км`, `limit=1500`; для z=6 —
  `5 км`/`2000`; для z=7 — без изменений (`2 км`/`3000`). DP-tolerance
  расширен парой стопов: z=6 → 0.018° (~2 км), z≤5 → 0.04° (~4 км).
  На клиенте константа `GPS_TRACKS_MIN_ZOOM` понижена до 5;
  `line-width`/halo-stops в MapLibre получили stop на z=5 (0.8/1.8 px),
  hint обновлён с «Зум 8+» на «Зум 5+». Контракт API
  `/api/gps-tracks/tiles/{z}/{x}/{y}.mvt` не изменился (REQ-F-15);
  z≥8 не затронут (регрессия). Тесты: 18 unit zoom-tier+simplify,
  9 integration endpoint z5-z7, 2 perf (PERF-Z5-01/02; avg ~64 мс,
  p95 ~89 мс при 500 треках — ниже бюджета 200 мс/500 мс по M-6).
  *(Код уехал на прод в составе v0.0.5; отдельный deploy-log ET-012
  не закрыт — см. ET-013/14-deploy-log.md, раздел «Что фактически
  уехало в v0.0.5».)*
  Refs: ET-012.

## [v0.0.6] — 2026-06-04

> Деплой задеплоен на test (https://openclaw.mva154.duckdns.org/enduro/).
> Healthcheck + smoke PASS. См. `docs/work-items/ET-014/14-deploy-log.md`.

### Fixed
- ET-014: Фикс UX-конфликта `terrain-popup ↔ bottom-sheet` на mobile.
  При открытии любого bottom-sheet (route-details / settings / layers /
  search / track-details) активный `terrain-popup` (hillshade / TRI /
  hypso info) теперь корректно закрывается через `popup.remove()`,
  а не остаётся висеть поверх sheet, перехватывая клики (ADR-019).
  Поведение действует только при `window.innerWidth ≤ 768` (mobile);
  на desktop popup сохраняется (AC-01..AC-08, REQ-F-1..F-8).
  Файлы: `src/web/app.js` (+17 строк, новый блок «sheet-popup yield»
  с обработчиком события `sheet:open`). Покрытие: 16 unit-тестов
  (`tests/unit/sheet_popup.test.js` — 11 кейсов поведения + 5 boundary;
  `tests/unit/test_sheet_popup.py` — 4 архитектурных invariants
  ADR-019). API/БД/тайлы не затронуты. Refs: ET-014.

## [v0.0.5] — 2026-06-04

> Деплой задеплоен на test (https://openclaw.mva154.duckdns.org/enduro/).
> Healthcheck + smoke PASS. См. `docs/work-items/ET-013/14-deploy-log.md`.

### Added
- ET-013: Zoom-aware paint для terrain-слоёв `hillshade` и `tri`
  (Terrain Ruggedness Index) на z9-z11. UI-минзум `hillshade` понижен
  с 10 до 9; raster-paint обоих слоёв переведён в zoom-aware форму через
  MapLibre `interpolate`. На z9-z11 — пик `raster-opacity`/`raster-contrast`
  (видимость рельефа сопоставима с z8); на z12-z14 — возврат к исходным
  значениям (регрессия по AC-10). TRI на z8 сохранил opacity 0.70
  (регрессия по AC-06), пик 0.80-0.85 на z9-z11. Файлы: `src/web/app.js`
  (константы `HILLSHADE_PAINT` / `TRI_PAINT`, `applyTerrainLayer`
  расширена для поддержки object-paint, обратно-совместимо), `src/web/index.html`.
  Тесты: 17 unit `tests/unit/test_terrain_paint.py` (валидация
  interpolate-stops, инварианты opacity/contrast по zoom), 6 integration
  `tests/integration/test_terrain_z9_tiles.py` (`(hillshade, tri) × (z9, z10, z11)`).
  ADR-017. Refs: ET-013.
- ET-013 (review F-1 fix): Слой `tri` добавлен в whitelist
  FastAPI-endpoint'а `GET /terrain/{layer}/{z}/{x}/{y}.png` (`src/api/main.py`).
  На test/prod-среде nginx перехватывает `/enduro/terrain/*` и отдаёт
  PNG напрямую с диска, но в dev-режиме (`make dev` → FastAPI на :5556
  без nginx) endpoint должен поддерживать `tri` нативно. Изменение
  аддитивное: ответ-контракт и заголовки идентичны существующим слоям
  (`hypso`, `hillshade`); REQ-F-18 «API contract без изменений» не нарушен.
  Регрессия: integration-тест `test_known_terrain_layer_accepted_by_whitelist`
  параметризован по `(hypso, hillshade, tri)` и проверяет, что для
  заведомо отсутствующего файла возвращается `detail: "Tile not found"`,
  а не `"Unknown layer"`. Refs: ET-013, review F-1.

### Changed
- ET-013 (review F-2 fix): Integration-тест
  `tests/integration/test_terrain_z9_tiles.py` параметризован по
  `(layer ∈ {hillshade, tri}) × (zoom ∈ {9, 10, 11})` — 6 кейсов
  вместо 3, покрывает оба слоя на расширенном диапазоне зумов
  (ранее покрывался только `hillshade`). Refs: ET-013, review F-2.

## [v0.0.4] — 2026-06-04 (tagged earlier, deploy log pending)

> Тег `v0.0.4` создан в рамках ET-012 deploy, но 14-deploy-log пишется
> в отдельном PR `deploy/ET-012-v0.0.4-log` (см. PR #25). Артефакты
> ET-012 живут под `[Unreleased]` до закрытия того PR — не трогаю.

## [v0.0.3] — 2026-06-03 (tagged, NOT deployed)

> ⚠️ Тег создан и запушен, PR смерджен в `main`, но docker-образ на test
> **не задеплоен**: deploy-hook `/home/slin/bin/enduro-deploy-hook.sh`
> упал на `Permission denied` при записи в `/var/log/enduro-trails/`
> (каталог root-owned, у `slin` нет права записи и нет `NOPASSWD sudo`).
> Подробности и инструкция для ops: `docs/work-items/ET-011/14-deploy-log.md`.

### Added
- ET-011: Скачивание GPX из popup публичного трека. Новый эндпоинт
  `GET /api/gps-tracks/{track_id}/download` собирает GPX 1.1 из геометрии
  трека и отдаёт с `Content-Disposition: attachment` (UTF-8 имя файла по
  RFC 5987). В popup на карте появилась кнопка «Скачать GPX» (32×32 CSS px,
  mobile-friendly). Реализация: новый модуль `src/api/gps_tracks/export.py`
  (`build_gpx`, `safe_filename`); расширение `config/gps_sources.yaml`
  per-source флагом `download_allowed` (default-deny; MVP whitelist = `osm`,
  см. ADR-015); helper `load_download_allowed_sources` в `config.py`.
  Тесты: 13 unit GPX-builder + 10 unit filename + 11 integration download.
  ADR-014, ADR-015. Refs: ET-011.

## [v0.0.2] — 2026-06-02

### Added
- ET-009: Активация GPS-источников EnduroRussia и Wikiloc — `config/gps_sources.yaml`
  включает оба источника (`enabled: true`), для Wikiloc добавлен soft-cap
  `max_tracks_per_run: 50` и activity-фильтр; `config/gps_regions.yaml` подписывает
  `wikiloc` на регион `tsfo_plus_chuvashia`. Парсер `wikiloc.py` извлекает время из
  GPX-metadata (для корректной дедупликации) и поддерживает `max_tracks_per_run`
  cap. UI: цвет `wikiloc`, чекбокс источника, динамическая атрибуция
  (`GPS_SOURCE_ATTRIBUTIONS`) подтягивается с `/api/gps-tracks/health`.
  Тесты: 10 unit ER + 10 unit WL + 5 integration + 2 contract (nightly only).
  PR #16, tag v0.0.2.

### Fixed
- ET-009: исправлен URL `enduro_russia` в `config/gps_sources.yaml`
  (`https://enduro-russia.ru` → `https://endurorussia.ru`, без дефиса).

## [v0.0.1] — 2026-06-01

### Added
- ET-008: GPS-треки с публичных платформ на карте — новый модуль `src/web/gps_tracks.js`
  с отображением публичных GPS-треков (OSM Traces, enduro_russia, ttrails) в виде
  MVT-тайлов (z 8–11) и GeoJSON (z ≥ 12); фильтрация по активности и источнику,
  попап с мета-данными трека, z-order ниже личных GPX-треков (AC-10).
  Backend: FastAPI-пакет `src/api/gps_tracks/` (endpoint, MVT, LRU-кэш, дедупликация),
  миграция `migrations/gps_tracks_001_init.sql`, pipeline-скрипт `scripts/gps_collect.py`,
  Docker-сервис `gps-collector`. PR #12, tag v0.0.1.

## [Unreleased]

- Initial project structure
- CLAUDE.md project passport
- Agent system prompts (architect, developer, reviewer, tester, deployer)
- CI pipeline (Gitea Actions)
- Docker configuration
- ET-002: чекбокс «POI» в попапе рельефа — показ/скрытие маркеров POI
  с сохранением состояния в localStorage (ключ `poi-visible`)
- ET-005: переключатель единиц измерения расстояний (км/мили) в попапе
  рельефа — новый модуль `src/web/units.js` с централизованным
  форматтером `Units.formatDistance()`; выбор сохраняется в localStorage
  (ключ `distance_unit`), пересчёт всех видимых расстояний выполняется
  единым оркестратором по событию `unitchange`
- ET-006: загрузка и визуализация GPX-треков — новый модуль
  `src/web/gpx.js` с клиентским парсингом GPX 1.1 (`DOMParser`,
  чанковая конвертация), отрисовкой треков и waypoints на карте,
  панелью `#sheet-gpx` со списком треков, статистикой и canvas-профилем
  высот; GPX-слои восстанавливаются после смены стиля карты через
  `rebuildMapOverlays()`. Данные треков хранятся только в памяти сессии
