--- type: data-requirements work_item_id: ET-014 title: "Требования к данным — ET-014: Z-index фикс — terrain-popup уступает sheet'у" version: 1 status: approved created_at: 2026-06-04 authors: - "agent:architect" --- # Требования к данным — ET-014 ## 1. Резюме ET-014 — **pure client UI ordering change**. Никаких изменений в данных: ни в БД, ни в файлах на диске, ни в localStorage, ни в API-контрактах, ни в конфигурациях. Меняется **порядок вызова двух уже существующих UI-функций** в `src/web/app.js`: при открытии любого `.bottom-sheet` теперь принудительно вызывается helper `closeTerrainPopup()`, который скрывает `#terrain-popup` (если он открыт) и снимает класс `.active` с `#terrain-toggle`. **Меняется:** - Порядок DOM-операций при `openSheet(id)` (1 дополнительный вызов). - Видимое состояние `#terrain-popup` в момент открытия любого bottom-sheet (теперь скрывается; раньше оставался открытым → визуальный баг ET-014). **Не меняется:** - Содержимое и схема БД `centralfederal.sqlite`, `gps_tracks.sqlite`. - Содержимое и формат PNG-тайлов в `data/terrain/*`. - Контракты API (`/api/gps-tracks/*`, `/terrain/*`, `/api/route/*`, `/api/health`, прочие). - Ключи `localStorage` (`terrain-hillshade`, `terrain-tri`, `gps-tracks-enabled`, gps-фильтры, theme, units и т. д.). - `style.json`, `style-dark.json`. - `config/*.yaml`. - `src/web/index.html`, `src/web/gps_tracks.js`, `src/web/app.css`. ## 2. Архитектурные границы данных | Слой данных | Тип | Расположение | Изменения в ET-014 | |-----------------------------------|----------------|----------------------------------------------|-------------------------------------------------| | OSM-vector (`trails`) | существующий | `/app/data/centralfederal.sqlite` | **нет** | | Личные GPX треки (ET-006) | существующий | браузер (memory) | **нет** | | Публичные GPS треки (ET-008) | существующий | `/app/data/gps_tracks.sqlite` | **нет** | | OSRM-граф | существующий | `/app/data/enduro.osrm.*` | **нет** | | Terrain hillshade/TRI/hypso PNG | существующий | `data/terrain/*` | **нет** | | User UI state | существующий | `localStorage` | **нет** новых ключей, нет миграции | | MapLibre client tile cache | существующий | браузер (LRU MapLibre) | **нет** | | Серверный кэш | не предусмотрен | n/a | **нет** | | DOM-state `#terrain-popup` | runtime UI | браузер (DOM) | **меняется**: `display:none` при `openSheet()` | | DOM-state `#terrain-toggle` | runtime UI | браузер (DOM) | **меняется**: класс `.active` снимается | | DOM-state `.bottom-sheet` | runtime UI | браузер (DOM) | **не меняется** (та же логика `.open`) | | DOM-state `#sheet-backdrop` | runtime UI | браузер (DOM) | **не меняется** (та же логика `.visible`) | | `closeTerrainOnOutside` listener | runtime UI | браузер (event listener на `document`) | **снимается** через `removeEventListener` | ## 3. Серверные данные ### 3.1 БД **Без изменений vs ET-013/ET-008.** - `centralfederal.sqlite` — read-only для ET-014. - `gps_tracks.sqlite` — read-only для ET-014. - Никаких ALTER/CREATE/INSERT/UPDATE/DELETE. - Никаких миграций. ### 3.2 Тайлы на диске **Без изменений.** `data/terrain/*`, `data/osm/*`, `data/osrm/*` — не трогаются. ### 3.3 Статика `src/web/` | Файл | Изменение | |-----------------------|-----------------------------------------------------------------| | `src/web/app.js` | +1 helper-функция `closeTerrainPopup()` (~7 строк), +1 вызов в `openSheet()` | | `src/web/app.css` | **нет** | | `src/web/index.html` | **нет** | | `src/web/gps_tracks.js` | **нет** | | `src/web/gpx.js` | **нет** | | `src/web/units.js` | **нет** | | `src/web/style.json` | **нет** | | `src/web/style-dark.json` | **нет** | Дельта размера `app.js`: ~+300 байт (helper-функция + комментарий + вызов). Пренебрежимо. ## 4. Клиентские данные ### 4.1 localStorage **Без изменений.** Используются существующие ключи (read-only для ET-014): | Ключ | Назначение | Изменения в ET-014 | |----------------------------|---------------------------------------------|--------------------| | `terrain-hillshade` | `'1' | '0'` — чекбокс «Тени рельефа» | **нет** | | `terrain-tri` | `'1' | '0'` — чекбокс «Перепады» | **нет** | | `gps-tracks-enabled` | публичные треки on/off | **нет** | | `gps-filter-*` | состояние фильтров публичных треков | **нет** | | `theme` | `'dark' | 'light'` | **нет** | | `units` | `'km' | 'mi'` | **нет** | | `base-layer` | подложка | **нет** | Никакой миграции. Существующие сессии при следующей загрузке автоматически получают исправленное UI-поведение. ### 4.2 MapLibre LRU (browser-side) Без изменений. Тайловый кэш не задействован — мы не меняем тайлы, zoom-уровни, source.minzoom, или paint properties. ### 4.3 DOM runtime state Ниже — единственное место, где ET-014 «меняет данные» (в runtime браузера, не на диске): #### `#terrain-popup` - **До ET-014**: при клике на `#public-tracks-filters-btn` popup остаётся `display: block`, z=500. - **После ET-014**: при любом `openSheet(id)`, если `popup.style.display !== 'none'`, popup переключается в `display: none`. #### `#terrain-toggle` - **До ET-014**: при открытии sheet'а сохраняет класс `.active`. - **После ET-014**: при `openSheet(id)` класс `.active` снимается (синхронно с popup'ом). #### Event listener `closeTerrainOnOutside` на `document` - **До ET-014**: добавлен в `toggleTerrainPopup()` через `addEventListener('click', closeTerrainOnOutside)`. Удаляется в двух местах: повторный клик по `#terrain-toggle` и срабатывание самого `closeTerrainOnOutside`. - **После ET-014**: дополнительно удаляется внутри `closeTerrainPopup()`, который вызывается из `openSheet()`. Двойной `removeEventListener` безвреден (DOM-спека: removeEventListener на отсутствующий listener — no-op). ### 4.4 In-memory constants **Нет.** Никаких новых JS-констант (в отличие от ET-013 с `HILLSHADE_PAINT` / `TRI_PAINT`). Только новая функция и вызов. ## 5. Контракты API ### 5.1 Backend endpoints **Без изменений.** ET-014 — чистый клиент. Никаких новых вызовов, никакого изменения параметров запросов, никакого изменения частоты запросов. | Endpoint | До ET-014 | После ET-014 | |-----------------------------------------|-------------|--------------| | `GET /api/gps-tracks/tiles/{z}/{x}/{y}.mvt` | без изменений | без изменений | | `GET /api/gps-tracks?bbox=…` | без изменений | без изменений | | `GET /api/gps-tracks/{id}/download` | без изменений | без изменений | | `GET /api/gps-tracks/health` | без изменений | без изменений | | `GET /terrain/{layer}/{z}/{x}/{y}.png` | без изменений | без изменений | | `GET /api/route/*` | без изменений | без изменений | | `GET /api/trails/*` | без изменений | без изменений | ### 5.2 Frontend internal API (`src/web/app.js`) | Функция | До ET-014 | После ET-014 | |-------------------------------|-------------------------------------------------|------------------------------------------------------------------------------| | `openSheet(id)` | публичный (вызывается из всех `toggle*Sheet`) | публичный, контракт сохранён; добавлен внутренний вызов `closeTerrainPopup()` | | `closeSheet(id)` | публичный | без изменений | | `closeAllSheets()` | публичный | без изменений | | `toggleTerrainPopup()` | публичный | без изменений | | `closeTerrainOnOutside(e)` | публичный (выставляется как event handler) | без изменений (опциональный TD-1 рефакторинг описан в ADR-019) | | `closeTerrainPopup()` | **отсутствует** | **новая** publish-функция (для возможного reuse) | Контракт `openSheet(id)` совместим со всеми существующими вызовами: ```bash $ grep -n 'openSheet(' src/web/*.js ``` - `app.js:openSheet(...)` — собственная реализация. - `app.js:openSheet('sheet-route')`, `openSheet('sheet-recon')`, `openSheet('sheet-scenic')`, `openSheet('sheet-link')`, `openSheet('sheet-gpx')` — все продолжают работать как раньше. - `gps_tracks.js:openSheet('sheet-gps-filters')` — продолжает работать; дополнительно теперь корректно закрывает popup. ## 6. Миграции **Нет.** Никаких миграций БД, миграций localStorage, миграций конфигов. При деплое в test: - `data/*` — без изменений. - БД — без изменений. - localStorage — старые ключи интерпретируются как раньше. - MapLibre LRU — самоочищается при reload браузера; явной инвал. не нужно. ## 7. Тестовые данные ### 7.1 Для unit-тестов В ET-014 **новых python unit-тестов не добавляется** — поведение исключительно UI и тестируется через Playwright. Опционально (cleanup, не обязательно): тест на статический grep по `src/web/app.js`, что: - Есть функция `closeTerrainPopup`. - В теле `openSheet` есть вызов `closeTerrainPopup()`. Если такой тест добавляется, формат — как `test_terrain_paint.py` в ET-013 (`tests/unit/test_ui_z_index_fix.py`, regex по исходнику без JS-runtime). Это **не блокирующий гейт** ET-014. ### 7.2 Для integration-тестов Не применимо. ET-014 не трогает API endpoints, integration-тесты не нужны. ### 7.3 Для UI-тестов (Playwright) `04b-ui-test-cases.md` — TC-UI-01..TC-UI-08: - Запускается на test-среде `https://openclaw.mva154.duckdns.org/enduro/`. - Данные — реальные (БД, тайлы) на mva154. - Скриншоты в `tests/e2e/__screenshots__/ET-014/`. - Не пиксельный diff; визуальная приёмка оператором + DOM-assertion'ы (`classList.contains('open')`, `elementFromPoint`, `getBoundingClientRect`). ## 8. Резервные копии и DR **Без изменений.** ET-014 не пишет данных. RPO = 0. ## 9. Privacy / Compliance | Аспект | Требование | |-------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------| | PII | **Нет.** ET-014 не собирает, не обрабатывает, не передаёт никаких данных | | Licensing | Не применимо | | Attribution | MapLibre attribution control — без изменений | | GDPR / 152-ФЗ | Не применимо | ## 10. Связанные документы - `01-brd.md` §1 (бизнес-контекст), §3 (бизнес-цель), §4 (BR-01..BR-06) - `02-trz.md` §1.1 (DOM-структура), §1.2 (стек z-index), §1.3 (корень), §2 (REQ-F, REQ-NF), §3 (варианты) - `03-acceptance-criteria.md` AC-01..AC-14 - `04b-ui-test-cases.md` TC-UI-01..TC-UI-08 - `06-adr/ADR-019-terrain-popup-yields-to-sheet.md` - `07-infra-requirements.md` - `10-tech-risks.md` - `docs/work-items/ET-013/08-data-requirements.md` — образец «read-only data» документа (наследие) - `docs/work-items/ET-012/08-data-requirements.md` — образец «read-pattern change» документа (наследие)