README.md + SETUP_GUIDE.md — документация по образцу РВС
README: назначение/контекст, политика закрытого контура, архитектура, стек, структура репо, БД (21 таблица), матмодель (контрольные точки), OSM-геослой, API (12 роутеров), фронт, RBAC (142 юнита, 4 роли/9 прав), мультипоиск, интеграция КОНТУР, аудит, планы. SETUP_GUIDE: 18 разделов — требования, Docker, .env (смена секретов), миграции/сиды, импорт OSM в PostGIS, проверки, пользователи, КОНТУР, прокси/HTTPS, обновление (up -d для env!), бэкапы, диагностика (11 типовых проблем), чек-лист развёртывания.
This commit is contained in:
@@ -0,0 +1,387 @@
|
||||
# ВЕКТОР МЧС — Система определения приоритетных направлений поиска
|
||||
|
||||
**Программное средство поддержки принятия решений при поисково-спасательных работах (ПСР) на открытой местности МЧС Республики Беларусь.**
|
||||
|
||||
ВЕКТОР рассчитывает приоритетные направления поиска пропавшего человека по матмодели: на основании данных о потерявшемся (возраст, диагнозы, физподготовка, транспорт), обстоятельствах потери (время, причина, направление), среде (рельеф, погода, сезон) и точке последней пропажи (ТНП) система строит концентрическую зону вероятного нахождения и подсвечивает приоритетные направления обследования с учётом рельефа из OSM-данных.
|
||||
|
||||
> **Версия документа:** соответствует состоянию репозитория на 9 сентября 2026 г.
|
||||
> **Репозиторий:** [`Sadmin/vector`](http://192.168.0.106:3000/Sadmin/vector)
|
||||
> **Развёртывание:** см. [SETUP_GUIDE.md](SETUP_GUIDE.md) — пошаговый гайд по развёртыванию на серверах МЧС.
|
||||
|
||||
---
|
||||
|
||||
## Оглавление
|
||||
|
||||
1. [Назначение и контекст](#1-назначение-и-контекст)
|
||||
2. [Ключевая политика: полностью закрытый контур](#2-ключевая-политика-полностью-закрытый-контур)
|
||||
3. [Архитектура](#3-архитектура)
|
||||
4. [Стек технологий](#4-стек-технологий)
|
||||
5. [Структура репозитория](#5-структура-репозитория)
|
||||
6. [База данных](#6-база-данных)
|
||||
7. [Математическая модель расчёта](#7-математическая-модель-расчёта)
|
||||
8. [OSM-геослой (PostGIS)](#7-osm-геослой-postgis)
|
||||
9. [Бэкенд (FastAPI) — структура и API](#8-бэкенд-fastapi--структура-и-api)
|
||||
10. [Фронтенд (React)](#9-фронтенд-react)
|
||||
11. [Аутентификация, роли и подразделения (RBAC)](#10-аутентификация-роли-и-подразделения-rbac)
|
||||
12. [Мультипоиск и операции](#11-мультипоиск-и-операции)
|
||||
13. [Интеграция с КОНТУР (отправка зон)](#12-интеграция-с-контуром-отправка-зон)
|
||||
14. [Аудит](#13-аудит)
|
||||
15. [Тестирование](#14-тестирование)
|
||||
16. [Справочники](#14-справочники)
|
||||
17. [Что готово и что в планах](#15-что-готово-и-что-в-планах)
|
||||
18. [Контакты и сопровождение](#16-контакты-и-сопровождение)
|
||||
|
||||
---
|
||||
|
||||
## 1. Назначение и контекст
|
||||
|
||||
### Что делает ВЕКТОР
|
||||
|
||||
ВЕКТОР — рабочий инструмент РЦУ (расчётно-центрального управления) МЧС Республики Беларусь при организации поиска пропавших людей:
|
||||
|
||||
- **Карточка поиска** — структурированный ввод данных: субъект (возраст, пол, диагнозы — РАС, эпилепсия, СДВГ, ЗПР, психотип), обстоятельства (причина потери, время, направление движения, надёжность свидетельства), среда (сезон, погода, температура, рельеф), ресурсы (группы, кинолог, транспорт)
|
||||
- **Матрасчёт** — детерминированный расчёт: максимальный радиус по методике ПСР (КМЧ × коэффициенты), приоритетные направления (сектора 45° с весами), прогноз поведения по психотипу, срочность и критические действия
|
||||
- **Карта зон** — Leaflet: концентрические круги возможной зоны (0.5R / 0.75R / R) + подсветка приоритетных направлений; слои воды/болот полигонами и ж/д линий из локальной OSM
|
||||
- **Рекомендации** — тактические рекомендации по профилям случая (проверить водоёмы, обследовать вдоль дорог и т.д.)
|
||||
- **Мультипоиск** — несколько одновременных поисков, каждое ОУМЧС/Г(Р)ОЧС работает со своими операциями
|
||||
- **Интеграция с КОНТУР** — отправка зон в полевую систему координации (ATAK + Meshtastic)
|
||||
- **Архив завершённых поисков** — факт vs прогноз (дистанция, направление, место находки) для калибровки зонального скоринга
|
||||
- **Администрирование** — пользователи по иерархии МЧС, журнал аудита, статистика
|
||||
|
||||
### Методическая основа
|
||||
|
||||
Расчёт радиуса основан на статистических таблицах ПСР (поиск и спасение, экстремум-методика): базовая скорость смещения по среднему лесу (НормС) умножается на коэффициенты возраста, диагноза, рельефа, погоды, времени суток, транспорта. Скоринг зон — взвешенная сумма факторов рельефа (лес, вода, дороги, НП) по секторам вокруг ТНП.
|
||||
|
||||
### Домен
|
||||
|
||||
МЧС осуществляет поиски **только в природных экосистемах** — не в городах. Город учтён в коэффициентах рельефа, но приоритетные зоны строятся для природной среды.
|
||||
|
||||
---
|
||||
|
||||
## 2. Ключевая политика: полностью закрытый контур
|
||||
|
||||
**Все данные о поисках (включая ПДн детей) не покидают контур организации.**
|
||||
|
||||
- **ИИ/LLM удалён из проекта полностью** (решение руководства): анализ детерминированный, `backend/services/claude_service.py` и любые облачные API исключены. В `docker-compose` и `.env` НЕТ никаких API-ключей внешних сервисов
|
||||
- **Расчёт локальный**: вся математика в `services/*.py` (Python), выполняется на сервере за миллисекунды
|
||||
- **Карты — из локальной OSM**: дамп Geofabrik (беларусь-latest.osm.pbf, ~333 МБ) импортирован в PostGIS внутри организации; бэкенд не ходит в Overpass/интернет (fallback на Overpass остаётся только на случай пустых OSM-таблиц)
|
||||
- **Фронтенд** тянет OSM-тайлы и иконки Leaflet с CDN — для полностью offline-контура требуется локальный tile-сервер (в планах)
|
||||
|
||||
Тест-страж: `backend/tests/test_rules_analysis.py::TestNoLLM` — падает, если в код возвращается внешний ИИ.
|
||||
|
||||
---
|
||||
|
||||
## 3. Архитектура
|
||||
|
||||
```
|
||||
┌───────────────────────────────────────────────────┐
|
||||
│ Браузер пользователя │
|
||||
│ (Chrome / Firefox / Edge — любая ОС) │
|
||||
└──────────────────────┬────────────────────────────┘
|
||||
│ HTTP
|
||||
┌──────────────────────▼────────────────────────────┐
|
||||
│ vector-frontend (React 18, CRA, порт 3000) │
|
||||
│ Форма карточки · карта Leaflet · дашборд · админка│
|
||||
└──────────────────────┬────────────────────────────┘
|
||||
│ REST JSON :8000
|
||||
┌──────────────────────▼────────────────────────────┐
|
||||
│ vector-backend (FastAPI, порт 8000) │
|
||||
│ ┌──────────────────────────────────────────────┐ │
|
||||
│ │ Роутеры: auth, cases, analyze, operations, │ │
|
||||
│ │ admin, admin_users, closed_cases, contour, │ │
|
||||
│ │ water, geocode, stats, health │ │
|
||||
│ └──────────────────────────────────────────────┘ │
|
||||
│ ┌──────────────────────────────────────────────┐ │
|
||||
│ │ Services (математика, без БД/HTTP): │ │
|
||||
│ │ search_engine (модель), distance_service │ │
|
||||
│ │ (радиус), scoring_service (сектора), │ │
|
||||
│ │ rules_analysis (правила), psychotype, │ │
|
||||
│ │ geo_service → osm_local (PostGIS) │ │
|
||||
│ └──────────────────────────────────────────────┘ │
|
||||
└──────────────────────┬────────────────────────────┘
|
||||
│ SQLAlchemy / psycopg2
|
||||
┌──────────────────────▼────────────────────────────┐
|
||||
│ vector-postgres (PostgreSQL 16 + PostGIS 3.6) │
|
||||
│ БД vector_mchs: кейсы, операции, юниты, аудит, │
|
||||
│ OSM (planet_osm_*: 1 млн дорог, 192 тыс. лесов) │
|
||||
└───────────────────────────────────────────────────┘
|
||||
│ (опционально, outbound)
|
||||
┌──────────────────────▼────────────────────────────┐
|
||||
│ КОНТУР (CT130, полевая координация ATAK) │
|
||||
│ POST /api/v1/vector/zones — приоритетные зоны │
|
||||
└───────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### Принципы архитектуры
|
||||
|
||||
- **Чистая математика**: `services/*.py` не знают ни о БД, ни об HTTP — только входные словари на выходе модели. Тонкие роутеры-обёртки в `backend/routers/`
|
||||
- **Контракт /analyze**: `zone.forest_pct` — доля 0..1 (не проценты!), дистанции — км (в PostGIS SRID 3857 раздувание мерка: real = mercator × cos(lat))
|
||||
- **Анализ воспроизводим**: тот же вход — тот же выход; прогон модели сохраняется в `analysis_log` кейса и сравнивается с фактом в архиве
|
||||
|
||||
---
|
||||
|
||||
## 4. Стек технологий
|
||||
|
||||
| Слой | Технология | Версия | Назначение |
|
||||
|------|-----------|--------|-----------|
|
||||
| Бэкенд | FastAPI | 0.115 | REST API |
|
||||
| ORM | SQLAlchemy 2.0 + psycopg2 | | БД + миграции Alembic 1.14 |
|
||||
| БД | PostgreSQL 16 + PostGIS 3.6 | | Данные + гео (PostGIS) |
|
||||
| OSM | osm2pgsql 2.1 | | Импорт дамп OSM → planet_osm_* |
|
||||
| Auth | python-jose + passlib | | JWT + bcrypt, server-side сессии |
|
||||
| Фронт | React 18 (CRA) + react-leaflet | | SPA |
|
||||
| Карта | Leaflet 1.9 + OSM-тайлы | | Отображение зон |
|
||||
| Контейнеры | Docker Compose | | 4 сервиса |
|
||||
|
||||
Полный список зависимостей — `backend/requirements.txt` и `frontend/package.json`.
|
||||
|
||||
---
|
||||
|
||||
## 5. Структура репозитория
|
||||
|
||||
```
|
||||
vector/
|
||||
├── backend/ # FastAPI-приложение
|
||||
│ ├── main.py # Сборка приложения (12 роутеров)
|
||||
│ ├── models.py # 21 таблица (SQLAlchemy)
|
||||
│ ├── schemas.py # Pydantic-схемы
|
||||
│ ├── database.py # Репозиторий кейсов + статистика
|
||||
│ ├── audit.py # Журнал аудита + гео-скоуп
|
||||
│ ├── rbac.py # Роли/права/политика безопасности
|
||||
│ ├── alembic/ # Миграции (006…009)
|
||||
│ ├── seed_users.py # Сид первых пользователей
|
||||
│ ├── seed_units.py # Сид подразделений (РЦУ РЧС → ОУМЧС → Г(Р)ОЧС, 142 юнита)
|
||||
│ ├── routers/ # 12 модулей API (см. раздел 8)
|
||||
│ ├── services/ # Адаптеры расчёта
|
||||
│ └── tests/ # 231 тест (pytest)
|
||||
├── services/ # Математика (чистые функции)
|
||||
│ ├── search_engine.py # SearchInput/SearchModel — ядро расчёта
|
||||
│ ├── distance_service.py # Максимальный радиус (КМЧ × коэффициенты)
|
||||
│ ├── scoring_service.py # Взвешенный скоринг секторов
|
||||
│ ├── rules_analysis.py # Правила: срочность, действия, поведение
|
||||
│ ├── psychotype_service.py # Психотипирование (опрос)
|
||||
│ ├── geo_service.py # Геоданные секторов (лес/вода/дороги/НП)
|
||||
│ ├── osm_local.py # Локальный PostGIS-провайдер OSM
|
||||
│ └── recommendation_service.py
|
||||
├── frontend/ # React SPA
|
||||
│ └── src/
|
||||
│ ├── App.js # Роутинг (/dashboard, /desktop, /users, /admin)
|
||||
│ ├── constants.js # Единые справочники (место находки, кто нашёл, румбы)
|
||||
│ ├── api/client.js # apiFetch/apiJson — Bearer + 401-перехват
|
||||
│ ├── components/ # CaseForm (5 шагов), SearchMap, ProtectedRoute
|
||||
│ └── pages/ # Dashboard, DesktopSARPage, analysis/, AdminDashboard,
|
||||
│ # UsersAdmin, ClosedCases, Login
|
||||
├── scripts/ # Развёртывание и живые проверки
|
||||
│ ├── b16-import.sh # Импорт OSM-дампа в PostGIS
|
||||
│ ├── e2e-*.sh # e2e-сценарии
|
||||
│ ├── eN-live-check.sh # Живые проверки этапов E1–E4
|
||||
│ └── prod-stamp-backfill.sql
|
||||
├── docker-compose.yml # 4 сервиса: postgres, adminer, backend, frontend
|
||||
├── .env.example # Шаблон окружения (без внешних ключей)
|
||||
├── SETUP_GUIDE.md # Развёртывание на серверах МЧС
|
||||
├── vector_tasks.md # Живой план работ (B1…B21+)
|
||||
└── README.md # Этот документ
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 6. База данных
|
||||
|
||||
**PostgreSQL 16 + PostGIS 3.6**, БД `vector_mchs`. Схема управления — Alembic (`backend/alembic/versions/`), актуальная ревизия **009_e3_operations**.
|
||||
|
||||
### Основные таблицы
|
||||
|
||||
| Таблица | Назначение |
|
||||
|---------|-----------|
|
||||
| `cases` | Карточки поисков: субъект, обстоятельства, среда, ТНП, исход |
|
||||
| `analysis_log` | JSONB-лог прогонов анализа (аудит расчётов) |
|
||||
| `search_models` | Слой 4: сохранённые матмодели по кейсам (GeoJSON-зоны) |
|
||||
| `search_teams`, `field_observations`, `areas_checked`, `found_events` | Оперативные слои (состав групп, наблюдения, проверенные квадраты, находки) |
|
||||
| `reference_priors` | Слой 1: справочные приоритеты |
|
||||
| `users`, `mchs_units` | Пользователи; иерархия РЦУ РЧС → 6 ОУМЧС → 135 Г(Р)ОЧС |
|
||||
| `roles`, `permissions`, `role_permissions`, `user_roles` | RBAC: 4 роли, 9 прав, матрица связей |
|
||||
| `sessions`, `auth_events` | Server-side сессии (sha256-токены), журнал входов |
|
||||
| `security_settings` | Политика безопасности (10 параметров) |
|
||||
| `search_operations` | Поисковые операции (статусная машина, привязка к кейсу и КОНТУРу) |
|
||||
| `audit_events`, `audit_changes` | Неизменяемый журнал аудита, field-level изменения (ретенция 90 дней) |
|
||||
| `planet_osm_*` | Импорт OSM Беларуси (osm2pgsql, SRID 4326/3857): дороги, леса, вода, НП |
|
||||
|
||||
### Политика безопасности (`security_settings`, меняется в админке)
|
||||
|
||||
| Параметр | Значение |
|
||||
|----------|----------|
|
||||
| Минимальная длина пароля | 8 |
|
||||
| Сложность пароля | требуются буквы+цифры |
|
||||
| Срок действия пароля | 90 дней |
|
||||
| История паролей | 5 (нельзя переиспользовать) |
|
||||
| Блокировка после неудачных входов | 5 (на 15 минут) |
|
||||
| Тайм-аут сессии / неактивности | 24 ч / 60 мин |
|
||||
| Макс. параллельных сессий | 3 (старые отзываются) |
|
||||
| Ретенция журнала аудита | 90 дней |
|
||||
|
||||
---
|
||||
|
||||
## 7. Математическая модель расчёта
|
||||
|
||||
Ядро — `services/search_engine.py`: `SearchInput` → `SearchModel` (чистая функция, без БД/HTTP).
|
||||
|
||||
### Состав расчёта
|
||||
|
||||
1. **Максимальный радиус** (`distance_service.py`): НормС (скорость смещения по среднему лесу, км/ч) × коэффициенты возраста / диагноза / рельефа / погоды / времени суток / транспорта, с учётом усталости. Контрольные точки: подросток 14 л, 3 ч, лес = 5.1 км; велосипедист 8 л, 2 ч = 10.8 км
|
||||
2. **Коэффициенты рельефа** (`terrain_map`): лес/поле/луг/город/неизвестно = 1.0; густой лес = 0.5; болото = 0.4; горы/овраги = 0.6; дорога/тропа = 0.8
|
||||
3. **Сектора направлений** (`scoring_service.py`): 8 секторов по 45° вокруг ТНП; каждый сектор оценивается по составу рельефа из локальной OSM (лес — доля 0..1, вода/НП — расстояние в км), приоритетные подсвечиваются на карте
|
||||
4. **Психотип** (`psychotype_service.py`): опрос из формы → доминантный / гармоничный / тревожный / интроверт → модификаторы поведения и рекомендаций
|
||||
5. **Правила** (`rules_analysis.py`): срочность (critical/high/elevated/normal), критические действия, прогноз поведения по профилям (не_умеет_плавать ×3.0 к водоёмам и т.п.), тактические рекомендации («проверить водоёмы», не «перекрыть»)
|
||||
6. **Профили, не покрытые моделью** (ДЦП, слабое зрение/слух) — честно помечаются `unmodeled_profiles`, не искажают расчёт
|
||||
|
||||
**Коэффициенты меняются только по явному решению руководства** — молча таблицы не трогать.
|
||||
|
||||
---
|
||||
|
||||
## 7. OSM-геослой (PostGIS)
|
||||
|
||||
- Импорт: дамп [Geofabrik](https://download.geofabrik.de/europe/belarus-latest.osm.pbf) (~333 МБ) → `scripts/b16-import.sh` (osm2pgsql --slim, ~4,5 мин, RAM 2 ГБ)
|
||||
- Содержимое: 1 010 507 дорог, 192 374 леса, 81 772 воды, 2 731 НП
|
||||
- Провайдер `services/osm_local.py` читает `planet_osm_*`; `geo_service.py` переключается на Overpass только если таблицы пусты
|
||||
- Полный `/analyze` на локальных данных: ~10 мс (см. `scripts/e2e-b16-timing.sh`)
|
||||
- Обновление дампа — по решению (раз в квартал / заморозить)
|
||||
|
||||
---
|
||||
|
||||
## 8. Бэкенд (FastAPI) — структура и API
|
||||
|
||||
`backend/main.py` собирает 12 роутеров. Авторизация — Bearer JWT (form-urlencoded логин, OAuth2PasswordRequestForm).
|
||||
|
||||
| Префикс | Модуль | Назначение |
|
||||
|---------|--------|-----------|
|
||||
| `/api/v1/health` | health.py | Liveness |
|
||||
| `/api/v1/auth` | auth.py | Логин/логаут/me/смена пароля, блокировки |
|
||||
| `/api/v1/cases` | cases.py | CRUD карточек поисков |
|
||||
| `/api/v1/analyze` | analyze.py | Матрасчёт зон (по payload или case_id) |
|
||||
| `/api/v1/operations` | operations.py | Операции мультипоиска (CRUD, статусная машина, /summary), завершение поиска |
|
||||
| `/api/v1/operations/{id}/send-to-contour` | contour.py | Отправка зон в КОНТУР; GET areas-checked (прокси) |
|
||||
| `/api/v1/admin` | admin.py | Список/редактирование кейсов, дашборд-метрики |
|
||||
| `/api/v1/admin/users` | admin_users.py | Пользователи (создание/роли/юниты/блокировка/сброс пароля) + журнал аудита |
|
||||
| `/api/v1/closed-cases` | closed_cases.py | Архив завершённых поисков (ручной ввод + прогон модели) |
|
||||
| `/api/v1/water/{case_id}` | water.py | Вода/болота (полигоны), ж/д (линии) вокруг ТНП |
|
||||
| `/api/v1/geocode` | geocode.py | Прокси Nominatim (формат «пункт, район, адрес») |
|
||||
| `/api/v1/stats` | stats.py | Тепловая карта, агрегаты |
|
||||
|
||||
Swagger: `http://<сервер>:8000/docs`.
|
||||
|
||||
**Синхронизация закрытия**: кейс закрывается через ЛЮБОЙ из путей (`PATCH /admin/cases` или `POST /operations/{id}/complete`) — активная операция кейса автоматически завершается (`completed` + `closed_at`).
|
||||
|
||||
---
|
||||
|
||||
## 9. Фронтенд (React)
|
||||
|
||||
SPA на react-scripts (CRA). Роутинг:
|
||||
|
||||
| Путь | Страница |
|
||||
|------|----------|
|
||||
| `/dashboard` | Главная: «Активные поиски» (счётчики, карточки операций, «+ Новый поиск», «Пользователи») |
|
||||
| `/desktop` | Рабочее пространство: форма карточки (5 шагов) + карта + результат анализа |
|
||||
| `/analysis/:case_id` | Результат анализа: карта зон, КОНТУР-панель, «Завершить поиск» |
|
||||
| `/users` | Админка пользователей + вкладка «Аудит» |
|
||||
| `/admin` | Администрирование: Кейсы / Операции / Завершённые поиски |
|
||||
|
||||
Компоненты:
|
||||
- **CaseForm** — 5 шагов: субъект → обстоятельства → среда → координаты (ТНП + геокодирование) → ресурсы; после сохранения автоматически создаётся поисковая операция
|
||||
- **SearchMap** — концентрические круги (0.5R/0.75R/R) + подсветка приоритетных направлений 45°-секторами (палитра ЦОУ: #ff4d00 / #ff9f1a / #ffd166)
|
||||
- **Dashboard / UsersAdmin / AdminDashboard** — VCL-density, тёмная тема (#0d1117 / #161b22 / #30363d / #e6edf3)
|
||||
|
||||
Единые справочники исхода — `frontend/src/constants.js` (тип места находки, кто нашёл, 8 румбов) — используются во всех точках ввода исхода.
|
||||
|
||||
---
|
||||
|
||||
## 10. Аутентификация, роли и подразделения (RBAC)
|
||||
|
||||
### Иерархия подразделений
|
||||
|
||||
РЦУ РЧС (республиканский) → 6 областных ОУМЧС → 135 Г(Р)ОЧС/ПАСО. Справочник — идемпотентный сид `backend/seed_units.py` (источник: справочник подразделений РВС).
|
||||
|
||||
### Роли
|
||||
|
||||
| Роль | Права | Скоуп видимости |
|
||||
|------|-------|----------------|
|
||||
| **admin** (РЦУ РЧС) | Все 9 прав | Все операции и пользователи республики |
|
||||
| **coordinator** (ОУМЧС) | view/create/update/export/manage_users/view_audit | Своё ОУМЧС + подчинённые Г(Р)ОЧС |
|
||||
| **operator** (Г(Р)ОЧС) | view/create/update | Свои поиски |
|
||||
| **observer** | view | Только просмотр |
|
||||
|
||||
- Управление пользователями (`manage_users`): РЦУ РЧС — все; ОУМЧС — только своё поддерево (кросс-областные операции отбиваются 403 на бэкенде)
|
||||
- Созданный пользователь обязан сменить пароль при первом входе (`must_change_password`)
|
||||
- Сессии server-side: JWT несёт идентификатор, в БД — sha256-хэш; сброс пароля отзывает все сессии
|
||||
|
||||
---
|
||||
|
||||
## 11. Мультипоиск и операции
|
||||
|
||||
`search_operations` — надстройка над кейсами для одновременной работы с несколькими поисками:
|
||||
|
||||
- Одна операция на карточку (case_id unique)
|
||||
- **Статусная машина**: planned → active ⇄ paused → completed → archived (недопустимые переходы → 400)
|
||||
- Авто-создание операции при сохранении карточки; дашборд показывает активные
|
||||
- `POST /operations/{id}/complete` — завершение поиска: исход (найден живым/погибшим, дистанция, направление, кто нашёл) → кейс в архив + детерминированный прогон матмодели → сравнение «прогноз vs факт» (accuracy_note)
|
||||
- `GET /operations/summary` — счётчики для дашборда (активные / всего / завершено за 24 ч)
|
||||
|
||||
---
|
||||
|
||||
## 12. Интеграция с КОНТУР (отправка зон)
|
||||
|
||||
КОНТУР — система полевой координации (ATAK + Meshtastic). ВЕКТОР отдаёт приоритетные зоны (outbound):
|
||||
|
||||
1. В операции задаётся `contour_operation_id` (UUID операции в КОНТУРе)
|
||||
2. `POST /api/v1/operations/{id}/send-to-contour` строит `SearchZones[]` (GeoJSON-полигоны секторов ±22.5°, `zone_id = vec:<НАПР>:<дист>m`, probability по приоритету) и отправляет на `{CONTOUR_API_URL}/api/v1/vector/zones?operation_id=…` с `Bearer CONTOUR_TOKEN`
|
||||
3. Каждый шаг аудируется (`contour_send_ok` / `contour_send_failed`); ошибка КОНТУРа → 502
|
||||
4. `GET /api/v1/operations/{id}/areas-checked` — прокси проверенных полевых квадратов (inbound, B17)
|
||||
|
||||
Переменные окружения: `CONTOUR_API_URL` (по умолчанию `http://192.168.0.130:8000`), `CONTOUR_TOKEN`.
|
||||
|
||||
---
|
||||
|
||||
## 13. Аудит
|
||||
|
||||
Неизменяемый журнал (append-only):
|
||||
|
||||
- `audit_events`: кто, что, когда, IP, user-agent, тип события (login/lockout/user_*/operation_*/contour_send_*/case_closed)
|
||||
- `audit_changes`: field-level `старое → новое` по каждому изменённому полю
|
||||
- Ретенция 90 дней (фильтруется при чтении из `security_settings`)
|
||||
- Доступ: право `view_audit` — вкладка «Аудит» в админке `/users` с фильтром по типу и пагинацией
|
||||
|
||||
---
|
||||
|
||||
## 15. Что готово и что в планах
|
||||
|
||||
### Реализовано
|
||||
|
||||
- Форма карточки поиска (5 шагов), справочники, автоподсчёт «прошло времени»
|
||||
- Детерминированный матрасчёт: радиус, сектора, поведение, срочность, рекомендации — без ИИ
|
||||
- Локальный OSM-геослой в PostGIS (Беларусь), /analyze ~10 мс, без внешних вызовов
|
||||
- Карта: концентрические круги + подсветка направлений (дизайн согласованный)
|
||||
- РБАК: иерархия РЦУ РЧС → ОУМЧС → Г(Р)ОЧС (142 юнита), 4 роли / 9 прав, блокировки, сессии
|
||||
- Мультипоиск: операции, статусная машина, дашборд «Активные поиски»
|
||||
- Завершение поиска с внесением исхода, архив завершённых с «прогноз vs факт»
|
||||
- Аудит 90 дней с field-level деталями
|
||||
- Интеграция с КОНТУР: отправка зон (контракт B20)
|
||||
- Журнал аудита пользователей: входы, изменения, отправки
|
||||
- 231 автотест (pytest), 5 skipped
|
||||
|
||||
### В планах
|
||||
|
||||
- **E5 (B17)** — приём полевых данных от КОНТУРа: треки групп, проверенные квадраты (areas-checked) на карте операции
|
||||
- **Живая интеграция с КОНТУР** (CT130) — настройка токена и реальная отправка зон
|
||||
- **Локальный tile-сервер** — для полностью offline-фронта (сейчас тайлы OSM с CDN в браузере)
|
||||
- **Калибровка settlement_score** — вкладка населённых пунктов в скоринге секторов (открытый методический вопрос)
|
||||
- **Калибровка зонального скоринга** по накопленному архиву «прогноз vs факт»
|
||||
|
||||
---
|
||||
|
||||
## 16. Контакты и сопровождение
|
||||
|
||||
- Развёртывание и эксплуатация: см. [SETUP_GUIDE.md](SETUP_GUIDE.md)
|
||||
- План работ и статус этапов: `vector_tasks.md`
|
||||
- API-документация: Swagger `http://<сервер>:8000/docs`
|
||||
- Репозиторий: [`Sadmin/vector`](http://192.168.0.106:3000/Sadmin/vector)
|
||||
|
||||
Смежные системы МЧС: **РВС** («Регистрация входящих сообщений», [`Sadmin/rvs-web`](http://192.168.0.106:3000/Sadmin/rvs-web)), **КОНТУР** (полевая координация).
|
||||
+386
@@ -0,0 +1,386 @@
|
||||
# ВЕКТОР МЧС — Гайд по развёртыванию на серверах МЧС
|
||||
|
||||
**Пошаговое руководство для IT-специалистов МЧС Республики Беларусь по развёртыванию системы определения приоритетных направлений поиска (ВЕКТОР) на серверах организации.**
|
||||
|
||||
> **Версия документа:** 1.0 от 9 сентября 2026 г.
|
||||
> **Репозиторий:** [`Sadmin/vector`](http://192.168.0.106:3000/Sadmin/vector)
|
||||
|
||||
---
|
||||
|
||||
## Оглавление
|
||||
|
||||
1. [Требования к серверу](#1-требования-к-серверу)
|
||||
2. [Архитектура развёртывания](#2-архитектура-развёртывания)
|
||||
3. [Подготовка сервера](#3-подготовка-сервера)
|
||||
4. [Установка Docker и Docker Compose](#4-установка-docker-и-docker-compose)
|
||||
5. [Получение кода проекта](#5-получение-кода-проекта)
|
||||
6. [Конфигурация окружения (.env)](#6-конфигурация-окружения-env)
|
||||
7. [Запуск сервисов](#7-запуск-сервисов)
|
||||
8. [Инициализация базы данных (миграции, сиды)](#8-инициализация-базы-данных-миграции-сиды)
|
||||
9. [Загрузка OSM-геослоя (PostGIS)](#9-загрузка-osm-геослоя-postgis)
|
||||
10. [Проверка работоспособности](#10-проверка-работоспособности)
|
||||
11. [Создание пользователей и справочника подразделений](#11-создание-пользователей-и-справочника-подразделений)
|
||||
12. [Настройка интеграции с КОНТУР](#12-настройка-интеграции-с-контуром)
|
||||
13. [Обратный прокси и HTTPS](#13-обратный-прокси-и-https)
|
||||
14. [Обновление проекта](#14-обновление-проекта)
|
||||
15. [Резервное копирование](#15-резервное-копирование)
|
||||
16. [Мониторинг и логи](#16-мониторинг-и-логи)
|
||||
17. [Диагностика проблем](#17-диагностика-проблем)
|
||||
18. [Чек-лист развёртывания](#18-чек-лист-развёртывания)
|
||||
|
||||
---
|
||||
|
||||
## 1. Требования к серверу
|
||||
|
||||
### Минимальные требования
|
||||
|
||||
| Параметр | Значение |
|
||||
|----------|----------|
|
||||
| ОС | Debian 12/13, Ubuntu 22.04+ (любая с Docker) |
|
||||
| CPU | 2 vCPU |
|
||||
| RAM | 4 ГБ (2 ГБ свободно для импорта OSM — см. раздел 9) |
|
||||
| Диск | 20 ГБ + 1 ГБ под дамп OSM |
|
||||
| Сеть | Доступ браузеров к серверу по HTTP(S); для первичной загрузки дампа OSM — доступ в интернет (одноразово) |
|
||||
|
||||
### Требования безопасности
|
||||
|
||||
- Сервер в закрытом контуре организации; **данные ПДн не должны покидать контур** — не настраивать проксирование на внешние сервисы
|
||||
- Смена всех паролей по умолчанию (см. раздел 6)
|
||||
- Для полностью offline-сценария без интернета: скачать дамп OSM заранее (раздел 9) и учесть, что фронт тянет OSM-тайлы с CDN — для абсолютного offline нужен локальный tile-сервер (в планах)
|
||||
|
||||
---
|
||||
|
||||
## 2. Архитектура развёртывания
|
||||
|
||||
Docker Compose поднимает 4 сервиса:
|
||||
|
||||
| Контейнер | Образ | Порт | Назначение |
|
||||
|-----------|-------|------|-----------|
|
||||
| `vector-postgres` | postgres:16 (+PostGIS 3.6 в контейнере) | 5432 | БД `vector_mchs`, данные + OSM |
|
||||
| `vector-backend` | сборка backend/Dockerfile | 8000 | FastAPI (uvicorn --reload) |
|
||||
| `vector-frontend` | сборка frontend/Dockerfile | 3000 | React SPA (CRA dev-сервер) |
|
||||
| `vector-adminer` | adminer | 8080 | Веб-администрирование БД |
|
||||
|
||||
Код backend/services и frontend смонтирован volume'ами — правки подхватываются без пересборки (dev-режим).
|
||||
|
||||
---
|
||||
|
||||
## 3. Подготовка сервера
|
||||
|
||||
```bash
|
||||
# 1. Обновление системы
|
||||
apt update && apt upgrade -y
|
||||
|
||||
# 2. Базовые утилиты
|
||||
apt install -y curl git ca-certificates gnupg
|
||||
|
||||
# 3. (опционально) NTP-синхронизация — важна для корректных меток времени аудита
|
||||
apt install -y systemd-timesyncd
|
||||
timedatectl set-ntp true
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. Установка Docker и Docker Compose
|
||||
|
||||
```bash
|
||||
# Официальный скрипт (или репозиторий docker-ce — по политике организации)
|
||||
curl -fsSL https://get.docker.com | sh
|
||||
systemctl enable --now docker
|
||||
|
||||
docker --version # 24+
|
||||
docker compose version # v2
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. Получение кода проекта
|
||||
|
||||
```bash
|
||||
mkdir -p /root/vector && cd /root/vector
|
||||
git clone http://<gitea-host>:3000/Sadmin/vector.git .
|
||||
```
|
||||
|
||||
Ключевые ветки: `master` — рабочая.
|
||||
|
||||
---
|
||||
|
||||
## 6. Конфигурация окружения (.env)
|
||||
|
||||
```bash
|
||||
cp .env.example .env
|
||||
```
|
||||
|
||||
Обязательные переменные:
|
||||
|
||||
```ini
|
||||
# Подключение к БД (внутри compose — хост postgres)
|
||||
DATABASE_URL=postgresql://postgres:<СМЕНИТЬ_ПАРОЛЬ>@postgres:5432/vector_mchs
|
||||
|
||||
# Секрет JWT — сгенерировать: openssl rand -hex 32
|
||||
JWT_SECRET=<СЛУЧАЙНАЯ_СТРОКА>
|
||||
|
||||
# CORS — адрес(а) фронтенда
|
||||
CORS_ORIGINS=http://<адрес-сервера>:3000
|
||||
|
||||
# Интеграция с КОНТУР (раздел 12; можно отложить)
|
||||
CONTOUR_API_URL=http://<kontur-host>:8000
|
||||
CONTOUR_TOKEN=<токен из КОНТУРа>
|
||||
```
|
||||
|
||||
> **НЕ добавлять** никаких ключей внешних ИИ/API — по политике закрытого контура их в проекте нет и быть не должно (тест-страж `TestNoLLM`).
|
||||
|
||||
Пароль БД должен совпадать с `POSTGRES_PASSWORD` в `docker-compose.yml` (сервис postgres).
|
||||
|
||||
---
|
||||
|
||||
## 7. Запуск сервисов
|
||||
|
||||
```bash
|
||||
cd /root/vector
|
||||
docker compose up -d
|
||||
docker compose ps # все 4 контейнера Up/healthy
|
||||
```
|
||||
|
||||
Первый старт backend создаёт таблицы через `init_db` (create_all). Порядок применения Alembic-миграций — раздел 8.
|
||||
|
||||
---
|
||||
|
||||
## 8. Инициализация базы данных (миграции, сиды)
|
||||
|
||||
### 8.1 Миграции Alembic
|
||||
|
||||
```bash
|
||||
docker exec vector-backend sh -c 'cd /app/backend && alembic upgrade head'
|
||||
docker exec vector-backend sh -c 'cd /app/backend && alembic current' # 009_e3_operations
|
||||
```
|
||||
|
||||
Миграции идемпотентны на чистой БД. **Если** БД уже была инициализирована через create_all и `alembic upgrade` падает `DuplicateTable` — применить стемп-скрипт:
|
||||
|
||||
```bash
|
||||
docker exec -i vector-postgres psql -U postgres -d vector_mchs < scripts/prod-stamp-backfill.sql
|
||||
```
|
||||
|
||||
### 8.2 Сид первого администратора
|
||||
|
||||
```bash
|
||||
docker exec vector-backend sh -c 'cd /app && python backend/seed_users.py'
|
||||
```
|
||||
|
||||
Создаётся стартовый администратор (логин `admin`, пароль по умолчанию — сменить при первом входе через форму). Скрипт пропускается, если пользователи уже есть.
|
||||
|
||||
### 8.3 Сид подразделений (142 юнита)
|
||||
|
||||
```bash
|
||||
docker exec vector-backend sh -c 'cd /app && python backend/seed_units.py'
|
||||
```
|
||||
|
||||
Создаёт РЦУ РЧС → 6 ОУМЧС → 135 Г(Р)ОЧС/ПАСО (справочник идемпотентный: существующие названия не дублируются). Без него админка пользователей бесполезна (пустые селекты подразделений).
|
||||
|
||||
---
|
||||
|
||||
## 9. Загрузка OSM-геослоя (PostGIS)
|
||||
|
||||
Бэкенд рассчитывает рельеф секторов из локальной OSM. На чистой БД геосервис автоматически fallback'ится на публичный Overpass (медленно, требует интернет) — **для продуктива импортируйте дамп**.
|
||||
|
||||
### 9.1 Установка PostGIS в контейнер БД
|
||||
|
||||
```bash
|
||||
docker exec -u root vector-postgres apt update
|
||||
docker exec -u root vector-postgres apt install -y postgresql-16-postgis-3 osm2pgsql
|
||||
docker exec vector-postgres psql -U postgres -d vector_mchs -c 'CREATE EXTENSION IF NOT EXISTS postgis;'
|
||||
```
|
||||
|
||||
> Установка пакетом в живой контенер переживает перезапуск контейнера (данные в volume), но слетает при ПЕРЕСОЗДАНИИ контейнера — тогда повторить команды.
|
||||
|
||||
### 9.2 Импорт дампа OSM
|
||||
|
||||
```bash
|
||||
# Скачивание (одноразово, ~333 МБ; можно перенести на сервер любым носителем)
|
||||
wget https://download.geofabrik.de/europe/belarus-latest.osm.pbf -O /tmp/belarus-latest.osm.pbf
|
||||
|
||||
# Импорт (~4,5 мин, RAM 2 ГБ, node cache 800)
|
||||
sh scripts/b16-import.sh
|
||||
```
|
||||
|
||||
Скрипт сам: удаляет старые planet_osm_* таблицы, копирует дамп в контейнер, запускает osm2pgsql (--slim, SRID по умолчанию), выводит список таблиц.
|
||||
|
||||
### 9.3 Проверка
|
||||
|
||||
```bash
|
||||
docker exec vector-postgres psql -U postgres -d vector_mchs -t -c "
|
||||
SELECT 'roads', count(*) FROM planet_osm_roads
|
||||
UNION ALL SELECT 'forests', count(*) FROM planet_osm_polygon WHERE landuse='forest';"
|
||||
```
|
||||
|
||||
Ожидается ~1 млн дорог, ~190 тыс. лесов.
|
||||
|
||||
---
|
||||
|
||||
## 10. Проверка работоспособности
|
||||
|
||||
```bash
|
||||
# 1. Health бэкенда
|
||||
curl -s http://localhost:8000/api/v1/health
|
||||
|
||||
# 2. Логин (ТОЛЬКО form-urlencoded!)
|
||||
TOKEN=$(curl -s -X POST http://localhost:8000/api/v1/auth/login \
|
||||
-H 'Content-Type: application/x-www-form-urlencoded' \
|
||||
--data 'username=admin&password=<пароль>' | python3 -c 'import sys,json;print(json.load(sys.stdin)["access_token"])')
|
||||
|
||||
# 3. Профиль (9 прав у admin)
|
||||
curl -s http://localhost:8000/api/v1/auth/me -H "Authorization: Bearer $TOKEN"
|
||||
|
||||
# 4. Фронт
|
||||
curl -s -o /dev/null -w '%{http_code}\n' http://localhost:3000/ # 200
|
||||
|
||||
# 5. Полный расчёт (e2e-скрипты в scripts/e2e-*.sh — см. примеры вызовов)
|
||||
```
|
||||
|
||||
В браузере: `http://<адрес>:3000` → дашборд «Активные поиски».
|
||||
|
||||
---
|
||||
|
||||
## 11. Создание пользователей и справочника подразделений
|
||||
|
||||
Пользователи создаются через UI: **Дашборд → Пользователи → «+ Новый пользователь»** (доступ: роль admin РЦУ РЧС или coordinator ОУМЧС в рамках своего поддерева).
|
||||
|
||||
- При создании задаётся временный пароль — пользователь обязан сменить его при первом входе
|
||||
- Роли: РЦУ РЧС / ОУМЧС / Г(Р)ОЧС / Наблюдатель (описание прав — README.md, раздел RBAC)
|
||||
- Инлайн-операции в таблице: смена роли/подразделения, отключение/включение, сброс пароля (отзывает все сессии)
|
||||
- Все изменения пишутся в журнал аудита (вкладка «Аудит», ретенция 90 дней)
|
||||
|
||||
Иерархию подразделений менять: правкой `backend/seed_units.py` (идемпотентно, kind ∈ rcu/oblast/gor_rayon — ограничение БД `ck_mchs_units_kind`).
|
||||
|
||||
---
|
||||
|
||||
## 12. Настройка интеграции с КОНТУР
|
||||
|
||||
КОНТУР — система полевой координации (ATAK + Meshtastic) на отдельном сервере. ВЕКТОР отправляет в неё приоритетные зоны.
|
||||
|
||||
1. В `.env`: `CONTOUR_API_URL` (адрес API КОНТУРа) и `CONTOUR_TOKEN` (выдаётся на стороне КОНТУРа)
|
||||
2. `docker compose up -d backend` — **пересоздать** контейнер (restart не перечитывает env!)
|
||||
3. Проверка: операция → «Отправить зоны в КОНТУР» на странице анализа; при недоступности КОНТУРа бэкенд вернёт понятную ошибку 502 и запишет `contour_send_failed` в аудит
|
||||
|
||||
Входящие данные (треки групп, проверенные квадраты) — этап B17, в разработке.
|
||||
|
||||
---
|
||||
|
||||
## 13. Обратный прокси и HTTPS
|
||||
|
||||
Для доступа пользователей по HTTPS поставьте nginx/traefik перед фронтендом и API:
|
||||
|
||||
```nginx
|
||||
server {
|
||||
listen 443 ssl;
|
||||
server_name vector.mchs.example;
|
||||
|
||||
ssl_certificate /etc/ssl/certs/vector.crt;
|
||||
ssl_certificate_key /etc/ssl/private/vector.key;
|
||||
|
||||
location / {
|
||||
proxy_pass http://127.0.0.1:3000;
|
||||
proxy_set_header Host $host;
|
||||
}
|
||||
location /api/ {
|
||||
proxy_pass http://127.0.0.1:8000;
|
||||
proxy_set_header Host $host;
|
||||
client_max_body_size 10m;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
В `CORS_ORIGINS` укажите итоговый https-адрес. В закрытом контуре допустима работа по HTTP без прокси (порты 3000/8000 напрямую).
|
||||
|
||||
---
|
||||
|
||||
## 14. Обновление проекта
|
||||
|
||||
```bash
|
||||
cd /root/vector
|
||||
git pull origin master
|
||||
|
||||
# Если менялись миграции:
|
||||
docker exec vector-backend sh -c 'cd /app/backend && alembic upgrade head'
|
||||
|
||||
# Если менялись env-переменные (.env / compose environment) — ПЕРЕСОЗДАТЬ контейнер:
|
||||
docker compose up -d backend # restart НЕ перечитывает env!
|
||||
|
||||
# Обычное обновление кода:
|
||||
docker restart vector-backend vector-frontend
|
||||
```
|
||||
|
||||
Схема обновления, применяемая при разработке: правки коммитятся в Gitea → на сервере `git pull` → `docker restart`. После рестарта frontend пользователи перелогиниваются.
|
||||
|
||||
---
|
||||
|
||||
## 15. Резервное копирование
|
||||
|
||||
```bash
|
||||
# Полный дамп БД (данные + OSM-таблицы)
|
||||
docker exec vector-postgres pg_dump -U postgres -d vector_mchs -F c \
|
||||
-f /tmp/vector_mchs_$(date +%F).dump
|
||||
docker cp vector-postgres:/tmp/vector_mchs_$(date +%F).dump /root/backups/
|
||||
|
||||
# Только прикладные данные (без тяжёлых planet_osm_* — их восстанавливают импортом дампа):
|
||||
docker exec vector-postgres pg_dump -U postgres -d vector_mchs \
|
||||
--exclude-table='planet_osm_*' -F c -f /tmp/vector_app_$(date +%F).dump
|
||||
```
|
||||
|
||||
Рекомендация: ежедневный cron прикладного дампа (он небольшой) + еженедельный полный. Хранить копии вне сервера.
|
||||
|
||||
---
|
||||
|
||||
## 16. Мониторинг и логи
|
||||
|
||||
```bash
|
||||
docker compose logs -f # все сервисы
|
||||
docker compose logs -f backend # API + аудит-сообщения
|
||||
docker compose logs -f frontend # сборка CRA / ошибки компиляции
|
||||
docker stats # потребление контейнеров
|
||||
```
|
||||
|
||||
Ключевые события в логах backend: `admin closed case ... операция(ий) завершены` (синхронизация закрытия), ошибки расчёта (полный traceback uvicorn).
|
||||
|
||||
---
|
||||
|
||||
## 17. Диагностика проблем
|
||||
|
||||
| Симптом | Причина | Решение |
|
||||
|---------|---------|---------|
|
||||
| Логин даёт 422 | JSON вместо form-urlencoded | Логин строго `application/x-www-form-urlencoded` |
|
||||
| «Session expired or revoked» сразу после логина | Несовпадение sha256-токена | Убедиться, что БД и backend на одной БД; пересоздать сессии |
|
||||
| Селекты подразделений пусты | Не выполнен сид юнитов | `python backend/seed_units.py` |
|
||||
| `alembic upgrade` → DuplicateTable | create_all создал таблицы раньше миграций | `scripts/prod-stamp-backfill.sql`, затем upgrade |
|
||||
| Зоны «всегда вверх-вправо» | Расчёт по case_id терял tnp_lat/lon | Исправлено; при доработках сверять имена полей карточки с входом движка |
|
||||
| Расчёт падает TypeError float×None | Payload содержит None-поля | SearchInput.to_case_data() выбрасывает None — регресс-тест есть |
|
||||
| Правка .env не применилась | restart не перечитывает env | `docker compose up -d backend` (пересоздание) |
|
||||
| Импорт OSM OOM | Мало RAM | Параметры --cache 800 --number-processes 2 уже в скрипте; закрыть лишние сервисы |
|
||||
| КОНТУР недоступен при отправке зон | Нет связи/токена | curl до CONTOUR_API_URL; проверить CONTOUR_TOKEN; после правки env — up -d |
|
||||
| Тайлы карты не грузятся | Нет интернета у браузера | Для полного offline — локальный tile-сервер (в планах) |
|
||||
|
||||
---
|
||||
|
||||
## 18. Чек-лист развёртывания
|
||||
|
||||
- [ ] Docker + Compose установлены
|
||||
- [ ] Код получен (`/root/vector`), `.env` создан из `.env.example`
|
||||
- [ ] `JWT_SECRET` заменён на случайный; пароль БД сменён (compose + DATABASE_URL)
|
||||
- [ ] `docker compose up -d` — 4 контейнера Up
|
||||
- [ ] `alembic current` = `009_e3_operations`
|
||||
- [ ] `seed_users.py` выполнен, пароль админа сменён при первом входе
|
||||
- [ ] `seed_units.py` выполнен (142 подразделения в селектах)
|
||||
- [ ] PostGIS установлен в контейнере БД, extension создан
|
||||
- [ ] Дамп OSM импортирован (`b16-import.sh`), таблицы заполнены
|
||||
- [ ] Логин через UI работает, смена пароля обязательна
|
||||
- [ ] Пробный поиск: карточка → анализ → зоны на карте, радиус соответствует контрольным точкам
|
||||
- [ ] Создан тестовый пользователь ОУМЧС — скоуп видимости проверен
|
||||
- [ ] Завершение поиска: исход внесён, кейс в архиве, «прогноз vs факт» отображается
|
||||
- [ ] (опционально) КОНТУР: env-переменные, пересоздание backend, тестовая отправка зон
|
||||
- [ ] (опционально) HTTPS/обратный прокси настроен, CORS обновлён
|
||||
- [ ] Cron резервного копирования настроен, копия выгружена вне сервера
|
||||
- [ ] Внешние ИИ/API-ключи отсутствуют в `.env` и `docker-compose.yml` (политика закрытого контура)
|
||||
|
||||
---
|
||||
|
||||
*Сопровождение: репозиторий [`Sadmin/vector`](http://192.168.0.106:3000/Sadmin/vector), план работ — `vector_tasks.md`, описание системы — [README.md](README.md).*
|
||||
Reference in New Issue
Block a user