Files
enduro-trails/docs/work-items/ET-013/08-data-requirements.md
claude-bot 6b88bcee28
Some checks failed
CI / lint (push) Successful in 5s
CI / test (push) Failing after 5s
CI / build (push) Has been skipped
architect(ET): auto-commit from architect run_id=79
2026-06-04 09:40:50 +00:00

20 KiB
Raw Blame History

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
agent:architect

Требования к данным — 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/ — наследие нарезки тайлов