293 lines
14 KiB
Markdown
293 lines
14 KiB
Markdown
---
|
||
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» документа (наследие)
|