217 lines
21 KiB
Markdown
217 lines
21 KiB
Markdown
---
|
||
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,
|
||
гарантируем читаемость и производительность тестами и
|
||
скриншот-тестами.
|