Files
claude-bot 0840818c9a
All checks were successful
CI / lint (push) Successful in 5s
CI / test (push) Successful in 5s
CI / build (push) Successful in 1s
analyst(ET-008): BRD, TRZ, AC, TestPlan, UI tests v2
2026-06-01 11:44:40 +00:00

23 KiB
Raw Permalink Blame History

type, work_item_id, title, version, status, created_at, updated_at, changelog, authors
type work_item_id title version status created_at updated_at changelog authors
brd ET-008 BRD: GPS-треки с публичных платформ на карте 2 draft 2026-06-01 2026-06-01
v2 (2026-06-01): полная переработка под реальный business request — серверная агрегация из ≥3 источников по региону, дедупликация, фильтры по активности и источнику, расширяемость на регионы. Предыдущая v1 трактовала задачу как URL-импорт + OSM live-поиск, что не соответствовало бизнес-цели.
agent:analyst

BRD — ET-008: GPS-треки с публичных платформ на карте

1. Цель

Показать пользователю Enduro Trails реальные GPS-треки, заранее собранные с публичных платформ (Wikiloc, Offmaps.ru, Тропинки.ру, EnduroRussia.ru, OSM Public GPS Traces, Nakarte.me, Komoot и т.п.) и сохранённые на сервере. Цель — три практические задачи мотоэндуриста:

  1. Видеть реальные дороги/тропы, которых нет в OSM. Vector-тайлы trails показывают только OSM-данные; реальные грунтовки/тропы из GPS-логов дают информацию, которой в OSM никогда не было.
  2. Понимать, где реально ездят. Плотность публичных треков на участке — прямая прокси-метрика популярности и проходимости.
  3. Выявлять «мёртвые» дороги. OSM-грунтовка, не покрытая ни одним публичным треком за последние N лет — кандидат на «давно никто не ездит, может быть заросла».

ET-008 даёт новый отдельный слой (поверх trails, ниже маршрута OSRM) с отдельными линиями (не heatmap), цветом по источнику или типу активности, с UI-фильтрами.

