# Техническое задание: Прототип 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 | --- *Документ создан автоматически. Для правок — связаться со Стрим.*