--- type: brd work_item_id: ET-012 title: "BRD: Показывать пользовательские треки с зума z5 (сейчас с z8)" version: 1 status: draft created_at: 2026-06-04 updated_at: 2026-06-04 authors: - "agent:analyst" related: - "ET-008" - "ET-009" --- # BRD — ET-012: Показывать пользовательские треки с зума z5 ## 1. Цель Снизить нижний порог видимости слоя публичных GPS-треков (`gps-tracks-layer-mvt`) с **z8** до **z5**, чтобы пользователь видел общее покрытие сети треков на средних/мелких масштабах (z5 ≈ ¼ Европы в кадре, z7 ≈ область размером с ЦФО) и мог «с высоты птичьего полёта» искать интересные треки. На сегодня (после ET-008/ET-009) слой публичных треков физически скрыт ниже z8 двумя механизмами: - vector-source задаёт `minzoom: 8` (тайлы не запрашиваются); - клиентский visibility-фильтр `zoom >= GPS_TRACKS_MIN_ZOOM` (8) в `_syncGpsLayersVisibility` и `applyGpsHaloVisibility`; - UI-hint «Зум 8+» (`#public-tracks-zoom-hint`) висит как обоснование «почему пусто». ET-012 = **снизить порог + сохранить читаемость и производительность** на новых зумах z5-z7. ## 2. Контекст ### 2.1 Текущее поведение (после ET-009) - Источник `gps-tracks-tiles` (MVT): `tiles: /api/gps-tracks/tiles/{z}/{x}/{y}.mvt`, `minzoom: 8`, `maxzoom: 11`. - Источник `gps-tracks-geo` (GeoJSON, через `/api/gps-tracks?bbox=…`) включается при `zoom >= GPS_TRACKS_ZOOM_CUTOFF = 12` — ET-012 в этом регионе ничего не меняет. - `build_gps_mvt` (`src/api/gps_tracks/mvt.py`) уже содержит zoom-aware упрощение и пороги: - `_simplify_coords`: tolerance `0.008°` (~800м) на z≤7, `0.002°` (~200м) на z8-9, `0.0005°` (~50м) на z10-11, без упрощения на z≥12. - В `build_gps_mvt`: при z≤7 — `min_length_m=2000`, `limit=3000` features на тайл; на больших зумах limit/min_length мягче. - Endpoint `/api/gps-tracks/tiles/{z}/{x}/{y}.mvt` принимает любой `0 ≤ z ≤ 22`; никакой пре-нарезки тайлов нет — каждый тайл строится из БД on-demand и кэшируется в FIFO размером 1024. - На клиенте используется LRU-кэш MapLibre и сетевой кэш браузера. - Текущая БД (test-среда) содержит порядка нескольких сотен треков (ожидаемо ≤ 5000 в горизонте года), геометрия каждого трека — десятки-тысячи точек. ### 2.2 Почему это бизнес-важно - На малых масштабах (z5-z7) пользователю **сейчас негде искать треки**: при первом открытии карта по умолчанию показывает обзор региона; чтобы увидеть хоть что-то из публичных треков, нужно сразу зумить до z8 — это лишний шаг и плохой UX. - Видимость на z5-z7 = понимание «где вообще катаются» в масштабах целого региона/страны, что помогает планировать выезды и оценивать покрытие. - Конкуренты (Wikiloc, Komoot) показывают clustered/density слои с z3-z4; для нас достаточно начать с z5. ### 2.3 Открытые вопросы из бизнес-запроса — ответы по результатам анализа | Вопрос | Ответ | | ---------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- | | Где задаётся minzoom слоя? | Клиент: `src/web/gps_tracks.js`, константа `GPS_TRACKS_MIN_ZOOM = 8` (используется в source.minzoom, visibility, halo, hint). | | Тайлы уже нарезаны до z5 или нужно догенерить? | Нарезки нет вообще — тайлы строятся on-demand из SQLite по bbox. Никакой генерации/инвалидации делать не нужно. | | Нужна ли генерализация линий на малых зумах? | Базовая уже есть в `_simplify_coords` (DP-tolerance 800м при z≤7). Для z5-z6 нужно ужесточить пороги (min_length, limit, tolerance) — F-04..F-06. | ## 3. Scope ### In scope | # | Функция | | ----- | -------------------------------------------------------------------------------------------------------------------- | | F-01 | Снизить клиентскую константу `GPS_TRACKS_MIN_ZOOM` с 8 до 5 в `src/web/gps_tracks.js`. | | F-02 | Уменьшить `minzoom` vector-source `gps-tracks-tiles` с 8 до 5 (использует ту же константу). | | F-03 | На бэкенде в `build_gps_mvt` расширить tier-структуру: добавить уровни z5, z6 с более жёсткими min_length_m и limit. | | F-04 | В `_simplify_coords` добавить tier для z5-z6: tolerance ~0.02° (~2 км) на z5, ~0.01° (~1 км) на z6. | | F-05 | Расширить `line-width` (основной слой) и `line-width` (halo) для z5: явные stops чтобы линия читалась. | | F-06 | UI-hint `#public-tracks-zoom-hint`: либо обновить текст до «Зум 5+», либо скрывать всегда (после снижения порога порог фактически недостижим в обычных сценариях). | | F-07 | Halo на спутнике активируется на z5-z11 (как и основной MVT-слой). | | F-08 | Производительность: p95 generation одного MVT-тайла z5 ≤ 500 мс при размере БД ≤ 5000 треков; p95 endpoint не выше +50 мс относительно baseline ET-009. | | F-09 | Читаемость: на z5 с включённым слоем при ≥ 200 треках по ЦФО карта остаётся «читаемой» — линии не сливаются в сплошную кашу. Критерий приёмки качественный, см. AC-08. | | F-10 | Halo на спутнике на z5-z7: не «глушит» подложку. Halo-width на z5 ≤ 2 px. | | F-11 | Регрессия: поведение на z8-z11 (MVT) и z12+ (GeoJSON) не меняется. | | F-12 | Регрессия: фильтры по `activity` / `source` работают на z5-z7 так же, как на z8+. | | F-13 | Регрессия: popup трека и кнопка «Скачать GPX» (ET-011) работают при клике на трек на z5-z7. (Замечание: на низких зумах кликнуть в линию пальцем сложнее — оставляем как есть, hit-area не расширяем.) | ### Out of scope - **Clustering / heat-map на z3-z4.** Идея здравая, но требует отдельной серверной агрегации (например, h3-cell counts) и нового UI-слоя. Делаем отдельным work item. - **Пре-нарезка тайлов на диск.** Не требуется при текущем размере БД; on-demand + LRU справляются. - **Изменение поведения GeoJSON-слоя на z12+.** Не трогаем. - **Изменение фильтров по activity/source.** Не трогаем. - **Изменения popup'а трека.** Не трогаем. - **Расширение `gps_tracks_minzoom` в админ-конфиг.** Константа остаётся хардкодом — менять через релиз. Если в будущем появится потребность в feature-flag — отдельный work item. - **Изменения схемы БД и dedup-алгоритма.** Не трогаем. - **Изменения OSRM / routing.** Не трогаем. ## 4. Метрики успеха | # | Метрика | Критерий | | --- | -------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- | | M-1 | Видимость на z5 | При включённом чекбоксе «Публичные треки» и `zoom = 5` слой `gps-tracks-layer-mvt` имеет `visibility: visible`. На карте отображаются линии треков. | | M-2 | Видимость на z6, z7 | Аналогично M-1 для z6 и z7. | | M-3 | Поведение на z8-z11 не изменилось | Регрессия: на z8-z11 виден тот же набор треков, что и до ET-012 (с поправкой на улучшенную z5-z7 генерализацию — не считается регрессией). | | M-4 | Поведение на z12+ не изменилось | Регрессия: GeoJSON-слой включается ровно на z=12 как раньше; MVT слой скрывается ровно на z=12. | | M-5 | Hint «Зум 5+» / «Зум 8+» | После ET-012: при включённом слое и zoom ≥ 5 hint скрыт. (До ET-012 hint показывал «Зум 8+» при zoom < 8.) | | M-6 | p95 MVT tile generation на z5 | ≤ 500 мс на test-среде при размере БД до 5000 треков; ≤ 1 с при размере до 20 000 треков (запас). | | M-7 | p95 endpoint `/api/gps-tracks/tiles/5/x/y.mvt` | cold ≤ 700 мс, hit ≤ 50 мс (кэш). | | M-8 | Размер MVT тайла z5 | ≤ 200 KB после генерализации и фильтра min_length (защита от мобильного трафика). Если больше — F-03/F-04 переусиливают (ужесточить limit). | | M-9 | Читаемость z5 | На скриншоте z5 с ≥ 200 треков по ЦФО видны минимум 3 разных линии в разных частях кадра; нет «сплошной заливки» одной зоны. Качественная проверка по TC-UI-12-Z5-Q. | | M-10 | Регрессия фильтров | Снятие галки «EnduroRussia» в `#sheet-gps-filters` на z=6 убирает соответствующие линии (как и на z=10). | | M-11 | LRU-кэш не переполняется ненужно | После панорамирования по миру на z5-z6 (≈ 50 уникальных тайлов) кэш-хит на повторных тайлах ≥ 80 %. | ## 5. Риски | # | Риск | Вероятность | Влияние | Митигация | | ---- | ------------------------------------------------------------------------------------------ | ----------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ | | R-1 | На z5 слишком много фич в одном тайле → MVT > 1 MB, тормоза рендера на мобильном. | Средняя | Высокое | F-03: жёсткий `min_length_m` и `limit` для z=5. Метрика M-8 (≤ 200 KB) — гейт. При нарушении — ужесточить limit/min_length. | | R-2 | На z5 линии после Douglas-Peucker превращаются в «обрубки» (трек из 1000 точек → 3 точки). | Средняя | Низкое | Качественная проверка по TC-UI-12-Z5-Q. Tolerance подобрана так, чтобы трек ≤ 5 км превращался в прямую — это норма на z5. | | R-3 | Линия `line-width: 0.5 px` на z5 невидима на retina-дисплеях. | Низкая | Низкое | F-05: явные stops `interpolate linear zoom 5 0.8 8 1.0 12 2.0 16 3.0`. Проверка по TC-UI-01-Z5. | | R-4 | Бэкенд-запрос к БД с огромным bbox (z5 тайл ~1250×1250 км) тянет ВСЕ треки региона. | Средняя | Среднее | Запрос уже идёт через индекс по min_lon/max_lon/min_lat/max_lat в SQLite; при ≤ 5000 строк это < 100 мс. M-7 — гейт. При деградации — добавить индекс `length_m`. | | R-5 | На z5 buffer 10 % bbox в endpoint раздувает запрос до 130 % площади. | Низкая | Низкое | На z5 это уже не имеет смысла (соседний тайл всё равно отрисует пограничные фичи). Опционально — снизить buffer до 5 % для z≤6. См. TRZ §3.10. | | R-6 | LRU-кэш в 1024 тайла на z5 (всего 32×32 = 1024 тайла в мире) — теоретически переполняется на «walk through world». | Низкая | Низкое | На практике пользователь видит ~10-20 тайлов одновременно на z5; ротация работает. Опционально — увеличить `_GPS_TILE_CACHE_MAX` до 2048. См. TRZ §3.11. | | R-7 | Hint «Зум 8+» забыли удалить → пользователь видит и линии, и подсказку «увеличь зум». | Средняя | Низкое | F-06 явно: либо hide-always при `GPS_TRACKS_MIN_ZOOM = 5`, либо текст «Зум 5+». См. AC-05. | | R-8 | Регрессия halo на спутнике: halo на z5 «закрывает» линию. | Низкая | Низкое | F-10: halo-width ≤ 2 px на z5; проверка по TC-UI-09-Z5-SAT. | | R-9 | Пользователи на мобильном с медленным интернетом получают раздутые тайлы z5-z6 при первом открытии. | Средняя | Среднее | Размер ≤ 200 KB (M-8) + gzip на nginx + браузерный кэш. Опционально — отсрочить включение слоя до первого panMove (не в scope ET-012). | | R-10 | Конфликт с поведением другого слоя `gps-tracks-halo-mvt-satellite`: оба используют те же фичи MVT — на z5 halo и линия должны быть согласованы. | Низкая | Низкое | Используют тот же source/source-layer; видимость синхронизируется через `_syncGpsLayersVisibility` + `applyGpsHaloVisibility`. Регрессионная проверка TC-UI-09-Z5-SAT. | ## 6. Зависимости ### Backend - `src/api/gps_tracks/mvt.py:build_gps_mvt` — расширить tier-таблицу для z5, z6 (F-03). - `src/api/gps_tracks/mvt.py:_simplify_coords` — добавить tier для z5-z6 (F-04). - `src/api/gps_tracks/endpoint.py` — без изменений логики, опциональная правка buffer для z≤6 (R-5). По умолчанию не меняем. - Endpoint `/api/gps-tracks/tiles/{z}/{x}/{y}.mvt` уже принимает z 0..22 — не трогаем. ### Frontend - `src/web/gps_tracks.js`: - константа `GPS_TRACKS_MIN_ZOOM = 5` (F-01, F-02). - `_gpsLayerDef` paint.line-width — расширить interpolate-выражение для z5 (F-05). - `_gpsHaloDef` paint.line-width — то же (F-05, F-10). - `src/web/index.html`: - `#public-tracks-zoom-hint` — обновить текст или скрыть навсегда (F-06). - Стили `style.json` / `style-dark.json` — без изменений (минзум слоя в стилях не задаётся; он живёт в коде клиента). ### Тесты - Новые unit-тесты `tests/unit/test_gps_mvt_zoom_tiers.py` (новый файл): тиры min_length и limit для z=5..z=12. - Новые unit-тесты `tests/unit/test_gps_mvt_simplify.py` или расширение существующих: tolerance для z5-z6. - Новые integration-тесты `tests/integration/test_gps_tile_z5_z7.py`: endpoint отдаёт непустой MVT для z=5/6/7 на регионе с ≥ 10 треками. - UI-тесты см. `04b-ui-test-cases.md`. ### Документация - `01-brd.md` (этот файл). - `02-trz.md`, `03-acceptance-criteria.md`, `04-test-plan.yaml`, `04b-ui-test-cases.md` — этот пакет. - Опциональный ADR не требуется: tile-pipeline уже спроектирован под динамические тиры в ET-008/ET-009; это calibration, а не архитектурное решение. Если разработчик в реализации обнаружит нужду в смене политики (например, переход к heat-map на z5) — добавляет ADR в `06-adr/`. ### Инфра / Данные - Test-среда `https://openclaw.mva154.duckdns.org/enduro/` — существующий деплой. - БД `data/gps_tracks.sqlite` — без миграций. - nginx gzip уже включён. ### Связи с другими work items - **ET-008** — родительский слой публичных GPS-треков. - **ET-009** — заполнил БД треками EnduroRussia/Wikiloc; без этих данных z5-z7 будет визуально пустым в test-среде. - **ET-011** — кнопка «Скачать GPX» в popup'е; регрессия покрывается. - **PH-3 Smart Route** — независимо. - Будущий work item «Heat-map / clustering на z3-z4» — отдельная задача. ## 7. План в одну строку Снижаем константу `GPS_TRACKS_MIN_ZOOM` с 8 до 5, расширяем zoom-tier структуру в `build_gps_mvt` и `_simplify_coords` для z5-z6, добавляем явные line-width stops для z5, скрываем/обновляем hint, гарантируем читаемость и производительность тестами и скриншот-тестами.