# Enduro Trails — Концепция и Архитектура

**Дата:** 02.05.2026
**Автор:** Стрим 🌊
**Статус:** Концепция, ожидает согласования со Славой

---

## 🎯 Проблема

Обычные OSM-карты оптимизированы для автомобилей — они ярко подсвечивают магистрали, а грунтовые дороги и тропы прячутся в шум. Для эндуро это **бесполезно**: асфальт не интересен, хочется увидеть где можно проехать по-настоящему.

## 💡 Решение

Создать карту, где **грунтовки/тропы — главный слой**, а асфальт — тусклый фон. Плюс фичи для поиска и построения красивых маршрутов.

---

## Архитектура

Схема архитектуры: `enduro_architecture.png`

```
OSM данные → ETL парсинг → Spatialite/PostGIS
                                    ├── Слой: Грунтовки
                                    ├── Слой: Рельеф (SRTM)
                                    ├── Слой: Препятствия
                                    ├── Роутинг (OSRM/GraphHopper)
                                    └── Аттрактивность (озёра, виды)
                                    ↓
                              API Backend (FastAPI)
                                    ↓
                ┌───────────────────┼───────────────────┐
                ↓                   ↓                   ↓
          Фронт (PWA)          Экспорт GPX/KML     Мобильный оффлайн
```

---

## Компоненты

### 1. Источник данных

| Метод | Плюсы | Минусы | Когда нужен |
|-------|--------|---------|-------------|
| **PBF дамп** (Geofabrik) | Один раз скачал → локально нет API limits | Обновление раз в неделю | Основной метод |
| **Overpass API** | Свежие данные (1-5 мин) | Rate limits, нужен интернет | По требованию / дельты |

**Рекомендация:** PBF как база + Overpass для свежих изменений

**Регион:** По умолчанию Центральный ФО, потом — расширение на всю Россию

### 2. ETL Парсинг

**Технология:** Pyrosm (Python + osmium) или нативный Osmium

**Что парсим:**

#### Дороги (highway=*)
- `track` — грунтовые дороги (основной фокус!)
  - `tracktype=grade1-5` — классификация по твёрдости
  - `surface=unpaved/gravel/sand/mud/earth` — покрытие
  - `trail_visibility=yes/no/negative` — видимость тропы
- `path` — тропы (пешие + вел/мото)
  - `mtb:scale=0-6` — сложность МТБ
  - `sac_scale=hiking/alpine/demanding` — уровень
- `unclassified` + `residential` + `service` + `footway` — только для связки (фон)
- `motorway/trunk/primary/secondary/tertiary` — асфальт (фон, минимум деталей)

#### Рельеф
- SRTM DEM (30 м) или SRTM 90 м
- Тангенс угла наклона → визуализация крутизны
- Перепады высот для оценки аттрактивности

#### Препятствия и ориентиры
```
waterway=ditch + ford     — броды и канавы (пройти или нет?)
waterway=stream + ford    — ручьи с бродом
natural=wetland           — болота (сложно!)
natural=sand              — пески
natural=mud               — грязевые участки
power=line + tower        — ЛЭП как визуальные ориентиры
barrier=gate + bollard    — шлагбаумы, столбики
highway=milestone         — километровые столбы
abandoned=*               — заброшенные дороги, шахты
ruins=yes                 — ruins, объекты интереса
leisure=nature_reserve    — заповедники, ограничения
boundary=national_park    — нацпарки

man_made=bridge
ford=yes                  — броды!
surface=water + highway=track — переправы
highway=construction      — строящиеся дороги (проехать?)
```

### 3. Хранилище

**Основной выбор:** Spatialite (SQLite с SpatialExtensions)
- Меньше зависимостей, portable
- Файл .sqlite, легко бэкап/мигрировать
- Достаточно для одного региона

**Альтернатива:** PostGIS (есть на FR24 VM!)
- Если нужен мультирегион или больше данных
- Лучшая производительность на больших масштабах
- Уже есть инфраструктура

**Структура таблиц:**

