# План: выпадающий список подсетей и чарт «успешные проверки по целям / площадкам» в «Реестре» Редакция 2 (решения по вопросам подтверждены пользователем). Продолжение [2026-10-06_12-12_registry-subnet-direction-protocol-filters](2026-10-06_12-12_registry-subnet-direction-protocol-filters-plan.md). Фильтры работают; улучшаем удобство и восприятие. ## Задача 1. **Подсеть** выбирается из выпадающего списка (сейчас — поле ввода с подсказками). 2. Когда выбраны **направление и протокол** (например, Egress + https), над таблицей показывается чарт «количество успешных проверок» по каждой цели 1…N: - **Egress** — в разрезе целей; - **Ingress** — в разрезе площадок (та же логика). 3. Строка чарта кликабельна и открывает список адресов с детализацией. 4. Подход переиспользуем из «Аналитика → Egress по целям». ## Что уже есть (граф + код) - Аналитика: блок «Egress по целям» — строки `an-bar-row` (название, полоса `an-track`/`an-fill`, число и процент), вкладки по типу проверки. Диалог со списком адресов (`analytics-dialog.js`, шаблон `analytics_dialog`, «Копировать», «Скачать CSV», подсказки при наведении) подключается страницей и уже обслуживает списки по запросу `load(url)` → `fill(...)`. Стили — `static/analytics.css`. - Данные в БД: в `checks` для egress `target` — адрес цели (`https://github.com`), `source='egress'`. Для ingress `source = inbound-site-N` (площадка), а `target` — сам проверяемый адрес, поэтому ingress группируется по `source`, а не по `target`. Имена площадок берутся по индексу (как `SiteNames` в аналитике), без имени — `site-N`. - Срез данных (запуск / последний цикл, направление, протокол, статус, подсеть) уже реализован в `internal/db/queries_registry.go` (`registrySlice`, `scopeFrom`). Чарт строится по тому же срезу и тому же набору адресов, что и таблица. - Список настроенных подсетей уже грузится в форму (`GetSubnets`), 45 штук на стенде. - Таблица `/registry` обновляется через htmx (`#registry-table-wrap`). ## Решения (подтверждены пользователем) 1. **Когда показывать чарт:** выбраны **и** направление, **и** протокол. С одним направлением вместо чарта — короткая подсказка «Выберите протокол, чтобы увидеть распределение по целям/площадкам». 2. **Набор адресов — все под текущим фильтром** (запуск, подсеть, статус, поиск), а не только текущая страница. Чарт совпадает с «Найдено адресов: N». Чарт строится в разрезе проверок выбранного типа в рамках проверочного цикла среза: цикл адреса в выбранном запуске или его последний цикл. 3. **Что считается:** число записанных проверок выбранного типа в проверочном цикле среза: `успешных из всего`. Полоса — доля успешных; подпись: `1 234 из 1 250 · 98,7%`. У tcp и tls на ingress у адреса может быть несколько проверок на площадку (порты 22 и 443), поэтому считаются именно проверки, а не адреса (пояснение в подписи под чартом). 4. **Порядок строк:** **от большего к меньшему** по числу успешных проверок, при равенстве — по названию. Полоса масштабируется по наибольшему значению; доля успешных остаётся в подписи. 5. **Подпись цели:** адрес цели без схемы и без завершающего `/` (`repo.almalinux.org/almalinux`), ключ — исходное значение `target`. Разные пути на одном хосте остаются разными строками. 6. **Клик по строке:** диалог со списком **всех** адресов набора, у которых есть проверки этой цели/площадки, провалы сверху (порядок списка не связан с порядком чарта). Столбцы: Адрес, Результат (`успешно`/`провал`), Тип проверки (`https`, `tcp-22`…), Цель или Площадка, Валидатор (для egress), Задержка (мс), Детали (ошибка), Проверено. Сверху — счётчики «успешно N · провал M». Доступны «Копировать» и «Скачать CSV». 7. **Подсеть в списке** (ручной ввод убирается, решение подтверждено): варианты — «Все подсети» + настроенные подсети (`CIDR — метка`). Ручной ввод убирается. Подсеть из URL (переход из аналитики), которой нет в списке, добавляется отдельным выбранным пунктом. Если подсети не настроены — список недоступен, рядом ссылка на `/settings` с их настройкой. 8. **Egress + ssh/tcp/tls** (таких проверок нет): чарт показывает «Для этого сочетания проверок нет», как и пустая таблица. ## Изменения ### 1. БД (`internal/db`) - Выделить сборку условий `FROM`/`WHERE` из `ListRegistryPage` в функцию, которую используют и список, и новая выборка (поведение списка не меняется; существующие тесты — страховка). - Новый файл `queries_registry_breakdown.go`: - `RegistryBreakdown(ctx, filter) (*Breakdown, error)`: требует `Level` и `Family` (иначе `ErrValidation`); один запрос `GROUP BY` по `target` (egress) или `source` (ingress) поверх проверок среза: `COUNT(*)`, `SUM(success)`. Возвращает группу (`target`|`site`), число адресов, строки `{key, total, ok}`. - `RegistryBreakdownList(ctx, filter, key)`: строки проверок выбранного ключа с адресом, типом, валидатором, задержкой, деталью, временем; провалы сверху. - Индексы `idx_checks_run` и `idx_checks_registry_cycle` уже подходят; проверить `EXPLAIN QUERY PLAN`. ### 2. HTTP API (`internal/httpapi`) - `GET /api/v1/admin/registry/breakdown` — те же параметры, что у реестра (`q`, `last_result`, `run`, `subnet`, `direction`, `protocol`); без `direction` или `protocol` — `400`. Ответ: `{group, direction, protocol, run, addresses, rows:[{key,label,total,ok}]}`; имена площадок подставляются здесь. - `GET /api/v1/admin/registry/breakdown/list?…&key=` — таблица `{columns, rows}`; `format=csv` — файл. Неизвестный ключ — `404`. - Маршруты — в таблицу маршрутов (`TestRouteTableIsClassified`: admin-доступ). `docs/API.md` — описание и примеры. ### 3. Дашборд (`internal/dashboard`) - `client.go`: `GetRegistryBreakdown`, `GetRegistryBreakdownList`, `…CSV`. - `handlers_registry.go`: при выбранных направлении и протоколе запросить чарт и передать в шаблон; ошибка чарта показывается в самом блоке, страница не ломается. Прокси-маршруты `GET /registry/breakdown/list` и `GET /registry/breakdown/csv` (как `analytics/lists`). - `templates/registry.html`: - поле «Подсеть» → `` с выбранным пунктом и пунктом из URL; прокси списка. - `TestScaleSmoke6440`: чарт и список на 6440 адресов в пределах лимита. - Правки существующих тестов, где проверялось поле ввода подсети. ## Порядок работы 1. Утвердить план и «Решения». 2. Субагент (Sonnet 5.5, Medium effort) пишет код и тесты: п.1 → п.2 → п.3 → п.4. 3. Ревью, `gofmt`, `go build ./... && go vet ./... && go test -count=1 ./...`, `EXPLAIN QUERY PLAN`. 4. Проверка на тестовом стенде `civ-test` (порты 18081/18091): пересобрать образы тега `filters`, `docker compose up -d` в `/opt/lvraid/claude/civ-teststand`, снять замеры на копии боевой БД. Боевые контейнеры не трогаем. 5. Summary в `docs/changes/…-summary.md`; обновить `README.md`, `docs/API.md`, `docs/USAGE.md`; обновить граф `/graphify . --update`. ## Риски - Объём списка: до 6–7 тысяч адресов в диалоге, как в аналитике; для CSV — серверная выгрузка. - Время ответа чарта на 1 млн проверок: ожидается долей секунды (один `GROUP BY` по срезу); проверить замером на копии БД стенда. При деградации — не считать чарт, пока не выбраны оба фильтра (уже предусмотрено). - Названия площадок и целей берутся из текущей конфигурации: удалённая площадка отображается как `site-N`. - Незавершённый запуск даёт частичные данные — как и таблица. - Подсеть только из списка: чтобы отфильтровать произвольный CIDR, подсеть нужно добавить в настройки (ссылка рядом с полем).