Netpulse_SasS/ROADMAP.md
byrsapty ee3f653bd8 Каталог команд збору конфігу як власні дані
Команди для зчитування конфігу тепер живуть у db/profiles/catalog.json —
147 платформ, 67 вендорів. Міграція з нього породжується збіркою:
два описи одного й того самого розійшлися б із першою ж правкою, і
невідомо було б, який справжній. build.py --check звіряє, чи міграція
не відстала.

Каталог — код, а не дані клієнта: однаковий для всіх інсталяцій,
переглядається в code review, їде з релізом. Тенант при цьому може
завести власний профіль через tenant_id — вбудовані лишаються
недоторканими.

Промпт і вимкнення пейджера тримаються раз на родину CLI, а не в
кожному профілі: bdcom, arista, brocade і ще з десяток говорять
діалектом Cisco, h3c і 3com — діалектом Huawei. Це різниця між правкою
в одному місці й правкою в сорока.

Прибрано разовий імпортер db/import разом із його залежністю від
зовнішнього формату. Слово NOC лишилось тільки там, де воно означає
центр керування мережею (NOC-екран, NOC TV) — це термін із ТЗ.

Лічильники в шапці міграції обчислюються: зашите «148 платформ»
розійшлося зі згенерованими 147 одразу.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-24 02:46:23 +03:00

19 KiB
Raw Blame History

NetPulse — план робіт

Документ доповнює HISTORY.md: той описує зроблене, цей — що лишилось і чому саме в такому порядку.

Де ми зараз

Працює наскрізний ланцюг кабель → браузер: зонд знаходить сусідів по LLDP/CDP/ARP, сервер зводить їх у topo.links, сам заводить чеки на трафік, API віддає готове полотно з живими статусами, редактор пише назад із контролем конфліктів і відкатом.

Перевірено на живому стенді проти справжнього snmpd. Деталі — в README кожного компонента.

Чого немає: чесний зріз

Схема БД з Етапу 1 покриває майже все з технічного завдання, але схема ≠ реалізація. Нижче — розрив між ними.

Підсистема Схема Реалізація
Мапа, топологія, телеметрія
Автовиявлення LLDP/CDP/ARP/FDB
Користувачі, ролі, вхід
Шаблони опитування
NCM (збір конфігів) ⚠️ half
Керування зондом із UI ⚠️ транспорт є
Алерти й сповіщення
Мобільна адаптивність, PWA ⚠️ адаптив є, PWA немає
Веб-інтерфейс (навігація, сторінки)
Дашборди, NOC TV
Білінг, ліцензії

Етап 5. Веб із користувачами і правами — зроблено 2026-08-15

Реалізовано: вхід, JWT + ротація refresh-сесій, RBAC на всіх ендпоїнтах, netpulse-user для першого власника, сторінка входу, приховування дій без права, мобільний адаптив. Подробиці — HISTORY.md, контракт — server/API.md.

Доповнено 2026-08-15: повноцінний веб — навігація й вісім сторінок (мапа, пристрої, алерти, правила, канали, зонди, команда, профіль), примітиви UI з мобільними картками замість таблиць, захист маршрутів правами.

Відкладено з цього етапу: TOTP (totp_secret_enc є в схемі, коду немає), запрошення поштою (core.invitations порожня — користувача заводять із паролем одразу), кастомні ролі (POST /api/v1/roles), фільтр за memberships.scope_group_ids, редагування умови правила (лише створення й вимкнення), маршрути сповіщень і вікна обслуговування в UI.

Навіщо перше. Зараз API автентифікує лише машинні токени (core.api_tokens). Людина увійти не може, а core.roles / permissions / memberships лежать порожні. Без цього не можна ані впустити клієнта, ані розмежувати доступ між інженером і глядачем — тобто продукт неможливо продати навіть одній команді.

Сервер

POST   /api/v1/auth/login          email + пароль → access (JWT, 15 хв) + refresh
POST   /api/v1/auth/refresh        обмін refresh-токена
POST   /api/v1/auth/logout         відкликання сесії
GET    /api/v1/me                  профіль + ефективні права
POST   /api/v1/auth/totp/enroll    двофакторка (поле totp_secret_enc уже є)

GET    /api/v1/users               керування командою
POST   /api/v1/users/invite        запрошення (core.invitations уже є)
PATCH  /api/v1/users/{id}          зміна ролі, скоупу груп
GET    /api/v1/roles               системні + кастомні (Enterprise)
POST   /api/v1/roles               кастомна роль із набором прав

Паролі — argon2id, не bcrypt: він стійкіший до GPU-перебору, а password_hash у схемі вже text і формат не диктує.

Refresh-токен зберігається як sha256 у core.sessions — так само, як агентські. Витік дампа БД не дає жодної живої сесії.

RBAC замінює перевірку scopes. Зараз обробники питають tok.Can("maps:write"). Стане: посередник резолвить memberships → roles → role_permissions у набір прав і кладе в контекст; машинні токени лишаються, але їхні scopes перетинаються з правами власника. Скоуп груп (memberships.scope_group_ids) фільтрує вибірки пристроїв — це вже не middleware, а предикат у запитах store.

