Files
cloud-ip-validator/docs/PLAN_ADMIN_DASHBOARD.md
T

9.4 KiB
Raw Blame History

План: cmd/admin-dashboard — веб-панель администратора

Статус: реализовано. Актуальное описание — docs/DASHBOARD.md.

Context

Единственный способ управлять control-api (очередь IP, валидаторы, площадки, цели проверки) — HTTP API через curl (см. docs/API.md). API уже покрывает весь необходимый функционал (POST /api/v1/admin/ips для постановки/принудительного повтора, POST /api/v1/admin/ips/{ip}/cancel для остановки, /api/v1/admin/config/{validators,sites,targets,check-types} для CRUD), но curl неудобен для повседневного оперирования и не даёт наглядной картины состояния очереди. Нужен браузерный admin dashboard — графический доступ ко всей этой функциональности: сводная статистика (текущая проверка / итог последней завершённой), управление конфигурацией и принудительные операции над очередью — без YAML и без перезапуска control-api.

Согласованные решения:

  • Без сборки фронтенда. Server-rendered html/template + htmx (частичные AJAX-обновления) + Alpine.js (точечная клиентская интерактивность) + Pico.css classless (минимализм на голой семантической разметке). Все три библиотеки вендорятся как статические файлы и встраиваются через //go:embed — без CDN во время выполнения (принцип проекта — полностью автономный бинарник, работает офлайн).
  • Никакого нового backend-состояния. «Текущая проверка» — live-снимок IP не в терминальном состоянии. «Последняя завершённая» — последние N (по умолчанию 20, настраивается) по AggregatedAt desc среди done/failed, с разбивкой по OverallResult. Оба вычисляются на каждый запрос из GET /admin/status + GET /admin/ips — никакого понятия «запуска»/«батча» в control-api не добавляется.
  • Без аутентификации — как и сам API; доступ ограничивается сетью/firewall.
  • Отдельный 4-й бинарник (cmd/admin-dashboard), не новые маршруты внутри control-api. Ходит в control-api только через существующий HTTP admin API (internal/apiclient.Client). Рендеринг на сервере — браузер не видит JSON control-api напрямую, CORS/reverse-proxy не нужны.
  • Малые допущения: без пагинации очереди (текущий масштаб — десятки адресов); баннер ошибок различает 4xx (жёлтый) и 5xx/транспортные (красный); порт дашборда по умолчанию :8090.

1. Структура файлов

cmd/admin-dashboard/main.go

internal/dashboard/
  server.go, routes.go, client.go, dto.go, render.go, embed.go
  handlers_overview.go, handlers_ips.go, handlers_validators.go,
  handlers_sites.go, handlers_targets.go, handlers_checktypes.go
  templates/  (layout, overview[+fragment], ips[+table], ip_detail,
               validators[+table+row], sites[+table], targets[+table+row],
               checktypes[+table+row], error_banner)
  static/vendor/{htmx.min.js,alpine.min.js,pico.classless.min.css,VENDOR.md}
  static/dashboard.css

configs/admin-dashboard.example.yaml
deploy/systemd/admin-dashboard.service
docs/DASHBOARD.md

Таблица ips перерисовывается целиком при любой мутации (POST /admin/ips может завести новые строки и поменять sequence). validators/sites/targets/check-types — точечный swap одной <tr>.

2. Маршруты дашборда

Метод Путь Вызов к control-api
GET / редирект на /overview
GET /overview, /overview/fragment GET /admin/status, GET /admin/ips
GET /ips, /ips/{ip} GET /admin/ips, GET /admin/ips/{ip}
POST /ips POST /admin/ips
POST /ips/{ip}/recheck POST /admin/ips {"addresses":[ip]}
POST /ips/{ip}/cancel POST /admin/ips/{ip}/cancel
GET/POST /validators, PUT/DELETE /validators/{id} .../config/validators[/{id}]
GET /sites, PUT/DELETE /sites/{index} .../config/sites[/{index}]
GET/POST /targets, PUT/DELETE /targets/{group} .../config/targets[/{group}]
GET/POST /check-types, PUT/DELETE /check-types/{name} .../config/check-types[/{name}]
GET /static/* embed.FS

overview/fragment — hx-trigger="every Ns" (из конфига), без фонового тикера на сервере. POST /targets//check-types — перевод «форма с именем» → PUT .../{name} (control-api там upsert).

3. Ошибки control-api

client.go: не-2xx → *apiErr{Status, Message}. Хендлеры не отдают 500 — рендерят страницу/фрагмент + out-of-band error_banner.html (hx-swap-oob="true", id="error-banner" в layout.html); статус ответа дашборда = статус control-api (502 при транспортной ошибке). Баннер жёлтый для 4xx, красный для 5xx/транспортных.

4. Конфигурация

internal/config/config.go, секция AdminDashboard{Server, ControlAPI{ BaseURL, TimeoutSeconds}, Overview{LastCompletedCount, PollIntervalSeconds}}

  • LoadAdminDashboard (defaults: :8090, timeout 10s, N=20, poll=5s; BaseURL обязателен). configs/admin-dashboard.example.yaml, deploy/systemd/admin-dashboard.service (без CAP_NET_RAW/EnvironmentFile).

5. DTO и клиент

internal/dashboard/dto.go — свои wire-структуры (не импортируют приватные DTO internal/httpapi, тот же паттерн, что internal/probercore): snake_case-структуры дословно повторяют internal/httpapi/dto_admin.go; для GET /admin/ips[/{ip}]/GET /admin/validators — зеркала untagged PascalCase db.IPQueueItem/db.Validator/db.Check/db.Event.

client.go — обёртка над apiclient.Client: Status, ListIPs, GetIP, SubmitIPs, CancelIP, CRUD-методы для validators/sites/target-groups/ check-types.

handlers_overview.go — чистые функции: currentlyChecking, lastCompleted(items, n), resultBreakdown.

6. Вендоринг статики

Скачать один раз, закоммитить, задокументировать в VENDOR.md: htmx.min.js (unpkg htmx.org, ядро без расширений), alpine.min.js (unpkg alpinejs dist/cdn.min.js, IIFE-сборка), pico.classless.min.css (unpkg @picocss/pico).

7. Тестирование

httptest-фейковый control-api + httptest-дашборд поверх него, проверка рендера через strings.Contains (по образцу internal/httpapi/handlers_config_test.go). Кейсы: overview live-агрегация и resultBreakdown; submit (happy + пустой список); recheck (done→requeued, checking→skipped, явно показано); cancel (happy + 409); CRUD-раунд-трип + конфликты (409/400) по всем 4 сущностям; control-api недоступен → баннер + 502.

Обязательный ручной шаг: браузерный смоук-тест против scripts/run-local-e2e.sh (или отдельного mock control-api) — все страницы/формы/действия, live-обновление во время реального прогона, проверка через DevTools Network отсутствия внешних (CDN) запросов.

8. Документация

Новый docs/DASHBOARD.md; README.md («три компонента» → «четыре»); docs/SETUP.md (компонент + раздел развёртывания + сетевые доступы); docs/API.md (отсылка на дашборд в предупреждении об открытости API).

Критичные файлы

internal/dashboard/{client.go,dto.go,routes.go,server.go, handlers_overview.go,render.go,embed.go}, internal/config/config.go (AdminDashboard), cmd/admin-dashboard/main.go.

Проверка

  1. go build ./... && go test ./...
  2. scripts/run-local-e2e.sh + admin-dashboard отдельно против того же control-api
  3. Ручной браузерный смоук-тест (обязателен, не пропускается)