# 2026-05-05 — Дневник

## Enduro Trails — работа над прототипом

### Кнопка «Поделиться» → «Скачать GPX»
- Слава попросил убрать кастомный диалог «Поделиться» (Telegram/WhatsApp)
- Оставить только скачивание GPX через `downloadGPX()`
- Иконка заменена на download-стрелку (стрелка вниз + линия) в том же стиле что и другие кнопки header
- HTML уже обновлён: `onclick="downloadGPX()"`, иконка download
- Из app.js удалены функции: `shareRoute`, `closeShareDialog`, `shareTelegram`, `shareWhatsApp`, `shareNative`
- Из app.css удалены стили: `.share-dialog`, `.sd-*`, `#share-dialog`

### Drag-and-drop для точек маршрута
- Слава попросил добавить иконку «перетаскивания» (grip) в каждый wl-item
- Дев-агент добавил grip SVG (6 кружков) и touch-drag логику
- Логика вынесена в `_initWaypointDragHandles(list)` с общими функциями `startDrag/moveDrag/endDrag`
- **Проблема:** на десктопе не работало — дев сделал только touch-события
- **Фикс:** добавлены mouse-события (mousedown/mousemove/mouseup) с `document`-level listeners для корректного завершения drag за пределами списка

### Баг: «Добавить точку» не работала в баре маршрутов
- Причина: `addWaypointMode()` не устанавливала `routeMode = true`
- При закрытом/свайпнутом sheet `routeMode` мог быть `false`
- Клик на карте проверяет `if (!routeMode) return` — и игнорировал добавление
- Фикс: в `addWaypointMode()` добавить `routeMode = true` перед установкой `addingWaypoint = true`

## Технические заметки
- Web Share API требует HTTPS — на HTTP молча падает, даже на Android Chrome
- Кастомные диалоги через DOM работают всегда, но Слава предпочёл простоту (только скачать)
- Mouse drag: важно вешать mousemove/mouseup на `document`, а не на `list` — иначе drag ломается при выходе курсора за пределы элемента
# 2026-05-05 — Дневник

## Enduro Trails — работа над прототипом

### Кнопка «Поделиться» → «Скачать GPX»
- Слава попросил убрать кастомный диалог «Поделиться» (Telegram/WhatsApp)
- Оставить только скачивание GPX через `downloadGPX()`
- Иконка заменена на download-стрелку (стрелка вниз + линия) в том же стиле что и другие кнопки header
- HTML уже обновлён: `onclick="downloadGPX()"`, иконка download
- Из app.js удалены функции: `shareRoute`, `closeShareDialog`, `shareTelegram`, `shareWhatsApp`, `shareNative`
- Из app.css удалены стили: `.share-dialog`, `.sd-*`, `#share-dialog`

### Drag-and-drop для точек маршрута
- Слава попросил добавить иконку «перетаскивания» (grip) в каждый wl-item
- Дев-агент добавил grip SVG (6 кружков) и touch-drag логику
- Логика вынесена в `_initWaypointDragHandles(list)` с общими функциями `startDrag/moveDrag/endDrag`
- **Проблема:** на десктопе не работало — дев сделал только touch-события
- **Фикс:** добавлены mouse-события (mousedown/mousemove/mouseup) с `document`-level listeners для корректного завершения drag за пределами списка

### Баг: «Добавить точку» не работала в баре маршрутов
- Причина: `addWaypointMode()` не устанавливала `routeMode = true`
- При закрытом/свайпнутом sheet `routeMode` мог быть `false`
- Клик на карте проверяет `if (!routeMode) return` — и игнорировал добавление
- Фикс: в `addWaypointMode()` добавить `routeMode = true` перед установкой `addingWaypoint = true`

### Расстояние по маршруту между точками
- Слава попросил показывать расстояние по маршруту (не по прямой) для каждого сегмента
- Бэкенд не возвращает `legs` — только общий `distance_m`
- Решение: функция `getRouteSegmentDistances()` — snap waypoints к геометрии маршрута, суммировать haversine по точкам геометрии
- Проблема 1: сумма сегментов не совпадала с `route.distance_m` из-за неточного snap
- Решение: масштабировать сегменты пропорционально чтобы сумма = `route.distance_m`
- Проблема 2: при смене варианта маршрута расстояния не обновлялись
- Фикс: добавить `renderWaypointsList()` в `selectRoute()` и `selectMiniRoute()`

