Files
enduro-trails/docs/work-items/ET-012/07-infra-requirements.md
claude-bot c7d472023f
All checks were successful
CI / lint (push) Successful in 4s
CI / test (push) Successful in 7s
CI / build (push) Successful in 2s
architect(ET): auto-commit from architect run_id=73
2026-06-04 06:19:02 +00:00

21 KiB
Raw Blame History

type, work_item_id, title, version, status, created_at, authors
type work_item_id title version status created_at authors
infra-requirements ET-012 Инфраструктурные требования — ET-012: Снижение minzoom публичных треков до z5 1 approved 2026-06-04
agent:architect

Инфраструктурные требования — ET-012

1. Резюме

ET-012 — calibration only. Меняются три файла исходного кода (src/api/gps_tracks/mvt.py, src/web/gps_tracks.js, src/web/index.html) + добавляются тесты. Инфраструктура не меняется:

  • 0 новых docker-сервисов;
  • 0 изменений в Dockerfile;
  • 0 изменений в docker-compose.yml;
  • 0 новых файлов БД, миграций, индексов;
  • 0 новых cron-записей;
  • 0 новых env / секретов / API-ключей;
  • 0 новых исходящих HTTPS-соединений;
  • 0 новых портов;
  • 0 изменений в nginx (новый minzoom прозрачен для прокси).

Эскалация: minor change (см. ADR-016 §«Классификация изменения»).

2. Контейнеры и сервисы