2. Контекст

  • Vector-тайлы из OSM (/api/tiles/{z}/{x}/{y}.mvt) уже отдают грунтовки/тропы/POI. ET-008 их не заменяет — добавляет параллельный слой публичных GPS-треков.
  • ET-006 реализовал клиентский импорт GPX-файлов пользователем (window.gpxTracks, #sheet-gpx). Это другой сценарий: ET-006 — «мой трек в памяти браузера», ET-008 — «треки сообщества с сервера». Модели данных не пересекаются.
  • Стек БД: SQLite + Spatialite. Для ET-008 заводится отдельная БД data/gps_tracks.sqlite — чтобы не смешивать данные с основной centralfederal.sqlite и иметь независимый цикл обновления / бэкапа.
  • Pipeline сбораофлайн-скрипт на cron, не runtime. На запрос пользователя сервер отдаёт уже собранные данные.
  • Регион MVP: ЦФО + Чувашия (18 субъектов ЦФО + Чувашская Республика, площадь ≈ 670 тыс. км²). Расширение на другие регионы — через конфиг-файл.

3. Scope

In scope

# Функция
F-01 Pipeline сбора GPX-треков с ≥ 3 публичных источников
F-02 Хранение треков в SQLite + Spatialite: геометрия + метаданные
F-03 Дедупликация: один реальный трек = одна запись, даже если найден в N источниках
F-04 Метаданные трека: источник, URL, тип активности, дата, длина, кол-во точек, автор (если публичен)
F-05 API endpoint GET /api/gps-tracks?bbox=…&activity=…&source=… для отдачи треков клиенту
F-06 Векторные тайлы публичных треков GET /api/gps-tracks/tiles/{z}/{x}/{y}.mvt для эффективной отдачи на низких зумах
F-07 Визуализация отдельными линиями (не heatmap) на карте
F-08 Цветовая дифференциация: палитра по источнику (default) с возможностью переключения на палитру по типу активности
F-09 UI-чекбокс «Публичные треки» в #terrain-popup: включить/выключить весь слой
F-10 UI-фильтр по типу активности (enduro / moto / offroad / bicycle / hike / other), multi-select
F-11 UI-фильтр по источнику, multi-select
F-12 Конфиг-файл регионов: bbox + название + список активных источников
F-13 MVP-датасет: ЦФО + Чувашия, ≥ 5000 треков
F-14 Совместимость со сменой стиля карты (через rebuildMapOverlays() по аналогии с ET-006 REQ-F-13 и ET-007 REQ-F-06)
F-15 Совместимость со спутниковой подложкой (ET-007): треки видны на спутнике с halo для контраста
F-16 Клик по треку → popup с метаданными: имя/тип активности/источник/дата/длина и ссылка на оригинал
F-17 Health-эндпоинт /api/gps-tracks/health: дата последнего сбора, кол-во треков по источникам, ошибки последнего прогона

Out of scope

  • Real-time сбор: только периодический офлайн (cron, 12 раза в неделю).
  • Wikiloc Premium / Komoot Premium / любые платные API: используем только бесплатные публичные endpoints и публичные HTML-страницы там, где это разрешено ToS источника.
  • Strava Metro как источник линий: это heatmap, не отдельные треки — не соответствует бизнес-требованию «отдельные линии». Опционально в будущем — как метрика популярности для валидации, не для MVP.
  • OAuth-интеграции (вход пользователя в Strava/Komoot со своим аккаунтом): отдельный work item.
  • Загрузка пользователем своих треков в общую базу: отдельный work item.
  • Редактирование/обрезка треков на стороне сервера.
  • Конвертация из KML/FIT/TCX: pipeline принимает только GPX.
  • Snap-to-road для треков (выравнивание под дороги OSM).
  • Учёт сложности (drag-level) внутри трека: фильтр только по типу активности; сложность — отдельная задача (требует анализа геометрии и скорости).

4. Источники (с оценкой реализуемости в MVP)

Анализ каждого источника из business request с честной оценкой доступности и юридических условий:

# Источник Тип доступа MVP Комментарий
1 OSM Public GPS Traces Документированный API да /api/0.6/trackpoints?bbox=…&page=…. Лицензия ODbL, атрибуция OSM. Объём для ЦФО оценочно ≈ 50100K точек, тыс. треков.
2 EnduroRussia.ru Web (HTML + GPX-ссылки) да По регионам, есть прямые GPX-ссылки. Лицензия и условия скрейпинга — фиксируются в ADR 06-adr/source-licensing.md до начала разработки.
3 Тропинки.ру / ttrails.ru Web (GPX/KML) да Эндуро-категория, GPX доступен без авторизации. Условия скрейпинга — то же ADR.
4 Offmaps.ru Web пилот Требует ревью формата выдачи и лицензии. Подключаем в пилот-режим если ADR разрешает.
5 Nakarte.me Public layers + JSON пилот Агрегатор: содержит ссылки на треки внешних источников. Может быть «бесплатным» путём к Wikiloc/Strava-treki косвенно. Требует ревью лицензии.
6 Wikiloc API (премиум) нет Бесплатный публичный API не отдаёт GPX. Без премиума — невозможно. Откладываем.
7 Komoot API (партнёрский) нет Публичный API ограничен, нет публичной выдачи GPX по bbox. Откладываем.
8 Strava Metro API (исследовательский) нет Heatmap, не отдельные треки → не соответствует бизнес-требованию. Out of scope.

MVP-минимум: 3 источника живут в продакшне — обязательно OSM (гарантированно доступен), плюс минимум 2 из (2)(5) по результатам ADR-ревью лицензий.

Юридический минимум

Перед началом разработки каждого источника (2)(5) — обязательный ADR docs/work-items/ET-008/06-adr/<source>-licensing.md:

  1. Что говорит ToS источника о скрейпинге / массовой загрузке GPX.
  2. Что говорит robots.txt.
  3. На каких условиях разрешена публикация чужих треков (имя/анонимизация/атрибуция).
  4. Rate-limit, который мы будем соблюдать (default: 1 req / 5 sec, с корректным User-Agent: enduro-trails/<v> (+contact)).
  5. Список метаданных, которые нельзя сохранять/публиковать (личные адреса, имена при отсутствии явного согласия).

Источник без явного зелёного света в ADR — не включается в pipeline.

5. Метрики успеха

Метрика Критерий MVP
Покрытие региона ≥ 5000 уникальных треков для ЦФО + Чувашии после первого полного прогона pipeline
Источники в продакшне ≥ 3 источника, отдающих данные в БД
Дедупликация < 5% дублей (один реальный трек — одна запись). Метрика: руками отсэмплировать 100 треков, посчитать дубли.
Производительность отдачи bbox GET /api/gps-tracks?bbox=… ≤ 300 мс p95 на z ≥ 10 (≤ 500 треков в видимой области)
Производительность отдачи тайлов GET /api/gps-tracks/tiles/{z}/{x}/{y}.mvt ≤ 200 мс p95 на z = 811
Производительность отрисовки При включённом слое pan/zoom без видимых фризов на десктопе и мобильных с 4 ГБ RAM
Расширяемость на регион Добавить новый регион (bbox + название + список источников) — ≤ 30 строк YAML-конфига, без правки кода
Скорость UI-фильтров Переключение фильтра по активности/источнику меняет видимую выборку за ≤ 200 мс (фильтрация на клиенте)
Сохранение слоя при setStyle() Слой не теряется при переключении тёмной темы / спутника / hillshade — восстанавливается через rebuildMapOverlays()
Pipeline стабильность Падение парсера одного источника не валит остальных; лог + алерт в /api/gps-tracks/health
Атрибуция На карте видна атрибуция каждого активного источника; в popup трека — ссылка на оригинал

6. Риски

Риск Вероятность Влияние Митигация
Источник меняет HTML → парсер ломается Высокая Среднее Каждый источник в отдельном модуле, изолированная ошибка. Pipeline пишет статус по источнику в health-эндпоинт. Алерт при 2 неудачных прогонах подряд.
ToS источника запрещает скрейпинг Средняя Высокое Обязательный ADR с фиксацией лицензии до подключения источника. Источник без явного разрешения — не включается.
Дубли треков из разных источников (один и тот же трек выкладывают на 2 платформах) Высокая Среднее Spatial+temporal hash: bbox округлённый до 0.01° + длина ± 5% + дата ± 1 день → одна запись. Алгоритм в TRZ §6.
Перегрузка карты на низких зумах (10K+ треков в видимой области) Высокая Высокое На клиенте: на z < 10 — отдача через MVT-тайлы с упрощением геометрии (как simplify_coords для trails). На z ≥ 10 — JSON с лимитом 500 треков.
Размер БД растёт неконтролируемо (миллионы треков при расширении на РФ) Низкая Среднее Отдельная gps_tracks.sqlite. Ротация: треки старше N лет (по конфигу, default 5) удаляются. Метрика размера БД в health.
Скрейпер банится по IP Средняя Среднее Rate-limit + backoff + User-Agent с контактом. Сбор по cron 12 раза в неделю, не чаще. Per-source конфигурируемый delay.
Персональные данные в треках (точки «дом», имена) Низкая Высокое Не сохраняем waypoint без явного публичного флага. Не сохраняем author если ToS требует анонимизации. Список запрещённых полей — в 08-data-requirements.md.
Лицензия источника обязывает менять/удалять данные по требованию автора Средняя Среднее Сохраняем external_id и external_url — можем удалить точечно по запросу. Pipeline уважает «удалённое на источнике» → удалять и у нас.
Pipeline ест слишком много трафика mva154 Средняя Низкое Per-source лимит на прогон (например, max 1000 новых треков за прогон). Метрики в health.
Отдача больших MVT тайлов медленная Средняя Среднее Серверный кэш тайлов (LRU 1024 записи, как уже сделано для trails). Упрощение геометрии по зуму.

7. Зависимости

Backend

  • Новый пакет src/api/gps_tracks/ с подмодулями:
    • models.py — Pydantic + SQL schema
    • sources/<source>.py — модули per-source (OSM, EnduroRussia, ttrails, …)
    • dedup.py — алгоритм дедупликации
    • db.py — обвязка SQLite + Spatialite
    • endpoint.py — FastAPI routes
    • mvt.py — генерация MVT-тайлов
  • Зависимости Python: httpx (есть), lxml или defusedxml (новая — для безопасного парсинга XML на сервере), shapely (есть).

Pipeline

  • Скрипт scripts/gps_collect.py — точка входа.
  • Конфиг config/gps_sources.yaml — список источников и параметры.
  • Конфиг config/gps_regions.yaml — список регионов (bbox + список активных источников per-region).
  • Cron на mva154: 0 3 * * 1,4 /usr/local/bin/python /opt/enduro-trails/scripts/gps_collect.py (Mon + Thu, 03:00 UTC).
  • Логи: /var/log/enduro-trails/gps-collect.log.

Frontend

  • Новый модуль src/web/gps_tracks.js — слой, фильтры, popup, по аналогии с gpx.js.
  • Расширение index.html:
    • Чекбокс «Публичные треки» и кнопка «Фильтры» в #terrain-popup.
    • Bottom sheet #sheet-gps-filters с фильтрами по активности и источнику.
  • Расширение style.json / style-dark.json: layer + halo-layer для спутника (по аналогии с trails-track-halo-satellite из ET-007).
  • Интеграция с rebuildMapOverlays() в app.js.

Инфра

  • Файловая: data/gps_tracks.sqlite на mva154, права чтения для FastAPI, права записи только для pipeline. Бэкап в общий backup-стек проекта.
  • Сетевая: исходящие HTTPS к источникам с mva154 (уже разрешено).

Документация

  • 06-adr/source-licensing.md — лицензии всех источников.
  • 06-adr/dedup-algorithm.md — обоснование выбора алгоритма дедупликации.
  • 06-adr/storage-schema.md — обоснование отдельной БД vs единой.
  • 07-infra-requirements.md — cron, бэкапы, ротация, мониторинг.
  • 08-data-requirements.md — схема БД, поля, ограничения, политика персональных данных.
  • 10-tech-risks.md — расширенный риск-реестр (расширяет §6 BRD).

Связи с другими work items

  • ET-006 — модель window.gpxTracks живёт параллельно. ET-008 не трогает её, использует свою модель window.gpsTracksLayer.
  • ET-007 — спутниковая подложка. ET-008 добавляет halo-слой для публичных треков в режиме «Спутник» по тому же паттерну.
  • PH-3 Smart Route — публичные треки в будущем могут стать входом для построения «реально-езженого» маршрута. Не в scope ET-008.
  • PH-9 PWA — слой публичных треков должен корректно работать в офлайне (через cached MVT). Учитывается в TRZ, но реализация офлайна — задача PH-9.