docs(ET-002): add ADR-0001 and infra requirements for POI toggle
All checks were successful
CI / lint (push) Successful in 4s
CI / test (push) Successful in 4s
CI / build (push) Successful in 3s

Record architecture decision to implement POI visibility toggling
client-side (setLayoutProperty + localStorage), reusing the existing
layerState model, with no backend, DB or infrastructure changes.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-21 14:51:37 +00:00
parent 73c9dc46a0
commit af579f7f2a
2 changed files with 233 additions and 0 deletions

View File

@@ -0,0 +1,139 @@
---
type: adr
work_item_id: ET-002
adr_id: adr-0001
title: "ADR-0001: Управление видимостью POI — клиентское решение на localStorage"
status: accepted
created_at: 2026-05-21
authors:
- "agent:architect"
supersedes: []
superseded_by: []
labels: []
---
# ADR-0001 — Управление видимостью POI: клиентское решение на localStorage
## Статус
Accepted
## Контекст
ET-002 добавляет в попап кнопки «Рельеф» (`terrain-popup`) чекбокс «POI»,
позволяющий пользователю скрывать маркеры POI (слои `poi-circles`,
`poi-labels`), чтобы не загромождать карту при планировании маршрута.
Существующее состояние кодовой базы (`src/web/app.js`):
- объект `layerState = { tracks, paths, poi, basemap }` — внутренняя модель
видимости слоёв (строка 377), `poi: true` по умолчанию;
- карта групп слоёв `poi: ['poi-circles', 'poi-labels']` (строка 381);
- функция `toggleLayer(group)` уже переключает видимость через
`map.setLayoutProperty(..., 'visibility', ...)` (строки 385389), но
завязана на кнопку-тулбар (`btn.classList.toggle('active', ...)`), а не на
чекбокс попапа;
- сложился устойчивый паттерн персистентности в `localStorage` со
значениями `'1'`/`'0'`: ключи `terrain-hillshade`, `terrain-tri`,
`trails-track`, `trails-path`, `enduro-theme-mode`, `MARKERS_KEY`.
Backend (FastAPI) и БД (SQLite/Spatialite) к видимости POI отношения не
имеют — POI отдаются как часть тайлов/источника, видимость регулируется
исключительно на уровне рендера MapLibre.
## Рассматриваемые варианты
### Вариант A — Клиентское решение: `setLayoutProperty` + `localStorage` (выбран)
Видимость переключается через `map.setLayoutProperty()` для слоёв
`poi-circles` и `poi-labels`; состояние хранится в `localStorage` под
ключом `poi-visible`; `layerState.poi` остаётся единственным источником
истины в рантайме.
- **Плюсы:** нулевые изменения backend/БД/инфраструктуры; переключение
мгновенное (тайлы не перезагружаются — слой остаётся в источнике,
меняется только `layout.visibility`); полностью консистентно с уже
существующими чекбоксами попапа и принципом «минимум зависимостей».
- **Минусы:** настройка не синхронизируется между устройствами/браузерами
(для данной фичи это приемлемо и зафиксировано как Out of scope в BRD).
### Вариант B — Хранение настройки на backend (профиль пользователя)
Видимость POI сохраняется через новый API-эндпоинт в SQLite.
- **Плюсы:** синхронизация между устройствами.
- **Минусы:** требует модели пользователя/сессий (в проекте отсутствует),
новый эндпоинт, миграцию БД, сетевой round-trip — несопоставимо
избыточно для одного UI-флага. Противоречит принципам BRD (минимум
зависимостей, нет необходимости в server-state).
### Вариант C — Удаление/повторное добавление слоёв POI
Скрытие через `map.removeLayer()`, показ через `map.addLayer()`.
- **Плюсы:** нет «невидимых» слоёв в стиле.
- **Минусы:** дороже по производительности, риск рассинхрона порядка
слоёв и обработчиков событий (`map.on('click', 'poi-circles', ...)`,
строка 1515), усложняет код. `setLayoutProperty` — штатный механизм
MapLibre именно для этого сценария.
## Решение
Принимается **Вариант A**.
1. **Видимость** слоёв `poi-circles` и `poi-labels` переключается через
`map.setLayoutProperty(layerId, 'visibility', 'visible' | 'none')`.
2. **Персистентность**`localStorage`, ключ `poi-visible`, значения
`'1'` / `'0'`, в соответствии с уже сложившейся конвенцией проекта.
3. **Источник истины в рантайме**`layerState.poi`. Обработчик
`onPoiCheckbox()` обязан синхронно обновлять `layerState.poi`,
`localStorage` и `layout.visibility` обоих слоёв.
4. **Без дублирования логики.** Логика установки видимости группы POI
должна переиспользовать существующую карту групп слоёв
(`poi: ['poi-circles','poi-labels']`). Допускается выделение общего
приватного хелпера (например `applyPoiVisibility(visible)`),
вызываемого как из `onPoiCheckbox()`, так и из восстановления
состояния при загрузке. `toggleLayer('poi')` (тулбар-кнопка) и
`onPoiCheckbox()` (чекбокс попапа) должны оставаться консистентны
через общий `layerState.poi` — недопустимо, чтобы кнопка и чекбокс
показывали разное состояние.
5. **Backend, БД, API, инфраструктура — без изменений.** Состав
компонентов C4 не меняется, обновление C4-диаграмм не требуется.
## Последствия
### Положительные
- Изменение полностью клиентское: deploy без миграций и без изменения
состава контейнеров.
- Переключение < 50 мс (REQ-NF-01) — тайлы не перезагружаются.
- Конвенция `localStorage` остаётся единообразной — ниже когнитивная
нагрузка при поддержке.
### Отрицательные / ограничения
- Настройка локальна для браузера: при очистке `localStorage` или смене
устройства сбрасывается на дефолт (POI включены). Принято осознанно.
- В стиле карты остаются слои с `visibility: none` — это штатно для
MapLibre и не влияет на производительность.
### Технический долг
- `toggleLayer()` и `onPoiCheckbox()` частично дублируют намерение
«переключить группу слоёв». Если в будущих фазах появятся ещё
popup-чекбоксы для слоёв, стоит унифицировать тулбар-кнопки и
popup-чекбоксы в единый контроллер слоёв. На ET-002 — вне scope.
## Классификация изменения
Minor change. Новые сервисы/БД/эндпоинты не вводятся, состав компонентов
не меняется. Лейбл `arch:major-change` **не требуется**. Обязательного
архитектурного approve не требуется.
## Связанные документы
- `docs/work-items/ET-002/01-brd.md`
- `docs/work-items/ET-002/02-trz.md`
- `docs/work-items/ET-002/03-acceptance-criteria.md`
- `docs/work-items/ET-002/07-infra-requirements.md`
- `docs/architecture/README.md`

