diff --git a/docs/work-items/ET-001/02-trz.md b/docs/work-items/ET-001/02-trz.md index f80717f..bab276b 100644 --- a/docs/work-items/ET-001/02-trz.md +++ b/docs/work-items/ET-001/02-trz.md @@ -1,123 +1,103 @@ --- type: trz work_item_id: ET-001 -title: "ТЗ: Исключить шлагбаумы и тротуары из OSRM" -version: 1 -status: approved -created_at: 2026-05-15 -authors: - - "agent:stream" +title: "ТЗ: Чекбокс показа/скрытия POI в кнопке рельефа" +version: 2 +status: proposed +created_at: 2026-06-14 +author: "agent:analyst" +relates_to: ET-002 --- -# Техническое задание — ET-001 +# Техническое задание — ET-001: Видимость POI -## 1. Что менять +> Поведение, описанное ниже, **уже реализовано в рамках ET-002**. ТЗ +> служит спецификацией для **верификации** существующей реализации плюс +> единственной новой правки — подписи чекбокса (REQ-F-01). Описание +> текущей реализации приведено как **контекст для тестирования**, а не +> как предлагаемая архитектура. -### Файл: OSRM профиль `enduro.lua` +## 1. Функциональные требования -Расположение на сервере: `/home/slin/enduro-trails/osrm/enduro.lua` -В репо: `infra/osrm/enduro.lua` (скопировать текущий + внести изменения) +### REQ-F-01 — Подпись чекбокса «Показывать POI» (НОВАЯ ПРАВКА) +- В попапе рельефа (`#terrain-popup`) чекбокс `#poi-visible-cb` должен + иметь текстовую подпись **«Показывать POI»**. +- Текущее состояние: подпись — «POI» (`src/web/index.html`, узел + `` рядом с `#poi-visible-cb`). +- Приёмка: видимый текст подписи равен «Показывать POI»; layout попапа не + ломается (одна строка, без обрезки) на desktop и mobile. -#### Изменение 1: process_node — блокировка шлагбаумов +### REQ-F-02 — Чекбокс присутствует в попапе рельефа +- Чекбокс находится внутри `#terrain-popup`, открываемого кнопкой + `#terrain-toggle` (`toggleTerrainPopup()`). -В функции `process_node` заменить текущую обработку barriers: +### REQ-F-03 — Включён по умолчанию +- При первом заходе (ключ `localStorage['poi-visible']` отсутствует) + чекбокс отмечен, POI видны. -```lua --- Блокируемые типы препятствий (полный запрет проезда) -local blocked_barriers = { - gate = true, - bollard = true, - lift_gate = true, - chain = true, - cycle_barrier = true, - motorcycle_barrier = true, - border_control = true, - block = true, -} +### REQ-F-04 — Снятие чекбокса скрывает POI +- Снятие `#poi-visible-cb` скрывает все маркеры POI: слои `poi-circles` + и `poi-labels` получают `visibility: none`. -function process_node(profile, node, result) - local barrier = node:get_value_by_key("barrier") - if barrier and blocked_barriers[barrier] then - result.barrier = true - result.forward_mode = mode.inaccessible - result.backward_mode = mode.inaccessible - return - end -end -``` +### REQ-F-05 — Установка чекбокса возвращает POI +- Обратная установка возвращает `visibility: visible` тем же слоям. -#### Изменение 2: process_way — исключение тротуаров +### REQ-F-06 — Персистентность между сессиями +- Выбор сохраняется в браузере и применяется при следующей загрузке + страницы (наблюдаемо: после перезагрузки состояние совпадает). -В начале функции `process_way`, после получения highway, добавить: +### REQ-F-07 — Устойчивость к смене темы +- Смена темы (`#btn-theme`, пересоздание стиля карты) не сбрасывает + выбранную видимость POI; чекбокс и слои остаются в согласованном + состоянии. -```lua --- Исключаемые типы дорог (тротуары, пешеходные зоны) -local excluded_highways = { - footway = true, - pedestrian = true, - steps = true, - corridor = true, -} +## 2. Нефункциональные требования --- В process_way, после local highway = way:get_value_by_key("highway"): -if excluded_highways[highway] then return end -``` +### REQ-NF-01 — Без новых зависимостей +- Реализация остаётся клиентской, без новых npm/python пакетов + (ограничение инфраструктуры, ET-002 `07-infra-requirements.md`). -Также удалить `footway`, `pedestrian`, `steps` из таблицы `highway_rate` (если есть). +### REQ-NF-02 — Без изменения серверного контракта +- Эндпоинты `/api/tiles/{z}/{x}/{y}.mvt` и слой `poi` в MVT не меняются. + Управление видимостью — только переключение `visibility` слоёв + MapLibre на клиенте. -## 2. Пересборка графа +### REQ-NF-03 — Согласованность состояния +- Единый источник истины в рантайме — `layerState.poi`; чекбокс, + `localStorage` и фактическая видимость слоёв не расходятся. -После изменения lua-профиля — пересобрать граф: +## 3. Текущая реализация (контекст для верификации) -```bash -cd /home/slin/enduro-trails/osrm -docker run --rm -v $(pwd):/data ghcr.io/project-osrm/osrm-backend:latest osrm-extract -p /data/enduro.lua /data/enduro.osm.pbf -docker run --rm -v $(pwd):/data ghcr.io/project-osrm/osrm-backend:latest osrm-partition /data/enduro.osrm -docker run --rm -v $(pwd):/data ghcr.io/project-osrm/osrm-backend:latest osrm-customize /data/enduro.osrm -docker restart osrm-osrm-routed-1 -``` +> Информативно. Изменять требуется только подпись (REQ-F-01). -Время: ~40 мин (extract) + ~5 мин (partition + customize). +- `src/web/index.html` + - стр. ~86–89: `` и `POI` внутри + `#terrain-popup`. +- `src/web/app.js` + - `layerState.poi` (стр. ~406) и `layerGroups.poi = ['poi-circles', + 'poi-labels']` (стр. ~410). + - `applyPoiVisibility(visible)` — переключает `visibility` слоёв POI и + синхронизирует `layerState.poi`. + - `onPoiCheckbox()` — пишет `localStorage['poi-visible']` ('1'/'0') и + вызывает `applyPoiVisibility()`. + - `restorePoiState()` — восстановление при загрузке и после смены темы; + дефолт (ключ отсутствует или '1') — POI видимы. + - Блок-маркеры `>>> ET-002 POI visibility block <<<`. +- ADR: `docs/work-items/ET-002/06-adr/adr-0001-poi-visibility-client-side.md`. -## 3. Что добавить в репо +## 4. Объём изменений для ET-001 -1. `infra/osrm/enduro.lua` — обновлённый профиль -2. `scripts/rebuild-osrm.sh` — скрипт пересборки графа -3. `tests/integration/test_routing_barriers.py` — тесты +1. `src/web/index.html`: заменить текст подписи `POI` → + `Показывать POI` у `#poi-visible-cb`. +2. Синхронно обновить unit-тест, если он проверяет текст подписи + (`tests/unit/poi_toggle.test.js`). +3. Прогнать регрессию по REQ-F-02…REQ-F-07 (поведение ET-002 не должно + измениться). -## 4. Тесты +## 5. Зависимости и ограничения -### Unit/Integration тесты (pytest + httpx) - -```python -# tests/integration/test_routing_barriers.py - -import pytest -from httpx import AsyncClient, ASGITransport -from src.api.main import app - -OSRM_URL = "http://172.22.0.1:5559" - -@pytest.mark.asyncio -async def test_route_avoids_barrier(): - """Маршрут через точку с известным шлагбаумом должен обходить его""" - # Точка с шлагбаумом: 55.7558, 37.6173 (пример) - # Тест проверяет что маршрут не проходит через эту ноду - pass # Architect определит конкретные координаты - -@pytest.mark.asyncio -async def test_route_no_footway(): - """Маршрут в городе не должен проходить по тротуарам""" - pass # Architect определит конкретные координаты - -@pytest.mark.asyncio -async def test_route_allows_cattle_grid(): - """Маршрут через cattle_grid должен работать (не заблокирован)""" - pass -``` - -## 5. Ограничения -- НЕ менять веса существующих дорог (только добавить блокировку) -- НЕ трогать scenic/link/recon логику -- cattle_grid и ford — НЕ блокировать -- Пересборка графа — отдельный ручной шаг (не в CI) +- Не править артефакты ET-002 и заархивированной барьерной задачи. +- Не закрывать ET-001 самостоятельно — закрытие за Owner/CI. +- Если Owner решит, что переименование не нужно — ТЗ аннулируется, + ET-001 закрывается как дубликат ET-002 (см. `09-analyst-decision-required.md`). diff --git a/docs/work-items/ET-001/03-acceptance-criteria.md b/docs/work-items/ET-001/03-acceptance-criteria.md index ed3cb1e..7c9b9c0 100644 --- a/docs/work-items/ET-001/03-acceptance-criteria.md +++ b/docs/work-items/ET-001/03-acceptance-criteria.md @@ -1,33 +1,72 @@ --- type: acceptance-criteria work_item_id: ET-001 -version: 1 -status: approved +title: "Критерии приёмки: Чекбокс показа/скрытия POI" +version: 2 +status: proposed +created_at: 2026-06-14 +author: "agent:analyst" +relates_to: ET-002 --- -# Acceptance Criteria — ET-001 +# Критерии приёмки — ET-001: Видимость POI -## AC-1: Шлагбаумы заблокированы в профиле -- [ ] В `enduro.lua` функция `process_node` блокирует ноды с barrier=gate|bollard|lift_gate|chain|cycle_barrier|motorcycle_barrier|border_control|block -- [ ] Блокировка через `mode.inaccessible` (не penalty) -- [ ] `cattle_grid` и `ford` НЕ заблокированы +Формат Given/When/Then. Среда проверки: test +(`https://openclaw.mva154.duckdns.org/enduro/`). Большинство критериев +(AC-02…AC-08) — **регрессия** уже поставленного в ET-002 поведения; +AC-01 — **новая дельта** (подпись). -## AC-2: Тротуары исключены из графа -- [ ] В `enduro.lua` функция `process_way` пропускает highway=footway|pedestrian|steps|corridor -- [ ] Эти типы удалены из `highway_rate` (если были) +## AC-01 — Подпись «Показывать POI» (новая дельта, REQ-F-01) +- **Given** открытое приложение. +- **When** пользователь нажимает `#terrain-toggle`. +- **Then** в `#terrain-popup` виден чекбокс `#poi-visible-cb` с подписью + ровно **«Показывать POI»**; подпись помещается в одну строку, layout + попапа не сломан. -## AC-3: Скрипт пересборки -- [ ] `scripts/rebuild-osrm.sh` — рабочий скрипт для пересборки графа -- [ ] Скрипт содержит extract + partition + customize + restart +## AC-02 — Чекбокс включён по умолчанию (REQ-F-03) +- **Given** первый заход (нет ключа `poi-visible` в localStorage). +- **When** открыт попап рельефа. +- **Then** `#poi-visible-cb` отмечен (checked), маркеры POI видны на карте. -## AC-4: Тесты -- [ ] Минимум 3 integration теста в `tests/integration/test_routing_barriers.py` -- [ ] Тесты проходят (pytest green) +## AC-03 — Снятие чекбокса скрывает POI (REQ-F-04) +- **Given** открытый попап, POI видны. +- **When** пользователь снимает `#poi-visible-cb`. +- **Then** все маркеры POI (`poi-circles`, `poi-labels`) исчезают с карты. -## AC-5: Lint -- [ ] `ruff check src/` — 0 ошибок -- [ ] Lua-файл синтаксически корректен +## AC-04 — Установка чекбокса возвращает POI (REQ-F-05) +- **Given** POI скрыты чекбоксом. +- **When** пользователь снова отмечает `#poi-visible-cb`. +- **Then** маркеры POI снова отображаются на карте. -## AC-6: Обратная совместимость -- [ ] Существующие маршруты (без шлагбаумов/тротуаров) строятся как раньше -- [ ] API `/api/route` и `/api/route` (POST) работают без изменений +## AC-05 — Сохранение состояния «скрыто» после перезагрузки (REQ-F-06) +- **Given** пользователь снял чекбокс (POI скрыты). +- **When** страница перезагружается. +- **Then** POI не отображаются сразу после загрузки, а `#poi-visible-cb` + при открытии попапа — снят. + +## AC-06 — Сохранение состояния «показано» после перезагрузки (REQ-F-06) +- **Given** чекбокс отмечен (POI видны). +- **When** страница перезагружается. +- **Then** POI видны, чекбокс отмечен. + +## AC-07 — Устойчивость к смене темы (REQ-F-07) +- **Given** POI скрыты чекбоксом. +- **When** пользователь переключает тему (`#btn-theme`). +- **Then** POI остаются скрытыми, `#poi-visible-cb` остаётся снятым. + +## AC-08 — Согласованность состояния (REQ-NF-03) +- **Given** любое из действий выше. +- **Then** значение чекбокса, `localStorage['poi-visible']` + ('1'/'0') и фактическая видимость слоёв POI не противоречат друг другу. + +## AC-09 — Регрессия unit-тестов POI +- **Given** ветка с правкой подписи. +- **When** запускается `make test`. +- **Then** `tests/unit/poi_toggle.test.js` и + `tests/unit/test_poi_toggle.py` проходят (с обновлённым ожиданием + текста подписи, если оно проверяется). + +## AC-10 — Без побочных эффектов на сервере (REQ-NF-02) +- **Given** переключение чекбокса. +- **Then** запросы к `/api/tiles/.../*.mvt` и серверная отдача слоя `poi` + не меняются; видимость управляется только на клиенте. diff --git a/docs/work-items/ET-001/04-test-plan.yaml b/docs/work-items/ET-001/04-test-plan.yaml index cf89bb9..ddc4863 100644 --- a/docs/work-items/ET-001/04-test-plan.yaml +++ b/docs/work-items/ET-001/04-test-plan.yaml @@ -1,41 +1,204 @@ -work_item_id: ET-001 -version: 1 +# Test Plan — ET-001: Чекбокс показа/скрытия POI в кнопке рельефа +# ВНИМАНИЕ: функциональность уже поставлена в ET-002. Этот план — +# верификация/регрессия существующей реализации + проверка одной новой +# дельты (подпись «Показывать POI», REQ-F-01). UI-кейсы — в 04b-ui-test-cases.md. +# Среда e2e/ui: https://openclaw.mva154.duckdns.org/enduro/ + +work_item: ET-001 +version: 2 +relates_to: ET-002 +related_acs: [AC-01, AC-02, AC-03, AC-04, AC-05, AC-06, AC-07, AC-08, AC-09, AC-10] + tests: - - id: TC-001 - type: integration - title: "Маршрут обходит шлагбаум" - precondition: "OSRM граф пересобран с новым профилем" - steps: - - "POST /api/route с точками, между которыми есть шлагбаум" - - "Проверить что маршрут не проходит через ноду шлагбаума" - expected: "Маршрут обходит шлагбаум или возвращает 404" - - id: TC-002 - type: integration - title: "Маршрут не идёт по тротуару" - precondition: "OSRM граф пересобран" - steps: - - "POST /api/route с точками в городе" - - "Проверить что геометрия маршрута не содержит footway-сегментов" - expected: "Маршрут идёт только по проезжим дорогам" - - - id: TC-003 - type: integration - title: "cattle_grid не блокирует маршрут" - steps: - - "POST /api/route через точку с cattle_grid" - expected: "Маршрут проходит через cattle_grid нормально" - - - id: TC-004 + # ─── Unit (frontend, JS) ──────────────────────────────────────────── + - id: TC-U-01 type: unit - title: "Lua профиль — синтаксис" - steps: - - "luac -p infra/osrm/enduro.lua" - expected: "Exit code 0, нет ошибок" + layer: frontend + title: applyPoiVisibility(false) скрывает слои POI и синхронизирует layerState + target: src/web/app.js :: applyPoiVisibility + given: | + JSDOM/мок map с методами getLayer (true для poi-circles, poi-labels) + и setLayoutProperty (spy). layerState.poi = true. + when: | + Вызвать applyPoiVisibility(false). + then: | + - setLayoutProperty вызван для 'poi-circles' и 'poi-labels' со + значением 'none'. + - layerState.poi === false. + covers: [REQ-F-04, REQ-NF-03, AC-03, AC-08] - - id: TC-005 - type: regression - title: "Существующий маршрут не сломан" - steps: - - "POST /api/route с точками без шлагбаумов/тротуаров" - expected: "Маршрут строится, distance > 0, geometry не пустая" + - id: TC-U-02 + type: unit + layer: frontend + title: onPoiCheckbox пишет localStorage и применяет видимость + target: src/web/app.js :: onPoiCheckbox + given: | + JSDOM с #poi-visible-cb; spy на localStorage.setItem и + applyPoiVisibility. + when: | + Снять чекбокс (checked=false) и вызвать onPoiCheckbox(); + затем отметить (checked=true) и вызвать снова. + then: | + - localStorage['poi-visible'] === '0', applyPoiVisibility(false). + - localStorage['poi-visible'] === '1', applyPoiVisibility(true). + covers: [REQ-F-04, REQ-F-05, REQ-F-06, AC-03, AC-04, AC-05] + + - id: TC-U-03 + type: unit + layer: frontend + title: restorePoiState — дефолт «видимы» при отсутствии ключа + target: src/web/app.js :: restorePoiState + given: | + localStorage без ключа 'poi-visible'; #poi-visible-cb в DOM. + when: | + Вызвать restorePoiState(). + then: | + - #poi-visible-cb.checked === true. + - applyPoiVisibility(true) (слои POI видимы). + covers: [REQ-F-03, AC-02] + + - id: TC-U-04 + type: unit + layer: frontend + title: restorePoiState — восстановление «скрыто» из localStorage + target: src/web/app.js :: restorePoiState + given: | + localStorage['poi-visible'] === '0'; #poi-visible-cb в DOM. + when: | + Вызвать restorePoiState() (имитация загрузки/смены темы). + then: | + - #poi-visible-cb.checked === false. + - слои POI скрыты (visibility 'none'). + covers: [REQ-F-06, REQ-F-07, AC-05, AC-07] + + - id: TC-U-05 + type: unit + layer: frontend + title: Подпись чекбокса равна «Показывать POI» (новая дельта) + target: src/web/index.html :: #poi-visible-cb label + given: | + Разобранный DOM index.html (или тест из poi_toggle.test.js, + проверяющий текст подписи). + when: | + Прочитать textContent рядом с #poi-visible-cb. + then: | + Текст строго равен «Показывать POI». + note: | + ДО правки кейс обязан падать (сейчас «POI»). Обновить ожидание + синхронно с правкой index.html. + covers: [REQ-F-01, AC-01] + + # ─── Unit (python, регресс серверного контракта) ──────────────────── + - id: TC-U-06 + type: unit + layer: backend + title: Серверная отдача слоя POI в MVT не изменилась + target: tests/unit/test_poi_toggle.py (регресс ET-002) + given: | + Существующий python-тест, фиксирующий, что видимость POI — + клиентская и /api/tiles по-прежнему включает слой 'poi'. + when: | + make test. + then: | + Тест зелёный; контракт MVT (layer 'poi') не тронут. + covers: [REQ-NF-02, AC-10] + + # ─── Integration (DOM) ────────────────────────────────────────────── + - id: TC-I-01 + type: integration + layer: frontend + title: Чекбокс POI присутствует в #terrain-popup и связан с обработчиком + given: | + Полный DOM из src/web/index.html. + when: | + Найти #poi-visible-cb внутри #terrain-popup. + then: | + - Элемент существует, имеет атрибут onchange="onPoiCheckbox()". + - По умолчанию checked. + covers: [REQ-F-02, REQ-F-03, AC-02] + + - id: TC-I-02 + type: integration + layer: frontend + title: Цикл скрыть→показать переключает visibility слоёв POI + given: | + Полный DOM + мок map (getLayer/setLayoutProperty). + when: | + Снять #poi-visible-cb → onPoiCheckbox(); затем отметить → onPoiCheckbox(). + then: | + visibility 'poi-circles'/'poi-labels': none → visible. + covers: [REQ-F-04, REQ-F-05, AC-03, AC-04] + + # ─── E2E / UI (Playwright-сценарии; детали — 04b-ui-test-cases.md) ── + - id: TC-E-01 + type: e2e + layer: ui + title: Подпись «Показывать POI» и чекбокс включён по умолчанию + env: test + viewport: { width: 1440, height: 900 } + expected: | + #terrain-popup открыт; #poi-visible-cb checked; подпись + «Показывать POI» в одну строку. + covers: [AC-01, AC-02] + reference: 04b-ui-test-cases.md :: TC-UI-01 + + - id: TC-E-02 + type: e2e + layer: ui + title: Снятие чекбокса скрывает POI, установка возвращает + env: test + viewport: { width: 1440, height: 900 } + expected: | + После снятия маркеры POI исчезают; после повторной установки — видны. + covers: [AC-03, AC-04] + reference: 04b-ui-test-cases.md :: TC-UI-02, TC-UI-03 + + - id: TC-E-03 + type: e2e + layer: ui + title: Состояние «скрыто» сохраняется после перезагрузки + env: test + viewport: { width: 1440, height: 900 } + expected: | + После reload POI скрыты, чекбокс снят. + covers: [AC-05] + reference: 04b-ui-test-cases.md :: TC-UI-04 + + - id: TC-E-04 + type: e2e + layer: ui + title: Видимость POI устойчива к смене темы + env: test + viewport: { width: 1440, height: 900 } + expected: | + После #btn-theme POI остаются скрытыми, чекбокс снят. + covers: [AC-07] + reference: 04b-ui-test-cases.md :: TC-UI-05 + + - id: TC-E-05 + type: e2e + layer: ui + title: Mobile — чекбокс «Показывать POI» виден целиком, работает + env: test + viewport: { width: 390, height: 844 } + expected: | + Попап помещается; подпись не обрезана; снятие скрывает POI. + covers: [AC-01, AC-03] + reference: 04b-ui-test-cases.md :: TC-UI-06 + +# ─── Вне scope ────────────────────────────────────────────────────────── +out_of_scope: + - Разбивка POI по типам, отдельная кнопка POI, иконка-индикатор. + - Изменение серверной агрегации POI (/api/recon, /api/scenic). + - Производительность тайлов/роутинга. + +# ─── Примечание ───────────────────────────────────────────────────────── +notes: | + Поведенческая суть (TC-U-01..04, TC-I-*) уже покрыта unit-тестами + ET-002 (tests/unit/poi_toggle.test.js, tests/unit/test_poi_toggle.py). + Реальная новая проверка ET-001 — TC-U-05 / TC-E-01 (подпись). + Playwright-инфраструктуры в репозитории нет (ET-002 + 07-infra-requirements.md запрещает новые npm-пакеты) — e2e-кейсы + исполняются вручную/визуально либо в существующем CI-раннере, если он + появится. diff --git a/docs/work-items/ET-001/04b-ui-test-cases.md b/docs/work-items/ET-001/04b-ui-test-cases.md index ee9605f..f0ec73c 100644 --- a/docs/work-items/ET-001/04b-ui-test-cases.md +++ b/docs/work-items/ET-001/04b-ui-test-cases.md @@ -2,13 +2,14 @@ type: ui-test-cases work_item_id: ET-001 title: "UI тест-кейсы: Чекбокс показа/скрытия POI" -version: 6 +version: 7 status: proposed created_at: 2026-06-10 -updated_at: 2026-06-12 +updated_at: 2026-06-14 author: "agent:analyst" +relates_to: ET-002 purpose: > - Верификация дельты ET-001 (подпись чекбокса «Показывать POI», ТЗ §1.1) + Верификация дельты ET-001 (подпись чекбокса «Показывать POI», ТЗ REQ-F-01) + регрессия поведения, поставленного в ET-002 (скрытие/возврат POI, персистентность между сессиями, устойчивость к смене темы). До правки подписи TC-UI-01 обязан падать (в UI сейчас «POI»). @@ -41,7 +42,7 @@ base_url: "https://openclaw.mva154.duckdns.org/enduro/" 2. wait: 5000 3. click: #terrain-toggle 4. wait: 500 -5. check-visual: попап `#terrain-popup` открыт, виден чекбокс POI с подписью «Показывать POI» (целевое состояние ET-001, ТЗ §1.1; до реализации подпись «POI» — кейс обязан падать) +5. check-visual: попап `#terrain-popup` открыт, виден чекбокс POI с подписью «Показывать POI» (целевое состояние ET-001, ТЗ REQ-F-01; до реализации подпись «POI» — кейс обязан падать) 6. check-visual: чекбокс `#poi-visible-cb` отмечен (checked) 7. check-visual: подпись помещается в одну строку, layout попапа не сломан 8. screenshot: poi-checkbox-default-on