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

24 KiB
Raw Blame History

BRD: Enduro Trails — Фаза 3 «Умный маршрут»

Версия: 1.1
Дата: 2026-05-04
Автор: Стрим 🌊
Статус: Согласовано


1. Контекст и цели

Что уже есть (Фаза 12)

  • Карта грунтовок ЦФО+Чувашия (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. Нажимает «Дикий путь». Появляются 35 маршрутов разными цветами. Карточки вариантов показывают дистанцию, % грунта, время. Слава выбирает вариант с максимальным % грунта. Остальные исчезают, выбранный остаётся.

UC-01.2 — Сравнение вариантов

Слава видит вариант 1 (120 км, 85% грунт) и вариант 3 (95 км, 70% грунт). Хочет посмотреть оба на карте. Наводит мышь на карточку — соответствующий маршрут подсвечивается жирнее. Решает взять вариант 1 — больше грунта, пусть и длиннее.

UC-01.3 — Нет альтернатив

Точки A и B близко, только один разумный путь. Система показывает 12 варианта и поясняет: «Альтернативных маршрутов не найдено».

Требования

  • Минимум 1 маршрут, максимум 5 (подтверждено Славой)
  • Варианты визуально различимы: разные цвета (палитра: синий, зелёный, фиолетовый, оранжевый, серый)
  • Активный (выбранный) маршрут — жирнее и ярче
  • Hover на карточке → подсветка маршрута на карте
  • Клик на карточке → выбор маршрута
  • Клик на маршруте на карте → выбор маршрута
  • Кнопка «Сбросить» убирает все маршруты и маркеры

Технические заметки

OSRM поддерживает alternatives=true (до 3 вариантов) и alternatives=N (до 5). Параметр передаётся в запросе к /route/v1/driving/. Дополнительно можно варьировать radiuses и snapping для получения более разнообразных вариантов. Запрашивать alternatives=5 всегда — показывать сколько вернёт OSRM (от 1 до 5).


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. Файл содержит и трек (полная геометрия), и waypoints (метки + точки маршрута).

UC-05.2 — GPX с промежуточными точками

Маршрут с 3 промежуточными точками. GPX содержит все waypoints + трек. В OsmAnd точки отображаются как промежуточные остановки.

UC-05.3 — Имя файла

Файл называется enduro-YYYYMMDD-HHMMSS.gpx — уникальное имя, не перезаписывает предыдущие.

Требования

  • GPX 1.1 формат
  • Содержит оба элемента (подтверждено Славой):
    • <trk> + <trkseg> — полная геометрия маршрута (все точки от OSRM)
    • <wpt> — точки A, промежуточные, B + все флажки/метки с карты
  • Метаданные: name (Enduro route YYYY-MM-DD), desc (дистанция + % грунта), time
  • Генерация на фронте (из геометрии OSRM ответа + localStorage меток) — не требует бэкенда
  • Кнопка «Скачать 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 (расширение существующего)

Запрос:

{
  "waypoints": [
    {"lon": 37.6, "lat": 55.7},
    {"lon": 38.1, "lat": 55.9},
    {"lon": 39.5, "lat": 56.2}
  ],
  "alternatives": 5
}

Ответ:

{
  "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. Решения (согласовано 2026-05-04)

# Вопрос Решение
1 Количество альтернатив 5 — запрашивать максимум, показывать сколько вернёт OSRM
2 Точность статистики ±5% ок — приближённый расчёт по сегментам
3 Перетаскивание точек Нужно — drag на карте с debounce 300ms
4 Синхронизация меток Только localStorage — между устройствами не нужно
5 Формат GPX Трек + метки<trk> с геометрией и <wpt> для всех точек и флажков

Документ согласован. Готов к передаче Dev-агенту.