feat(gpx): загрузка и визуализация GPX-треков (ET-006) #7

Merged
admin merged 14 commits from feature/ET-006-gpx-upload into main 2026-05-22 13:35:21 +03:00
Owner

Summary

Реализует ET-006 — загрузка и визуализация GPX-треков (стадия development).

  • src/web/gpx.js — новый модуль фичи (ADR-002): клиентский парсинг GPX 1.1 через DOMParser с чанковой конвертацией DOM → модель (ADR-003), модель window.gpxTracks, отрисовка треков и waypoints на карте, bottom sheet #sheet-gpx, статистика трека и canvas-профиль высот.
  • index.html / app.css — кнопка загрузки в правой панели карты, кнопка «GPX» в нижнем тулбаре, панель #sheet-gpx, toast-уведомления, индикатор парсинга.
  • app.js — одна строка-хук: rebuildGpxOverlays() в rebuildMapOverlays() — восстановление GPX-слоёв после map.setStyle() (REQ-F-13), защищён typeof.
  • GPX-слои встают ниже маршрута OSRM и выше базовых слоёв (REQ-F-04). Данные треков живут только в памяти сессии (REQ-NF-04).

Покрыты функциональные требования REQ-F-01..F-13 и нефункциональные REQ-NF-01..NF-04.

Test plan

  • ruff check — без замечаний
  • pytest tests/ — 51 passed, 4 skipped (skip — OSRM-интеграции без живого OSRM)
  • node --test tests/unit/gpx.test.js — 27 passed (группы U-01..U-21)
  • docker build — образ собирается
  • E2E (E-01..E-10) — за этапом тестирования (Playwright-инфраструктуры в репозитории нет)

Тесты

  • tests/unit/gpx.test.js — поведенческие JS unit-тесты модуля (парсер, статистика, палитра, GeoJSON, bbox); браузерный DOMParser подменён компактным мок-парсером.
  • tests/unit/test_gpx_upload.py — pytest-обёртка: статические проверки структуры gpx.js / index.html / app.css / app.js + запуск JS-тестов через node --test (паттерн ET-005).

Заметки для ревью

  • Объём PR. ~2042 строки, из них ~713 — тесты. Производственный код ~1329 строк. Декомпозиция на несколько PR не применима: ADR-002 предписывает единый модуль gpx.js, ET-006 — атомарный work-item на одной ветке; разбиение модуля было бы архитектурным решением без ADR.
  • Две неточности в числовых примерах 04-test-plan.yaml (сам ТЗ §5 корректен — расходятся лишь оценочные числа аналитика; артефакт не правил, см. комментарии в gpx.test.js):
    • U-10: каноническая Haversine (та же, что в app.js haversineKm) для шага 0.1°×0.1° даёт ≈25.5 км, а не 28.3 км.
    • U-11: для ele [100,150,120,200,180] сброс высоты = 30+20 = 50 м (как в расшифровке самого кейса), а не 70 м.
  • Ветка перебазирована на актуальный origin/main (включает ET-005). Один merge-коммит стратегией ours — синхронизация с устаревшим удалённым состоянием ветки без force-push.

Refs: ET-006

🤖 Generated with Claude Code

