Доки B23: README (010, password_history, таблица политики с колонкой «исполнение»), SETUP_GUIDE (cron бэкапа+purge, alembic 010, диагностика 400-пароль), чек-листы
This commit is contained in:
@@ -143,17 +143,19 @@
|
|||||||
vector/
|
vector/
|
||||||
├── backend/ # FastAPI-приложение
|
├── backend/ # FastAPI-приложение
|
||||||
│ ├── main.py # Сборка приложения (12 роутеров)
|
│ ├── main.py # Сборка приложения (12 роутеров)
|
||||||
│ ├── models.py # 21 таблица (SQLAlchemy)
|
│ ├── models.py # 22 таблицы (SQLAlchemy, +password_history)
|
||||||
│ ├── schemas.py # Pydantic-схемы
|
│ ├── schemas.py # Pydantic-схемы
|
||||||
│ ├── database.py # Репозиторий кейсов + статистика
|
│ ├── database.py # Репозиторий кейсов + статистика
|
||||||
│ ├── audit.py # Журнал аудита + гео-скоуп
|
│ ├── audit.py # Журнал аудита + гео-скоуп
|
||||||
|
│ ├── password_policy.py # B23: исполняемая политика паролей
|
||||||
|
│ ├── purge_logs.py # B23: ретенция журналов (DELETE, cron)
|
||||||
│ ├── rbac.py # Роли/права/политика безопасности
|
│ ├── rbac.py # Роли/права/политика безопасности
|
||||||
│ ├── alembic/ # Миграции (006…009)
|
│ ├── alembic/ # Миграции (006…010)
|
||||||
│ ├── seed_users.py # Сид первых пользователей
|
│ ├── seed_users.py # Сид первых пользователей
|
||||||
│ ├── seed_units.py # Сид подразделений (РЦУ РЧС → ОУМЧС → Г(Р)ОЧС, 142 юнита)
|
│ ├── seed_units.py # Сид подразделений (РЦУ РЧС → ОУМЧС → Г(Р)ОЧС, 142 юнита)
|
||||||
│ ├── routers/ # 12 модулей API (см. раздел 8)
|
│ ├── routers/ # 12 модулей API (см. раздел 8)
|
||||||
│ ├── services/ # Адаптеры расчёта
|
│ ├── services/ # Адаптеры расчёта
|
||||||
│ └── tests/ # 231 тест (pytest)
|
│ └── tests/ # 263 теста (pytest)
|
||||||
├── services/ # Математика (чистые функции)
|
├── services/ # Математика (чистые функции)
|
||||||
│ ├── search_engine.py # SearchInput/SearchModel — ядро расчёта
|
│ ├── search_engine.py # SearchInput/SearchModel — ядро расчёта
|
||||||
│ ├── distance_service.py # Максимальный радиус (КМЧ × коэффициенты)
|
│ ├── distance_service.py # Максимальный радиус (КМЧ × коэффициенты)
|
||||||
@@ -187,7 +189,7 @@ vector/
|
|||||||
|
|
||||||
## 6. База данных
|
## 6. База данных
|
||||||
|
|
||||||
**PostgreSQL 16 + PostGIS 3.6**, БД `vector_mchs`. Схема управления — Alembic (`backend/alembic/versions/`), актуальная ревизия **009_e3_operations**.
|
**PostgreSQL 16 + PostGIS 3.6**, БД `vector_mchs`. Схема управления — Alembic (`backend/alembic/versions/`), актуальная ревизия **010_b23_policy**.
|
||||||
|
|
||||||
### Основные таблицы
|
### Основные таблицы
|
||||||
|
|
||||||
@@ -199,25 +201,30 @@ vector/
|
|||||||
| `search_teams`, `field_observations`, `areas_checked`, `found_events` | Оперативные слои (состав групп, наблюдения, проверенные квадраты, находки) |
|
| `search_teams`, `field_observations`, `areas_checked`, `found_events` | Оперативные слои (состав групп, наблюдения, проверенные квадраты, находки) |
|
||||||
| `reference_priors` | Слой 1: справочные приоритеты |
|
| `reference_priors` | Слой 1: справочные приоритеты |
|
||||||
| `users`, `mchs_units` | Пользователи; иерархия РЦУ РЧС → 6 ОУМЧС → 135 Г(Р)ОЧС |
|
| `users`, `mchs_units` | Пользователи; иерархия РЦУ РЧС → 6 ОУМЧС → 135 Г(Р)ОЧС |
|
||||||
|
| `password_history` | История паролей (bcrypt-хэши; проверка переиспользования, B23) |
|
||||||
| `roles`, `permissions`, `role_permissions`, `user_roles` | RBAC: 4 роли, 9 прав, матрица связей |
|
| `roles`, `permissions`, `role_permissions`, `user_roles` | RBAC: 4 роли, 9 прав, матрица связей |
|
||||||
| `sessions`, `auth_events` | Server-side сессии (sha256-токены), журнал входов |
|
| `sessions`, `auth_events` | Server-side сессии (sha256-токены), журнал входов |
|
||||||
| `security_settings` | Политика безопасности (10 параметров) |
|
| `security_settings` | Политика безопасности (10 параметров, **исполняется кодом с B23**) |
|
||||||
| `search_operations` | Поисковые операции (статусная машина, привязка к кейсу и КОНТУРу) |
|
| `search_operations` | Поисковые операции (статусная машина, привязка к кейсу и КОНТУРу) |
|
||||||
| `audit_events`, `audit_changes` | Неизменяемый журнал аудита, field-level изменения (ретенция 90 дней) |
|
| `audit_events`, `audit_changes` | Неизменяемый журнал аудита, field-level изменения (ретенция 90 дней) |
|
||||||
| `planet_osm_*` | Импорт OSM Беларуси (osm2pgsql, SRID 4326/3857): дороги, леса, вода, НП |
|
| `planet_osm_*` | Импорт OSM Беларуси (osm2pgsql, SRID 4326/3857): дороги, леса, вода, НП |
|
||||||
|
|
||||||
### Политика безопасности (`security_settings`, меняется в админке)
|
### Политика безопасности (`security_settings`, меняется в админке)
|
||||||
|
|
||||||
| Параметр | Значение |
|
| Параметр | Значение | Исполнение (B23) |
|
||||||
|----------|----------|
|
|----------|----------|------------------|
|
||||||
| Минимальная длина пароля | 8 |
|
| Минимальная длина пароля | 8 | ✅ при смене/сбросе пароля |
|
||||||
| Сложность пароля | требуются буквы+цифры |
|
| Сложность пароля | требуются буквы+цифры | ✅ при смене/сбросе пароля |
|
||||||
| Срок действия пароля | 90 дней |
|
| Срок действия пароля | 90 дней | ✅ `enforce_expiry` на каждом запросе → `must_change_password` |
|
||||||
| История паролей | 5 (нельзя переиспользовать) |
|
| История паролей | 5 (нельзя переиспользовать) | ✅ таблица `password_history` (5 последних старых хэшей + текущий) |
|
||||||
| Блокировка после неудачных входов | 5 (на 15 минут) |
|
| Блокировка после неудачных входов | 5 (на 15 минут) | ✅ (с B21) |
|
||||||
| Тайм-аут сессии / неактивности | 24 ч / 60 мин |
|
| Тайм-аут сессии | 24 ч | ✅ проверка `expires_at` при каждом запросе |
|
||||||
| Макс. параллельных сессий | 3 (старые отзываются) |
|
| Тайм-аут неактивности | 60 мин | ⚠️ `last_seen_at` пишется, но не проверяется |
|
||||||
| Ретенция журнала аудита | 90 дней |
|
| Макс. параллельных сессий | 3 (старые отзываются) | ✅ (с B21) |
|
||||||
|
| Ретенция журнала аудита | 90 дней | ✅ реальный DELETE: cron `python -m backend.purge_logs` (03:10) или POST `/admin/users/maintenance/purge-logs` |
|
||||||
|
|
||||||
|
Семантика истории: `password_history_count = N` хранит N последних *старых* хэшей;
|
||||||
|
вместе с текущим паролем защищено N+1 последних значений.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -401,7 +408,8 @@ SPA на react-scripts (CRA). Роутинг:
|
|||||||
- Прикладное логирование `vector.*`: события анализа, входов, КОНТУРа, аудита (README §13а)
|
- Прикладное логирование `vector.*`: события анализа, входов, КОНТУРа, аудита (README §13а)
|
||||||
- Интеграция с КОНТУР: отправка зон (контракт B20)
|
- Интеграция с КОНТУР: отправка зон (контракт B20)
|
||||||
- Журнал аудита пользователей: входы, изменения, отправки
|
- Журнал аудита пользователей: входы, изменения, отправки
|
||||||
- 239 автотестов (pytest), 5 skipped
|
- 263 автотеста (pytest), 5 skipped
|
||||||
|
- B23: исполняемая политика паролей (срок/сложность/история), ретенция журналов реальным DELETE + cron
|
||||||
|
|
||||||
### В планах
|
### В планах
|
||||||
|
|
||||||
|
|||||||
+18
-3
@@ -153,7 +153,7 @@ docker compose ps # все 4 контейнера Up/healthy
|
|||||||
|
|
||||||
```bash
|
```bash
|
||||||
docker exec vector-backend sh -c 'cd /app/backend && alembic upgrade head'
|
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
|
docker exec vector-backend sh -c 'cd /app/backend && alembic current' # 010_b23_policy
|
||||||
```
|
```
|
||||||
|
|
||||||
Миграции идемпотентны на чистой БД. **Если** БД уже была инициализирована через create_all и `alembic upgrade` падает `DuplicateTable` — применить стемп-скрипт:
|
Миграции идемпотентны на чистой БД. **Если** БД уже была инициализирована через create_all и `alembic upgrade` падает `DuplicateTable` — применить стемп-скрипт:
|
||||||
@@ -330,6 +330,18 @@ docker exec vector-postgres pg_dump -U postgres -d vector_mchs \
|
|||||||
|
|
||||||
Рекомендация: ежедневный cron прикладного дампа (он небольшой) + еженедельный полный. Хранить копии вне сервера.
|
Рекомендация: ежедневный cron прикладного дампа (он небольшой) + еженедельный полный. Хранить копии вне сервера.
|
||||||
|
|
||||||
|
### Cron (рекомендуемый на сервере)
|
||||||
|
|
||||||
|
```cron
|
||||||
|
# 03:10 — ретенция журналов (удаление audit_events/auth_events старше audit_retention_days)
|
||||||
|
10 3 * * * docker exec vector-backend python -m backend.purge_logs >> /var/log/vector-purge.log 2>&1
|
||||||
|
# 03:00 — прикладной дамп (planet_osm_* исключены; OSM восстанавливается b16-import.sh)
|
||||||
|
0 3 * * * docker exec vector-postgres pg_dump -U postgres -d vector_mchs --exclude-table="planet_osm_*" -F c -f /tmp/vector_app_$(date +\%F).dump && docker cp vector-postgres:/tmp/vector_app_$(date +\%F).dump /root/backups/ && find /root/backups -name vector_app_*.dump -mtime +14 -delete >> /var/log/vector-backup.log 2>&1
|
||||||
|
```
|
||||||
|
|
||||||
|
Проверка разового прогона: `docker exec vector-backend python -m backend.purge_logs`
|
||||||
|
→ `purge: {'audit_events': N, 'auth_events': N}` (0 — норма).
|
||||||
|
|
||||||
**Docker volume — не backup.** Если сервер умер вместе с диском, volume умер вместе с ним. Что подлежит резервному копированию:
|
**Docker volume — не backup.** Если сервер умер вместе с диском, volume умер вместе с ним. Что подлежит резервному копированию:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
@@ -412,6 +424,8 @@ df -h && free -h # диск/память
|
|||||||
|
|
||||||
### Диагностика по цепочке (начинать с места проблемы, не с перезапусков)
|
### Диагностика по цепочке (начинать с места проблемы, не с перезапусков)
|
||||||
|
|
||||||
|
**Смена пароля даёт 400 «Пароль должен содержать буквы и цифры» / «совпадает с ранее использованным»** — это B23-политика (`security_settings`), не ошибка: с 25.09.2026 требования сложности и истории исполняются. Пароль, возвращённый ранее, отвергается, пока он в последних `password_history_count` записях.
|
||||||
|
|
||||||
**Бэкенд не подключается к БД** — цепочка `backend → docker network → postgres:5432 → authentication → vector_mchs`:
|
**Бэкенд не подключается к БД** — цепочка `backend → docker network → postgres:5432 → authentication → vector_mchs`:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
@@ -490,7 +504,7 @@ docker exec vector-postgres psql -U postgres -d vector_mchs -c \
|
|||||||
|
|
||||||
- [ ] прикладные логи `vector.*` доступны (`docker compose logs backend`, файл в контейнере)
|
- [ ] прикладные логи `vector.*` доступны (`docker compose logs backend`, файл в контейнере)
|
||||||
- [ ] аудит 90 дней читается (вкладка «Аудит», право `view_audit`)
|
- [ ] аудит 90 дней читается (вкладка «Аудит», право `view_audit`)
|
||||||
- [ ] ретенция настроена в `security_settings`
|
- [ ] ретенция **исполняется**: cron purge-логов установлен, `python -m backend.purge_logs` даёт счётчики
|
||||||
|
|
||||||
### Backup
|
### Backup
|
||||||
|
|
||||||
@@ -506,7 +520,8 @@ docker exec vector-postgres psql -U postgres -d vector_mchs -c \
|
|||||||
- [ ] Код получен (`/root/vector`), `.env` создан из `.env.example`
|
- [ ] Код получен (`/root/vector`), `.env` создан из `.env.example`
|
||||||
- [ ] `JWT_SECRET` заменён на случайный; пароль БД сменён (compose + DATABASE_URL)
|
- [ ] `JWT_SECRET` заменён на случайный; пароль БД сменён (compose + DATABASE_URL)
|
||||||
- [ ] `docker compose up -d` — 4 контейнера Up
|
- [ ] `docker compose up -d` — 4 контейнера Up
|
||||||
- [ ] `alembic current` = `009_e3_operations`
|
- [ ] `alembic current` = `010_b23_policy`
|
||||||
|
- [ ] cron бэкапа И cron purge-логов настроены (`crontab -l`), первый дамп лежит в /root/backups
|
||||||
- [ ] `seed_users.py` выполнен, пароль админа сменён при первом входе
|
- [ ] `seed_users.py` выполнен, пароль админа сменён при первом входе
|
||||||
- [ ] `seed_units.py` выполнен (142 подразделения в селектах)
|
- [ ] `seed_units.py` выполнен (142 подразделения в селектах)
|
||||||
- [ ] PostGIS установлен в контейнере БД, extension создан
|
- [ ] PostGIS установлен в контейнере БД, extension создан
|
||||||
|
|||||||
Reference in New Issue
Block a user