# Техническое задание: Прототип Enduro Trails v0.1

**Проект:** Enduro Trails 🏍️  
**Документ:** TECHNICAL_SPEC.md  
**Версия:** 0.1  
**Дата:** 02.05.2026  
**Автор:** Стрим 🌊  
**Исполнитель:** Dev-агент  
**Статус:** на согласовании

---

## 1. Цель

Создать прототип на mva154, который визуализирует грунтовые дороги ЦФО+Чувашия на карте с «перевёрнутой логикой»: грунтовки яркие и заметные, асфальт — тусклый фон. Без роутинга — только данные + визуализация.

---

## 2. Область (Scope)

### ✅ Включено в v0.1
- Скачивание PBF дампа с Geofabrik (ЦФО)
- Парсинг дорог (highway=track, highway=path) с тегами
- Импорт в Spatialite (.sqlite файл)
- Слой POI (водоёмы, видовые точки, заброчки)
- Генерация Mapbox GL совместимых тайлов (z10–z16)
- Кастомный стиль: грунтовки яркие, асфальт серый
- Веб-карта (MapLibre GL JS) с контролами слоёв
- Клик по дороге → popup с информацией

### ❌ НЕ включено в v0.1
- OSRM роутинг (фаза 2)
- SRTM рельеф + уклоны (фаза 3)
- PWA / оффлайн работа (фаза 5)
- GPS трекинг
- Мобильное приложение
- «Красивый маршрут», «Горка», «Связка» и прочие алгоритмы

---

## 3. Технические требования

### 3.1 Хост
- **Сервер:** mva154 (localhost, Docker)
- **Порт:** 5558 (или первый свободный 555X)
- **Доступ:** Docker контейнеры + docker-compose
- **Ресурсы:** без ограничений (это прототип)

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

| Параметр | Значение |
|----------|----------|
| **Формат** | OSM PBF |
| **Источник** | `https://download.geofabrik.de/russia/centralfederal.ru-latest.osm.pbf` + `https://download.geofabrik.de/russia/volga.osm.pbf` |
| **Регион** | Центральный ФО + Чувашия (Приволжский ФО) |
| **Чувашия** | ⚠️ Чувашия входит в Приволжский ФО, не в ЦФО. Скачать `volga.osm.pbf`, объединить с `centralfederal.osm.pbf` через `osmium merge`, затем отфильтровать по BBOX |
| **BBOX фильтрация** | west=30.0, east=48.0, south=51.0, north=59.0 (east расширен до 48.0 чтобы захватить Чувашию) |

### 3.3 Парсинг

**Инструмент:** Pyrosm (Python) + osmium

**Фильтр дорог (выбираем):**
```
highway: track, path, bridleway, cycleway, footway (для связки)
```

**Теги для каждого сегмента:**
| Тег | Описание |
|-----|----------|
| `surface` | paved, unpaved, gravel, sand, mud, earth, grass, asphalt, concrete |
| `tracktype` | grade1–grade5 |
| `mtb:scale` | 0–6 |
| `trail_visibility` | yes, no, negative |
| `smoothness` | excellent, good, intermediate, bad, very_bad, horrible |
| `access` | private, no, permissive, destination |
| `vehicle` | yes, no, agricultural, forestry |
| `name` | название (если есть) |
| `osm_id` | ID из OSM |
| `geometry` | LINESTRING |
| `length_m` | длина в метрах (рассчитать) |

**POI точки:**
```
natural=water + name (озёра, реки — крупные)
tourism=viewpoint (видовые точки)
historic=ruins / abandoned=yes (заброшки)
natural=peak (вершины)
natural=cave_entrance (пещеры)
ford=yes (броды)
```

### 3.4 Хранение — Spatialite

**Файл:** `tasks/enduro-trails/data/centralfederal.sqlite`

**Таблица `trails`:**
```sql
CREATE TABLE trails (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    osm_id INTEGER NOT NULL,
    highway_type TEXT,
    track_type TEXT,
    surface TEXT,
    name TEXT,
    length_m REAL,
    mtb_scale TEXT,
    visibility TEXT,
    smoothness TEXT,
    access TEXT,
    tags TEXT,                          -- JSON с остальными тегами
    geom GEOMETRY                       -- LINESTRING, SRID 4326
);
-- ⚠️ Spatialite синтаксис (НЕ PostGIS!)
SELECT CreateSpatialIndex('trails', 'geom');
CREATE INDEX idx_trails_highway ON trails(highway_type);
CREATE INDEX idx_trails_surface ON trails(surface);
```

**Таблица `poi`:**
```sql
CREATE TABLE poi (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    osm_id INTEGER NOT NULL,
    poi_type TEXT,                      -- lake, viewpoint, ruins, peak, cave, ford
    name TEXT,
    geom GEOMETRY                       -- POINT, SRID 4326
);
-- ⚠️ Spatialite синтаксис (НЕ PostGIS!)
SELECT CreateSpatialIndex('poi', 'geom');
CREATE INDEX idx_poi_type ON poi(poi_type);
```

### 3.5 Генерация тайлов

**Формат:** Mapbox GL совместимые векторные тайлы (PBF + JSON)  
**Уровни:** z10, z11, z12, z13, z14, z15, z16