## Summary Реализует **ET-006 — загрузка и визуализация GPX-треков** (стадия development). - **`src/web/gpx.js`** — новый модуль фичи (ADR-002): клиентский парсинг GPX 1.1 через `DOMParser` с чанковой конвертацией DOM → модель (ADR-003), модель `window.gpxTracks`, отрисовка треков и waypoints на карте, bottom sheet `#sheet-gpx`, статистика трека и canvas-профиль высот. - **`index.html` / `app.css`** — кнопка загрузки в правой панели карты, кнопка «GPX» в нижнем тулбаре, панель `#sheet-gpx`, toast-уведомления, индикатор парсинга. - **`app.js`** — одна строка-хук: `rebuildGpxOverlays()` в `rebuildMapOverlays()` — восстановление GPX-слоёв после `map.setStyle()` (REQ-F-13), защищён `typeof`. - GPX-слои встают **ниже** маршрута OSRM и **выше** базовых слоёв (REQ-F-04). Данные треков живут только в памяти сессии (REQ-NF-04). Покрыты функциональные требования REQ-F-01..F-13 и нефункциональные REQ-NF-01..NF-04. ## Test plan - [x] `ruff check` — без замечаний - [x] `pytest tests/` — 51 passed, 4 skipped (skip — OSRM-интеграции без живого OSRM) - [x] `node --test tests/unit/gpx.test.js` — 27 passed (группы U-01..U-21) - [x] `docker build` — образ собирается - [ ] E2E (E-01..E-10) — за этапом тестирования (Playwright-инфраструктуры в репозитории нет) ## Тесты - `tests/unit/gpx.test.js` — поведенческие JS unit-тесты модуля (парсер, статистика, палитра, GeoJSON, bbox); браузерный `DOMParser` подменён компактным мок-парсером. - `tests/unit/test_gpx_upload.py` — pytest-обёртка: статические проверки структуры `gpx.js` / `index.html` / `app.css` / `app.js` + запуск JS-тестов через `node --test` (паттерн ET-005). ## Заметки для ревью - **Объём PR.** ~2042 строки, из них ~713 — тесты. Производственный код ~1329 строк. Декомпозиция на несколько PR не применима: ADR-002 предписывает единый модуль `gpx.js`, ET-006 — атомарный work-item на одной ветке; разбиение модуля было бы архитектурным решением без ADR. - **Две неточности в числовых *примерах* `04-test-plan.yaml`** (сам ТЗ §5 корректен — расходятся лишь оценочные числа аналитика; артефакт не правил, см. комментарии в `gpx.test.js`): - U-10: каноническая Haversine (та же, что в `app.js haversineKm`) для шага 0.1°×0.1° даёт ≈25.5 км, а не 28.3 км. - U-11: для `ele [100,150,120,200,180]` сброс высоты = 30+20 = **50 м** (как в расшифровке самого кейса), а не 70 м. - Ветка перебазирована на актуальный `origin/main` (включает ET-005). Один merge-коммит стратегией `ours` — синхронизация с устаревшим удалённым состоянием ветки без force-push. Refs: ET-006 🤖 Generated with [Claude Code](https://claude.com/claude-code)
admin added 10 commits 2026-05-22 04:02:15 +03:00
docs(ET-006): BRD, ТЗ, AC, Test Plan — загрузка GPX-треков
All checks were successful
CI / lint (push) Successful in 4s
CI / test (push) Successful in 4s
CI / build (push) Successful in 3s
9b930c5c83
docs(ET-006): status → approved
All checks were successful
CI / lint (push) Successful in 3s
CI / test (push) Successful in 4s
CI / build (push) Successful in 3s
9fc1ef485a
docs(ET-006): TRZ v2 — persist GPX layers across map style switch
All checks were successful
CI / lint (push) Successful in 3s
CI / test (push) Successful in 5s
CI / build (push) Successful in 1s
a0546abdd1
architect(ET-006): ADR-002/003, infra-requirements, data-requirements, tech-risks
All checks were successful
CI / lint (push) Successful in 3s
CI / test (push) Successful in 4s
CI / build (push) Successful in 3s
fda40f20fe
Клиентская загрузка GPX 1.1: парсинг через DOMParser с чанковой
конвертацией (ADR-003), отрисовка треков и waypoints на карте,
панель #sheet-gpx со списком треков, статистикой и canvas-профилем
высот. GPX-слои встают ниже маршрута OSRM и восстанавливаются после
смены стиля карты (REQ-F-13).

- src/web/gpx.js — новый модуль фичи (ADR-002): парсинг, модель
  window.gpxTracks, слои/маркеры карты, sheet-gpx, профиль высот
- index.html / app.css — кнопка загрузки, кнопка тулбара, панель
  #sheet-gpx, toast-уведомления, индикатор парсинга
- app.js — один хук rebuildGpxOverlays() в rebuildMapOverlays()
- тесты: gpx.test.js (node --test, U-01..U-21) +
  test_gpx_upload.py (pytest: статические проверки + JS-раннер)