```sql
-- Дороги
CREATE TABLE trails (
    id INTEGER PRIMARY KEY,
    osm_id INTEGER,
    highway_type TEXT,           -- track, path, etc.
    track_type TEXT,             -- grade1-5
    surface TEXT,                -- paved, gravel, sand, etc.
    name TEXT,
    geometry GEOMETRY,           -- LINESTRING
    length_m REAL,               -- длина в метрах
    start_elevation REAL,        -- высота начала
    end_elevation REAL,          -- высота конца
    max_slope REAL,              -- макс уклон %
    avg_slope REAL,              -- средний уклон %
    mtb_scale TEXT,              -- mtb:scale
    visibility TEXT,             -- trail_visibility
    access TEXT,                 -- access=private/no
    bridge TEXT,                 -- yes/no
    ford TEXT,                   -- yes/no
    tags JSON                    -- остальные теги
);

-- Точки интереса (POI)
CREATE TABLE poi (
    id INTEGER PRIMARY KEY,
    osm_id INTEGER,
    poi_type TEXT,               -- lake, viewpoint, ruins, etc.
    name TEXT,
    geometry GEOMETRY,           -- POINT
    elevation REAL,
    tags JSON
);

-- Слой рельефа
CREATE TABLE elevation_grid (
    id INTEGER PRIMARY KEY,
    geometry GEOMETRY,           -- POLYGON (ячейка сетки)
    min_elev REAL,
    max_elev REAL,
    avg_elev REAL,
    slope_pct REAL               -- наклон
);
```

### 4. Роутинг

**Технология:** OSRM (Open Source Routing Machine) или GraphHopper

**Кастомизация профиля "Enduro":**

| Фактор | Вес |
|--------|-----|
| Грунтовки grade3-5 | 🟢 Минимальный вес (привлекают!) |
| Асфальт primary+ | 🔴 Максимальный вес (избегать) |
| Рядом с озером/видом | 🟢 Бонус (притягивает маршрут) |
| Броды | ⚠️ Средний (зависит от настроек) |
| Болота/пески | 🔴 Высокий (сложность) |
| Частная территория | ⛔ Проклятие (не роутить!) |
| Макс уклон > 20% | ⚠️ Высокий (по желанию) |

### 5. Фичи для построения маршрутов

#### 🛤️ "Дикий путь" (Wild Route)
- **Вход:** точки А и Б
- **Цель:** максимизировать грунтовку, минимизировать асфальт
- **Реализация (v0.2, OSRM):**
  - Кастомный профиль `enduro.lua` для `osrm-routed`
  - `weight_name = 'routability'` — OSRM оптимизирует не по времени, а по предпочтительности дорог
  - `forward_speed = 30` для всех типов дорог — duration одинаковый, выбор идёт ТОЛЬКО по `forward_rate`
  - `forward_rate` (чем выше — тем предпочтительнее): track=100, bridleway=90, path=85, cycleway=70, motorway=0.1
  - `tracktype` мультипликатор: grade1×1.3 (твёрдая грунтовка), grade3×1.0, grade5×0.8 (размытая тропа)
  - `weight = distance / forward_rate` — самый короткий путь по грунтовкам, даже если ехать дольше
  - U-turn penalty 20s, развороты разрешены
  - Граф ~5.2 GB из `enduro.osm.pbf` (ЦФО + Чувашия), контейнер `osrm-routed` порт 5559
- **Проблемы:** может строить "вне дорог" через unmapped-связи между нодами OSM

#### 🎨 "Красивый маршрут" (Scenic Route)
- **Вход:** начальная точка, желаемая дистанция
- **Цель:** замкнутый круг через живописные места
- **Оценка аттрактивности:**
  - Близость к водоёмам (+10)
  - Перепад высот > 300 м (+15)
  - Видовые точки на маршруте (+20)
  - Наличие заброек/руин (+10)
  - Тропы с trail_visibility=yes (+5)
  - Прохождение через ЛЭП как ориентир (+3)

#### 🏔️ "Горка" (Elevation Route)
- **Вход:** точка старта, желаемый набор высоты
- **Цель:** максимизировать перепад высоты, минимизировать дистанцию
- **Использование:** тренировка, эндуро-кросс

#### 🔗 "Связка" (Link Route)
- **Вход:** два существующих трека
- **Цель:** соединить их грунтовками, не по асфальту

#### 📍 "Разведка" (Recon Mode)
- **Вход:** точка на карте
- **Выход:** все грунтовые дороги в радиусе X км
- **Использование:** посмотреть что есть вокруг, исследовать местность

#### 🚧 "Препятствия" (Obstacle Layer)
- Карта с подсветкой всех бродов, шлагбаумов, болот, ЛЭП
- Фильтр по сезонам: некоторые дороги непроходимы в межсезонье
- Отчёт "что тебя ждёт" перед поездкой

#### 📊 Статистика маршрута
- Общая дистанция, % грунтовки, % асфальта
- Набор/потеря высоты
- Максимальный уклон
- Прогноз времени (зависит от сложности)
- Техничность: 1-5 по grade дорогам

---

## Фронтенд

