20 KiB
type, work_item_id, title, version, status, created_at, authors
| type | work_item_id | title | version | status | created_at | authors | |
|---|---|---|---|---|---|---|---|
| data-requirements | ET-013 | Требования к данным — ET-013: Zoom-aware paint для terrain-слоёв на z9-z11 | 1 | approved | 2026-06-04 |
|
Требования к данным — ET-013
1. Резюме
ET-013 — pure client render change. Никаких изменений схемы БД,
никаких новых таблиц/индексов/миграций, никаких изменений тайлов на
диске, никаких новых ключей localStorage, никаких изменений
конфигов источников.
Меняется только то, как уже существующие PNG-тайлы рельефа отрисовываются MapLibre на клиенте:
raster-opacityстановитсяinterpolate-выражением по['zoom'](вместо константы).- Для hillshade добавляется
raster-contrast(тожеinterpolate). raster-resamplingдля обоих terrain-слоёв переключается с'linear'на'nearest'.
Меняется:
- набор
raster paint propertiesу двух MapLibre-слоёв (terrain-hillshade,terrain-tri); - визуальная читаемость рельефа на z9-z11 (целевое улучшение).
Не меняется:
- содержимое и формат PNG-тайлов в
data/terrain/{hillshade,tri,hypso}/(PH-6 наследие); - schema БД
centralfederal.sqliteиgps_tracks.sqlite; - контракт API
/terrain/{layer}/{z}/{x}/{y}.png(REQ-F-18); - содержимое тайлов hypso (в UI не подключён, OOS);
- параметры генератора hillshade на сервере (azimuth, altitude, z-factor — PH-6, OOS);
- параметры классификации TRI (5-уровневая палитра — PH-6, OOS);
- ключи
localStorage(terrain-hillshade,terrain-tri— REQ-F-17); - содержимое
config/*.yaml; - стили
style.json,style-dark.json(растровые terrain-слои в них не описаны — добавляются динамически из JS).
2. Архитектурные границы данных
| Слой данных | Тип | Расположение | Изменения в ET-013 |
|---|---|---|---|
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 PNG | существующий | data/terrain/hillshade/{z}/{x}/{y}.png (z=8..14) |
read-only: добавляется новая комбинация (z=9, x, y), которая клиент раньше не запрашивал. Тайлы на диске уже есть (PH-6 нарезка) |
| Terrain TRI PNG | существующий | data/terrain/tri/{z}/{x}/{y}.png (z=8..14) |
read-only: те же тайлы, что и раньше; меняется только paint |
| Terrain hypso PNG | существующий | data/terrain/hypso/{z}/{x}/{y}.png |
не используется в ET-013 (OOS) |
| User UI state | существующий | localStorage |
нет новых ключей, нет миграции |
| MapLibre client tile cache | существующий | браузер (LRU MapLibre, ~100 MB) | расширяется ключевым пространством: теперь могут лежать тайлы hillshade с z = 9 (раньше не запрашивались) |
Серверный кэш /terrain/* |
не предусмотрен | n/a (FileResponse + Cache-Control immutable) | нет |
3. Серверные данные
3.1 Структура data/terrain/
Без изменений vs PH-6. Структура каталога:
data/terrain/
├── hillshade/
│ ├── 8/{x}/{y}.png # baseline
│ ├── 9/{x}/{y}.png # используется ET-013 впервые на клиенте
│ ├── 10/{x}/{y}.png # baseline (10+ уже использовался)
│ ├── 11/{x}/{y}.png
│ ├── 12/{x}/{y}.png
│ ├── 13/{x}/{y}.png
│ └── 14/{x}/{y}.png
├── tri/ # та же структура, z=8..14
└── hypso/ # та же структура, в UI не подключён
Никаких ALTER/CREATE/INSERT/UPDATE/DELETE на стороне данных. Никакой догенерации тайлов. Никакого преобразования формата (PNG остаётся PNG 256×256).
3.2 Объёмы данных
| Метрика | Текущее (PH-6) | После ET-013 | Гейт |
|---|---|---|---|
| Объём PNG hillshade на диске | ~ X MB (PH-6 baseline) | без изменений | n/a |
| Объём PNG TRI на диске | ~ Y MB | без изменений | n/a |
| Запросы hillshade за сессию | N (только z≥10) | ~ 1.25-1.35 × N (добавился z=9) | BRD M-10: ≤ +35% |
| Запросы TRI за сессию | M (z=5..14) | без изменений | n/a |
3.3 Pre-deploy validation тайлов z9-z11
Обязательная проверка перед merge (BRD R-11, AC-19):
curl -sI 'https://openclaw.mva154.duckdns.org/enduro/terrain/hillshade/9/308/158.png' | head -1
curl -sI 'https://openclaw.mva154.duckdns.org/enduro/terrain/hillshade/10/617/317.png' | head -1
curl -sI 'https://openclaw.mva154.duckdns.org/enduro/terrain/hillshade/11/1234/635.png' | head -1
Ожидается HTTP/1.1 200 OK на все три. Если 404 — задача
останавливается, открывается PH-6 follow-up «hillshade-z9-z14
backfill». См. 07-infra-requirements.md §6.2 шаг 1.
3.4 API endpoint terrain_tile
Без изменений (src/api/main.py:1240):
- URL:
GET /terrain/{layer}/{z}/{x}/{y}.png,layer ∈ {hillshade, tri, hypso}. - Возвращает: PNG из файловой системы (sendfile через
FileResponse). - Заголовки:
Cache-Control: public, max-age=31536000, immutable— без изменений. Браузерный кэш и nginx-кэш агрессивно поглощают повторы. - Контракт OpenAPI — без изменений (REQ-F-18, NFR-04).
4. Клиентские данные
4.1 localStorage
Без изменений vs PH-6 / ET-007. Используются ключи:
| Ключ | Назначение | Изменения в ET-013 |
|---|---|---|
terrain-hillshade |
`'1' | '0'` — чекбокс «Тени рельефа» |
terrain-tri |
`'1' | '0'` — чекбокс «Перепады» |
REQ-F-17 в TRZ §3: «никакой миграции localStorage не нужно».
Существующие сессии при следующей загрузке автоматически получают
новый UI-порог 9 (вместо 10) и новые HILLSHADE_PAINT / TRI_PAINT
константы. Если у пользователя terrain-hillshade === '1' и текущий
zoom ≥ 9 — hillshade покажется автоматически (раньше показался бы
только на z ≥ 10).
4.2 MapLibre LRU (browser-side)
Браузерный MapLibre кэширует растровые тайлы в собственном LRU (~100 MB по умолчанию). После ET-013:
- Ключевое пространство кэша:
(source_id, z, x, y)— расширяется дляterrain-hillshade-sourceнаz = 9(раньше source имелminzoom: 10→ запросов z=9 не было). - Объём — управляется MapLibre, ~100 MB. Дельта мизерная (тайл hillshade ≈ 8-30 KB).
- Никакой синхронизации/инвалидации не нужно (тайлы на сервере
не меняются;
Cache-Control: immutableгарантирует консистентность).
4.3 In-memory paint constants
Новые константы в src/web/app.js после TERRAIN_BASE_URL:
const HILLSHADE_PAINT = {
'raster-opacity': ['interpolate', ['linear'], ['zoom'],
9, 0.65, 10, 0.60, 11, 0.55, 12, 0.50, 14, 0.40],
'raster-contrast': ['interpolate', ['linear'], ['zoom'],
9, 0.40, 10, 0.35, 11, 0.30, 12, 0.15, 14, 0.00],
'raster-resampling': 'nearest'
};
const TRI_PAINT = {
'raster-opacity': ['interpolate', ['linear'], ['zoom'],
5, 0.55, 7, 0.65, 8, 0.70,
9, 0.80, 10, 0.85, 11, 0.85,
12, 0.75, 15, 0.70],
'raster-resampling': 'nearest'
};
- Это компилируемые MapLibre
interpolate-выражения, не «данные» в архитектурном смысле. Живут в коде, изменяются коммитом (BRD §6 q&a «Делать ли paint-таблицы переменными окружения / config'ом? Нет — преждевременная абстракция»). - Память: < 1 KB суммарно. Производительность: MapLibre кэширует скомпилированные выражения (NFR-01).
5. Контракты API
5.1 GET /terrain/{layer}/{z}/{x}/{y}.png
| Аспект | До ET-013 | После ET-013 |
|---|---|---|
Поддерживаемые layer |
hillshade, tri, hypso |
без изменений |
Path-параметр z |
принимается любой валидный z, тайлы на диске z=8..14 | без изменений |
| Response 200 | для существующих (z, x, y) PNG |
без изменений |
| Response 404 | для несуществующих (z, x, y) |
без изменений |
| Response Content-Type | image/png |
без изменений |
| Cache-Control | public, max-age=31536000, immutable |
без изменений |
Старые клиенты (старый app.js со старым minzoom = 10 для
hillshade) — продолжают работать. Никакого breaking change в
контракте нет (NFR-04).
5.2 Прочие endpoint'ы
ET-013 не трогает: /api/gps-tracks/*, /api/trails/*, /api/route/*,
/api/health. Их контракты — без изменений.
6. Миграции
Нет. Никаких миграций БД, миграций localStorage, миграций конфигов, миграций тайлов.
При деплое в test:
data/terrain/*— без изменений (read-only дляapp).- БД
centralfederal.sqlite,gps_tracks.sqlite— без изменений. - Серверный кэш — отсутствует у
/terrain/*(статическая раздача сCache-Control: immutable). - Клиентский MapLibre LRU — самоочищается при reload браузера; явной миграции не нужно.
- localStorage — старые ключи интерпретируются как раньше; включённый ранее hillshade автоматически появится на z9 (REQ-F-17, AC-14).
7. Тестовые данные
7.1 Для unit-тестов
tests/unit/test_terrain_paint.py (новый, REQ-F-13 / REQ-F-14):
- Python-парсер исходного
src/web/app.jsчерезre. - Никаких внешних зависимостей.
- Никаких фикстур данных.
- Проверяет наличие
HILLSHADE_PAINT/TRI_PAINT, наличие ключевых stops (9, 0.65,11, 0.55,14, 0.40,8, 0.70,10, 0.85), наличие'raster-resampling': 'nearest', порогzoom < 9вupdateHillshadeAvailability.
7.2 Для integration-тестов
tests/integration/test_terrain_z9_tiles.py (новый, REQ-F-15):
- Использует FastAPI
TestClientдляsrc/api/main.py:app. - Опирается на наличие файла
data/terrain/hillshade/9/<x>/<y>.png— если каталога нет, тестskippedс reason (CI без данных). - На test-среде mva154 (где данные есть) — выполняется как smoke-проверка endpoint'а.
- Дополнительно:
test_hillshade_invalid_zoom_404— sanity на невалидном zoom.
7.3 Для UI-тестов (Playwright)
04b-ui-test-cases.md — список тест-кейсов TC-UI-01..TC-UI-10:
- Запускается на test-среде
https://openclaw.mva154.duckdns.org/enduro/. - Данные — реальные PNG-тайлы рельефа на mva154 (PH-6 нарезка).
- Скриншот-эталоны для AC-06..AC-12 (визуальная читаемость) — в
tests/e2e/screenshots/et013/. - Скриншоты сравниваются оператором (качественная приёмка), не пиксельный diff (BRD M-9, R-1..R-3).
8. Резервные копии и DR
Без изменений vs PH-6.
- БД
centralfederal.sqlite,gps_tracks.sqlite— бэкап тем же crontab-скриптом, что и раньше; ET-013 не трогает. - PNG-тайлы
data/terrain/*— регенерируются из SRTM при необходимости (PH-6 pipeline). RPO для тайлов = время регенерации (часы), но они read-only и не теряются при деплое ET-013.
RPO для ET-013: 0 (никаких данных не пишется/не теряется).
9. Privacy / Compliance
| Аспект | Требование |
|---|---|
| PII | Нет. PNG-тайлы рельефа — derivative из SRTM 30 м (NASA, public domain). Никаких персональных данных нигде в data-flow ET-013 |
| Licensing | Без изменений (PH-6 наследие: SRTM 30 m — public domain; derivative PNG распространяется свободно). ET-013 не меняет источник данных |
| Attribution | MapLibre attribution control отображает атрибуцию активных источников (OSM, Esri). Атрибуция SRTM/NASA не выводится в UI (PH-6 решение); ET-013 это не меняет |
| GDPR / 152-ФЗ | Не применимо (нет PII) |
10. Связанные документы
01-brd.md§2.1 (текущая реализация), §3 (F-01..F-14), §6 (Зависимости.Данные)02-trz.md§3 REQ-F-04..REQ-F-09 (paint constants), REQ-F-13..REQ-F-15 (тесты), REQ-F-17 (localStorage), REQ-F-18 (API), REQ-F-19 (configs/styles)06-adr/ADR-017-zoom-aware-terrain-paint.md§«Решение», §«Последствия»07-infra-requirements.md§3 (network), §6 (deploy procedure), §3.1 (ingress estimate)10-tech-risks.md(этот пакет)docs/work-items/ET-012/08-data-requirements.md— образец «read-pattern change» документа (наследие)docs/phases/PH-6.terrain/— наследие нарезки тайлов