Refs: ET-006

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Merge stale remote ET-006 branch after rebase onto main
All checks were successful
CI / lint (push) Successful in 4s
CI / test (push) Successful in 5s
CI / build (push) Successful in 1s
CI / lint (pull_request) Successful in 3s
CI / test (pull_request) Successful in 4s
CI / build (pull_request) Successful in 1s
8dc150ae14
Локальная ветка была перебазирована на актуальный origin/main (стадия
development, алгоритм п.2). Удалённая ветка содержала те же 4 doc-коммита
ET-006 до ребейза. Стратегия `ours`: дерево уже корректно (перебазировано
на main + реализация), удалённый тип становится предком для fast-forward
push без force-push.
admin added 1 commit 2026-05-22 04:06:46 +03:00
reviewer(ET): auto-commit from reviewer run_id=16
All checks were successful
CI / lint (push) Successful in 4s
CI / test (push) Successful in 5s
CI / lint (pull_request) Successful in 3s
CI / build (push) Successful in 2s
CI / test (pull_request) Successful in 5s
CI / build (pull_request) Successful in 2s
19354ed905
claude-bot requested changes 2026-05-22 08:53:44 +03:00
Dismissed
claude-bot left a comment
Collaborator

P1-1: Math.min.apply RangeError on large arrays. Fix required.

P1-1: Math.min.apply RangeError on large arrays. Fix required.
admin added 1 commit 2026-05-22 09:02:00 +03:00
fix(gpx): устранить падение статистики на больших треках, учесть все треки файла
All checks were successful
CI / lint (push) Successful in 4s
CI / test (push) Successful in 5s
CI / lint (pull_request) Successful in 3s
CI / test (pull_request) Successful in 5s
CI / build (push) Successful in 3s
CI / build (pull_request) Successful in 2s
25e4476cf7
Правки по код-ревью ET-006 (docs/work-items/ET-006/12-review.md):

- P1-1: trackStats считал min/max высот через Math.min/max.apply — на
  треках в сотни тысяч точек это бросало RangeError и валило загрузку
  файла (нарушение REQ-NF-01). Расчёт переписан на однопроходный
  аккумулятор (makeStatsAccumulator/accumulatePoint/finalizeStats)
  без apply.
- P2-1: статистика и профиль высот учитывали только tracks[0].
  Добавлены aggregateStats() и buildFileProfileSamples() — сводка и
  профиль теперь охватывают все треки файла (REQ-F-09, AC-02).
- P2-2: расчёт статистики на async-пути парсинга вынесен в чанковый
  trackStatsChunked() — соответствие букве ADR-003 §2.
- P3-1: ось и tooltip профиля высот форматируют расстояние через
  formatKm() — согласование с выбором км/мили из ET-005.
- P3-2: childText() переименована в firstTagText() — имя соответствует
  фактическому поведению (поиск по всем потомкам).
- P3-4: убран дублирующийся 'use strict'.

Добавлены регрессионные unit-тесты: большой трек без падения,
эквивалентность trackStatsChunked синхронному trackStats (в т.ч. на
треке длиннее размера чанка), агрегация статистики и профиля по
многотрековому файлу.

Refs: ET-006

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
admin added 1 commit 2026-05-22 09:04:58 +03:00
reviewer(ET): auto-commit from reviewer run_id=18
All checks were successful
CI / lint (push) Successful in 3s
CI / test (push) Successful in 4s
CI / lint (pull_request) Successful in 3s
CI / test (pull_request) Successful in 5s
CI / build (push) Successful in 3s
CI / build (pull_request) Successful in 2s
e1dd7039a7
claude-bot approved these changes 2026-05-22 09:18:55 +03:00
Dismissed
claude-bot left a comment
Collaborator

APPROVED v2 - all P1/P2 fixed. Ready for testing.

APPROVED v2 - all P1/P2 fixed. Ready for testing.
admin added 1 commit 2026-05-22 09:45:36 +03:00
tester(ET): auto-commit from tester run_id=19
All checks were successful
CI / lint (push) Successful in 4s
CI / test (push) Successful in 6s
CI / lint (pull_request) Successful in 3s
CI / build (push) Successful in 1s
CI / test (pull_request) Successful in 5s
CI / build (pull_request) Successful in 1s
23cc89d416
admin dismissed claude-bot's review 2026-05-22 09:45:36 +03:00
Reason:

New commits pushed, approval review dismissed automatically according to repository settings

claude-bot approved these changes 2026-05-22 13:35:07 +03:00
claude-bot left a comment
Collaborator

All tests PASS. Ready to merge.

All tests PASS. Ready to merge.
admin merged commit 7bf1205c5e into main 2026-05-22 13:35:21 +03:00
Sign in to join this conversation.
No Reviewers
No Label
2 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: admin/enduro-trails#7