Фронтенд

Сторінка входу, зберігання refresh у httpOnly-cookie, сторінки «Команда» й «Ролі», приховування дій без права (кнопка, яка завжди дає 403, гірша за її відсутність).

Обсяг: ~23 дні. Ризиків мало: схема готова, візерунок автентифікації в проєкті вже відпрацьований на агентських токенах.


Етап 6. Шаблони опитування (Zabbix-подібні)

Найбільша нова підсистема. Зараз snmp.if-чеки народжує захардкоджений autochecks.go. Це працює рівно для одного випадку — інтерфейсів. Щойно знадобиться CPU Cisco, температура MikroTik чи ємність UPS, доведеться дописувати Go-код під кожен вендор. Шаблони роблять це даними.

Нова схема: tpl

tpl.templates          -- key, name, vendor, is_builtin, tenant_id NULL = вбудований
tpl.template_links     -- успадкування шаблон → шаблон
tpl.macros             -- {$SNMP_COMMUNITY}, три рівні: глобальний → шаблон → пристрій
tpl.items              -- один OID → одна метрика: key, check_type, params, interval,
                       -- units, value_type, preprocessing, metric_key
tpl.discovery_rules    -- LLD: walk по таблиці (ifTable, entPhysicalTable, dot1dBase)
tpl.item_prototypes    -- прототипи з {#IFNAME}, {#SNMPINDEX}
tpl.trigger_prototypes -- пороги, що народжують alr.rules
inv.device_templates   -- прив'язка шаблон → пристрій
inv.group_templates    -- прив'язка шаблон → динамічна група

Рішення, які треба зафіксувати одразу

Шаблон — декларація, core.checks — матеріалізація. Агент не має знати про шаблони взагалі: він і далі отримує плаский план задач. Сервер реконсилює шаблони × пристрої × LLD → core.checks при кожній зміні шаблону, складу групи або результату виявлення. Це зберігає контракт агента незмінним і дозволяє міняти шаблони без оновлення зондів у полі.

Low-level discovery — це той самий snmp.walk, результат якого йде не в метрики, а в реконсиляцію. Тобто autochecks.go узагальнюється: замість «знайшов інтерфейси → створив snmp.if» стане «правило виявлення повернуло рядки → застосував прототипи → створив items».

Препроцесинг ділиться між агентом і сервером. Дельта лічильника (change per second) лишається на агенті: лише він знає фактичний інтервал між двома опитуваннями — це вже реалізовано й перевірено. Решта (множник, регулярка, JSONPath, discard unchanged) — на сервері при записі: інакше кожна зміна правила вимагала б оновлення агентів.

Макроси розшифровуються на сервері й доїжджають до агента вже підставленими, разом із креденшелами. Секретні макроси ({$SNMP_COMMUNITY}) лягають у core.secrets тим самим механізмом, що й паролі.

Готова база шаблонів

Формат tpl.* варто спроєктувати так, щоб він приймав Zabbix-експорт (YAML/JSON з items, discovery rules, prototypes, macros): його структура майже один-до-одного лягає на запропоновану схему, а публічних шаблонів там сотні. Це знімає потребу набивати базу вручну.

Команди збору конфігу вже є власним каталогом — db/profiles/catalog.json, 147 платформ. Шаблони опитування SNMP — окрема задача, і базу для них варто починати саме з імпортера, а не з ручного наповнення.

Обсяг: ~57 днів на схему + реконсиляцію + імпортер + UI редактора шаблонів.


Етап 7. NCM — збір конфігів до кінця

Половина шляху вже є: ncm.* у схемі, ConfigJob/ConfigUpload у контракті, сервер приймає чанки, звіряє sha256, дедуплікує за content_hash і шифрує тіло. Бракує трьох частин.

Модуль ncm на агенті. SSH через golang.org/x/crypto/ssh, Telnet своїм кодом (протокол тривіальний). Виконує команди з профілю, ловить prompt за регуляркою, віддає сирий текст чанками. Для bdcom-olt і mikrotik-routeros профілі вже в сіді — вони й стануть першими підопічними.

Планувальник на сервері. Cron із ncm.device_policies.cron плюс тригер за Syslog-подією (on_syslog, %SYS-5-CONFIG_I) — обидва поля в схемі є, читати їх нікому. Видає ConfigJob у живу сесію зонда.

Git-двигун. go-git замість libgit2 — чистий Go, без cgo, що зберігає статичний бінарник без залежностей. Комітить у refs/heads/device/<id>, віддає diff між ревізіями. Зараз commit_sha тимчасово містить hex контентного хеша, і міняти доведеться лише джерело цього поля.

UI: список версій, side-by-side diff, кнопка відкату (сутність ncm.rollbacks із двоетапним погодженням уже є).

Обсяг: ~45 днів.


Етап 8. Керування зондом із UI

Транспорт готовий повністю: сервер уже вміє штовхати ModuleControl (які модулі вмикати), TaskDelta (що опитувати), ліміти в Welcome (паралельність, розмір батчу, темп ICMP) і Directive (пауза, перезавантаження конфігу, оновлення). Бракує того, що це все вмикає.

POST   /api/v1/agents                створити зонд + одноразовий enrollment-токен
PATCH  /api/v1/agents/{id}           ліміти, дозволені модулі, сайт
POST   /api/v1/agents/{id}/discover  запустити автовиявлення зараз (TriggerNow уже є)
DELETE /api/v1/agents/{id}

EnrollmentService — реалізувати серверну сторону: зонд приходить із одноразовим токеном і CSR, іде з підписаним сертифікатом. Контракт написано ще на Етапі 2, реалізації немає. Без цього зонди заводяться INSERTом, що прийнятно на стенді й неприйнятно у клієнта.

UI: сторінка зонда з самометриками (ts.agent_health уже наповнюється), повзунки лімітів, перемикачі модулів, кнопка «запустити виявлення», інструкція встановлення з готовою командою й токеном.

Обсяг: ~23 дні.


Етап 9. Алерти й сповіщення — зроблено 2026-08-15

Реалізовано: движок правил (icmp/interface/metric/no_data), антифлап вікном, кореляція за топологією, вікна обслуговування й ручне заглушення, маршрути з тихими годинами, доставка в Telegram/webhook/ SMTP, панель алертів у UI. Подробиці — HISTORY.md, контракт — server/API.md.

Відкладено з цього етапу: ескалації й повторні сповіщення, приймач кнопок Telegram (callback_data), Web Push (іде з Етапом 10), правила з джерел syslog/trap/ncm/compliance.

Те, без чого це не моніторинг. Система малює мапу, але мовчить, коли щось падає. Схема готова з Етапу 1 (alr.rules, alerts, channels, routes, escalation_policies, maintenance_windows, mutes) і повністю порожня.

Дані вже течуть: зміни статусу йдуть через core.event_outbox, метрики лежать у TSDB, пороги описані в map_edges.thresholds.

Движок правил читає ts.icmp_samples, ts.if_counters і ts.samples_5m, застосовує for_seconds (антифлап) і пише в alr.alerts. Дедуплікацію вже гарантує унікальний індекс alerts_active_dedup_uniq.

Кореляція за топологією — та, заради якої будувалась topo.links: коли падає маршрутизатор, 40 пристроїв за ним не мають дати 40 сповіщень. Поля root_alert_id і depends_on_topology для цього вже є.

Канали: Telegram (бот + Mini App із кнопками Ack/Mute), Web Push, email, webhook. alr.push_subscriptions у схемі готова.

Обсяг: ~45 днів.


Етап 10. Мобільна адаптивність і PWA

Зараз UI розрахований лише на десктоп: фіксований сайдбар 240 px, шапка з десятком елементів в один рядок, жодного брейкпойнта, полотно без тач-жестів.

Адаптив: сайдбар у висувну панель під md, шапка в дві смуги, цілі дотику не менше 44 px, інспектор вузла — нижнім аркушем замість бічної колонки.

Полотно на дотик: React Flow вміє pinch-zoom і pan, але перетягування вузла пальцем конфліктує з панорамуванням — потрібен явний режим «редагування», інакше кожна спроба посунути карту рухатиме вузол.

PWA: manifest, service worker (кеш оболонки, не даних — застаріла мапа гірша за її відсутність), Web Push через alr.push_subscriptions.

Telegram Mini App: перегляд мапи й алертів, кнопки Ack / Mute / View Diffусе з ТЗ.

Обсяг: ~34 дні на адаптив + PWA, Mini App окремо.


Порядок і чому саме такий

  1. Етап 5 (користувачі) — без входу продукт не можна віддати нікому.
  2. Етап 9 (алерти) — без сповіщень це не моніторинг.
  3. Етап 6 (шаблони) — знімає потребу дописувати Go під кожен вендор; що раніше, то менше захардкодженого коду доведеться викидати.
  4. Етап 8 (керування зондом) — дешевий і робить онбординг можливим.
  5. Етап 7 (NCM) — головний аргумент Enterprise-тарифу.
  6. Етап 10 (мобільний) — після того, як є що показувати.

Далі за ТЗ лишаються дашборди з NOC TV-режимом, білінг зі Stripe і ліцензійні ключі — усі три мають готову схему й жодного коду.

Дрібний борг

  • Повторне малювання зв'язку між тією ж парою вузлів дає загальне «такий запис уже існує» замість зрозумілого пояснення.
  • Перетягування вузла через UI не покрите автотестом: синтетичні події не запускають d3-drag у React Flow. Шлях перевірений тестами сервера.
  • Підкладки-плани приміщень віддаються API, але полотно їх не малює — потрібен прийом і роздача файлів (S3/MinIO або локальний диск).
  • Модулі http/ssl і modbus оголошені в сіді плагінів, але не написані.