**Варианты реализации:**
1. **Spatialite → MBTiles → TileServer GL** — конвертация через `tippecanoe` или `ogr2ogr`, затем TileServer GL отдаёт MBTiles
2. **Martin** (Rust) — быстрый тайл-сервер, поддерживает SQLite/MBTiles напрямую, проще цепочка
3. **Python self-hosted** — FastAPI отдаёт тайлы на лету из Spatialite

**Рекомендация:** Martin через Docker — поддерживает SQLite напрямую, минимум шагов.

⚠️ **Важно:** TileServer GL не работает с Spatialite напрямую — нужна конвертация в MBTiles (tippecanoe или ogr2ogr) перед использованием.

**Слои тайлов:**
| Слой | Источник | Описание |
|------|----------|----------|
| `trails` | trails table | Все грунтовые дороги |
| `poi` | poi table | Точки интереса |

### 3.6 Стиль карты (Mapbox GL Style JSON)

**Принцип «перевёрнутой логики»:**

| Элемент | Стиль |
|---------|-------|
| Грунтовки (grade3–5, unpaved) | Яркие оранжевые/жёлтые линии, толщина 3–4px |
| Грунтовки (grade1–2, paved) | Средние оранжевые, толщина 2px |
| Path/bridleway | Пунктирные жёлтые, толщина 1.5px |
| Асфальт primary+ | Тонкие серые, 1px |
| Асфальт secondary/tertiary | Серые, 1.5px |
| Fon | Очень тёмный/приглушённый |
| POI озёра | 💙 голубые точки |
| POI viewpoints | 📷 фиолетовые |
| POI ruins | 🏚️ коричневые |
| POI peaks | 🔺 красные треугольники |

### 3.7 Веб-карта (Frontend)

**Технологии:**
- HTML + CSS + JavaScript (Vanilla или React по выбору Dev-агента)
- MapLibre GL JS (CDN, без сборки)

**Структура:**
```
tasks/enduro-trails/prototype/
├── app.py              # FastAPI сервер (раздаёт статику + API)
├── static/
│   ├── index.html
│   ├── style.json      # MapLibre GL Style
│   ├── app.js          # Логика карты
│   └── app.css
└── data/
    └── centralfederal.sqlite
```

**Функции (всё выполнено ✅):**
- [x] Отображение карты с кастомным стилем
- [x] Контролы слоёв (вкл/выкл: грунтовки, POI)
- [x] Клик по дороге → popup (name, surface, tracktype, length)
- [x] Клик по POI → popup (name, type)
- [x] Поиск по bbox (кнопка «показать всё»)
- [x] Зум/пан — стандартные

---

## 4. Структура проекта

```
tasks/enduro-trails/
├── PROJECT.md
├── CONCEPT.md
├── TECHNICAL_SPEC.md
├── DEV_TASK.md
├── TASKS/
│   └── active/
│       └── prototype-setup/
│           └── TASK.md
├── prototype/
│   ├── app.py                  # FastAPI: /api/tiles, /api/route, /api/health, /api/cache/clear
│   ├── requirements.txt
│   ├── Dockerfile
│   ├── docker-compose.yml
│   ├── README.md
│   └── static/
│       ├── index.html
│       ├── app.js
│       ├── app.css
│       └── style.json
├── scripts/
│   ├── parse.py                # Парсинг PBF → SQLite (Spatialite)
│   ├── requirements-parse.txt
│   └── smoke_check.py
└── osrm/
    └── enduro.lua              # Профиль OSRM (кастомный по грунтовкам)
```

---

## 5. Критерии приёмки (Acceptance Criteria)

Прототип считается готовым когда:

1. ✅ Скачан PBF дамп ЦФО с Geofabrik
2. ✅ `parse.py` парсит PBF → `centralfederal.sqlite` (trails + POI)
3. ✅ Тайлы генерируются (FastAPI on-the-fly из SQLite)
4. ✅ Веб-карта на `localhost:5558` показывает:
   - Грунтовки яркие (жёлтые/красно-оранжевые)
   - Асфальт тусклый (серый)
   - POI отображаются иконками
5. ✅ Клик по дороге → popup с name, surface, tracktype, length
6. ✅ Базовые контролы слоёв (toggle trails, POI)
7. ✅ `docker-compose up` запускает всё одной командой

---

## 6. Ограничения и заметки

- **Без роутинга** — OSRM ставится в фазе 2
- **Без рельефа** — SRTM слой в фазе 3
- **Без PWA** — только веб, вёрстка для десктопа
- **Один регион** — ЦФО, масштабирование потом
- **Данные статичные** — обновление PBF = перезапуск parse.py
- **Без авторизации** — локальный хост, только для Славы пока
- **Pyrosm** может потребовать GDAL — если сложно, использовать Osmium

---

## 7. Следующие шаги (после v0.1)

| Фаза | Что | Приоритет |
|------|-----|-----------|
| Фаза 2 | OSRM роутинг + «Дикий путь» | High |
| Фаза 3 | SRTM рельеф + уклоны | Medium |
| Фаза 4 | «Красивый маршрут», «Горка» | Medium |
| Фаза 5 | PWA + оффлайн | Low |

---

*Документ создан автоматически. Для правок — связаться со Стрим.*
