B13–B19: дорожная карта реструктуризации Вектора в систему подсистем
B13 — каркас-видение: 7 подсистем (Core/GIS/Search Area/Field Data/ Real-time/Backend/UI) + 4 ключевых принципа (развязка движка, 4 слоя данных, итеративная модель, очередь задач) + технический контур PostGIS. B14 — чистый SearchEngine (поведение-сохраняющий, B1-safe). B15 — 4 слоя данных: схема + Alembic-миграция + версионирование моделей. B16 — GIS: PostGIS + локальный OSM (замена живого Overpass). B17 — Field Data: модель + ингестия операционных данных. B18 — итеративный пересчёт модели + очередь задач (event-driven). B19 — «Контур» (ATAK + Meshtastic, реал-тайм) — плейсхолдер, отдельный проект. Сводка и рекомендуемый порядок обновлены. Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
+149
-11
@@ -661,9 +661,14 @@ sed -i 's/sar_mchs/vector_mchs/g; s#/root/sar-mchs#/root/vector#g' DEPLOY.md
|
||||
|
||||
**Жёсткое правило:** ни ISRID, ни архив не дают права автоматически перезаписывать формулу весов — изменение коэффициентов проходит через ревью человека (см. B1 и «Жёсткие исключения» в начале файла).
|
||||
|
||||
B13 Структурирование проекта
|
||||
## B13 — Структурирование «Вектора» в систему подсистем (видение-каркас)
|
||||
|
||||
1. Ядро «Вектора»
|
||||
**Тип:** архитектура / реструктуризация, needs-context. Исключено из делегирования локальной модели: затрагивает контракты данных, схему БД, бизнес-логику SAR.
|
||||
|
||||
**Цель:** ВЕКТОР — не один монолит, а система относительно независимых подсистем с чистыми границами. Упрощает разработку, тестирование и будущее подключение ATAK/Meshtastic.
|
||||
|
||||
**Подсистемы:**
|
||||
```
|
||||
ВЕКТОР
|
||||
│
|
||||
├── Core
|
||||
@@ -716,9 +721,24 @@ B13 Структурирование проекта
|
||||
├── вероятностная карта
|
||||
├── группы
|
||||
└── статистика
|
||||
```
|
||||
|
||||
2. Технический
|
||||
**Ключевые принципы (добавлены к изначальному скелету B13):**
|
||||
|
||||
1. **Развязка движка.** Search Engine — чистая функция: исходные данные + данные поиска + параметры человека → `(ProbabilitySurface, SearchAreas, Recommendations)`. Он ничего не знает об ATAK, Meshtastic, веб-интерфейсе, БД, auth. Доставка (web/ATAK/Mesh) — отдельный слой, подписанный на результат.
|
||||
|
||||
2. **Четыре слоя данных, не смешиваются:**
|
||||
- **Слой 1 — исходные (неизменяемые):** OSM, DEM, гидрография, лес, дороги, здания, ISRID, исторические поиски.
|
||||
- **Слой 2 — конкретный поиск:** исходная точка, время исчезновения, категория, возраст/пол/состояние, известный маршрут, погодные условия, доп. факторы.
|
||||
- **Слой 3 — оперативные (во время операции):** Position, Observation, Track, Clue, Team, AreaChecked, WitnessReport, FoundPerson.
|
||||
- **Слой 4 — результат модели:** ProbabilitySurface, SearchZone, Priority, Confidence, RecommendedRoute. **Результат не смешивается с исходными данными.**
|
||||
|
||||
3. **Итеративная модель.** Не «Вектор один раз нарисовал круг», а постоянный пересчёт наиболее вероятного положения по мере поступления полевых данных: расчёт → поисковые группы → найдено/не найдено → новые данные → новый расчёт. Сюда же естественно ложатся ATAK + Meshtastic.
|
||||
|
||||
4. **Очередь задач** для тяжёлых расчётов (terrain analysis, probability calculation, routing, recalculation) — сейчас `analyze_case` синхронно ждёт Overpass + Claude.
|
||||
|
||||
**Технический контур:**
|
||||
```
|
||||
PostgreSQL
|
||||
│
|
||||
├── PostGIS
|
||||
@@ -727,7 +747,7 @@ B13 Структурирование проекта
|
||||
|
||||
▲
|
||||
│
|
||||
┌───────┴────────┐
|
||||
┌──────┴────────┐
|
||||
│ Vector Backend │
|
||||
├────────────────┤
|
||||
│ Search Engine │
|
||||
@@ -735,13 +755,129 @@ B13 Структурирование проекта
|
||||
│ ISRID Engine │
|
||||
│ Routing │
|
||||
│ Event Engine │
|
||||
└───────┬────────┘
|
||||
└──────┬─────────┘
|
||||
│
|
||||
├──────── Web UI
|
||||
│
|
||||
├──────── ATAK
|
||||
│
|
||||
└──────── Meshtastic
|
||||
├── Web UI
|
||||
├── ATAK
|
||||
└── Meshtastic
|
||||
```
|
||||
|
||||
**Зависимости / блокеры:**
|
||||
- **ISRID (B12) — внешний правовой блокер.** Итеративная модель (B18) строится на экспертных коэффициентах сейчас; ISRID подключается позже как источник априорных, когда вопрос правового статуса решён.
|
||||
- **B1 (ядро скоринга) — коэффициенты под ревью человека.** Экстракция движка (B14) их НЕ меняет; любая калибровка — отдельно через B1.
|
||||
- **Реал-тайм (B19) — фактически отдельный проект**, оформляется после ядра и Field Data.
|
||||
|
||||
**Декомпозиция в фазы:** B14 → B15 → (B16, B17 параллельно) → B18 → B19. См. ниже.
|
||||
|
||||
---
|
||||
|
||||
## B14 — Чистый SearchEngine (поведение-сохраняющий)
|
||||
**Тип:** refactor / архитектура, needs-context. Фундамент всей развязки (B13-принцип 1). Низкий риск: поведение НЕ меняется, коэффициенты НЕ трогаются (B1-safe).
|
||||
|
||||
**Что:** Вынести расчёт поисковой модели из `backend/routers/analyze.py` в отдельный модуль `services/search_engine.py` с чистой границей:
|
||||
- `SearchInput` (pydantic): age, gender, terrain, weather, elapsed_hours, season, diagnosis_type, has_transport, psychotype_answers, profiles, lat/lon, loss_time, … — то, что сегодня собирается в `analyze_case` из payload + `db.get_case`.
|
||||
- `SearchModel` (результат): max_distance_km, coefficients, time_of_day, psychotype (+modifiers +recommendations), weights, distance_multiplier, active_profiles, critical_warnings, urgency, primary_zones, search_radius_km, key_locations, behavioral_prediction, immediate_actions, summary, fallback_used.
|
||||
- `build_search_model(input: SearchInput) -> SearchModel` — чистая функция, БЕЗ DB / auth / HTTP. Внутри вызывает `calculate_max_distance`, `claude_analyze`, `WeightedScorer`, `detect_psychotype` (вся логика из `analyze_case` переезжает сюда).
|
||||
- `analyze.py::analyze_case` становится тонкой обёрткой: собрать `SearchInput` из payload + `db.get_case` → `build_search_model` → записать `analysis_log` → вернуть. Вся SAR-математика — в `search_engine.py`.
|
||||
|
||||
**Границы (НЕ делать в B14):**
|
||||
- НЕ менять коэффициенты (`distance_service`, `scoring_service`) — это B1.
|
||||
- НЕ менять схему БД / миграции.
|
||||
- НЕ добавлять Field Data / итеративность / PostGIS — это B15–B18.
|
||||
- НЕ менять внешний контракт ответа `/analyze` (фронт B5 от него зависит) — состав полей тот же.
|
||||
|
||||
**Критерий приёмки:**
|
||||
- `analyze.py` не содержит расчётной логики (только сборка `SearchInput` + запись БД + возврат).
|
||||
- Поведение `/analyze` идентично: bike 8yo 2h лес день → max_distance 5.4; РАС+bike → профили [РАС, велосипед]; psychotype-answers → detect. Регресс-кейсы из B5 проходят.
|
||||
- `PYTHONPATH=/app python -m pytest backend/tests -q` — зелёный; добавлены юнит-тесты на `build_search_model` (моки на `claude_analyze`).
|
||||
|
||||
---
|
||||
|
||||
## B15 — Четыре слоя данных: схема + миграция
|
||||
**Тип:** schema / migration, needs-context. Исключено из делегирования: миграции БД.
|
||||
|
||||
**Что:** Ввести слоистую модель данных (B13-принцип 2) через Alembic-миграцию:
|
||||
- **Слой 2 (поиск):** `cases` — уже есть; оставить как карточку поиска (исходная точка, время, категория, параметры человека), вынеся поля других слоёв.
|
||||
- **Слой 4 (результат):** `analysis_log` → явная таблица `search_models` (case_id, version, input_snapshot, model_json, created_at) с **версионированием** (несколько версий на случай — фундамент для B18).
|
||||
- **Слой 3 (оперативные):** НОВЫЕ таблицы `field_observations` (position/observation/track/clue/witness), `search_teams`, `areas_checked`, `found_events` — пока схема + пустые + модели; ингестия в B17.
|
||||
- **Слой 1 (исходные):** версионированный справочник `reference_priors` (source, category, value, units, provenance) — заглушка под B12 (ISRID) и экспертные значения; данные вносятся позже, сейчас структура.
|
||||
- Бэкфилл существующих `cases`/`analysis_log` в новую схему без потери данных.
|
||||
- API `/analyze` и `/cases` продолжают работать (адаптер поверх новой схемы).
|
||||
|
||||
**Границы:** НЕ заполнять `reference_priors` (B12 заблокирован). НЕ реализовывать ингестию полевых данных (B17). Коэффициенты не трогать.
|
||||
|
||||
**Критерий приёмки:**
|
||||
- `alembic upgrade head` проходит чисто на пустой и на текущей БД; даун-миграция работает.
|
||||
- Существующие кейсы и `analysis_log` доступны после миграции (бэкфилл проверен на тестовом наборе).
|
||||
- `/analyze` и `/cases` отвечают тем же контрактом (фронт B5 не сломался).
|
||||
- `pytest backend/tests` — зелёный.
|
||||
|
||||
---
|
||||
|
||||
## B16 — GIS: PostGIS + локальный OSM (замена живого Overpass)
|
||||
**Тип:** infra / architecture, needs-context. Крупная инфра-задача.
|
||||
|
||||
**Мотив:** `services/geo_service.py` дёргает живой Overpass API (8 направлений × 4 дистанции = 32 запроса на анализ) — медленно и ненадёжно: при недоступности Overpass зоны получают одинаковые нейтральные оценки (см. тест B5 — все зоны с одинаковым скором). Локальный OSM в PostGIS даёт быстрые пространственные запросы, рельеф (DEM), гидрографию — фундамент для качественной вероятностной поверхности.
|
||||
|
||||
**Что:**
|
||||
- Подключить PostGIS к `vector-postgres` (расширение `postgis`, docker-compose).
|
||||
- Импорт OSM-экстракта региона (Беларусь / округа) через `osm2pgsql` в таблицы PostGIS (roads, water, forest/wood, buildings, landuse).
|
||||
- Переписать `geo_service.build_search_zones` на PostGIS-запросы (`ST_DWithin`, `ST_Intersects`, длина дорог в буфере, расстояние до ближайших water/settlement/forest) вместо Overpass.
|
||||
- Опционально DEM / рельеф (уклон, проходимость) — можно вынести в B16b.
|
||||
- Сохранить контракт `Zone` (forest_pct, road_density, water_distance_km, settlement_distance_km), чтобы `scoring_service` не менялся.
|
||||
|
||||
**Границы:** Коэффициенты скоринга не трогать. DEM — опционально. ISRID — отдельно (B12).
|
||||
|
||||
**Критерий приёмки:**
|
||||
- `vector-postgres` имеет PostGIS; OSM-данные загружены.
|
||||
- `build_search_zones(53.9, 27.56, case, 1.08)` отдаёт зоны с РЕАЛЬНЫМИ характеристиками (road_density/water/forest различаются между направлениями) без обращений во внешний интернет.
|
||||
- Время анализа < 1с (без Overpass-латентности и без Claude fallback).
|
||||
- `test_geo_service` адаптированы и зелёные.
|
||||
|
||||
---
|
||||
|
||||
## B17 — Field Data: модель + ингестия операционных данных
|
||||
**Тип:** new subsystem, needs-context. Зависит от B15 (оперативные таблицы).
|
||||
|
||||
**Что:** Реализовать слой 3 (B13-принцип 2) — приём и хранение операционных данных во время поиска:
|
||||
- Модели/таблицы: `field_observations` (тип: position/observation/track/clue/witness, geom, timestamp, team_id, confidence, raw), `search_teams` (id, name, members, role), `areas_checked` (geom-полигон, team_id, checked_at, result), `found_events`.
|
||||
- API приёма: `POST /api/v1/cases/{id}/observations`, `…/teams`, `…/areas_checked`; `GET` для списка/карты. Auth: operator/field/admin.
|
||||
- Валидация (тип наблюдения, геом в разумных пределах, таймстемп).
|
||||
- События новых наблюдений — источник для B18 (перерасчёт).
|
||||
|
||||
**Границы:** НЕ реализовывать сам пересчёт (B18). НЕ подключать ATAK/Meshtastic (B19) — только API-ингестия. Коэффициенты не трогать.
|
||||
|
||||
**Критерий приёмки:**
|
||||
- Создание/чтение наблюдений/групп/проверенных участков через API работает (тесты).
|
||||
- Геометрии в PostGIS (если B16 готов) или в JSONB-заглушке (оговорить, если B16 ещё нет).
|
||||
- Событие нового наблюдения попадает в очередь/лог для B18.
|
||||
|
||||
---
|
||||
|
||||
## B18 — Итеративный пересчёт модели + очередь задач
|
||||
**Тип:** architecture / core value, needs-context. Зависит от B14 (движок), B15 (версионирование), B17 (источник событий). Самая ценная фаза (B13-принцип 3).
|
||||
|
||||
**Что:**
|
||||
- Job-queue (arq / Celery / RQ — выбрать) для тяжёлых расчётов: probability, routing, recalculation. Сейчас `analyze_case` синхронный — не масштабируется на итерации.
|
||||
- Event-driven пересчёт: поступление новых полевых данных (B17) → задача «пересчитать модель для case_id» → `build_search_model` с учётом оперативных данных (исключённые территории из `areas_checked`, уточнения из `observations`/`clues`) → новая версия `search_models` (B15).
|
||||
- Версионирование: история моделей на случай; UI/ATAK показывают актуальную.
|
||||
- Учёт «найдено/не найдено» — подтверждение/опровержение наблюдений корректирует апостериорную поверхность.
|
||||
- Работает на экспертных коэффициентах; ISRID (B12) подключается как источник априорных, когда разблокируется.
|
||||
|
||||
**Границы:** Коэффициенты — B1 (ревью). ATAK/Mesh — B19. Без ISRID-данных пока (экспертные априоры).
|
||||
|
||||
**Критерий приёмки:**
|
||||
- Поступление observation/area_checked ставит задачу пересчёта; новая версия модели сохраняется.
|
||||
- Тяжёлый расчёт не блокирует HTTP-запрос (async через очередь).
|
||||
- История версий модели доступна; можно откатиться/сравнить.
|
||||
- Демонстрация: кейс → отметка «сектор N проверен, никого нет» → пересчёт снижает приоритет N, поднимает соседние.
|
||||
|
||||
---
|
||||
|
||||
## B19 — «Контур» (ATAK + Meshtastic, реал-тайм) — отдельный проект, плейсхолдер
|
||||
**Тип:** отдельный проект, пока не детализируется. Зависит от B17 (Field Data) и B18 (перерасчёт).
|
||||
|
||||
**Состав:** интеграция позиций/событий полевых групп в реал-тайм → Field Data (B17) → триггерит пересчёт (B18). Протоколы: ATAK — CoT (Cursor on Target); Meshtastic — LoRa-mesh. Оформлять как самостоятельный workstream после того, как ядро (B14), слои данных (B15) и Field Data (B17) устоялись.
|
||||
|
||||
---
|
||||
|
||||
@@ -752,5 +888,7 @@ B13 Структурирование проекта
|
||||
| Atomic (backend) | A1–A9 | локальной LLM |
|
||||
| Atomic (frontend) | A10–A16 | локальной LLM |
|
||||
| Needs-context | B1–B12 | сильной модели / человеку |
|
||||
| Архитектура / рефакторинг | B13 (каркас), B14 (SearchEngine), B15 (слои данных), B16 (GIS/PostGIS), B17 (Field Data), B18 (итеративность + queue) | сильной модели / человеку |
|
||||
| Отдельный проект | B19 «Контур» (ATAK/Meshtastic) | позже, плейсхолдер |
|
||||
|
||||
**Рекомендуемый порядок для локальной модели:** A8 и A7 первыми (чистка мёртвого кода и зелёный CI дают чистую базу для проверки остальных), затем backend A1–A6, затем docs A9, затем frontend A10–A16. После каждой backend-задачи прогонять `PYTHONPATH=/root/vector python -m pytest backend/tests -q`.
|
||||
**Рекомендуемый порядок:** сначала B14 (чистый движок, поведение-сохраняющий — фундамент), затем B15 (слои данных), затем B16 (GIS) и B17 (Field Data) можно параллельно, затем B18 (итеративность + queue). B12 (ISRID) разблокируется внешне (правовой статус) и подключается как источник априорных к B18. B19 «Контур» — отдельным проектом после B17/B18. Коэффициенты (B1) — под ревью человека на каждом шаге.
|
||||
|
||||
Reference in New Issue
Block a user