Files
wiki/tasks/enduro-trails/PROJECT.md
2026-05-12 23:40:01 +03:00

23 KiB
Raw Blame History

Enduro Trails 🏍️

OSM-карта с фокусом на грунтовые дороги для построения красивых эндуро-маршрутов

Статус: active
Старт: 2026-05-02
Автор: Слава


Концепция

Обычные карты оптимизированы под автомобили — асфальт яркий, грунтовки не видны. Enduro Trails переворачивает эту логику: грунтовки/тропы — главный слой, асфальт — тусклый фон. Плюс фичи для поиска и построения красивых маршрутов (минимум асфальта, максимум красоты).


Регион

  1. ЦФО + Чувашия (первый регион, прототип)
  2. Расширение на новые ФО по запросу

Архитектура

Стек

  • Pyrosm/Osmium → парсинг PBF
  • Spatialite → хранение (прототип), PostGIS → продакшен
  • OSRM (кастомный профиль enduro.lua) → роутинг
  • FastAPI + uvicorn (4 workers) → бэкенд
  • MapLibre GL JS → фронт (веб + PWA)

Инфраструктура

  • Сервер: slin@82.22.50.71, sudo motoZ@yaz2010
  • Контейнер приложения: prototype-enduro-trails-1, порт 5558
  • URL: https://openclaw.mva154.duckdns.org/enduro/
  • Код на сервере: /home/slin/enduro-trails/prototype/
  • Workspace: /home/node/.openclaw/workspace/tasks/enduro-trails/prototype/
  • БД: /home/slin/enduro-trails/data/centralfederal.sqlite (431 MB, 1.1M треков, 14K POI)
  • OSRM контейнер: osrm-osrm-routed-1, порт 5559
  • OSRM данные: /home/slin/enduro-trails/data/enduro.osrm.* (~5.2 GB)
  • OSRM профиль: /home/slin/enduro-trails/osrm/enduro.lua
  • Swap: /home/slin/swapfile3 (4 GB), итого 6 GB swap
  • Деплой: Node.js ssh2 (SSH бинарник в контейнере не работает — glibc 2.36 vs 2.38)

Деплой

# ВАЖНО: docker cp нужно делать ПОСЛЕ рестарта контейнера!
# Образ перезаписывает статику при рестарте.

# 1. Загрузить файлы на сервер через SFTP (deploy_static.js)
# 2. docker restart prototype-enduro-trails-1
# 3. Подождать 8 сек
# 4. docker cp /home/slin/enduro-trails/prototype/static/app.js prototype-enduro-trails-1:/app/static/app.js
# 5. docker cp /home/slin/enduro-trails/prototype/static/app.css prototype-enduro-trails-1:/app/static/app.css
# 6. docker cp /home/slin/enduro-trails/prototype/static/index.html prototype-enduro-trails-1:/app/static/index.html

# Для бэкенда (app.py):
docker cp /home/slin/enduro-trails/prototype/app.py prototype-enduro-trails-1:/app/app.py
docker restart prototype-enduro-trails-1

# deploy_app2.js — только для app.py!
# deploy_static.js — SFTP статики, но cp делать вручную после рестарта

Схема БД

-- trails: id, osm_id, highway_type, track_type, surface, name, length_m,
--   mtb_scale, visibility, smoothness, access, tags, geom BLOB,
--   min_lon, max_lon, min_lat, max_lat

-- poi: id, osm_id, poi_type, name, geom BLOB, lon, lat

Реестр фич

