Files
wiki/tasks/enduro-trails/BRD_PHASE4.md
2026-05-04 23:10:01 +03:00

294 lines
16 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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 — Несколько вариантов**
> Система предлагает 23 кольцевых маршрута: северный (через озёра), восточный (через леса), южный (через поля). Слава выбирает северный — через озёра красивее.
**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: Выбрать 35 POI для маршрута**
- Жадный алгоритм: начать со старта, на каждом шаге выбирать ближайший POI с максимальными баллами
- Суммарная дистанция до POI ≤ желаемая дистанция × 0.8 (оставить запас на возврат)
- После последнего POI — маршрут обратно к старту
**Шаг 3: Построить маршрут через POI**
- Использовать OSRM: старт → POI1 → POI2 → ... → старт
- Каждый сегмент — запрос к OSRM с `alternatives=false`
**Шаг 4: Проверить дистанцию**
- Если итоговая дистанция > желаемая × 1.3 — уменьшить кол-во POI, перестроить
- Если < желаемая × 0.5 — добавить POI, перестроить
**Шаг 5: Альтернативы**
- Повторить с другим набором POI (другое направление от старта)
- Дать 23 варианта
#### 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 сек (35 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-агенту.*