View File

@@ -0,0 +1,94 @@
---
type: infra-requirements
work_item_id: ET-002
title: "Инфраструктурные требования — ET-002: Чекбокс показа/скрытия POI"
version: 1
status: approved
created_at: 2026-05-21
authors:
- "agent:architect"
---
# Инфраструктурные требования — ET-002
## 1. Резюме
ET-002 — изменение **исключительно фронтенда** (`src/web/index.html`,
`src/web/app.js`). Новой инфраструктуры не требуется. Документ
зафиксирован для полноты work-item и явно подтверждает отсутствие
инфра-воздействия (см. ADR-0001).
## 2. Контейнеры и сервисы
| Аспект | Требование |
|--------|------------|
| Новые контейнеры | Нет |
| Изменения существующих сервисов (api, osrm, nginx) | Нет |
| Изменения `docker-compose.yml` | Нет |
| Изменения `Dockerfile` | Нет |
## 3. Сеть
| Аспект | Требование |
|--------|------------|
| Новые порты | Нет |
| Изменения reverse proxy (nginx, `/enduro/`) | Нет |
| Новые внешние домены / DNS | Нет |
| Исходящие сетевые вызовы из фронтенда | Нет (вся логика локальная) |
## 4. Хранилища данных
| Аспект | Требование |
|--------|------------|
| Изменения схемы SQLite/Spatialite | Нет |
| Миграции БД (`migrations/`) | Нет |
| Серверное хранилище состояния | Нет |
| Клиентское хранилище | `localStorage`, ключ `poi-visible` (`'1'`/`'0'`), ≈ 1 байт полезной нагрузки на браузер |
## 5. Конфигурация и секреты
| Аспект | Требование |
|--------|------------|
| Новые переменные окружения | Нет |
| Новые секреты | Нет |
| Изменения конфигурации FastAPI / uvicorn | Нет |
## 6. Зависимости
| Аспект | Требование |
|--------|------------|
| Новые npm/Python пакеты | Нет |
| Новые внешние сервисы | Нет |
| Версия MapLibre GL JS | Без изменений (`setLayoutProperty` — штатный API) |
## 7. Сборка и деплой
- **Pipeline:** существующий Gitea Actions без изменений (`lint`, `test`,
`build`).
- **Артефакт:** статические ассеты фронтенда (`src/web/`). Деплой —
штатная пересборка/перевыкладка и `docker compose up -d` на mva154.
- **Простой (downtime):** нет — изменение только в статике фронтенда.
- **План отката:** обратный коммит (revert) и повторный деплой;
миграций/состояния, требующих отдельного отката, нет.
## 8. Ресурсы (CPU / RAM / диск)
Воздействие отсутствует. Переключение `layout.visibility` слоёв
выполняется в браузере клиента; тайлы не перезапрашиваются (REQ-NF-01).
## 9. Наблюдаемость
Новые метрики, логи и алерты не требуются. Поведение проверяется
e2e-тестами фронтенда согласно `04-test-plan.yaml`.
## 10. Влияние на C4
Состав компонентов системы не меняется. Обновление
`docs/architecture/c4-*.mmd` не требуется (диаграммы C4 в репозитории
на данный момент отсутствуют — только `docs/architecture/README.md`).
## 11. Вывод
Инфраструктурных, сетевых, конфигурационных изменений и изменений БД
**нет**. ET-002 безопасен для деплоя в рамках обычного релизного цикла
фронтенда. Эскалация `arch:major-change` не требуется.