ID Фича Описание Статус Фаза
F-01 Альтернативные маршруты До 5 вариантов с разным балансом грунт/асфальт Готово 3
F-02 Статистика маршрута Карточки с % покрытия, полоска, развёрнутый вид Готово 3
F-03 Человекочитаемое время "2 ч 35 мин" вместо "155 мин" Готово 3
F-04 Промежуточные точки Добавление, удаление, drag, debounce 300ms Готово 3
F-05 GPX экспорт Трек + waypoints + флажки, имя enduro-YYYYMMDDHHMMSS.gpx Готово 3
F-06 Флажки/метки localStorage, попап → A / → B / удалить, иконки Готово 3
F-07 Исключить шлагбаумы Баррьеры → inaccessible в OSRM 📋 BRD готов 3.1
F-08 Исключить тротуары footway/pedestrian/steps убрать из графа 📋 BRD готов 3.1
F-09 Больше альтернатив Penalized re-query + дедупликация 📋 BRD готов 3.1
F-10 Слой препятствий Шлагбаумы, броды, блокпосты на карте 📋 BRD готов 3.1
F-11 "Красивый маршрут" Замкнутый круг через живописные места, scenic_score, варианты Бэклог 4
F-12 "Горка" Макс набор высоты, мин дистанция (SRTM) Бэклог 6
F-13 "Связка" Соединить два трека грунтовками Бэклог 4
F-14 "Разведка" Грунтовки вокруг точки, статистика по типам, POI Бэклог 4
F-15 "Народные треки" OSM Traces, Wikiloc, Komoot, 4x4travel Бэклог 8
F-16 Тёмная тема + редизайн Две темы (авто/светлая/тёмная), SunCalc, мобильный UI, drag-and-drop точек, расстояние по маршруту Готово 5
F-29 Рельеф (terrain) Цветной рельеф (все зумы) + теневой (зум 10+). SRTM 30м, кнопка 🏔️ в toolbar с чекбоксами ⚠️ В работе 5.4
F-22 Линейка UX Расстояние сегмента под маркером, крестик удаления, зелёный Старт, панель fit-content, toast, toggle скрыть/показать, deleteRuler Готово 5.2
F-23 Метки UX Починен баг удаления через попап (popup.remove() перед marker.remove()) Готово 5.2
F-24 Поиск точек маршрута Inline Nominatim поиск в каждом wl-item, убран верхний search bar Готово 5.2
F-25 Route onboarding mini-bar При активации режима маршрута — мини-бар с пином S/F, подсказкой и поиском Nominatim. Большой лист не открывается автоматически Готово 5.3
F-26 Route sheet UX Крестик → шеврон сворачивания; «Добавить точку» показывает onboarding мини-бар с подсказкой и поиском Готово 5.3
F-27 Route корзина → мини-бар Корзина в листе маршрута закрывает лист и показывает onboarding мини-бар для старта (как первый тап на кнопку маршрута) Готово 5.3
F-28 Линейка: центрирование панели #ruler-info центрирован по горизонтали (left:50% + translateX(-50%)), не перекрывает кнопки масштаба Готово 5.3
F-17 PWA + офлайн Service Worker, MBTiles, GPS-трекинг Бэклог 7
F-18 Тёмная/светлая карта Карта переключается синхронно с темой UI: style.json (светлая) / style-dark.json (тёмная) Готово 5.1
F-19 Иконка колеса + спиннер SVG мотокросс-колесо (32 спицы, 36 зубцов кноблинга, 8 болтов ступицы, currentColor). Вращается при построении маршрута Готово 5.3
F-20 Линейка: перетаскивание точек Возможность перетащить уже поставленную точку линейки на новое место Бэклог 5.x
F-21 Линейка: сохранение между сессиями Сохранять точки линейки в localStorage, восстанавливать при перезагрузке Бэклог 5.x

Выполненные фазы

Фаза 1 — MVP (02.05.2026)

  • PBF парсинг (ЦФО + Чувашия)
  • Spatialite БД (1.1M треков, 14K POI)
  • FastAPI self-hosted MVT тайлы
  • MapLibre GL JS карта с кастомным стилем
  • Попапы с информацией о дороге
  • Контролы слоёв

Фаза 2 — Роутинг + UI (03.05.2026)

  • OSRM + кастомный профиль enduro.lua (порт 5559)
  • Роутинг «Дикий путь» — кнопка 🗺️, маркеры A/B
  • Поиск (Nominatim, debounce 400ms)
  • Линейка 📏 (haversine)
  • Геолокация 📍, компас 🧭

Фаза 3 — Умный маршрут (04.05.2026)

  • F-01: Альтернативные маршруты (до 5, цвета: синий/зелёный/фиолетовый/оранжевый/серый)
  • F-02: Статистика покрытия (карточки: компактные + развёрнутые, полоска покрытия, %)
  • F-03: formatDuration() — "2 ч 35 мин" / "1 дн 2 ч 50 мин"
  • F-04: Промежуточные точки (до 8, draggable, debounce 300ms)
  • F-05: GPX 1.1 экспорт (трек + waypoints + флажки)
  • F-06: Флажки 🚩 (localStorage, 50 лимит, попап → A / → B / удалить)

Баги исправлены (04.05):

  • formatDuration(86400) → "1 дн" (не "1 дн 0 ч")
  • OSRM TooBig → retry 5→3→1
  • Панель маршрута перекрывала кнопки → CSS right: 56px
  • Длинные маршруты не строились → radiuses=5000 + NoSegment retry с 10km + timeout 60s

Бэклог по фазам

📋 Фаза 3.1 — Улучшение роутинга (BRD готов, ожидает согласования)

BRD: BRD_PHASE3.1.md

Фича Описание Сложность Требует
F-07 Шлагбаумы → inaccessible в OSRM Низкая (lua) Пересборка графа ~40 мин
F-08 Убрать footway/pedestrian/steps из графа Низкая (lua) Пересборка графа ~40 мин
F-09 Penalized re-query для разных альтернатив Высокая
F-10 Слой препятствий на карте (🚧🌊) Средняя Перепарсинг PBF ~30 мин