### Дублированные сообщения в Telegram
- Слава заметил что от меня приходят дублированные сообщения
- Анализ: `streaming.mode: "partial"` шлёт промежуточные сообщения каждые 2 сек вместо edit
- Попробовали `progress` — тоже дублировало (маппится в partial на Telegram)
- Финальное решение: `streaming.mode: "off"` — только финальное сообщение, без превью
- Конфиг обновлён, hot-reload применился (лог: `config hot reload applied`)

### Расстояние по маршруту — финальный фикс
- Корневая проблема: `renderWaypointsList()` вызывается ДО завершения `debounceBuildRoute()` (async)
- В момент рендера `routeResults` пустой → fallback на haversine по прямой (52 км вместо 104 км)
- Фикс: добавить `renderWaypointsList()` сразу после `drawRouteResults()` — когда маршрут уже построен
- Масштабирование сегментов оставлено: сумма сегментов = `route.distance_m` точно (diff=0 м)
- Форматирование приведено к `toFixed(1)` везде для визуального совпадения

### voice-tts скилл — дублированные сообщения
- `send_voice.sh` пытался отправить через `openclaw message send` И через `MEDIA:` директиву одновременно
- Результат: в Telegram приходило сообщение с путём к файлу + голосовое
- Фикс: убрать блок `openclaw message send` из скрипта, оставить только генерацию OGG
- Доставка только через `MEDIA:` директиву в ответе ассистента

## Технические заметки
- Web Share API требует HTTPS — на HTTP молча падает, даже на Android Chrome
- Кастомные диалоги через DOM работают всегда, но Слава предпочёл простоту (только скачать)
- Mouse drag: важно вешать mousemove/mouseup на `document`, а не на `list` — иначе drag ломается при выходе курсора за пределы элемента
- OSRM бэкенд не возвращает `legs` — только общий `distance_m`. Сегменты считаем на фронте через snap к геометрии
- `streaming.mode: "progress"` — лучший режим для Telegram: нет промежуточных сообщений, только финальный ответ
# 2026-05-05 — Дневник

## Enduro Trails — работа над прототипом

### Кнопка «Поделиться» → «Скачать GPX»
- Слава попросил убрать кастомный диалог «Поделиться» (Telegram/WhatsApp)
- Оставить только скачивание GPX через `downloadGPX()`
- Иконка заменена на download-стрелку (стрелка вниз + линия) в том же стиле что и другие кнопки header
- HTML уже обновлён: `onclick="downloadGPX()"`, иконка download
- Из app.js удалены функции: `shareRoute`, `closeShareDialog`, `shareTelegram`, `shareWhatsApp`, `shareNative`
- Из app.css удалены стили: `.share-dialog`, `.sd-*`, `#share-dialog`

### Drag-and-drop для точек маршрута
- Слава попросил добавить иконку «перетаскивания» (grip) в каждый wl-item
- Дев-агент добавил grip SVG (6 кружков) и touch-drag логику
- Логика вынесена в `_initWaypointDragHandles(list)` с общими функциями `startDrag/moveDrag/endDrag`
- **Проблема:** на десктопе не работало — дев сделал только touch-события
- **Фикс:** добавлены mouse-события (mousedown/mousemove/mouseup) с `document`-level listeners для корректного завершения drag за пределами списка

### Баг: «Добавить точку» не работала в баре маршрутов
- Причина: `addWaypointMode()` не устанавливала `routeMode = true`
- При закрытом/свайпнутом sheet `routeMode` мог быть `false`
- Клик на карте проверяет `if (!routeMode) return` — и игнорировал добавление
- Фикс: в `addWaypointMode()` добавить `routeMode = true` перед установкой `addingWaypoint = true`

### Расстояние по маршруту между точками
- Слава попросил показывать расстояние по маршруту (не по прямой) для каждого сегмента
- Бэкенд не возвращает `legs` — только общий `distance_m`
- Решение: функция `getRouteSegmentDistances()` — snap waypoints к геометрии маршрута, суммировать haversine по точкам геометрии
- Проблема 1: сумма сегментов не совпадала с `route.distance_m` из-за неточного snap
- Решение: масштабировать сегменты пропорционально чтобы сумма = `route.distance_m`
- Проблема 2: при смене варианта маршрута расстояния не обновлялись
- Фикс: добавить `renderWaypointsList()` в `selectRoute()` и `selectMiniRoute()`

