План робіт: користувачі, шаблони опитування, NCM, керування зондом, мобільний
Зріз розриву між схемою й реалізацією: схема з Етапу 1 покриває майже все ТЗ, але користувачі/ролі, NCM на агенті й керування зондом із UI лишились без коду, а шаблонів опитування немає навіть у схемі. Ключове рішення для шаблонів: шаблон — декларація, core.checks — матеріалізація. Агент не знає про шаблони взагалі й далі отримує плаский план, тож їх можна міняти без оновлення зондів у полі. LLD — той самий snmp.walk, результат якого йде в реконсиляцію, а не в метрики. Препроцесинг ділиться: дельта лічильника лишається на агенті (лише він знає фактичний інтервал), решта — на сервері при записі. Формат tpl.* проєктується під імпорт Zabbix-експорту, щоб база з NOC project не була критичним шляхом: там профілі — Python-класи, а не декларативні описи. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
bee55be3d1
commit
ccaa9afcc4
2 changed files with 271 additions and 3 deletions
|
|
@ -584,6 +584,7 @@ web/src/hooks/useLiveMap.ts undo + canUndo
|
|||
|
||||
### Далі
|
||||
|
||||
- Підкладки-плани приміщень на полотні (потрібен прийом файлів).
|
||||
- Історія метрик для графіків.
|
||||
- `EnrollmentService` + видача сертифікатів зондам.
|
||||
План на наступні етапи винесено в окремий документ — [ROADMAP.md](ROADMAP.md).
|
||||
Коротко: користувачі й права (схема є, коду немає) → алерти → шаблони опитування
|
||||
(нова підсистема `tpl.*`) → керування зондом із UI → NCM до кінця → мобільний
|
||||
адаптив і PWA.
|
||||
|
|
|
|||
267
ROADMAP.md
Normal file
267
ROADMAP.md
Normal file
|
|
@ -0,0 +1,267 @@
|
|||
# NetPulse — план робіт
|
||||
|
||||
Документ доповнює [HISTORY.md](HISTORY.md): той описує зроблене, цей — що лишилось
|
||||
і чому саме в такому порядку.
|
||||
|
||||
## Де ми зараз
|
||||
|
||||
Працює наскрізний ланцюг **кабель → браузер**: зонд знаходить сусідів по
|
||||
LLDP/CDP/ARP, сервер зводить їх у `topo.links`, сам заводить чеки на трафік,
|
||||
API віддає готове полотно з живими статусами, редактор пише назад із контролем
|
||||
конфліктів і відкатом.
|
||||
|
||||
Перевірено на живому стенді проти справжнього `snmpd`. Деталі — в README кожного
|
||||
компонента.
|
||||
|
||||
## Чого немає: чесний зріз
|
||||
|
||||
Схема БД з Етапу 1 покриває майже все з технічного завдання, але **схема ≠
|
||||
реалізація**. Нижче — розрив між ними.
|
||||
|
||||
| Підсистема | Схема | Реалізація |
|
||||
|------------|-------|------------|
|
||||
| Мапа, топологія, телеметрія | ✅ | ✅ |
|
||||
| Автовиявлення LLDP/CDP/ARP/FDB | ✅ | ✅ |
|
||||
| **Користувачі, ролі, вхід** | ✅ | ❌ |
|
||||
| **Шаблони опитування** | ❌ | ❌ |
|
||||
| **NCM (збір конфігів)** | ✅ | ⚠️ half |
|
||||
| **Керування зондом із UI** | ✅ | ⚠️ транспорт є |
|
||||
| **Алерти й сповіщення** | ✅ | ❌ |
|
||||
| **Мобільна адаптивність, PWA** | — | ❌ |
|
||||
| Дашборди, NOC TV | ✅ | ❌ |
|
||||
| Білінг, ліцензії | ✅ | ❌ |
|
||||
|
||||
---
|
||||
|
||||
## Етап 5. Веб із користувачами і правами
|
||||
|
||||
**Навіщо перше.** Зараз 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, гірша за її відсутність).
|
||||
|
||||
**Обсяг:** ~2–3 дні. Ризиків мало: схема готова, візерунок автентифікації в
|
||||
проєкті вже відпрацьований на агентських токенах.
|
||||
|
||||
---
|
||||
|
||||
## Етап 6. Шаблони опитування (Zabbix-подібні)
|
||||
|
||||
**Найбільша нова підсистема.** Зараз `snmp.if`-чеки народжує захардкоджений
|
||||
`autochecks.go`. Це працює рівно для одного випадку — інтерфейсів. Щойно
|
||||
знадобиться CPU Cisco, температура MikroTik чи ємність UPS, доведеться дописувати
|
||||
Go-код під кожен вендор. Шаблони роблять це даними.
|
||||
|
||||
### Нова схема: `tpl`
|
||||
|
||||
```sql
|
||||
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` тим самим механізмом, що й паролі.
|
||||
|
||||
### Готова база шаблонів
|
||||
|
||||
Ти згадав, що візьмеш базу з **NOC project**. Це реалістично, але не безкоштовно:
|
||||
у NOC профілі — це Python-класи з методами розбору, а не декларативні YAML.
|
||||
Витягти з них набори OID і командні послідовності можна, але це окрема задача
|
||||
з непередбаченим обсягом.
|
||||
|
||||
**Пропоную страхуватись:** формат `tpl.*` спроєктувати так, щоб він приймав і
|
||||
**Zabbix-експорт** (YAML/JSON з items, discovery rules, prototypes, macros) —
|
||||
його структура майже один-до-одного лягає на запропоновану схему, а публічних
|
||||
шаблонів там сотні. Тоді імпортер із NOC стає бажаним, а не критичним шляхом.
|
||||
|
||||
**Обсяг:** ~5–7 днів на схему + реконсиляцію + імпортер + UI редактора шаблонів.
|
||||
Найбільший ризик — саме імпорт із NOC; його варто оцінити окремо, побачивши
|
||||
формат, який ти маєш.
|
||||
|
||||
---
|
||||
|
||||
## Етап 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` із двоетапним погодженням уже є).
|
||||
|
||||
**Обсяг:** ~4–5 днів.
|
||||
|
||||
---
|
||||
|
||||
## Етап 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` уже наповнюється),
|
||||
повзунки лімітів, перемикачі модулів, кнопка «запустити виявлення», інструкція
|
||||
встановлення з готовою командою й токеном.
|
||||
|
||||
**Обсяг:** ~2–3 дні.
|
||||
|
||||
---
|
||||
|
||||
## Етап 9. Алерти й сповіщення
|
||||
|
||||
**Те, без чого це не моніторинг.** Система малює мапу, але мовчить, коли щось
|
||||
падає. Схема готова з Етапу 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` у схемі готова.
|
||||
|
||||
**Обсяг:** ~4–5 днів.
|
||||
|
||||
---
|
||||
|
||||
## Етап 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* — усе з ТЗ.
|
||||
|
||||
**Обсяг:** ~3–4 дні на адаптив + PWA, Mini App окремо.
|
||||
|
||||
---
|
||||
|
||||
## Порядок і чому саме такий
|
||||
|
||||
1. **Етап 5 (користувачі)** — без входу продукт не можна віддати нікому.
|
||||
2. **Етап 9 (алерти)** — без сповіщень це не моніторинг. Можна поміняти місцями
|
||||
з п.1, якщо перший клієнт — ти сам.
|
||||
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` оголошені в сіді плагінів, але не написані.
|
||||
Loading…
Add table
Reference in a new issue