auto-sync: 2026-05-04 10:10:01
This commit is contained in:
399
tasks/enduro-trails/BRD_PHASE3.md
Normal file
399
tasks/enduro-trails/BRD_PHASE3.md
Normal file
@@ -0,0 +1,399 @@
|
||||
# BRD: Enduro Trails — Фаза 3 «Умный маршрут»
|
||||
|
||||
**Версия:** 1.0
|
||||
**Дата:** 2026-05-04
|
||||
**Автор:** Стрим 🌊
|
||||
**Статус:** На согласовании со Славой
|
||||
|
||||
---
|
||||
|
||||
## 1. Контекст и цели
|
||||
|
||||
### Что уже есть (Фаза 1–2)
|
||||
- Карта грунтовок ЦФО+Чувашия (1.1М треков)
|
||||
- Роутинг «Дикий путь» A→B (OSRM, кастомный профиль)
|
||||
- Поиск населённых пунктов (Nominatim)
|
||||
- Линейка расстояний
|
||||
|
||||
### Цель Фазы 3
|
||||
Превратить «Дикий путь» из простого роутинга в **инструмент планирования маршрута**: несколько вариантов на выбор, детальная статистика по каждому, удобный экспорт. Пользователь должен уметь сравнить маршруты и выбрать тот, который ему нравится — не вслепую, а опираясь на данные.
|
||||
|
||||
### Приоритеты
|
||||
1. **Удобство** — минимум кликов, всё под рукой
|
||||
2. **Наглядность** — статистика читается с первого взгляда
|
||||
3. **Качество** — данные точные, UI не ломается на крайних случаях
|
||||
|
||||
---
|
||||
|
||||
## 2. Фичи
|
||||
|
||||
---
|
||||
|
||||
### F-01: Альтернативные маршруты
|
||||
|
||||
#### Описание
|
||||
При построении маршрута A→B система генерирует **до 5 вариантов** с разным балансом грунтовок/асфальта/дистанции. Все варианты отображаются на карте одновременно. Пользователь выбирает понравившийся.
|
||||
|
||||
#### Зачем
|
||||
Один маршрут — это лотерея. Иногда OSRM строит «технически правильный» путь, но он скучный или неудобный. Пользователь хочет видеть спектр вариантов и выбрать осознанно.
|
||||
|
||||
#### Use Cases
|
||||
|
||||
**UC-01.1 — Базовый выбор маршрута**
|
||||
> Слава ставит точки A и B. Нажимает «Дикий путь». Появляются 3–5 маршрутов разными цветами. Карточки вариантов показывают дистанцию, % грунта, время. Слава выбирает вариант с максимальным % грунта. Остальные исчезают, выбранный остаётся.
|
||||
|
||||
**UC-01.2 — Сравнение вариантов**
|
||||
> Слава видит вариант 1 (120 км, 85% грунт) и вариант 3 (95 км, 70% грунт). Хочет посмотреть оба на карте. Наводит мышь на карточку — соответствующий маршрут подсвечивается жирнее. Решает взять вариант 1 — больше грунта, пусть и длиннее.
|
||||
|
||||
**UC-01.3 — Нет альтернатив**
|
||||
> Точки A и B близко, только один разумный путь. Система показывает 1–2 варианта и поясняет: «Альтернативных маршрутов не найдено».
|
||||
|
||||
#### Требования
|
||||
- Минимум 1 маршрут, максимум 5
|
||||
- Варианты визуально различимы: разные цвета (палитра: синий, зелёный, фиолетовый, оранжевый, серый)
|
||||
- Активный (выбранный) маршрут — жирнее и ярче
|
||||
- Hover на карточке → подсветка маршрута на карте
|
||||
- Клик на карточке → выбор маршрута
|
||||
- Клик на маршруте на карте → выбор маршрута
|
||||
- Кнопка «Сбросить» убирает все маршруты и маркеры
|
||||
|
||||
#### Технические заметки
|
||||
OSRM поддерживает `alternatives=true` (до 3 вариантов) и `alternatives=N` (до 5). Параметр передаётся в запросе к `/route/v1/driving/`. Дополнительно можно варьировать `radiuses` и `snapping` для получения более разнообразных вариантов.
|
||||
|
||||
---
|
||||
|
||||
### F-02: Статистика маршрута
|
||||
|
||||
#### Описание
|
||||
Каждый маршрут сопровождается **карточкой со статистикой**: дистанция, время, разбивка покрытия по типам дорог. Карточки компактные, читаются за 2 секунды.
|
||||
|
||||
#### Зачем
|
||||
Без статистики маршрут — просто линия на карте. Пользователь не может оценить «насколько это грунтовый маршрут» без цифр и визуализации.
|
||||
|
||||
#### Use Cases
|
||||
|
||||
**UC-02.1 — Быстрая оценка**
|
||||
> Слава видит 4 карточки маршрутов. На каждой — дистанция, время и цветная полоска покрытия. За 5 секунд понимает: вариант 2 самый «грунтовый» (80% жёлтого в полоске), вариант 4 самый короткий. Выбирает вариант 2.
|
||||
|
||||
**UC-02.2 — Детальная статистика**
|
||||
> Слава выбрал маршрут. Карточка разворачивается: показывает детальную разбивку по км и %, количество треков каждого типа, расчётное время. Слава видит что 15 км из 120 — асфальт (неизбежный участок через город).
|
||||
|
||||
**UC-02.3 — Сравнение двух маршрутов**
|
||||
> Слава не может выбрать между вариантом 1 и 3. Нажимает «Сравнить» — карточки встают рядом, колонки выровнены. Видно что вариант 1 длиннее на 25 км, но даёт +15% грунта.
|
||||
|
||||
#### Состав статистики
|
||||
|
||||
**Компактная карточка (всегда видна):**
|
||||
- Номер варианта + цветовой маркер
|
||||
- Дистанция: `142 км`
|
||||
- Время: `4 ч 35 мин` (см. F-03)
|
||||
- Полоска покрытия (цветная, пропорциональная):
|
||||
- 🟡 Lev1-2 (грунт твёрдый)
|
||||
- 🔴 Lev3-5 (грунт мягкий)
|
||||
- 🔴 Тропа (path/bridleway)
|
||||
- ⬜ Асфальт
|
||||
|
||||
**Развёрнутая карточка (по клику «Подробнее»):**
|
||||
- Разбивка по км и %:
|
||||
```
|
||||
Lev1-2 (твёрдый грунт): 68 км (48%)
|
||||
Lev3-5 (мягкий грунт): 42 км (30%)
|
||||
Тропы: 12 км (8%)
|
||||
Асфальт: 20 км (14%)
|
||||
```
|
||||
- Итого грунт: `122 км (86%)`
|
||||
- Итого асфальт: `20 км (14%)`
|
||||
|
||||
#### Требования
|
||||
- Полоска покрытия — пропорциональная, минимальная ширина сегмента 3px (чтобы не терялся)
|
||||
- Цвета полоски совпадают с цветами слоёв на карте
|
||||
- Статистика считается на бэкенде по геометрии маршрута + данным БД
|
||||
- Карточки не перекрывают карту (панель сбоку или снизу)
|
||||
|
||||
---
|
||||
|
||||
### F-03: Человекочитаемое время
|
||||
|
||||
#### Описание
|
||||
Время маршрута отображается в формате `X ч Y мин` или `X дн Y ч Z мин`. Никаких «135 минут».
|
||||
|
||||
#### Зачем
|
||||
«135 минут» — это неудобно. Мозг не воспринимает большие числа минут интуитивно. «2 ч 15 мин» — сразу понятно.
|
||||
|
||||
#### Use Cases
|
||||
|
||||
**UC-03.1 — Короткий маршрут**
|
||||
> Маршрут 45 минут → отображается `45 мин`
|
||||
|
||||
**UC-03.2 — Стандартный маршрут**
|
||||
> Маршрут 155 минут → отображается `2 ч 35 мин`
|
||||
|
||||
**UC-03.3 — Длинный маршрут**
|
||||
> Маршрут 1560 минут → отображается `1 дн 2 ч`
|
||||
|
||||
**UC-03.4 — Очень длинный маршрут**
|
||||
> Маршрут 2750 минут → отображается `1 дн 21 ч 50 мин`
|
||||
|
||||
#### Правила форматирования
|
||||
```
|
||||
< 60 мин → "X мин"
|
||||
60 мин – 23:59 → "X ч Y мин" (если Y=0 → "X ч")
|
||||
≥ 24 ч → "X дн Y ч Z мин" (если Z=0 → "X дн Y ч")
|
||||
```
|
||||
|
||||
#### Требования
|
||||
- Реализовать как утилитарную функцию `formatDuration(seconds)` в `app.js`
|
||||
- Применить везде где отображается время: карточки маршрутов, развёрнутая статистика
|
||||
- Время считается от OSRM (секунды) — конвертировать на фронте
|
||||
|
||||
---
|
||||
|
||||
### F-04: Промежуточные точки маршрута
|
||||
|
||||
#### Описание
|
||||
Пользователь может добавить **промежуточные точки** (waypoints) между A и B. Маршрут строится через все точки по порядку. Точки можно перетаскивать.
|
||||
|
||||
#### Зачем
|
||||
Часто нужно «зайти» в конкретное место — деревню, лесной массив, смотровую точку. Без промежуточных точек маршрут строится напрямую и может обойти интересное место стороной.
|
||||
|
||||
#### Use Cases
|
||||
|
||||
**UC-04.1 — Добавление точки**
|
||||
> Слава построил маршрут A→B. Видит что маршрут обходит интересный лесной массив. Нажимает «+ Точка» и кликает на карте в нужном месте. Маршрут перестраивается через новую точку C: A→C→B.
|
||||
|
||||
**UC-04.2 — Несколько точек**
|
||||
> Слава добавляет 3 промежуточные точки. Маршрут строится A→C1→C2→C3→B. В панели точек видны все 5 точек с возможностью удалить любую.
|
||||
|
||||
**UC-04.3 — Перетаскивание точки**
|
||||
> Слава хочет немного сдвинуть промежуточную точку. Перетаскивает маркер на карте. Маршрут перестраивается в реальном времени (debounce 300ms).
|
||||
|
||||
**UC-04.4 — Удаление точки**
|
||||
> В панели точек Слава нажимает ✕ рядом с промежуточной точкой. Точка удаляется, маршрут перестраивается.
|
||||
|
||||
**UC-04.5 — Изменение порядка**
|
||||
> Слава хочет поменять порядок точек. Перетаскивает строку в панели точек (drag-and-drop). Маршрут перестраивается.
|
||||
|
||||
#### Требования
|
||||
- Максимум 8 промежуточных точек (итого 10 точек включая A и B)
|
||||
- Маркеры промежуточных точек визуально отличаются от A/B (меньше, другой цвет — белый с цветной обводкой)
|
||||
- Перестройка маршрута при перетаскивании — debounce 300ms
|
||||
- Панель точек: список с иконками A, 1, 2, ..., B и кнопками удаления
|
||||
- При добавлении точки режим «добавить точку» активируется кнопкой, деактивируется после клика
|
||||
|
||||
---
|
||||
|
||||
### F-05: Экспорт GPX
|
||||
|
||||
#### Описание
|
||||
Выбранный маршрут можно скачать в формате GPX для загрузки в навигатор (OsmAnd, Garmin, Locus Map и др.).
|
||||
|
||||
#### Зачем
|
||||
Карта в браузере — для планирования. В поле нужен навигатор. GPX — универсальный формат, поддерживается всеми мото/вело навигаторами.
|
||||
|
||||
#### Use Cases
|
||||
|
||||
**UC-05.1 — Скачать маршрут**
|
||||
> Слава выбрал маршрут. Нажимает «Скачать GPX». Браузер скачивает файл `enduro-route-2026-05-04.gpx`. Слава загружает его в OsmAnd.
|
||||
|
||||
**UC-05.2 — GPX с промежуточными точками**
|
||||
> Маршрут с 3 промежуточными точками. GPX содержит все waypoints + трек. В OsmAnd точки отображаются как промежуточные остановки.
|
||||
|
||||
**UC-05.3 — Имя файла**
|
||||
> Файл называется `enduro-YYYYMMDD-HHMMSS.gpx` — уникальное имя, не перезаписывает предыдущие.
|
||||
|
||||
#### Требования
|
||||
- GPX 1.1 формат
|
||||
- Содержит: `<trk>` с геометрией маршрута + `<wpt>` для всех точек (A, промежуточные, B)
|
||||
- Метаданные: name, desc, time
|
||||
- Генерация на фронте (из геометрии OSRM ответа) — не требует бэкенда
|
||||
- Кнопка «Скачать GPX» активна только когда маршрут выбран
|
||||
|
||||
---
|
||||
|
||||
### F-06: Флажки / именованные метки
|
||||
|
||||
#### Описание
|
||||
Пользователь может расставить на карте **именованные метки** (флажки) — интересные места, точки старта, лагерь, заправка и т.д. Метки сохраняются в localStorage.
|
||||
|
||||
#### Зачем
|
||||
При планировании маршрута нужно отмечать «хочу заехать сюда», «здесь заправка», «здесь ночёвка». Без меток всё держится в голове или в отдельных заметках.
|
||||
|
||||
#### Use Cases
|
||||
|
||||
**UC-06.1 — Поставить метку**
|
||||
> Слава нажимает кнопку 🚩. Курсор меняется. Кликает на карте. Появляется диалог: поле для названия (placeholder «Метка 1»), выбор иконки (🚩⛺🔧⛽💧). Нажимает «Сохранить». Метка появляется на карте.
|
||||
|
||||
**UC-06.2 — Метка без названия**
|
||||
> Слава кликает и сразу нажимает Enter (пустое название). Метка сохраняется с автоименем «Метка N».
|
||||
|
||||
**UC-06.3 — Клик по метке**
|
||||
> Слава кликает по существующей метке. Попап: название, координаты, кнопки «Редактировать» и «Удалить».
|
||||
|
||||
**UC-06.4 — Метки сохраняются**
|
||||
> Слава закрывает браузер, открывает снова. Все метки на месте (localStorage).
|
||||
|
||||
**UC-06.5 — Использовать метку как точку маршрута**
|
||||
> В попапе метки есть кнопки «Сделать точкой A» и «Сделать точкой B». Слава нажимает «Сделать точкой A» — метка становится стартом маршрута.
|
||||
|
||||
**UC-06.6 — Экспорт меток в GPX**
|
||||
> При скачивании GPX (F-05) метки включаются как `<wpt>` с именами.
|
||||
|
||||
#### Требования
|
||||
- Хранение: localStorage, ключ `enduro_markers`
|
||||
- Максимум 50 меток (предупреждение при достижении лимита)
|
||||
- Иконки: 🚩 (по умолчанию), ⛺, 🔧, ⛽, 💧, 📍
|
||||
- Метки отображаются поверх всех слоёв
|
||||
- Кнопка «Очистить все метки» с подтверждением
|
||||
|
||||
---
|
||||
|
||||
## 3. Нефункциональные требования
|
||||
|
||||
### Производительность
|
||||
- Построение маршрута (включая статистику) — не более 5 секунд
|
||||
- При ожидании — спиннер на кнопке, карта не блокируется
|
||||
- Перестройка при перетаскивании точки — debounce 300ms, не тормозит UI
|
||||
|
||||
### Мобильность
|
||||
- Панель маршрутов не перекрывает карту на экранах < 768px
|
||||
- Карточки маршрутов скроллируются горизонтально на мобиле
|
||||
- Touch-события для перетаскивания точек
|
||||
|
||||
### Надёжность
|
||||
- Если OSRM не вернул альтернативы — показать 1 маршрут без ошибки
|
||||
- Если статистика не посчиталась — показать маршрут без статистики, не ломать UI
|
||||
- Если localStorage недоступен — метки работают только в сессии, без ошибки
|
||||
|
||||
---
|
||||
|
||||
## 4. Изменения в бэкенде
|
||||
|
||||
### Новый endpoint: `/api/route` (расширение существующего)
|
||||
|
||||
**Запрос:**
|
||||
```json
|
||||
{
|
||||
"waypoints": [
|
||||
{"lon": 37.6, "lat": 55.7},
|
||||
{"lon": 38.1, "lat": 55.9},
|
||||
{"lon": 39.5, "lat": 56.2}
|
||||
],
|
||||
"alternatives": 5
|
||||
}
|
||||
```
|
||||
|
||||
**Ответ:**
|
||||
```json
|
||||
{
|
||||
"routes": [
|
||||
{
|
||||
"index": 0,
|
||||
"geometry": { "type": "LineString", "coordinates": [...] },
|
||||
"distance_m": 142000,
|
||||
"duration_s": 16500,
|
||||
"stats": {
|
||||
"track_lev12_m": 68000,
|
||||
"track_lev345_m": 42000,
|
||||
"path_m": 12000,
|
||||
"asphalt_m": 20000,
|
||||
"track_lev12_pct": 48,
|
||||
"track_lev345_pct": 30,
|
||||
"path_pct": 8,
|
||||
"asphalt_pct": 14,
|
||||
"dirt_total_pct": 86
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### Логика расчёта статистики
|
||||
1. Получить геометрию маршрута от OSRM (LineString)
|
||||
2. Разбить на сегменты по 50м
|
||||
3. Для каждого сегмента — найти ближайший трек в БД (spatial query по bbox)
|
||||
4. Суммировать длины по типам: `highway_type` + `track_type`
|
||||
5. Вернуть в ответе вместе с геометрией
|
||||
|
||||
> ⚠️ Расчёт статистики — приближённый (snap to nearest road). Точность ±5% — достаточно для принятия решения.
|
||||
|
||||
---
|
||||
|
||||
## 5. UI/UX требования
|
||||
|
||||
### Панель маршрутов
|
||||
- Появляется справа (десктоп) или снизу (мобиле) после построения маршрутов
|
||||
- Карточки маршрутов: компактные, скроллируемые
|
||||
- Активный маршрут выделен рамкой/фоном
|
||||
- Кнопка «Сбросить всё» — сбрасывает маршруты и точки
|
||||
|
||||
### Карточка маршрута (компактная)
|
||||
```
|
||||
┌─────────────────────────────────┐
|
||||
│ ● Вариант 1 142 км │
|
||||
│ ████████████░░░ 4 ч 35 мин │
|
||||
│ 86% грунт · 14% асфальт │
|
||||
│ [Подробнее ▼] │
|
||||
└─────────────────────────────────┘
|
||||
```
|
||||
- Цветная точка = цвет маршрута на карте
|
||||
- Полоска = визуализация покрытия
|
||||
- Клик на карточку = выбор маршрута
|
||||
|
||||
### Карточка маршрута (развёрнутая)
|
||||
```
|
||||
┌─────────────────────────────────┐
|
||||
│ ● Вариант 1 142 км │
|
||||
│ ████████████░░░ 4 ч 35 мин │
|
||||
│ │
|
||||
│ 🟡 Lev1-2 68 км 48% │
|
||||
│ 🔴 Lev3-5 42 км 30% │
|
||||
│ 🔴 Тропы 12 км 8% │
|
||||
│ ⬜ Асфальт 20 км 14% │
|
||||
│ │
|
||||
│ [📥 GPX] [Выбрать маршрут] │
|
||||
└─────────────────────────────────┘
|
||||
```
|
||||
|
||||
### Панель точек
|
||||
```
|
||||
┌─────────────────────────────────┐
|
||||
│ 📍 Точки маршрута [+ Точка] │
|
||||
│ A Москва, ул. Ленина [✕] │
|
||||
│ 1 55.812, 37.441 [✕] │
|
||||
│ B Тверь, центр [✕] │
|
||||
└─────────────────────────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 6. Приоритет реализации
|
||||
|
||||
| # | Фича | Приоритет | Сложность | Ценность |
|
||||
|---|------|-----------|-----------|----------|
|
||||
| F-03 | Человекочитаемое время | 🔴 Высокий | Низкая | Высокая |
|
||||
| F-01 | Альтернативные маршруты | 🔴 Высокий | Средняя | Очень высокая |
|
||||
| F-02 | Статистика маршрута | 🔴 Высокий | Средняя | Очень высокая |
|
||||
| F-05 | Экспорт GPX | 🟡 Средний | Низкая | Высокая |
|
||||
| F-04 | Промежуточные точки | 🟡 Средний | Высокая | Высокая |
|
||||
| F-06 | Флажки/метки | 🟢 Низкий | Средняя | Средняя |
|
||||
|
||||
**Рекомендуемый порядок реализации:**
|
||||
1. F-03 (время) — быстро, сразу улучшает UX
|
||||
2. F-01 + F-02 (альтернативы + статистика) — ядро фазы, делать вместе
|
||||
3. F-05 (GPX) — логичное продолжение после выбора маршрута
|
||||
4. F-04 (промежуточные точки) — отдельный итерация
|
||||
5. F-06 (флажки) — последними, наименее критично
|
||||
|
||||
---
|
||||
|
||||
## 7. Открытые вопросы для Славы
|
||||
|
||||
1. **Количество альтернатив:** сколько вариантов хочешь видеть максимум? OSRM даёт до 5, но 3–4 обычно достаточно.
|
||||
2. **Статистика — точность vs скорость:** расчёт по сегментам даёт ~5% погрешность, но быстро. Нужна точнее — будет медленнее. Устраивает приближение?
|
||||
3. **Промежуточные точки — перетаскивание на карте:** нужно ли, или достаточно удалить + добавить заново?
|
||||
4. **Флажки — синхронизация:** метки только в браузере (localStorage) или хочешь чтобы сохранялись на сервере (между устройствами)?
|
||||
5. **GPX — треки или маршрут:** GPX может содержать трек (все точки геометрии) или маршрут (только waypoints для навигатора). Что нужно? Или оба варианта?
|
||||
|
||||
---
|
||||
|
||||
*Документ готов к передаче Dev-агенту после согласования со Славой.*
|
||||
Reference in New Issue
Block a user