--- type: data-requirements work_item_id: ET-015 title: "Требования к данным — ET-015: Healthcheck enduro-trails-app через python urllib" version: 1 status: approved created_at: 2026-06-05 authors: - "agent:architect" --- # Требования к данным — ET-015 ## 1. Резюме ET-015 — **pure container-config change**. Никаких изменений в данных: ни в БД, ни в файлах на диске, ни в localStorage, ни в API-контрактах, ни в конфигурациях приложения. Меняется **команда, которую Docker запускает для проверки живости контейнера** — она перестаёт зависеть от `curl` (отсутствующего в образе) и переключается на python `urllib.request`. Запрос ходит на **уже существующий** эндпоинт `/api/health` (`src/api/main.py:1224`), который не меняется. **Меняется:** - Runtime-состояние `docker inspect enduro-trails-app-1 --format '{{.State.Health.Status}}'`: переключается с `unhealthy` (ложный) на `healthy` (честный). - Содержимое `State.Health.Log`: теперь пишутся реальные `ExitCode: 0` результаты, а не `exec: "curl": executable file not found in $PATH`. **Не меняется:** - Содержимое и схема БД `centralfederal.sqlite`, `gps_tracks.sqlite`. - Содержимое и формат PNG-тайлов в `data/terrain/*`. - Файлы OSRM-графа (`data/osrm/*`), OSM-данные (`data/osm/*`). - Контракты API (`/api/gps-tracks/*`, `/terrain/*`, `/api/route/*`, `/api/health`, прочие). - Эндпоинт `/api/health` — формат ответа, поведение, путь (`src/api/main.py:1224`) (AC-08). - Ключи `localStorage` фронтенда. - `style.json`, `style-dark.json`. - `config/*.yaml`. - `src/web/*`, `src/api/*`, `Dockerfile`, миграции, скрипты деплоя. ## 2. Архитектурные границы данных | Слой данных | Тип | Расположение | Изменения в ET-015 | |-------------|-----|--------------|---------------------| | OSM-vector (`trails`) | существующий | `/app/data/centralfederal.sqlite` | **нет** | | Публичные GPS-треки (ET-008) | существующий | `/app/data/gps_tracks.sqlite` | **нет** | | OSRM-граф | существующий | `/app/data/osrm/enduro.osrm.*` | **нет** | | Terrain PNG-тайлы | существующий | `data/terrain/*` | **нет** | | Личные GPX-треки (ET-006) | существующий | браузер (memory) | **нет** | | User UI state | существующий | `localStorage` | **нет** | | MapLibre client tile cache | существующий | браузер (LRU MapLibre) | **нет** | | Серверный кэш | не предусмотрен | n/a | **нет** | | Docker container state | runtime | Docker daemon на mva154 | **меняется**: `State.Health.Status: unhealthy → healthy`, `FailingStreak: 3762 → 0`, `Log[].ExitCode: -1 → 0` | | `docker-compose.yml` | конфигурация | git, mva154 | **меняется**: секция `app.healthcheck` | | `CHANGELOG.md` | документация | git | **меняется**: +1 строка в `Unreleased` | ## 3. Серверные данные ### 3.1 БД **Без изменений vs ET-014/ET-013/ET-008/ET-012.** - `centralfederal.sqlite` — read-only для ET-015 (даже не читается). - `gps_tracks.sqlite` — read-only для ET-015 (даже не читается). - Никаких ALTER/CREATE/INSERT/UPDATE/DELETE. - Никаких миграций. **Косвенная связь:** эндпоинт `/api/health` возвращает поле `db_exists` (`os.path.exists(DATA_PATH)`). Это проверка **наличия файла**, не открытия БД, не SELECT'а. ET-015 не делает БД «зависимостью healthcheck'а» больше, чем она уже была. ### 3.2 Тайлы на диске **Без изменений.** `data/terrain/*`, `data/osm/*`, `data/osrm/*` — не трогаются. Healthcheck не обращается ни к одной плитке. ### 3.3 Статика `src/web/` **Без изменений.** Healthcheck не задевает фронтенд. | Файл | Изменение | |------|-----------| | `src/web/app.js` | **нет** | | `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` | **нет** | ### 3.4 Backend `src/api/` **Без изменений.** `/api/health` (`src/api/main.py:1224`) не правится (AC-08, BRD §7). | Файл | Изменение | |------|-----------| | `src/api/main.py` | **нет** | | `src/api/requirements.txt` | **нет** (никаких новых python-зависимостей) | | `src/api/gps_tracks/*` | **нет** | | Прочие модули | **нет** | ### 3.5 Конфиги | Файл | Изменение | |------|-----------| | `Dockerfile` | **нет** (см. ADR-020 Cons Варианта B) | | `docker-compose.yml` | **да** — секция `app.healthcheck` | | `config/gps_sources.yaml` | **нет** | | `config/gps_regions.yaml` | **нет** | | nginx-config на хосте | **нет** | | systemd / cron на mva154 | **нет** | ### 3.6 Скрипты и миграции | Каталог | Изменение | |---------|-----------| | `scripts/` | **нет** (никакого `scripts/healthcheck.py` — отклонено в Вариант E ADR-020) | | `migrations/` | **нет** | | `tests/` | **нет** *(новые тесты опциональны, см. test-plan; не блокируют merge)* | ## 4. Клиентские данные ### 4.1 localStorage **Без изменений.** ET-015 фронтенд не задевает. Никаких новых ключей, никакой миграции. ### 4.2 MapLibre LRU (browser-side) Без изменений. Тайловый кэш не задействован. ### 4.3 DOM runtime state Без изменений. UI не меняется. ### 4.4 In-memory constants Без изменений. ## 5. Контракты API ### 5.1 Backend endpoints **Без изменений.** ET-015 не добавляет, не модифицирует и не удаляет ни один endpoint. | Endpoint | До ET-015 | После ET-015 | |----------|-----------|--------------| | `GET /api/health` | HTTP 200, JSON `{"status": "ok", "db_path": ..., "db_exists": ...}` | **без изменений** (AC-08) | | `GET /api/gps-tracks/health` | без изменений | без изменений | | `GET /api/gps-tracks/tiles/{z}/{x}/{y}.mvt` | без изменений | без изменений | | `GET /api/gps-tracks?bbox=…` | без изменений | без изменений | | `GET /api/gps-tracks/{id}/download` | без изменений | без изменений | | `GET /terrain/{layer}/{z}/{x}/{y}.png` | без изменений | без изменений | | `GET /api/route/*` | без изменений | без изменений | | `GET /api/trails/*` | без изменений | без изменений | ### 5.2 Внутренний контракт healthcheck-команды | Контракт | До ET-015 | После ET-015 | |----------|-----------|--------------| | Команда | `curl -f http://localhost:5556/api/health` | `python -c "import urllib.request,sys; sys.exit(0 if urllib.request.urlopen('http://localhost:5556/api/health', timeout=3).status == 200 else 1)"` | | Тип команды (Docker) | `CMD` (массив) | `CMD` (массив) | | Зависимость от пакетов | curl (отсутствует ⇒ exec error) | stdlib (присутствует ⇒ работает) | | Exit code при HTTP 200 | 0 (если бы curl был) | 0 | | Exit code при HTTP 4xx/5xx | ≠ 0 (`-f` фейлит на 4xx/5xx) | ≠ 0 (`HTTPError` ⇒ ненулевой код) | | Exit code при connection refused | ≠ 0 (если бы curl был) | ≠ 0 (`URLError` ⇒ ненулевой код) | | Exit code при отсутствии команды | -1 (exec error) | n/a (команда есть) | | Внутренний timeout запроса | n/a (использовал default Docker) | 3 с (`urlopen(..., timeout=3)`) | | Внешний timeout Docker | 5 с | 5 с (без изменений) | | Interval | 30 с | 30 с (без изменений) | | Retries | 3 | 3 (без изменений) | | Start period | не задан | 20 с (новое) | ### 5.3 Что **не** становится зависимостью - **БД** (`centralfederal.sqlite`, `gps_tracks.sqlite`): healthcheck не открывает их. `/api/health` только проверяет `os.path.exists()` — это файловая операция, БД-движок не задействован. - **OSRM** (`http://172.22.0.1:5559`): healthcheck не дёргает routing. - **Тайл-каталог**: healthcheck не запрашивает PNG-плитки. - **Внешние тайл-провайдеры** (OSM, Esri): не задействованы. - **nginx**: не на пути healthcheck-запроса. ## 6. Миграции **Нет.** Никаких миграций БД, миграций localStorage, миграций конфигов приложения. При деплое в test: - `data/*` — без изменений. - БД — без изменений. - localStorage — старые ключи интерпретируются как раньше. - MapLibre LRU — без изменений. - Контейнер `enduro-trails-app-1` пересоздаётся (старый удаляется, новый создаётся с тем же образом и тем же файловым состоянием). Все volume-mounts (`./data:/app/data`, `./src/web:/app/src/web`, `./config:/app/config:ro`) подхватываются как раньше → никаких потерь данных. ## 7. Тестовые данные ### 7.1 Для unit-тестов См. `04-test-plan.yaml` UT-01..UT-03: - **UT-01**: live uvicorn на `:5556` (через `make dev`) либо mock-сервер; запуск python one-liner с хоста; проверка exit code 0. - **UT-02**: никто не слушает `:5556`; запуск python one-liner; проверка exit code ≠ 0 (URLError). - **UT-03**: mock-сервер отдаёт 500; запуск python one-liner; проверка exit code ≠ 0. Тестовые данные минимальны: либо реальный uvicorn (с реальной БД, которая уже есть), либо python `http.server`-mock. Никаких fixtures, seed-данных, моков БД. ### 7.2 Для integration-тестов См. `04-test-plan.yaml` IT-01..IT-04: - **IT-01..IT-04**: реальный `docker compose up -d app` на машине с доступом к `data/`. Данные реальные; ET-015 их не меняет. - Никаких новых fixtures, никаких CSV/JSON seed-файлов. ### 7.3 Для UI-тестов (Playwright) Не применимо. ET-015 не трогает UI. ### 7.4 Для E2E на mva154 См. `04-test-plan.yaml` E2E-01..E2E-02: - **E2E-01**: `ssh mva154 'docker inspect ...'` — данные читаются напрямую из Docker daemon, никакие тестовые fixtures не нужны. - **E2E-02**: `curl https://openclaw.mva154.duckdns.org/enduro/api/health` — проверка живого эндпоинта; ответ — реальный JSON с реальной БД на mva154. ## 8. Резервные копии и DR **Без изменений.** ET-015 не пишет данных. RPO = 0. Если деплой ET-015 сломается (например, новый healthcheck сам по себе помечает контейнер `unhealthy` из-за неучтённой особенности): - БД, тайлы, конфиги — не затронуты. - Rollback = `git revert` + `docker compose up -d app` (см. `07-infra-requirements.md` §6.3). - RTO ≤ 5 минут. ## 9. Privacy / Compliance | Аспект | Требование | |--------|------------| | PII | **Нет.** ET-015 не собирает, не обрабатывает, не передаёт никаких пользовательских данных | | Licensing | Не применимо | | Attribution | MapLibre attribution control — без изменений | | GDPR / 152-ФЗ | Не применимо (healthcheck — loopback внутри контейнера, не пересекает периметр) | | Egress на внешние сервисы | **Нет** (healthcheck не делает egress) | | Логирование PII | **Нет** (healthcheck-логи Docker содержат только exit code и stdout/stderr команды — пустые) | ## 10. Связанные документы - `01-brd.md` §1 (контекст), §2 (корень проблемы), §3 (бизнес-проблема), §4 (цель), §6 (ограничения), §7 (out of scope) - `02-trz.md` §1 (постановка), §2 (текущее состояние), §3 (целевое состояние), §4 (альтернативы), §5 (R-1..R-5), §6 (тестирование) - `03-acceptance-criteria.md` AC-01..AC-10 - `04-test-plan.yaml` ST-01..ST-07, UT-01..UT-03, IT-01..IT-04, E2E-01..E2E-02 - `06-adr/ADR-020-healthcheck-via-python-urllib.md` §«Решение», §«Что НЕ меняется», §«Технический долг» - `07-infra-requirements.md` §2 (контейнеры), §5 (конфигурация) - `10-tech-risks.md` - `docs/architecture/README.md` §«Компоненты», §«GPS Tracks Pipeline» (для контекста: ET-015 эту pipeline не трогает) - `docs/work-items/ET-014/08-data-requirements.md` — образец «pure client UI change» документа (наследие) - `docs/work-items/ET-013/08-data-requirements.md` — образец «read-only data» документа (наследие)