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