# BRD: Enduro Trails — Фаза 4 «Продвинутый роутинг» **Версия:** 1.0 **Дата:** 2026-05-04 **Автор:** Стрим 🌊 **Статус:** Согласовано ✅ --- ## 1. Контекст и цели ### Что уже есть - Роутинг A→B «Дикий путь» (OSRM, до 5 альтернатив) - Статистика покрытия (% грунт/асфальт/тропа) - Промежуточные точки, GPX экспорт - POI в БД: water, peak, viewpoint, ruins, ford, cave_entrance (14K штук) ### Проблема «Дикий путь» даёт маршрут от A до B с максимумом грунтовок. Но эндуристу часто нужно другое: - **«Покататься красиво»** — замкнутый круг от дома, через живописные места, и обратно - **«Найти грунтовки рядом»** — не знаешь куда ехать, покажи что есть вокруг - **«Соединить два трека»** — есть два хороших участка, как их связать грунтовками ### Цель Дать эндуристу 3 новых режима роутинга, которые закрывают типичные сценарии: покататься, разведать, связать. --- ## 2. Фичи --- ### F-11: «Красивый маршрут» (Scenic Route) #### Описание Пользователь указывает **точку старта** и **желаемую дистанцию**. Система строит **замкнутый кольцевой маршрут**, который проходит через максимально живописные места: озёра, видовые точки, заброшки, горы. #### Зачем Самый частый сценарий эндуриста: «Хочу покататься км на 150 от дома, но не по асфальту, а красиво». Сейчас нужно вручную ставить точки и строить маршрут. «Красивый маршрут» делает это автоматически. #### Use Cases **UC-11.1 — Покататься от дома** > Слава нажимает 🎨 «Красивый маршрут». Кликает на карте — точка старта (дом). Вводит дистанцию: 150 км. Система строит кольцевой маршрут: дом → озеро Сенеж → видовая точка → заброшка → грунтовки → дом. 142 км, 89% грунт. **UC-11.2 — Короткая поездка** > Слава хочет покататься на 50 км. Маршрут: дом → лесной массив → грунтовки → дом. 48 км, 94% грунт. **UC-11.3 — Несколько вариантов** > Система предлагает 2–3 кольцевых маршрута: северный (через озёра), восточный (через леса), южный (через поля). Слава выбирает северный — через озёра красивее. **UC-11.4 — Нет красивых мест рядом** > Слава в степи, рядом нет озёр и видов. Система строит максимально грунтовый кольцевой маршрут, но без бонусных точек. Подпись: «Живописных объектов поблизости не найдено, маршрут по грунтовкам». #### Алгоритм **Шаг 1: Найти привлекательные POI в радиусе** - Радиус = желаемая дистанция × 0.6 (примерное кольцо) - Выбрать POI с оценкой аттрактивности: | POI тип | Баллы | Вес | |---------|-------|-----| | `natural=water` (озёра, реки) | 10 | Высокий | | `tourism=viewpoint` (видовые точки) | 15 | Очень высокий | | `historic=ruins` (заброшки) | 10 | Высокий | | `natural=peak` (вершины) | 12 | Высокий | | `natural=cave_entrance` (пещеры) | 8 | Средний | | `ford=yes` (броды) | 5 | Низкий | **Шаг 2: Выбрать 3–5 POI для маршрута** - Жадный алгоритм: начать со старта, на каждом шаге выбирать ближайший POI с максимальными баллами - Суммарная дистанция до POI ≤ желаемая дистанция × 0.8 (оставить запас на возврат) - После последнего POI — маршрут обратно к старту **Шаг 3: Построить маршрут через POI** - Использовать OSRM: старт → POI1 → POI2 → ... → старт - Каждый сегмент — запрос к OSRM с `alternatives=false` **Шаг 4: Проверить дистанцию** - Если итоговая дистанция > желаемая × 1.3 — уменьшить кол-во POI, перестроить - Если < желаемая × 0.5 — добавить POI, перестроить **Шаг 5: Альтернативы** - Повторить с другим набором POI (другое направление от старта) - Дать 2–3 варианта #### UI **Кнопка:** 🎨 «Красивый маршрут» (рядом с 🗺️ «Дикий путь») **Панель:** ``` ┌─────────────────────────────────┐ │ 🎨 Красивый маршрут │ │ │ │ 📍 Точка старта: кликни на карте│ │ 📏 Дистанция: [150] км │ │ │ │ [Построить маршрут] │ └─────────────────────────────────┘ ``` **Карточка маршрута (после построения):** ``` ┌─────────────────────────────────┐ │ 🎨 Северный маршрут 142 км │ │ ████████████░░░ 4 ч 20 мин │ │ 89% грунт · 11% асфальт │ │ │ │ 💊 Живописные объекты: │ │ 💧 Озеро Сенеж │ │ 👁 Смотровая «Высокая» │ │ 🏚 Заброшенная ферма │ │ │ │ [📥 GPX] [Выбрать маршрут] │ └─────────────────────────────────┘ ``` #### Требования - Время построения ≤ 15 секунд (несколько OSRM запросов) - Дистанция: ввод от 20 до 500 км - Кольцевой маршрут = старт и финиш на одной точке - POI на маршруте показаны в карточке - Спиннер на время построения - До 3 вариантов маршрутов --- ### F-14: «Разведка» (Recon Mode) #### Описание Пользователь кликает на карту → система показывает **все грунтовые дороги в радиусе X км** с краткой статистикой: сколько дорог, какая длина, какие типы. #### Зачем «Приехал на новое место — что тут есть?». Не нужно строить маршрут — просто посмотреть какие грунтовки рядом, оценить стоит ли ехать сюда. #### Use Cases **UC-14.1 — Разведка в новом месте** > Слава приехал на дачу в незнакомый район. Нажимает 📍 «Разведка», кликает на карту. Появляется круг радиусом 20 км с выделенными грунтовками. Статистика: «124 грунтовки, 380 км грунтовых дорог, 85% grade3-5, 12 бродов». **UC-14.2 — Оценка перед поездкой** > Слава планирует поездку на выходные. Кликает на место на карте — видит что там всего 3 короткие грунтовки. Решает ехать в другое место. **UC-14.3 — Настройка радиуса** > По умолчанию радиус 20 км. Слава меняет на 50 км — видит больше грунтовок. #### Алгоритм 1. Получить координаты клика (lat, lon) 2. Запрос к БД: ```sql SELECT highway_type, track_type, surface, length_m, name FROM trails WHERE min_lon <= ? AND max_lon >= ? AND min_lat <= ? AND max_lat >= ? AND length_m >= 100 ``` где bbox = центр ± радиус (0.18° для 20 км, 0.45° для 50 км) 3. Агрегировать: количество, суммарная длина, распределение по типам 4. Отрисовать круг на карте + подсветить грунтовки внутри #### UI **Кнопка:** 📍 «Разведка» (рядом с 🗺️ и 🎨) **Попап при клике:** ``` ┌─────────────────────────────────┐ │ 📍 Разведка — 20 км радиус │ │ │ │ 🛤 124 грунтовки · 380 км │ │ │ │ 🟡 Lev1-2: 45 шт · 120 км │ │ 🔴 Lev3-5: 68 шт · 210 км │ │ 🔴 Тропы: 11 шт · 50 км │ │ │ │ 💧 Озёра: 3 · 👁 Виды: 2 │ │ 🌊 Броды: 12 · 🏚 Руины: 1 │ │ │ │ Радиус: [20] [50] [100] км │ └─────────────────────────────────┘ ``` **На карте:** - Круг (Circle) с полупрозрачной заливкой - Грунтовки внутри круга подсвечены (увеличена толщина / opacity) #### Требования - Радиус по умолчанию: 20 км, опции: 20 / 50 / 100 - Запрос к БД ≤ 2 секунды - Круг визуально не мешает карте - Статистика в попапе обновляется при изменении радиуса --- ### F-13: «Связка» (Link Route) #### Описание Пользователь указывает **два трека / точки на карте** → система строит **маршрут между ними по грунтовкам**, минуя асфальт. #### Зачем «Ехал по отличной грунтовке, потом по другой — а между ними 10 км асфальта. Можно ли как-то по грунтовкам перейти?» #### Use Cases **UC-13.1 — Связать два участка** > Слава проехал грунтовку А и грунтовку Б. Между ними 8 км асфальта. Нажимает 🔗 «Связка», ставит конечную точку А и начальную точку Б. Система находит обход по грунтовкам: 12 км вместо 8 км асфальта, но 100% грунт. **UC-13.2 — Нет грунтовой связки** > Между двумя точками нет никаких грунтовок — только асфальт. Система: «Грунтовая связка не найдена, кратчайший путь — 5 км по асфальту». #### Алгоритм Это просто роутинг A→B через «Дикий путь» — уже реализовано. Отличие только в UI: - Вместо кнопки «Дикий путь» — кнопка 🔗 «Связка» - Маркеры: не A/B, а «Трек 1 (конец)» и «Трек 2 (начало)» - Карточка показывает только % грунта (асфальт — нежелательный элемент) #### UI **Кнопка:** 🔗 «Связка» **Панель:** ``` ┌─────────────────────────────────┐ │ 🔗 Связка │ │ │ │ 1️⃣ Конец трека: кликни на карте│ │ 2️⃣ Начало трека: кликни │ │ │ │ [Найти грунтовую связку] │ └─────────────────────────────────┘ ``` **Карточка:** ``` ┌─────────────────────────────────┐ │ 🔗 Связка 12 км │ │ ██████████████████░ 24 мин │ │ 92% грунт · 8% асфальт │ │ │ │ [📥 GPX] [Выбрать] │ └─────────────────────────────────┘ ``` #### Требования - Использует тот же OSRM «Дикий путь» роутинг - Отличие от «Дикого пути» — только UI (другие маркеры, акцент на минимизацию асфальта) - До 3 альтернативных связок --- ## 3. Нефункциональные требования ### Производительность - «Красивый маршрут» — ≤ 15 сек (3–5 OSRM запросов) - «Разведка» — ≤ 2 сек (один SQL запрос) - «Связка» — ≤ 5 сек (один OSRM запрос) ### UI - 3 новые кнопки в панели управления: 🎨 🔗 📍 - Режимы взаимоисключающие: активный режим деактивирует остальные - При переключении режима — сброс предыдущего состояния --- ## 4. Приоритет реализации | # | Фича | Приоритет | Сложность | Ценность | |---|------|-----------|-----------|----------| | F-14 | «Разведка» | 🔴 Высокий | Низкая | Высокая | | F-13 | «Связка» | 🟡 Средний | Низкая | Средняя | | F-11 | «Красивый маршрут» | 🔴 Высокий | Высокая | Очень высокая | **Рекомендуемый порядок:** 1. **F-14 «Разведка»** — простая SQL-агрегация, быстрый результат, высокая ценность 2. **F-13 «Связка»** — почти готово (переиспользуем OSRM), минимум нового кода 3. **F-11 «Красивый маршрут»** — самый сложный (алгоритм выбора POI, несколько OSRM запросов), но самый ценный --- ## 5. Решения (согласовано 2026-05-04) | # | Вопрос | Решение | |---|--------|--------| | 1 | Ввод дистанции | Текстовое поле + пресеты (50/100/150/200 км) | | 2 | Направление маршрута | Система сама подбирает (без выбора направления) | | 3 | Радиус «Разведки» | 20/50/100 км — ок | | 4 | Точки «Связки» | Клик на карту (как «Дикий путь») | | 5 | Сезонность | Пока не учитываем | --- *Документ согласован. Готов к передаче Dev-агенту.*