9.4 KiB
План: 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, настраивается) по
AggregatedAtdesc среди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). Рендеринг на сервере — браузер не видит JSONcontrol-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.
Проверка
go build ./... && go test ./...scripts/run-local-e2e.sh+admin-dashboardотдельно против того же control-api- Ручной браузерный смоук-тест (обязателен, не пропускается)