# 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-агенту.*
