Files
ipam_control/docs/changes/039-device-status/PLAN.md
T
ayurishchevandClaude Opus 5.5 7d998066f5 Задача 039: статус устройства и сведения об устройстве в списке адресов
Статус устройства (Активен / Выключен / На обслуживании), назначается вручную на экране
устройств: колонка «Статус», выбор в диалоге, смена — в журнал. Миграция 0016,
существующие устройства — «Активен». В списке адресов префикса колонки «Тип устройства»,
«Устройство», «Статус устройства» (join без N+1). pytest не прогнан: учётная запись admin
из .env отключена на стенде.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-27 18:18:33 +03:00

64 lines
5.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Статус устройства и сведения об устройстве в списке адресов префикса (изменение 039)
## Context
Сейчас в списке адресов префикса (`screens.address`) не видно, к какому устройству привязан адрес, — только в диалоге правки.
У устройства нет эксплуатационного статуса. Нужно:
1. Ввести **статус устройства** — «Активен», «Выключен», «На обслуживании». Статус назначается вручную на экране устройств:
в диалоге создания и правки, в таблице устройств — новая колонка «Статус».
2. В списке адресов префикса — три новые колонки: **тип устройства**, **имя устройства**, **статус устройства**
(пусто или «—», если адрес не привязан к устройству).
## Модель и миграция `0016_device_status.py`
- `app/models.py`: `class DeviceStatus(str, enum.Enum): active, off, maintenance`.
`Device.status: Mapped[DeviceStatus]` — `Enum(DeviceStatus, name="device_status")`, `default=active`, `server_default='active'`, NOT NULL.
- Миграция: создать тип `device_status`, добавить колонку с `server_default 'active'` — существующие устройства станут «Активен».
`downgrade`: удалить колонку и тип.
## API
- `app/schemas.py`:
- `DeviceIn.status: DeviceStatus = DeviceStatus.active`;
- `DeviceUpdate.status: DeviceStatus | None = None`;
- `DeviceOut.status`;
- `AddressOut`: `device_type_name: str | None`, `device_status: str | None`.
- `app/api/v1/refs.py`: создание и правка устройства принимают `status`. Смена статуса попадает в журнал через существующий `apply_update`
(`device.updated` с `diff`); `_device_outs` отдаёт `status`.
- `app/api/v1/prefixes.py::list_addresses`:
- запрос `select(Address, Device.name)` расширить: `Device.status` и `DeviceType.name` через `outerjoin(DeviceType, …)`;
- `_addr_out(a, device_name, device_type_name, device_status)` — обновить все вызовы;
- остальные эндпоинты, возвращающие `AddressOut` (создание, правка, автоназначение), отдают поля так же — через общий хелпер
или отдельный запрос по `device_id`, без N+1 в списке.
- Фильтр и поиск по статусу устройства не требуются.
## UI — `web/app.js`
- Справочник `DEVICE_STATUS = {active: ["green","Активен"], off: ["", "Выключен"], maintenance: ["amber","На обслуживании"]}` —
цвет бейджа и подпись, по образцу `ADDR_STATUS`.
- **Экран устройств** (`screens.devices`):
- колонка «Статус» с бейджем (после «Тип»), расширить `selCols` и заголовок;
- в `deviceDialog` — `fSelect("status", "Статус", …)`, по умолчанию «Активен», значение уходит в `POST`/`PATCH`.
- **Список адресов** (`screens.address`): после «Описание» колонки «Тип устройства», «Устройство», «Статус устройства».
- имя устройства ссылкой не делаем — строка и так кликабельна; у свободных и непривязанных адресов — «—»;
- статус — тем же бейджем;
- ширины подобрать так, чтобы таблица не переполнялась: «Описание» может стать уже; «Изменено» оставить.
- Цвета — только через существующие классы бейджей и токены тёмной темы (изменение 038), без литералов.
## Тесты (минимально)
Одна проверка в существующем тесте `tests/test_api.py`, например в `test_in_use_objects_cannot_be_deleted` или рядом, без нового файла:
- создать устройство со `status="maintenance"`, привязать к нему адрес;
- `GET /prefixes/{id}/addresses` → у адреса `device_name`, `device_type_name`, `device_status == "maintenance"`;
- `PATCH /devices/{id} {"status": "off"}` → 200, `status == "off"`.
## Документация
- `README.md`: модель данных — статус устройства; «Интерфейс» — колонки; миграции `0001`–`0016`; строка 039 в истории.
- `SUMMARY.md` — по завершении (моя часть).
## Исполнение
По принятой схеме: код, миграцию, UI и тест пишет агент на Sonnet, он же пересобирает стенд с `--force-recreate`; тесты он не запускает.
Моя часть — ревью, `pytest`, проверка миграции и API. UI проверяет пользователь.
## Проверка
- `alembic current` = `0016`, `alembic check` чисто; откат до 0015 и повторный upgrade.
- Существующие устройства после миграции — `active`.
- `pytest -q` — все зелёные.
- API: статус меняется и пишется в журнал (`device.updated`, `diff.status`); адреса отдают три новых поля;
у свободных и непривязанных адресов — `null`.