Files
enduro-trails/docs/work-items/ET-015/08-data-requirements.md
claude-bot 4f80c250cf
All checks were successful
CI / lint (push) Successful in 4s
CI / test (push) Successful in 10s
CI / build (push) Successful in 3s
architect(ET): auto-commit from architect run_id=102
2026-06-05 15:27:58 +00:00

293 lines
14 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
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» документа (наследие)