Files
ayurishchevandClaude Sonnet 5 a846d30872 IPAM Manager: API, UI-админка, журнал аудита
Backend (FastAPI, SQLAlchemy 2, Alembic, PostgreSQL 16):
- организации, VRF, префиксы (дерево, использование, автоназначение),
  адреса, операторы связи, устройства и типы устройств; JWT, роли admin/viewer;
- VRF принадлежит организации (составной FK), смена VRF у префикса
  переносит поддерево, имя VRF уникально в организации;
- журнал аудита: поиск и фильтры, ротация (срок/количество), очистка
  по паролю с блокировкой, IP клиента и метаданные запроса
  (X-Forwarded-For только от TRUSTED_PROXIES).

UI (web/, без сборки): экраны и диалоги по макетам «IPAM Manager»,
кликабельные строки реестров, локальные шрифты IBM Plex,
собственные выпадающие списки.

Окружение: docker-compose (postgres + app), миграции Alembic 0001-0004,
scripts/gen_env.py, scripts/seed_demo.py, 11 автотестов (pytest).
Документация: README.md и docs/changes/001-005 (планы и итоги).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-20 12:27:47 +03:00

52 lines
6.1 KiB
Markdown

# План: смена VRF у префикса и целостность «VRF ⊂ организация» (изменение 002)
## Контекст
VRF — часть адресного плана организации. Сейчас:
- уникальность VRF уже в пределах организации: `UNIQUE(organization_id, name)` — одно имя допустимо в разных организациях;
- несколько префиксов организации могут быть в одном VRF (`UNIQUE(vrf_id, prefix)` — дубль CIDR запрещён только внутри VRF);
- **смена VRF у существующего префикса невозможна**: нет ни поля в UI (`web/app.js`, `prefixDialog`), ни `vrf_id` в `PrefixUpdate` (`app/schemas.py`);
- принадлежность VRF организации префикса проверяется только в коде (`create_prefix`), в БД гарантии нет.
Цель: разрешить смену VRF **только среди VRF той же организации**, сохранив целостность дерева, и закрепить правило на уровне БД.
## Правила
1. Организация префикса неизменна; целевой VRF обязан принадлежать той же организации (иначе 422).
2. Смена VRF переносит **префикс вместе со всем поддеревом** (вложенные по `parent_id`), чтобы дерево не «разрывалось» между VRF.
3. Дубль `(vrf, prefix)` у любого переносимого префикса в целевом VRF → 409 с перечнем конфликтующих CIDR; перенос отменяется целиком.
4. После переноса родитель корня поддерева пересчитывается в целевом VRF (самый узкий объемлющий); префиксы целевого VRF, лежащие внутри перенесённого, переподчиняются ему — та же логика, что при создании (выносим в общую функцию `attach_to_tree`).
5. Адреса остаются у своих префиксов (`prefix_id` не меняется); использование/ёмкость пересчитываются автоматически.
6. CIDR и родитель в окне редактирования по-прежнему не меняются (родитель определяется автоматически).
## Изменения
**Backend**
- `app/schemas.py`: `PrefixUpdate.vrf_id: int | None`.
- `app/api/v1/prefixes.py`: в `update_prefix` — валидация правил 1–3, перенос поддерева, `attach_to_tree` (рефакторинг из `create_prefix`), запись в audit `{vrf: "old → new", moved: N}`.
- Alembic `0002`:
- `UNIQUE(id, organization_id)` на `vrfs` + составной FK `prefixes(vrf_id, organization_id) → vrfs(id, organization_id)` — БД не даст связать префикс с VRF чужой организации;
- уникальность имени VRF без учёта регистра в пределах организации: индекс `(organization_id, lower(name))` вместо `UNIQUE(organization_id, name)`; перед применением — проверка на существующие дубли.
**UI (`web/app.js`)**
- В окне редактирования префикса показать поле «VRF» (только VRF текущей организации, уже загружены в `S.vrfs`).
- При выборе другого VRF — подсказка «Вместе с префиксом будет перенесено N вложенных» (N считается из `S.prefixes`); ошибки 409/422 — в стандартном баннере окна.
- Вёрстка — из существующего окна создания (макета редактирования нет, отступлений от дизайна не появляется).
**Тесты (2 новых, всего 6)**
1. Одноимённый VRF в двух организациях — ок; повтор в одной (в т.ч. другим регистром) — 409.
2. Смена VRF: поддерево переехало, родитель пересчитан, дубль в целевом VRF — 409 без частичных изменений, VRF другой организации — 422.
## Порядок работ
1. Рефакторинг `attach_to_tree` (поведение создания не меняется, тесты зелёные).
2. Миграция `0002` (сначала проверка дублей, затем применение через `docker compose up`).
3. `PrefixUpdate` + логика переноса.
4. UI: поле VRF и подсказка.
5. Тесты в контейнерах, прогон e2e-сценария UI, сверка окна с макетом «Новый префикс».
6. Обновить `README.md` (правила VRF), написать `SUMMARY.md` в этой папке.
## Риски
- Составной FK требует, чтобы `prefixes.organization_id` всегда совпадал с организацией VRF — уже так; миграция проверит данные и откажется применяться при расхождении.
- Перенос крупного поддерева — одна транзакция; при 409 откат целиком.
## Допущения (скажите, если не так)
- Переносится всё поддерево, а не только выбранный префикс (альтернатива — запретить смену VRF у префиксов с вложенными).
- Регистронезависимая уникальность имён VRF в организации допустима (`Lab` и `lab` считаются одним VRF).