| 2026-10-05 |
feat: MCP — тулы управления: создание и удаление серверов и сервисов
...
Пишущие тулы переиспользуют роут-функции (server_create возвращает ghm_-
ключ один раз; удаление каскадно чистит метрики/пробы). Запись для всех
валидных ключей — модель панели «любая сессия = админ»; rate-limit 20/10мин
in-memory, ошибки как данные {"error","detail"}. AGENT_INSTRUCTIONS: секция
«Управление (запись)», удаление — только по явной просьбе человека.
Eugene Sukhodolskiy
committed
1 day ago
|
| 2026-10-04 |
feat: персональные MCP-ключи (канон handbook mcp.md)
...
- таблица mcp_tokens: sha256-хэш (unique) + хвост-хинт, снейпшот roles
владельца на момент выпуска; миграции users.system_role/users.blocked
- выдача только из cookie-сессии: GET/POST /me/mcp_tokens (plaintext
ровно один раз, ≥10 активных → 409), ревок вместо архива; админ-роуты
для всех ключей; rate-limit на выдачу (5 за 10 мин)
- гард /mcp — require_mcp: Bearer mcp_* | статический GHARD_ADMIN_TOKEN |
cookie; отозванный/заблокированный — тот же 401 (причина не раскрывается)
- вебхуки user.blocked/deleted/archived → users.blocked=1 + ревок ключей
владельца; разблокировка — при следующем успешном логине; SSO-логаут
ключи не трогает
Eugene Sukhodolskiy
committed
1 day ago
|
feat: MCP — инструкции агенту как prompt agent_guide + тулы сервисов и журнала
...
Инструкции ИИ-агенту раздаются и при initialize (instructions), и как
MCP-prompt agent_guide (паттерн reference-реализации gnexus-creds):
назначение, карта инструментов по типам вопросов, словарь статусов
(online/offline, up/degraded/down + mode не падение) и событий,
правила (read-only, id из overview, история 7 дней).
Новые тулов: services_overview (health-чеки: state/latency/self-report),
service_incidents (моменты недоступности), events_recent (журнал с
фильтром по severity); panel_overview дополнен строкой по сервисам.
Заодно починен мост /mcp: FastAPI валидировал голый ASGI-объект как
endpoint — считывал scope/receive/send query-параметрами и отвечал 422
на любой запрос; теперь реальный endpoint, вручную докручивающий
ASGI-диалог (stateless + json_response — ответ всегда один JSON).
Eugene Sukhodolskiy
committed
1 day ago
|