Порядок: F-07+F-08 вместе (одна пересборка) → F-09 → F-10

Фаза 4 — Продвинутый роутинг (04.05.2026)

  • F-11 «Красивый маршрут» — замкнутый круг через живописные места, scenic_score, карточки с вариантами
  • F-13 «Связка» — соединить два трека грунтовками, альтернативы
  • F-14 «Разведка» — грунтовки в радиусе 20/50/100 км, статистика по типам, POI

Фаза 4 — Продвинутый роутинг (в разработке)

  • F-11 «Красивый маршрут» — замкнутый круг, scenic_score, варианты по дистанции (50/100/150/200 км)
  • F-13 «Связка» — соединить два трека грунтовками, альтернативы
  • F-14 «Разведка» — грунтовки в радиусе 20/50/100 км, статистика по типам, POI
  • Мини-бар маршрута (#mini-route-bar) — компактный HUD поверх карты

Фаза 5.3 — Route UX + Линейка (06.05.2026)

  • F-25 Route onboarding mini-bar — при активации режима маршрута показывается мини-бар с пином S/F, подсказкой и поиском Nominatim
  • F-26 Route sheet UX — крестик заменён на шеврон сворачивания; «Добавить точку» показывает onboarding мини-бар
  • F-27 Корзина в листе маршрута — закрывает лист и открывает onboarding мини-бар для старта
  • F-28 Линейка — панель #ruler-info центрирована по горизонтали, не перекрывает кнопки масштаба

Фаза 5 — Редизайн (05.05.2026)

BRD: BRD_PHASE5.md

  • F-16 Тёмная + светлая тема, авто-режим по SunCalc (восход/закат)
  • Bottom sheets, toolbar, SVG Lucide-иконки, skeleton loading
  • Свайп вниз для закрытия sheet
  • Drag-and-drop точек маршрута (touch + mouse)
  • Кнопка «Скачать GPX» (share dialog убран)
  • Фикс: «Добавить точку» из мини-бара
  • Десктоп-адаптив (toolbar слева, sheet max-width 400px)
  • Расстояние по маршруту между точками (по геометрии OSRM, масштабирование к route.distance_m)
  • Обновление расстояний при смене варианта маршрута

Баги исправлены (05.05):

  • «Добавить точку» не работала — addWaypointMode() не устанавливала routeMode = true
  • Drag-and-drop не работал на десктопе — добавлены mouse-события
  • Расстояние в списке точек показывало haversine по прямой вместо маршрута
  • При смене варианта маршрута расстояния не обновлялись (selectRoute/selectMiniRoute не вызывали renderWaypointsList)
  • renderWaypointsList вызывался до построения маршрута → добавлен вызов после drawRouteResults
  • Деплой статики через deploy_app2.js не работал (копировал только app.py) → нужен deploy_static.js + docker cp после рестарта контейнера (образ перезаписывает статику при рестарте)

Технические решения:

  • getRouteSegmentDistances() — snap waypoints к геометрии маршрута, суммирование haversine по точкам, масштабирование к route.distance_m
  • snapIdx[0] = 0, snapIdx[last] = n-1 — принудительный snap первой/последней точки
  • Деплой статики: SFTP → сервер → docker restartdocker cp (порядок важен!)
  • streaming.mode: "off" в Telegram канале — убраны дублированные сообщения
  • send_voice.sh — убрана отправка через openclaw message send, только генерация OGG + MEDIA: директива

⚠️ Фаза 5.4 — Рельеф на карте (12.05.2026, в работе)

BRD: BRD_TERRAIN.md
DEV TASK: DEV_TASK_TERRAIN.md
TEST CASES: TEST_CASES_TERRAIN.md

Что сделано:

  • SRTM данные скачаны (ЦФО + Чувашия)
  • Hillshade тайлы сгенерированы (зумы 10-15, 3.04M тайлов)
  • Hypso тайлы перегенерированы (зумы 5-15, 1.05M тайлов) — убран синий nodata
  • Nginx настроен: /enduro/terrain/ → alias /home/slin/enduro-trails/data/terrain/
  • Cache-Control: public, immutable
  • Кнопка 🏔️ в toolbar, попап с чекбоксами «Гипсометрия» / «Отмывка»
  • localStorage персистентность состояния
  • Кнопка active при включённом слое
  • Попап закрывается по клику вне / повторному нажатию
  • Hillshade чекбокс disabled на зуме < 10 + hint «Зум 10+»
  • scheme: 'tms' в sources (тайлы в TMS формате)
  • bounds: [35, 45, 55, 62] — ограничение запросов регионом данных
  • Z-index: рельеф под дорогами (beforeId = первый road/trail layer)

Известные проблемы:

  • ⚠️ Гипсометрия выглядит как однородный зелёный блок на малых зумах — ЦФО равнина, мало перепадов. Нужна корректировка color ramp для лучшей дифференциации низких высот (0-200м)
  • TC-24/TC-25 (мобильный попап) — не проверены, ждут ручного тестирования

Тест-кейсы (TC-07..TC-25):

  • 19 из 19 автоматизируемых — зелёные
  • 2 мобильных (TC-24, TC-25) — ожидают ручной проверки

Технические детали:

  • Тайлы генерировались gdal2tiles.py без --xyz → формат TMS (y инвертирован)
  • MapLibre source: scheme: 'tms' для корректного маппинга
  • Color ramp: hypso_ramp.txt, nodata → прозрачный (alpha), убрана строка -100 70 107 159
  • Hypso: opacity 0.55, hillshade: opacity 0.40
  • Фронтенд отдаётся через FastAPI (контейнер), статика через docker cp
  • Terrain тайлы отдаются nginx напрямую (не через контейнер)

Фаза 6 — SRTM рельеф (продвинутый)

  • F-12 «Горка» — макс набор высоты, мин дистанция
  • Профиль высот на маршруте
  • SRTM данные уже есть после фазы 5.4

Фаза 7 — PWA + офлайн

  • F-17 Service Worker, офлайн MBTiles, GPS-трекинг в реальном времени
  • Интеграция с OsmAnd/Locus (экспорт)

Фаза 8 — Народные треки

  • F-15 Источники: OSM Traces, Wikiloc, Komoot, 4x4travel.ru, Enduroad.ru
  • Отдельный слой community_tracks, фильтрация по типу активности

Ключевые решения

Решение Причина
4 uvicorn workers Устранение узкого места однопоточности
Фильтр по length_m на низких зумах Производительность, читаемость
Относительные пути в app.js Работает через nginx /enduro/ и по прямому IP
OSRM weight_name='routability' duration → OSRM выбирал асфальт
forward_rate = penalty Penalty/метр — прямой вес пути
radiuses=5000 в OSRM запросах Без этого длинные маршруты не снэппятся
Retry TooBig: 5→3→1 OSRM не даёт 5 альтернатив на длинных маршрутах
Retry NoSegment: radiuses=10000 Точки далеко от дорог — нужен широкий snap
Timeout 60s для retry Длинные маршруты строятся >30с
docker cp после рестарта (не до) Образ перезаписывает статику при рестарте — cp нужен после того как контейнер поднялся
deploy_app2.js только для app.py Скрипт не копирует статику — для фронтенда использовать deploy_static.js + ручной cp после рестарта
Масштабирование сегментов к route.distance_m OSRM геометрия упрощена — haversine по точкам даёт ~0.2% погрешность; масштабирование даёт точное совпадение
renderWaypointsList() после drawRouteResults() Список рендерится до построения маршрута — нужен повторный вызов когда routeResults заполнен
Тайлы terrain в TMS формате gdal2tiles.py без --xyz генерирует TMS; MapLibre по умолчанию XYZ → нужен scheme: 'tms' в source
bounds: [35, 45, 55, 62] в terrain sources Без bounds MapLibre запрашивает тайлы за пределами региона → 404
nodata → прозрачный (alpha) Строка -100 70 107 159 в ramp красила водоёмы/nodata в синий; убрана, добавлен -alpha при генерации
Terrain тайлы через nginx, не через контейнер Статика быстрее через nginx alias; контейнер обслуживает только API и фронтенд
streaming.mode: "off" для Telegram partial и progress шлют промежуточные сообщения — off даёт одно финальное
Сэмплирование каждые ~500м для stats Без этого расчёт >30с на длинных маршрутах
Grid cache для calc_route_stats Убирает повторные SQL запросы для близких точек

Документы

Документ Описание
PROJECT.md Этот файл — общее состояние проекта
CONCEPT.md Концепция и архитектура
TECHNICAL_SPEC.md ТЗ прототипа v0.1
DEV_TASK.md Стабилизация v0.1 (архив)
BRD_PHASE3.md Бизнес-требования Фазы 3 (согласовано)
BRD_PHASE3.1.md Бизнес-требования Фазы 3.1 (на согласовании)
BRD_PHASE5.md Бизнес-требования Фазы 5 ( реализовано)
BRD_TERRAIN.md Бизнес-требования Фазы 5.4 — Рельеф
DEV_TASK_TERRAIN.md ТЗ для Dev-агента Фаза 5.4
TEST_CASES_PHASE3.md 56 тест-кейсов
DEV_TASK_PHASE3.md ТЗ для Dev-агента Фаза 3
DEV_TASK_PHASE5.md ТЗ для Dev-агента Фаза 5
TEST_CASES_TERRAIN.md 25 тест-кейсов Фазы 5.4 (19/19 auto , 2 mobile )
reports/ Отчёты о тестировании

Ссылка на онтологию: proj_enduro_trails