### Веб-приложение (основное)
- **Картографический движок:** MapLibre GL JS (open source форк Mapbox GL)
- **Стили:** кастомный Mapbox GL Style JSON с перевёрнутой логикой:
  - Грунтовки = яркие, толстые, с градиентом по grade
  - Асфальт = тонкие серые линии
  - POI = иконки (озёра 💙, видовые точки 📷, заброек 🏚️)
  - Рельеф = heatmap с тангенсом угла
- **Функции:**
  - Клик → статистика дороги (название, длина, grade, покрытие)
  - Рисование маршрута (ручной + автоматический роутинг)
  - Поиск по названиям/тэгам
  - Фильтр слоёв (вкл/выкл)
  - Экспорт GPX/KML

### PWA (Mobile)
- Progressive Web App для работы оффлайн
- Кэш тайлов для оффлайн навигации
- GPS трекинг в реальном времени
- Оффлайн роутинг (загрузка графа в браузер)

---

## Данные и лицензии

### OpenStreetMap
- **Лицензия:** ODbL (Open Database License)
- **Требования:** атрибуция (© OpenStreetMap contributors)
- **Коммерческое использование:** разрешено с сохранением атрибуции

### SRTM (рельеф)
- **Источник:** NASA/USGS
- **Лицензия:** Public Domain
- **Качество:** 30 м (1 arc-second), 90 м для регионов без SRTM 30 м

### Overpass API
- **Термины использования:** https://wiki.openstreetmap.org/wiki/Overpass_API
- **Rate limits:** необходимо уважать (не чаще 1-2 запросов/сек)
- **Рекомендуемое использование:** для дельта-обновлений, not bulk download

---

## Технический стек (предварительный)

| Компонент | Технология | Обоснование |
|-----------|------------|-------------|
| Парсинг PBF | Pyrosm (Python) + Osmium | Простота, Python-стек |
| Хранилище | Spatialite | Портативность, zero-config |
| Роутинг | OSRM + кастомный профиль | Быстрый, проверенный |
| API Backend | FastAPI (Python) | Async, типизация |
| Тайлы | TileServer GL или самописный | Поддержка MapLibre |
| Фронт | MapLibre GL JS + React/Vanilla | Open source, производительность |
| Мобильный | PWA + Service Workers | Оффлайн, без store |

---

## Этапы реализации

### Фаза 1: MVP — ✅ ВЫПОЛНЕНО (02.05.2026)
- [x] Настройка PBF загрузки (ЦФО + Чувашия)
- [x] Парсинг и фильтрация highway=track/path/bridleway + surface
- [x] Импорт в Spatialite (1.1M треков, 14K POI)
- [x] FastAPI self-hosted MVT тайлы (вместо TileServer GL)
- [x] Веб-карта с MapLibre GL JS

### Фаза 2: Роутинг + UI — ✅ ВЫПОЛНЕНО (03.05.2026)
- [x] OSRM + кастомный профиль `enduro.lua` (порт 5559)
- [x] API endpoint `/api/route` (точки А→Б → маршрут)
- [x] "Дикий путь" — UI кнопка 🗺️, маркеры, дистанция/время
- [x] Поиск (Nominatim, debounce 400ms, flyTo)
- [x] Линейка 📏 (haversine, кружки + плашки)
- [x] Геолокация 📍, компас 🧭

### Фаза 3: Слои и фичи — ⏳ Бёклог
- [ ] Импорт SRTM DEM + расчёт уклонов
- [ ] Слой рельефа
- [ ] Флажки/метки на карте (localStorage)
- [ ] Слой препятствий (броды, шлагбаумы, болота)

### Фаза 4: Продвинутый роутинг — ⏳ Бёклог
- [ ] "Красивый маршрут" — через живописные места
- [ ] "Горка" — макс набор высоты
- [ ] "Разведка" — грунтовки вокруг точки
- [ ] Статистика маршрута (% грунт/асфальт), GPX экспорт

### Фаза 5: Мобильность — ⏳ Бёклог
- [ ] PWA с оффлайн тайлами
- [ ] GPS трекинг
- [ ] Интеграция с OsmAnd/Locus (экспорт)

---

## Вопросы для Славы

1. **Регион:** какой регион берём для начала? (ЦФО, вся Россия, конкретная область?)
2. **Хостинг:** разворачиваем FR24 VM (PostGIS) или локально на mva154?
3. **Бюджет на данные:** SRTM 30 м бесплатные, но если нужен ASTER (15 м) — $50/регион
4. **Мобильное:** PWA достаточно, или нужно нативное приложение (Android)?
5. **Совместное использование:** сделать публичным (кто хочет пользуется) или только для Славы?
6. **Приоритет:** что важней — роутинг, красивая визуализация, или оффлайн работа?

---

*Документ будет дорабатываться после согласования со Славой*