feat: журнал событий + интеграция с Gnexus Synapse (этап 4)
...
Все ивенты панели пишутся в единый журнал (events, retention 90 дней,
GET /api/v1/events) и — при настроенном GHARD_SYNAPSE_* — уходят конвертом
v1 в Synapse (gn-synapse-client-py, fire-and-forget, high/critical через
send с логом ошибок, остальное через emit).
Источники ивентов: пороги cpu/ram/swap/disk/load с гистерезисом (пары
*_high/*_recovered, disk — по маунтам), watchdog server_offline/online,
diff docker-контейнеров между пакетами, переходы сервисов
service_down/degraded/recovered на краях инцидент-периодов. Журнал сам
служит состоянием: пары открытие/закрытие переживают рестарт панели,
повторных оповещений нет; повторяющиеся открытия получают dedup_key
{type}-{id}-{UTC-день}, ttl конверта 24 ч.
Конверты не содержат адресатов и каналов — маршрутизацию решает Synapse.
Тройки subject×action регистрируются в админке Synapse заранее; пустой
GHARD_SYNAPSE_API_KEY = интеграция выключена (только журнал).
Eugene Sukhodolskiy
committed
1 day ago
|
feat: страницы сервисов — персональный график + журнал недоступности
...
- GET /services/{id}/incidents: периоды down+degraded из истории проб
(worst-состояние периода, код/причина из первой точки, идущий период end=NULL)
- /services/ график отклика 1h/6h/24h/7d, журнал инцидентов,
самосвидетельство (v/uptime/mode/gauges), редактирование и удаление
- список сервисов: без общего графика, карточка ведёт на страницу сервиса
Eugene Sukhodolskiy
committed
1 day ago
|
feat: парсер самосвидетельства health-ответов (handbook spec §5)
...
Панель читает расширенное тело health: identity (service/version/build/
environment/uptime|since), mode из белого списка {maintenance, readonly,
draining} — нейтральный бейдж в карточке, gauges — числа чипами.
Белый список известных полей: сырое тело не хранится и не логируется
(эндпоинт без авторизации), bool/вложенные значения в gauges отбрасываются,
неизвестный mode игнорируется (mode ≠ лайвность).
service_samples.report (JSON, NULL = нет самосвидетельства); колонка
добавляется к живым БД guarded ALTER в db.init_db (паттерн будущих
миграций). В API — report в списке сервисов и в истории проб.
Карточка «Сервисы»: v+environment+аптайм (fmtUptime), бейдж mode
(тексты i18n en/uk/ru), чипы gauges; пустые строки не рисуются.
Eugene Sukhodolskiy
committed
1 day ago
|
feat: health-чекер сервисов — раздел «Сервисы» + спека health-эндпоинтов
...
Панель опрашивает health-URL внешних gnexus-сервисов (GET, параллельно,
каждые GHARD_HEALTH_INTERVAL=30с, таймаут 5с) и показывает их состояние
отдельным разделом: карточки с состоянием/latency/причиной, история
отклика за 24ч (график), retention точек 7 дней.
Прогрессивный минимум интерпретации: 2xx = up; JSON-тело со строковым
status — ok-набор → up, degraded-набор → деградация, незнакомая строка
→ вниз; не-2xx / таймаут / сеть → вниз. Контракт зафиксирован в
docs/health-endpoint-spec.md (минимум + рекомендуемое расширение checks).
- backend: tables services/service_samples, services_probe.py (волны
проб через asyncio.gather, cap тела 64KB), api/services.py (CRUD +
samples, мгновенный замер на POST/PATCH url), config GHARD_HEALTH_*
- frontend: страница /services, api-методы, nav «Сервисы»,
i18n en/uk/ru
Eugene Sukhodolskiy
committed
1 day ago
|

feat: settings section + i18n (en/uk/ru) for the whole UI
...
Language comes from the gnexus-auth account profile by default; Settings
now hosts a per-service override that survives logouts and profile-webhook
syncs (users table keeps profile JSON verbatim, override in a separate
column that the upsert never touches). Open mode stores the choice in
localStorage.
- backend: users table (zero-migration, IF NOT EXISTS), app/locales.py
(normalize_locale/effective_locale), users upsert on session create and
user.updated webhook, GET /me returns locale + locale_effective,
new PATCH /api/v1/me (cookie-session only; 'auto'/'""' clears override)
- frontend: hand-rolled i18n mirror of gnexus-creds (locale ref, t() with
Slavic plurals, EN fallback), full dictionaries (~130 strings), <html
lang> + <title> tracked via watch; SettingsPage with language picker
(Auto/en/uk/ru); ServerCard/ServerPage/StoragePage status triple and
table columns unified into reactive computed t() lookups; fmtAgo/
fmtUptime localized; nav/login/shell translated; default html lang en
Co-Authored-By: Claude Code <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
1 day ago
|
fix: no-store on static/SPA responses — stale index.html survives deploys
...
Browsers heuristically cache FileResponse without explicit Cache-Control,
so after a container rebuild the tab kept serving the old JS bundle.
Co-Authored-By: Claude Code <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
1 day ago
|
fix: webhook route — verify+parse via ctx parts, not GAuthClient method
...
verify_and_parse_webhook exists only on GAuthClient; the route holds
HmacWebhookVerifier + JsonWebhookParser directly, so call verify() and
parse() separately (signature itself was always fine — the AttributeError
landed in the 401 bucket).
Co-Authored-By: Claude Code <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
1 day ago
|
feat: close the panel behind gnexus-auth (OAuth PKCE)
...
Auth off by default (client_id empty). When GHARD_AUTH_CLIENT_ID is set,
the web UI gets a creds-style sign-in gate: splash -> /me -> login screen
(OAuth starts from the click, not page load). Sessions and OAuth state
live in SQLite (survive restarts); webhook endpoint applies global_logout/
profile updates. Scripts/MCP keep working with the Bearer token, agents
keep X-Server-Key ingest. Includes compose env passthrough, README guide.
Co-Authored-By: Claude Code <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
1 day ago
|
| 2026-09-11 |
feat: network storage section — panel probes mounted shares itself
...
Backend: shares + share_samples tables, background probe loop
(os.statvfs every GHARD_SHARE_INTERVAL, 7-day retention, ok=0 when
the mount is unreachable), CRUD + samples API, instant first sample
on create/update, shares in MCP panel_overview.
Frontend: /storage page — share cards with status badge/progress/
used-free-total, 24h fill chart, add/delete via modal + confirm.
ChartLine shows a visible point while there are fewer than 3 samples.
README: CIFS/NFS mount + fstab examples, GHARD_SHARE_INTERVAL row.
Co-Authored-By: Claude Code <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
24 days ago
|
| 2026-09-10 |
feat: MCP server at /mcp — AI agents read server state from the panel
...
Streamable HTTP, stateless, JSON responses (proxy-friendly). Tools:
panel_overview (fleet summary), server_details (full current state),
server_history (downsampled metrics history). ASGI endpoint registered
directly on FastAPI routes (Mount misses exact /mcp) and the MCP session
manager runs in the app lifespan. mcp SDK pinned >=1.10,<2. README:
tool table, claude mcp add example, token caveat.
Co-Authored-By: Claude Code <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
25 days ago
|
feat: English UI, no-login API, logo/favicon, layout fixes
...
- UI fully translated to English (dashboard, server page, toasts, formatters)
- login removed: GHARD_ADMIN_TOKEN is optional now (unset = open API);
agent key auth untouched; README/.env.example updated
- SVG logo + favicon (monitor with pulse, kit-style)
- reactivity: dashboard poll 5s, server 5s, history 10s
- layout: metric cards full-row flex, metric value nowrap,
info/note 50/50 grid, topbar logo 48x48, server card max-width 420px,
uptime on its own line, delete confirmed via GnConfirmDialog
- docker: ca-certificates for npm git dependency
Co-Authored-By: Claude Code <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
25 days ago
|
feat: stage 3 — Vue web UI (dashboard, server page, charts) + docker build
...
Frontend (Vue 3 + Vite, gnexus-ui-kit, chart.js):
- login by admin token (localStorage, Bearer)
- dashboard: server cards with status, CPU/RAM/disk progress, net MB/s, note
- server page: metric cards, info (hostname/os/kernel/ips), editable note,
history charts (1ч/6ч/24ч/7д), tabs: overview/disks/net/processes/docker
- create-server flow with one-time key display + install command
Backend: serve built SPA from panel/backend/static (assets mount + fallback)
Docker: multi-stage build (node:22 → npm ci/build → static into python image),
build context moved to repo root, .dockerignore added
Co-Authored-By: Claude Code <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
25 days ago
|
feat: stage 1 — panel skeleton (FastAPI + SQLite) and ingest API
...
- FastAPI backend: config (pydantic-settings, GHARD_* env), aiosqlite + WAL
- SQLite schema: servers, metrics, events
- POST /api/v1/ingest: auth by X-Server-Key (sha256 hash), net rates in MB/s
computed on panel from raw counter deltas, server card upsert
- Servers API: create (key shown once), list with dashboard summary,
detail, PATCH name/note, delete, metrics history
- Dockerfile + docker-compose with persistent volume
Co-Authored-By: Claude Code <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
25 days ago
|