### Дублированные сообщения в Telegram
- Слава заметил что от меня приходят дублированные сообщения
- Анализ: `streaming.mode: "partial"` шлёт промежуточные сообщения каждые 2 сек вместо edit
- Попробовали `progress` — тоже дублировало (маппится в partial на Telegram)
- Финальное решение: `streaming.mode: "off"` — только финальное сообщение, без превью
- Конфиг обновлён, hot-reload применился (лог: `config hot reload applied`)

### Расстояние по маршруту — финальный фикс
- Корневая проблема: `renderWaypointsList()` вызывается ДО завершения `debounceBuildRoute()` (async)
- В момент рендера `routeResults` пустой → fallback на haversine по прямой (52 км вместо 104 км)
- Фикс: добавить `renderWaypointsList()` сразу после `drawRouteResults()` — когда маршрут уже построен
- Масштабирование сегментов оставлено: сумма сегментов = `route.distance_m` точно (diff=0 м)
- Форматирование приведено к `toFixed(1)` везде для визуального совпадения

### voice-tts скилл — дублированные сообщения
- `send_voice.sh` пытался отправить через `openclaw message send` И через `MEDIA:` директиву одновременно
- Результат: в Telegram приходило сообщение с путём к файлу + голосовое
- Фикс: убрать блок `openclaw message send` из скрипта, оставить только генерацию OGG
- Доставка только через `MEDIA:` директиву в ответе ассистента

### Фаза 5 — редизайн фронтенда (завершена)
- Убраны отладочные маркеры ✓/~ и console.log из app.js
- Задеплоена чистая версия: SFTP → docker restart → docker cp (правильный порядок)
- Документация обновлена: PROJECT.md, BRD_PHASE5.md

### Поиск точек маршрута (новая фича)
- Слава попросил убрать верхний search bar и добавить поиск прямо в waypoints
- BRD создан: `tasks/enduro-trails/BRD_WAYPOINT_SEARCH.md`
- Dev реализовал: кнопка-лупа в каждом wl-item, inline Nominatim поиск, btn-theme перенесён в map-controls-r
- Задеплоено успешно

### Онбординг маршрута + баги маркеров (Dev завершил)
- Баг: метки и линейка отображались в верхнем левом углу → фикс: `.maplibregl-marker { position: absolute !important }`
- Баг: подсказка «Тапни на карте» не видна → фикс: `#route-status { min-height: 20px }`
- Фича: онбординг при активации маршрута — поле «Откуда?» при 0 точках, «Куда?» при 1 точке
- Подсказка «или тапни на карте» видна в обоих состояниях

### Новые замечания Славы (в работе у Dev)
1. Иконка колеса — заменить на нормальную мотокросс иконку
2. Флажок финиша — чёрно-белая шахматная раскраска (финишный флаг)
3. Спиннер в основном листе маршрута пока строится (как в мини-баре)
4. Тёмная карта при тёмной теме — **в бэклог** (нет `style-light.json` на сервере, нужна отдельная задача)
5. Автозум на маршрут после построения — плавный `fitBounds`
6. Мини-бар перекрывает кнопки справа — исправить позиционирование

## Технические заметки
- Web Share API требует HTTPS — на HTTP молча падает, даже на Android Chrome
- Mouse drag: важно вешать mousemove/mouseup на `document`, а не на `list`
- OSRM бэкенд не возвращает `legs` — только общий `distance_m`. Сегменты считаем на фронте через snap к геометрии
- `streaming.mode: "off"` — только финальное сообщение в Telegram, без дублей
- `deploy_static.js` сломан (cp до рестарта) — использовать inline node скрипт: restart → sleep 8s → docker cp
- `style-light.json` отсутствует на сервере — тёмная тема карты требует отдельной задачи (MapLibre стиль)
- Деплой: SFTP → docker restart → docker cp (порядок критичен — образ перезаписывает статику при рестарте)