Аспект Требование
Новый сервис Нет
Изменения Dockerfile Нет
Изменения docker-compose.yml Нет
Перезапуск app после деплоя Нужен — docker compose up -d --no-deps app (≈ 5 сек простоя). Подхватывает новую tier-таблицу в build_gps_mvt, новый _simplify_coords, обновлённые src/web/*.js / *.html
Перезапуск gps-collector Не нужен — pipeline не затронут (collector только пишет в БД, отдачей не занимается)
Очистка серверного MVT-кэша после деплоя Нужна — _gps_tile_cache старых тайлов z5-z7 не существует (раньше слой был скрыт), но кэш z8-z11 надо инвалидировать через POST /api/gps-tracks/cache/clear (см. §6.2)
Очистка клиентского кэша / Service Worker Не нужно — gps_tracks.js подгружается с ?v=... версионным query-параметром (см. src/web/index.html загрузка модулей); пользователь получит обновлённый клиент при reload

2.1 Зависимости между сервисами

Без изменений vs ET-008/ET-009/ET-011. Те же зависимости:

  • app → файл /app/data/gps_tracks.sqlite (read-only при отдаче, read/write только из gps-collector).
  • gps-collector → тот же файл (offline pipeline, не затрагивается).
  • nginx (host)app:8000 через docker-network bridge.

3. Сеть

Аспект Требование
Новые входящие порты Нет
Изменения nginx Нет (тот же location /enduro/api/gps-tracks/tiles/{z}/{x}/{y}.mvt; новые z=5/6/7 — это просто другие значения существующего path-параметра)
nginx gzip для MVT Должен быть включён в mime.types/gzip_types для application/x-protobuf. Это уже было сделано в ET-008. Проверить при деплое (см. §6.2 шаг 3)
Кэш-заголовки на MVT Без изменений — endpoint отдаёт Cache-Control: public, max-age=300 (как было). На клиенте MapLibre LRU + браузер-кэш используют это
Новые исходящие соединения Нет — никаких внешних API не дёргается, всё локально
CORS Без изменений; middleware уже отдаёт Access-Control-Allow-Origin: * для всего /api/

3.1 Ingress traffic — оценка дельты

Размер MVT-тайла z=5 ≤ 200 KB до gzip (M-8), после nginx gzip ~50-70 KB.

Сценарий «пользователь открыл карту, увидел z5, попанил по ЦФО»:

  • Тайлов в кадре одновременно: ~6-10 на z5.
  • Уникальных за сессию (~5 минут pan): 20-30.
  • Итого ingress: 20-30 × 70 KB = ~1.5-2 MB на сессию сверх того, что было раньше (раньше на z5 запросов не было вообще — слой был скрыт).

Это допустимая дельта — uplink mva154 ≥ 100 Mbps по DuckDNS, при 10 одновременных пользователях пик ≈ 15 Mbps входящего трафика, ≈ 80 Mbps уходящего (тайлы клиенту).

3.2 Rate-limit на endpoint

Не вводим в этой итерации (BRD §3 «out of scope»). Текущий AbortController + 500 ms debounce на клиенте (ADR-008 §D) и серверный LRU защищают от шторма.

Если в продакшене обнаружится бот / scraper, дёргающий весь z=5 grid (1024 запроса) — добавляем slowapi-middleware отдельным DevOps-task'ом (out of ET-012).

4. Серверные ресурсы

Аспект Требование
CPU app Без изменений по архитектуре; рост нагрузки оценочно ≤ +5% при сценарии «один пользователь pan на z5» (генерация одного MVT ≤ 200 мс CPU). PERF-Z5-01 — гейт.
RAM app Без изменений. _gps_tile_cache ограничен 1024 записями × max 200 KB = 200 MB max. На практике средний размер MVT z5-z11 ≈ 50 KB → ≈ 50 MB в худшем случае
Disk app Без изменений. БД gps_tracks.sqlite не меняется; никаких новых файлов / volume
CPU gps-collector Без изменений (pipeline не затронут)
RAM gps-collector Без изменений
Disk gps-collector Без изменений

4.1 LRU cache size

_GPS_TILE_CACHE_MAX = 1024не меняем в MVP (ADR-016 §C).

Опционально можно поднять до 2048, если M-11 (cache hit ≥ 80%) не будет выполняться на test-среде после деплоя. Это маленький минорный патч (одна константа в src/api/gps_tracks/mvt.py), не требует архитектурного решения.

5. Конфигурация и секреты

Аспект Требование
Новые env-переменные Нет
Новые секреты Нет
Новые API-ключи Нет
Изменения config/gps_sources.yaml Нет
Изменения config/gps_regions.yaml Нет
Изменения runtime config НетGPS_TRACKS_MIN_ZOOM остаётся хардкодом в src/web/gps_tracks.js (BRD §3 Out of scope: «feature-flag для minzoom не вводим»)

6. Деплой

6.1 Среды

  • dev (локально): make dev (docker compose up app + gps-collector с overrides). Достаточно git pull && make dev для смены поведения.
  • test (mva154): https://openclaw.mva154.duckdns.org/enduro/. CI/CD — Gitea Actions; деплой через make deploy-test или ручной SSH + docker compose up -d --no-deps --build app (см. §6.2).
  • prod — пока не задействован; ET-012 деплоится только в test.

6.2 Процедура деплоя в test

Последовательность шагов (REQ-F-19 в TRZ §3):

  1. Сборка образа: docker compose build app на mva154 (после git pull).
  2. Перезапуск app: docker compose up -d --no-deps app.
  3. Smoke-проверка nginx gzip:
    curl -sI -H 'Accept-Encoding: gzip' \
      'https://openclaw.mva154.duckdns.org/enduro/api/gps-tracks/tiles/5/19/9.mvt' \
      | grep -i 'content-encoding'
    
    Ожидается content-encoding: gzip.
  4. Очистка серверного MVT-кэша (опционально, но рекомендуется после изменения tier-таблицы):
    curl -sX POST 'http://app:8000/api/gps-tracks/cache/clear'
    
    (Endpoint доступен только из docker-network, см. ADR-008 §7.)
  5. Ручная валидация AC-03..AC-08, AC-09..AC-10 через DevTools.
  6. Запись результатов в 13-test-report.md и 14-deploy-log.md (REQ-F-19).

6.3 Rollback

В случае проблем (например, размер MVT z5 > 200 KB на реальных данных → деградация мобильного клиента):

  1. Backend rollback: git revert <commit> + docker compose up -d --no-deps --build app.
  2. Frontend rollback: тот же образ; пользователи получают старый gps_tracks.js при следующем reload.
  3. Cache invalidation после rollback: POST /api/gps-tracks/cache/clear.

RTO: ≤ 5 минут (один docker compose up -d --no-deps app). RPO: 0 — никаких изменений в БД, никаких данных не теряется.

6.4 CI/CD-гейты

  • make lint (ruff + eslint) — должен быть зелёным (AC-21).
  • make test (pytest unit + integration) — зелёный (AC-11..AC-14, AC-21).
  • pytest -m perf (PERF-Z5-01) — отдельный джоб, не блокирующий merge в MVP, но логируется в 13-test-report.md. Если при росте БД (например, после очередного gps-collector runс +500 треков) тест начинает фейлить — задача в backlog: ужесточить tier-лимиты или ввести pre-rendering (ADR-016 вариант P-B).

7. Observability / Логирование

Аспект Требование
Новые лог-сообщения Нет (NFR-07 в TRZ §4)
Существующие лог-сообщения uvicorn.access логирует все запросы к /api/gps-tracks/tiles/{z}/{x}/{y}.mvt с длиной ответа — этого достаточно для мониторинга размера MVT z5
Метрики / Prometheus Не вводим в MVP. Если в будущем понадобятся p95-метрики build_gps_mvt — отдельный work-item (DevOps)
Health-endpoint GET /api/gps-tracks/health — без изменений; возвращает состояние БД, число треков по источникам

7.1 Что мониторить после деплоя

В nginx access.log на mva154 (вручную, без алёртов):

  • Размер ответа на /tiles/5/*/*.mvt: средняя ≤ 80 KB (после gzip), максимум ≤ 200 KB. Если max превышает 200 KB — ужесточить tier (limit=1000 вместо 1500 для z=5).
  • Status codes: только 200. Никаких 500/502 на z=5..7 (отлично индикатор регрессии).
  • Latency p95: ≤ 700 мс cold, ≤ 50 мс hit (M-7).

