-- GHard Monitor: схема SQLite.
-- Время — UTC ISO-8601 (строки, лексикографически сортируются корректно).
CREATE TABLE IF NOT EXISTS servers (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL, -- отображаемое имя, задаётся в UI
hostname TEXT NOT NULL DEFAULT '', -- как назвался агент
os TEXT NOT NULL DEFAULT '',
kernel TEXT NOT NULL DEFAULT '',
ips_json TEXT NOT NULL DEFAULT '[]', -- адреса интерфейсов из пакета агента
source_ip TEXT NOT NULL DEFAULT '', -- адрес входящего соединения
note TEXT NOT NULL DEFAULT '', -- заметка: одна на сервер, edit в UI
key_hash TEXT NOT NULL UNIQUE, -- sha256 ключа агента (plaintext нигде не храним)
interval INTEGER NOT NULL DEFAULT 30, -- интервал агента, сек (для детекта offline)
created_at TEXT NOT NULL,
last_seen TEXT -- время последнего ingest (по часам panel)
);
CREATE TABLE IF NOT EXISTS metrics (
id INTEGER PRIMARY KEY AUTOINCREMENT,
server_id INTEGER NOT NULL REFERENCES servers(id) ON DELETE CASCADE,
ts TEXT NOT NULL, -- timestamp пакета (агент или panel)
cpu REAL NOT NULL DEFAULT 0, -- cpu, %
load1 REAL NOT NULL DEFAULT 0,
load5 REAL NOT NULL DEFAULT 0,
load15 REAL NOT NULL DEFAULT 0,
ram_used INTEGER NOT NULL DEFAULT 0,
ram_total INTEGER NOT NULL DEFAULT 0,
swap_used INTEGER NOT NULL DEFAULT 0,
swap_total INTEGER NOT NULL DEFAULT 0,
uptime INTEGER NOT NULL DEFAULT 0, -- сек
net_in_mbs REAL NOT NULL DEFAULT 0, -- суммарный вход, МБ/с (panel считает по дельте)
net_out_mbs REAL NOT NULL DEFAULT 0, -- суммарный выход, МБ/с
disks_json TEXT NOT NULL DEFAULT '[]',
net_json TEXT NOT NULL DEFAULT '[]', -- сырые счётчики интерфейсов — для следующей дельты
processes_json TEXT NOT NULL DEFAULT '[]',
docker_json TEXT NOT NULL DEFAULT '[]',
extra_json TEXT NOT NULL DEFAULT '{}' -- temps, smart и прочее, что panel пока не разбирает
);
CREATE INDEX IF NOT EXISTS idx_metrics_server_ts ON metrics(server_id, ts);
CREATE TABLE IF NOT EXISTS events (
id INTEGER PRIMARY KEY AUTOINCREMENT,
server_id INTEGER REFERENCES servers(id) ON DELETE CASCADE,
type TEXT NOT NULL, -- cpu_high, server_offline, disk_added, ...
severity TEXT NOT NULL DEFAULT 'info', -- info | warning | critical
message TEXT NOT NULL,
data_json TEXT NOT NULL DEFAULT '{}',
ts TEXT NOT NULL,
acknowledged INTEGER NOT NULL DEFAULT 0
);
CREATE INDEX IF NOT EXISTS idx_events_server_ts ON events(server_id, ts);
-- Сетевые хранилища: шард-пути, примонтированные к машине с hard-panel.
-- Панель сама опрашивает их os.statvfs (share_samples.ok=0 — путь недоступен).
CREATE TABLE IF NOT EXISTS shares (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
path TEXT NOT NULL,
created_at TEXT NOT NULL
);
CREATE TABLE IF NOT EXISTS share_samples (
id INTEGER PRIMARY KEY AUTOINCREMENT,
share_id INTEGER NOT NULL REFERENCES shares(id) ON DELETE CASCADE,
ts TEXT NOT NULL,
total INTEGER NOT NULL DEFAULT 0, -- байты (statvfs f_blocks * f_frsize)
used INTEGER NOT NULL DEFAULT 0, -- байты (total - f_bfree)
ok INTEGER NOT NULL DEFAULT 1 -- 1 = путь примонтирован и читается
);
CREATE INDEX IF NOT EXISTS idx_share_samples_share_ts ON share_samples(share_id, ts);
-- Health-чеки внешних сервисов (панель сама опрашивает их /health).
-- Формат отклика не договорён — прогрессивный минимум:
-- 2xx → up; тело-JSON с строковым status: ok-набор → up,
-- degraded-набор → degraded, всё прочее → down;
-- не-2xx/таймаут/отказ → down (точка всё равно пишется).
CREATE TABLE IF NOT EXISTS services (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
url TEXT NOT NULL, -- полный health URL сервиса
created_at TEXT NOT NULL
);
CREATE TABLE IF NOT EXISTS service_samples (
id INTEGER PRIMARY KEY AUTOINCREMENT,
service_id INTEGER NOT NULL REFERENCES services(id) ON DELETE CASCADE,
ts TEXT NOT NULL,
state TEXT NOT NULL DEFAULT 'down', -- up | degraded | down
code INTEGER, -- HTTP-код; NULL = сеть/таймаут/DNS
latency_ms REAL NOT NULL DEFAULT 0,
message TEXT NOT NULL DEFAULT '', -- status из тела или текст сетевой ошибки
report TEXT -- самосвидетельство (JSON §5 спеки; NULL = нет)
);
CREATE INDEX IF NOT EXISTS idx_service_samples_service_ts ON service_samples(service_id, ts);
-- Незавершённые OAuth-потоки gnexus-auth (state → pkce_verifier, 10 минут)
CREATE TABLE IF NOT EXISTS oauth_states (
state TEXT PRIMARY KEY,
pkce_verifier TEXT NOT NULL,
return_to TEXT NOT NULL DEFAULT '/',
expires_at TEXT NOT NULL
);
-- Браузерные сессии gnexus-auth (cookie ↔ профиль; TTL по expires_at)
CREATE TABLE IF NOT EXISTS sessions (
id TEXT PRIMARY KEY,
user_id TEXT NOT NULL,
email TEXT NOT NULL,
display_name TEXT NOT NULL DEFAULT '',
avatar_url TEXT NOT NULL DEFAULT '',
expires_at TEXT NOT NULL,
created_at TEXT NOT NULL
);
CREATE INDEX IF NOT EXISTS idx_sessions_user_id ON sessions(user_id);
-- Пользователи gnexus-auth: пер-сервисные настройки панели.
-- profile = словарь профиля verbatim (язык аккаунта — profile.locale);
-- locale = override из настроек панели (NULL = следовать аккаунту).
-- Профиль живёт отдельно от сессий: сессии истекают/удаляются, настройка — нет.
CREATE TABLE IF NOT EXISTS users (
user_id TEXT PRIMARY KEY, -- sub из gnexus-auth (= sessions.user_id)
email TEXT NOT NULL,
display_name TEXT NOT NULL DEFAULT '',
profile TEXT NOT NULL DEFAULT '{}', -- JSON профиля gnexus-auth verbatim
locale TEXT, -- override 'en'|'uk'|'ru'; NULL = авто
created_at TEXT NOT NULL,
updated_at TEXT NOT NULL
);