Эти проверки выполняются вручную в первую неделю после деплоя; если стабильно — закрываются.

8. Резервное копирование / Disaster recovery

Аспект Требование
Backup БД Без изменений — БД gps_tracks.sqlite бэкапится тем же crontab-скриптом, что и раньше (ET-008)
Время восстановления (RTO) ≤ 5 минут (rollback контейнера, см. §6.3)
Точка восстановления (RPO) 0 — никаких данных не теряется

9. Безопасность

Аспект Требование
Auth / Authorization Без изменений (NFR-05 в TRZ §4). Endpoint /tiles/{z}/{x}/{y}.mvt — публичный (как и был на z=8..11)
Валидация входных данных Без изменений; existing 0 ≤ z ≤ 22 в get_gps_tile уже корректно пропускает z=5..7
CSP Без изменений
Rate-limit Не вводим в MVP (см. §3.2)
TLS Без изменений — nginx с Let's Encrypt сертификатом DuckDNS

10. Совместимость

Аспект Требование
API контракт /api/gps-tracks/* Не меняется (REQ-F-15). Старые клиенты (старый gps_tracks.js со стороны браузера, который где-то закэшировался) продолжают запрашивать z=8..11 — endpoint отвечает корректно
MapLibre GL JS совместимость Без изменений; используем существующее interpolate linear zoom выражение, которое поддерживается всеми текущими версиями MapLibre
Совместимость с centralfederal.sqlite Не затронуто (это другая БД, для слоя trails)
Совместимость с OSRM Не затронуто (роутинг работает с OSRM-графом независимо)
localStorage migration Не нужно (REQ-F-18). Существующие ключи gps-tracks-enabled, gps-tracks-activities, gps-tracks-sources, gps-tracks-color-mode — без изменений

11. Связанные документы

  • 01-brd.md §3 In/Out of scope, §6 Зависимости.Инфра
  • 02-trz.md §3 REQ-F-19 Деплой и валидация, §4 NFR
  • 06-adr/ADR-016-z5-tiling-policy.md §«Классификация изменения», §«Последствия»
  • 08-data-requirements.md (этот пакет)
  • 10-tech-risks.md (этот пакет)
  • docs/work-items/ET-008/07-infra-requirements.md §3 (nginx gzip для MVT, cache-clear network policy) — наследие
  • docs/work-items/ET-011/07-infra-requirements.md — образец «zero-infra» work-item