Files
router-lists-ui/AI_READY_DEVELOPMENT_SPEC.md
denozord e8ba6d47e3
Publish Docker image / build-and-push (push) Successful in 1m0s
Refactor project structure and improve component organization
- Restructured project files for better maintainability and clarity.
- Enhanced component organization to streamline imports and improve readability.
- Updated relevant documentation to reflect changes in project structure.

Made-with: Cursor
2026-04-26 15:26:04 +07:00

483 lines
32 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# AI-READY DEVELOPMENT SPEC
## 1. SYSTEM OVERVIEW (СИСТЕМНЫЙ КОНТЕКСТ)
Система `router-lists-ui` управляет сетевыми данными и конфигурациями RouterOS/MikroTik: домены, ASN, IP-диапазоны, фильтры, серверные конфиги, бэкапы и мониторинг доступности/ресурсов. UI (`React + Vite`) работает с API (`Express`) через `/api/*`.
Фактическая модель хранения гибридная:
- справочники BGP (domains/asns/ip-ranges/communities/auto-urls) обслуживаются через EvoBGP API (`evobgpClient`);
- локальные конфиги/кеш/версии хранятся в SQLite (`better-sqlite3`) через слой совместимости `s3Service`/`blobStorage`;
- `.rsc` backup MikroTik хранится в локальной ФС (`MIKROTIK_BACKUP_DIR`).
### Ключевые бизнес-процессы
- Управление BGP-справочниками (CRUD через EvoBGP).
- Управление фильтрами (`global/simple`) в `app_filter_rules`.
- Управление серверами, server-configs, server-filters.
- Генерация/применение MikroTik-конфигов и диагностические операции (ping/traceroute/speed-test).
- Планировщики: network-map, ping-services, uptime-monitor, backups.
- История/rollback для versioned blob-объектов.
### Основные сущности
- `DomainCommunity`: `{ domain, community }`
- `AsnCommunity`: `{ domain(asn), type(community) }`
- `IpRangeCommunity`: `{ ipRange, community }`
- `Server`: jumphost/exit + gateways + creds
- `FilterRule`: `{ community, gateway, description, ...extra }` + `scope`
- `BlobObject`: logical key + body + etag + versions
- `UiSettings`
- `MikrotikBackup`
### Критические ограничения (НЕ НАРУШАТЬ)
- Нельзя заменять EvoBGP-данные локальной SQLite-логикой для `domains-new/asns/ip-ranges/communities/auto-urls`.
- Нельзя удалять/ломать ETag-конкурентность (`If-None-Match`, `If-Match`, `412`) в read/write API.
- Нельзя ломать namespace/ключи blob-объектов (`servers.json`, `filter-manager/*`, `bgp_data/rt_ui_settings.json` и т.д.) без миграционного плана.
- Нельзя отключать `journal_mode=WAL`, `foreign_keys=ON`, `busy_timeout`.
- Нельзя менять формат ответа ошибок `{ code, message, details, requestId }`.
---
## 2. REPOSITORY MAP (КАРТА РЕПОЗИТОРИЯ)
> Примечание: в текущем репозитории нет отдельных top-level директорий `/db`, `/services`, `/api`, `/agents`; их роль реализована внутри `backend/`.
### `/frontend`
- Назначение: UI-приложение (`React 19`, `react-router-dom`, `@tanstack/react-query`, `axios`, Tabler).
- Ключевые зоны:
- `src/App.jsx`: роутинг, layout, providers (`QueryClientProvider`, `NotifyProvider`, `PingProvider`, `AlertsProvider`).
- `src/lib/api.js`: единый HTTP-клиент, retry, ETag-based GET-cache, нормализация ошибок.
- `src/hooks/useApiQuery.js`: реактивный data-layer + optimistic updates.
- Правила изменений:
- Любой новый экран регистрировать в `App.jsx` routes + navigation.
- Новые API-вызовы делать только через `src/lib/api.js`.
- Мутации должны инвалидацировать/обновлять react-query cache.
- Зависимости: backend `/api`, browser localStorage (theme/lang/layout), глобальный notifier.
### `/backend`
- Назначение: API, интеграции, storage abstraction, schedulers.
- Ключевые зоны:
- `server.js`: composition root, middleware, endpoint registration.
- `routes/*.js`: endpoint-level orchestration.
- `services/*.js`: storage/EvoBGP/MikroTik/scheduler логика.
- `db/sqliteDb.js` + `db/migrations/*.sql`: DB init/migrations.
- `middleware/*`: unified errors + soft locks.
- Правила изменений:
- Новый endpoint добавлять через route/service, не встраивать бизнес-логику в `server.js`.
- Для persistent данных использовать `s3Service`/`filterRulesStorage`/`backupFsService` по назначению.
- Сохранять совместимость legacy-имен (`s3*`) пока фронт/интеграции их используют.
- Зависимости: SQLite, EvoBGP HTTP API, локальная ФС для backups, env-конфиг.
### `/backend/db` (внутренний `/db`)
- Назначение: схема и поведение SQLite.
- Состав:
- `migrations/001_init.sql`: blobs/meta/cache/versioning.
- `migrations/002_filter_rules.sql`: `app_filter_rules`.
- Правила изменений:
- Только миграциями; прямые ручные правки существующих таблиц запрещены.
- Миграции должны быть backward-compatible и idempotent.
### `/backend/services` (внутренний `/services`)
- Назначение: слой бизнес-операций и инфраструктурных адаптеров.
- Ключевые модули:
- `evobgpClient.js` (внешний источник правды для BGP reference).
- `s3Service.js` + `blobStorage.js` (SQLite-backed blob API).
- `filterRulesStorage.js` (SQL-таблица фильтров).
- `mikrotik*`, `*Scheduler.js` (операции и периодические задачи).
- Правила изменений:
- Не смешивать transport-логику endpoint с data-access.
- Любая write-операция должна возвращать meta для `sendOk`.
### `/backend/routes` (внутренний `/api`)
- Назначение: HTTP contracts + валидация входа + orchestrator.
- Правила изменений:
- Вход валидируется до вызова сервиса.
- Ошибки наружу только через `sendError`.
- ETag/Last-Modified сохранять в GET/POST где уже реализовано.
### `/agents`
- В репозитории отсутствует.
---
## 3. ARCHITECTURE RULES (АРХИТЕКТУРНЫЕ ПРАВИЛА)
### Слои и границы
- DO: `Route -> Service -> Storage/External API`.
- DO: хранить валидацию запроса на route-слое, а доменную обработку в service.
- DON'T: вызывать SQLite напрямую из UI.
- DON'T: переносить доменную логику в `server.js`.
### Бизнес-логика
- DO: для filters использовать только `filterRulesStorage` (`app_filter_rules`).
- DO: для BGP-reference использовать только `evobgpClient`.
- DON'T: писать domains/asns/ip-ranges в `blobs`.
### State management (frontend)
- DO: network-state через React Query.
- DO: optimistic updates + rollback на error.
- DO: invalidation query keys после мутаций.
- DON'T: дублировать fetch/caching logic вне `api.js`/`useApiQuery.js`.
### Доступ к БД
- DO: через `s3Service`/`blobStorage`/`filterRulesStorage`.
- DO: учитывать `etag`, `lastModified`, `contentLength`.
- DON'T: менять ключевые `object_key` без миграции и impact map.
### Изменения высокой опасности
- Запрещено менять без полной цепочки рефакторинга:
- форматы payload для `/api/domains-new`, `/api/asns`, `/api/ip-ranges`;
- schema ключей blob-хранилища;
- `sendOk/sendError` формат;
- scheduler settings endpoints и их JSON-структуры;
- semantics `server-configs` (только jumphost в листинге).
---
## 4. BUSINESS LOGIC SPECIFICATION
### 4.1 Процесс: BGP Reference Sync (domains/asns/ip-ranges)
- Inputs: HTTP GET/POST, EvoBGP env (`EVOBGP_API_URL`, `EVOBGP_API_TOKEN`), payload массив.
- Outputs: данные справочников + `sendOk` metadata.
- States:
- `IDLE` -> `VALIDATE_INPUT` -> `CALL_EVOBGP` -> `NORMALIZE` -> `RESPOND_OK`
- ветка ошибки: `VALIDATE_INPUT -> RESPOND_400` или `CALL_EVOBGP -> RESPOND_5XX`.
- Errors: `E_BAD_REQUEST`, `E_SCHEMA`, `E_EVOBGP`, `E_EVOBGP_NOT_CONFIGURED`.
- Side effects: запись в EvoBGP, обновление remote reference set.
### 4.2 Процесс: Filter Rules Replace (`global/simple`)
- Inputs: `scope`, массив правил `{community,gateway,...}`.
- Outputs: новый snapshot правил + meta (`etag/lastModified`).
- States:
- `READ_SCOPE_META` -> `VALIDATE_ARRAY` -> `TX_BEGIN` -> `DELETE_SCOPE_ROWS` -> `INSERT_ROWS_ORDERED` -> `UPDATE_META_MTIME` -> `TX_COMMIT` -> `RESPOND_OK`
- rollback: `TX_BEGIN -> ERROR -> TX_ROLLBACK`.
- Errors: `E_BAD_REQUEST`, `E_SCHEMA`, `E_STORAGE`.
- Side effects: перезапись всех правил scope (full replace).
### 4.3 Процесс: Blob Object Write (legacy s3Service API)
- Inputs: `object_key`, `content`.
- Outputs: `sendOk(meta)`.
- States:
- `VALIDATE_KEY` -> `READ_EXISTING` -> `IF_VERSIONED_SAVE_OLD_VERSION` -> `UPSERT_BLOB` -> `TRIM_VERSIONS` -> `INVALIDATE_MEMORY_CACHE` -> `RESPOND_OK`.
- Errors: `E_STORAGE`.
- Side effects: изменение `blobs`, опционально `blob_versions`.
### 4.4 Процесс: Server Config Management
- Inputs: `serverId`, config text / filters json.
- Outputs: per-server config/filter data.
- States:
- `VALIDATE_SERVER_ID` -> `READ_OR_WRITE_BLOB_KEY` -> `RESPOND`.
- Для `/api/server-configs` list: `READ_SERVERS` -> `FILTER_JUMPHOST` -> `MAP_ID_NAME` -> `RESPOND`.
- Errors: `E_BAD_REQUEST`, `E_SCHEMA`, `E_S3/E_STORAGE`.
- Side effects: запись в `filter-manager/config-*.txt` и `filter-manager/server-filters-*.json`.
### 4.5 Процесс: Auto URLs Ingestion
- Inputs: список URL + community.
- Outputs: summary counters.
- States:
- `LOAD_URLS` -> `FETCH_CONTENT` -> `PARSE_LINES` -> `CLASSIFY(IP/CIDR/DOMAIN)` -> `DEDUP_WITH_CURRENT` -> `SAVE_TO_EVOBGP` -> `RESPOND`.
- Errors: `E_BAD_REQUEST`, `E_EVOBGP`.
- Side effects: расширение списков IP/domains в EvoBGP.
### 4.6 Процесс: Ping Services Cache Refresh
- Inputs: UI settings (`pingServicesSource`, cache TTL), services list.
- Outputs: `{ byId, history }`.
- States:
- `LOAD_UI_SETTINGS` -> (`ROUTER_MODE` | `WEB_MODE`) -> `MEASURE_RTT` -> `WRITE_CACHE` -> `APPEND_HISTORY` -> `RESPOND`.
- Errors: fallback на `ms: null` payload при деградации.
- Side effects: запись в blob-ключи `ping-services/cache_*`, `ping-services/history_*`.
### 4.7 Процесс: History Rollback
- Inputs: `resource`, `versionId`.
- Outputs: `sendOk(meta)` после rollback.
- States:
- `MAP_RESOURCE_TO_KEY` -> `VALIDATE_SUPPORT` -> `ROLLBACK_VERSION` -> `RESPOND`.
- Errors: `E_RESOURCE`, `E_HISTORY_EV`, `E_HISTORY_FILTERS_SQL`, `E_STORAGE`.
- Side effects: восстановление blob из `blob_versions`.
---
## 5. API CONTRACTS (ФОРМАЛЬНЫЕ КОНТРАКТЫ)
### 5.1 Глобальные правила API
- Base path: `/api`.
- Auth level: явной auth-схемы нет (network-level trust, rate-limit, CORS, security headers).
- Success write format: `{ ok, etag, lastModified, contentLength }`.
- Error format: `{ code, message, details, requestId }`.
- Конкурентность: `If-None-Match` для GET, `If-Match`/`etag` для отдельных write.
### 5.2 Контракты endpoint’ов
| Route | Method | Auth | Input schema (JSON) | Output schema | Side effects | Таблицы/ключи | Сервисы |
|---|---|---|---|---|---|---|---|
| `/health` | GET | public | - | `{ok:true}` | none | - | - |
| `/ready` | GET | public | - | `{ok:true}` | none | - | - |
| `/metrics` | GET | internal | - | Prometheus text | none | - | prom-client |
| `/api/version` | GET | public | - | `{version,gitSha,buildAt}` | none | - | env |
| `/api/domains` | GET/POST | public | POST: `{domains:[{domain,type}],etag?}` | GET std/raw list, POST `sendOk` | remote write/read | EvoBGP | evobgpClient |
| `/api/asns` | GET/POST | public | POST: `{domains:[{domain,type}],etag?}` | GET/POST аналогично | remote write/read | EvoBGP | evobgpClient |
| `/api/domains-new` | GET/POST | public | POST: `{domains:[{domain,community}],etag?}` | GET/POST аналогично | remote write/read | EvoBGP | evobgpClient |
| `/api/ip-ranges` | GET/POST | public | POST: `{ipRanges:[{ipRange,community}],etag?}` | GET/POST аналогично | remote write/read | EvoBGP | evobgpClient |
| `/api/servers` | GET/POST | public | POST: `{servers:[...],etag?}` | JSON list / `sendOk` | persist servers | `blobs:servers.json` | serversRoutes,s3Service |
| `/api/server-connections` | GET/POST | public | POST: `{domains:[{from,to,tunnelType,...}]}` | list / `sendOk` | persist graph links | blob key `server-connections.json` | jsonDataRoutes |
| `/api/billing` | GET/POST | public | POST: `{items:[...],etag?}` (route expects `domains` in factory; adapters normalize) | list / `sendOk` | persist billing | blob key `servers-billing.json` | jsonDataRoutes |
| `/api/filters` | GET/POST | public | POST: `{domains:[{community,gateway,...}]}` | list / `sendOk` | replace scope rules | `app_filter_rules(scope=global)` | filterRulesStorage |
| `/api/simple-filters` | GET/POST | public | POST: `{domains:[{community,gateway,...}]}` | list / `sendOk` | replace scope rules | `app_filter_rules(scope=simple)` | filterRulesStorage |
| `/api/network-config` | GET/POST | public | POST: `{domains:{gateways?,tunnelInterfaces?,ipPools?}}` | object / `sendOk` | persist network config | blob key `network-config.json` | jsonDataRoutes |
| `/api/communities` | GET/POST | public | POST: `{communities:[{value,name?,...}]}` | list / `sendOk` | EvoBGP write | EvoBGP | communitiesRoutes |
| `/api/communities/stats` | GET | public | - | `{stats:[{community,count}],total}` | none | EvoBGP + `app_filter_rules` | communitiesRoutes |
| `/api/filters/generate-config` | GET | public | query params | generated config | none/write temp | derived blobs | filtersRoutes |
| `/api/filters/export-config` | POST | public | export params | file/content json | write export | derived blobs/fs | filtersRoutes |
| `/api/server-filters/generate-config` | POST | public | `{serverId,...}` | generated config | none | per-server blobs | filtersRoutes |
| `/api/server-configs` | GET/POST | public | POST: `{servers:[jumphost...]}` | jumphost list / `sendOk` | rewrite servers subset | `servers.json` | serverConfigsRoutes |
| `/api/server-configs/:serverId` | GET/POST/DELETE | public | POST: `{config:string}` | `{config}` / `sendOk` | write/delete server config | `filter-manager/config-<id>.txt` | serverConfigsRoutes |
| `/api/server-configs/:serverId/complete` | DELETE | public | - | `{ok:true,...}` | delete config+filters | `filter-manager/config-*`, `server-filters-*` | serverConfigsRoutes |
| `/api/server-filters/:serverId` | GET/POST | public | POST: `{filters:[{community,gateway,...}],etag?}` | `{filters}` / `sendOk` | write server filters | `filter-manager/server-filters-<id>.json` | serverConfigsRoutes |
| `/api/locks/:resource` | GET/POST/DELETE | public | POST:`{owner?,ttlSeconds?}` | lock status/result | in-memory lock mutate | RAM only | lockManager |
| `/api/history/:resource` | GET | public | query:`countOnly,format` | versions list | none | `blob_versions` | miscRoutes+s3Service |
| `/api/history/:resource/rollback` | POST | public | `{versionId}` | `sendOk` | rollback snapshot | `blobs`,`blob_versions` | miscRoutes+s3Service |
| `/api/s3/last-modified` | GET | public | - | map metas | none | blobs/filter_rules | miscRoutes |
| `/api/auto-urls` | GET/POST | public | POST:`{urls:[{url,community,...}]}` | list / `sendOk` | EvoBGP write | EvoBGP | miscRoutes |
| `/api/auto-urls/process` | POST | public | optional params | process summary | pulls URLs, writes lists | EvoBGP | miscRoutes |
| `/api/servers/availability` | GET | public | query:`ttlSeconds?` | `{online,total,statuses}` | refresh memory cache | RAM | miscRoutes |
| `/api/update-bgp/background` | POST | public (rate limited) | passthrough body | upstream response | outbound HTTP POST | - | miscRoutes |
| `/api/ws/url` | GET | public | - | `{url}` | none | `bgp_data/rt_ui_settings.json` | miscRoutes |
| `/api/ui-settings` | GET/POST | public | POST:`{settings,etag?}` | settings / `sendOk` | write ui settings | `bgp_data/rt_ui_settings.json` | miscRoutes |
| `/api/ping-services-list` | GET | public | - | `{list:[...]}` | none | ui settings | miscRoutes |
| `/api/ping-services` | GET | public | query:`refresh|nocache` | `{byId,history}` | cache+history writes | `ping-services/cache_*`,`history_*` | miscRoutes |
| `/api/ipsec-passwords` | GET/POST | public | POST DTO ipsec secret | list / item / `sendOk` | secret storage update | blobs/config | ipsecPasswordsRoutes |
| `/api/ipsec-passwords/:id` | GET/PUT/DELETE | public | PUT DTO | item / `sendOk` | update/delete secret | blobs/config | ipsecPasswordsRoutes |
| `/api/mikrotik/generate` | POST | public | generation payload | config text/json | none | derived | mikrotikConfigRoutes |
| `/api/mikrotik/generate-interfaces` | GET | public | query | generated config | none | derived | mikrotikConfigRoutes |
| `/api/mikrotik/generate-recursive-routes` | GET | public | query | generated config | none | derived | mikrotikConfigRoutes |
| `/api/mikrotik/test-connection` | POST | public | connection payload | test result | network probe | - | mikrotikConfigRoutes |
| `/api/mikrotik/ping` | GET/POST | public | POST:`{serverId,gateway,target,...}` | health/ping result | RouterOS ping | - | mikrotikConfigRoutes |
| `/api/mikrotik/traceroute` | POST | public | traceroute payload | trace result | RouterOS command | - | mikrotikConfigRoutes |
| `/api/mikrotik/speed-test` | POST | public | speed-test payload | throughput metrics | RouterOS command | speed cache blobs | mikrotikConfigRoutes |
| `/api/mikrotik/apply` | POST | public | apply payload | apply report | config apply + backup | fs+blobs | mikrotikConfigRoutes |
| `/api/mikrotik/run-script` | POST | public | script payload | execution output | RouterOS script execution | - | mikrotikConfigRoutes |
| `/api/mikrotik/address-lists` | GET | public | query | list data | none | EvoBGP/derived | mikrotikConfigRoutes |
| `/api/mikrotik/ospf-interface-templates` | GET | public | query | templates | none | blobs/config | mikrotikConfigRoutes |
| `/api/mikrotik/ospf-interface-templates/apply` | POST | public | apply payload | `sendOk`/report | RouterOS mutation | - | mikrotikConfigRoutes |
| `/api/mikrotik/address-lists/apply-summary` | POST | public | summary payload | report | RouterOS mutation | - | mikrotikConfigRoutes |
| `/api/uptime/cache` | GET | public | query | uptime snapshot | none | uptime cache blob | mikrotikConfigRoutes |
| `/api/uptime/check` | POST | public | check payload | status report | ping/http checks | uptime cache blob | mikrotikConfigRoutes |
| `/api/traffic/interface-stats` | GET | public | query | traffic stats | optional cache update | cache blobs | trafficRoutes |
| `/api/resources/stats` | GET | public | query | cpu/ram/hdd stats | optional cache update | cache blobs | resourceStatsRoutes |
| `/api/alerts` | GET | public | query | alerts aggregate | none | combines caches | alertsRoutes |
| `/api/mikrotik/backups` | GET/POST | public | POST backup payload | list / backup result | write/read `.rsc` | local FS + metadata | mikrotikBackupRoutes |
| `/api/mikrotik/backups/item` | GET | public | query id/path | backup item | read FS | local FS | mikrotikBackupRoutes |
| `/api/mikrotik/backups/diff` | POST | public | `{from,to,...}` | diff result | none | local FS | mikrotikBackupRoutes |
| `/api/mikrotik/backups/run` | POST | public | optional | run-now result | scheduler trigger | local FS | mikrotikBackupRoutes |
| `/api/network-map-cache` | GET | public | query | cached map | none | cache blobs | schedulerRoutes |
| `/api/route-optimizer` | GET | public | query topology | optimization result | none | derived/cache | routeOptimizerRoutes |
| `/api/scheduler/network-map/settings` | GET/PATCH | public | PATCH settings DTO | settings/result | update scheduler config | blobs/ui settings | schedulerRoutes |
| `/api/scheduler/network-map/logs` | GET | public | query | logs | none | blobs/logs | schedulerRoutes |
| `/api/scheduler/network-map/run-now` | POST | public | optional | trigger result | immediate job | cache update | schedulerRoutes |
| `/api/scheduler/ping-services/settings` | GET/PATCH | public | PATCH settings DTO | settings/result | update scheduler config | ui settings | schedulerRoutes |
| `/api/scheduler/ping-services/run-now` | POST | public | optional | trigger result | immediate cache refresh | ping-services cache | schedulerRoutes |
| `/api/scheduler/uptime-monitor/settings` | GET/PATCH | public | PATCH settings DTO | settings/result | update scheduler config | ui settings | schedulerRoutes |
| `/api/scheduler/uptime-monitor/run-now` | POST | public | optional | trigger result | immediate uptime job | uptime cache | schedulerRoutes |
| `/api/mikrotik/validate` | POST | public | `{config:string}` | validation report | none | - | mikrotik-validator |
---
## 6. DATABASE BEHAVIOR MODEL
### 6.1 Критичные таблицы
| Таблица | Назначение | Критичность | Можно менять? |
|---|---|---|---|
| `blobs` | текущее состояние logical objects | very high | только через миграцию + compatibility layer |
| `blob_versions` | история версий для rollback | high | нельзя удалять без замены rollback механизма |
| `versioned_keys` | whitelist ключей с версионированием | high | расширять можно, удаление рискованно |
| `app_filter_rules` | глобальные/simple фильтры | very high | менять с миграцией + route/service sync |
| `app_meta` | meta timestamps/flags | medium | осторожно; используется для etag/mtime |
| `cache_entries` | TTL-кеш | medium | можно расширять, не ломая purge logic |
| `schema_migrations` | applied versions | critical | не редактировать вручную |
### 6.2 Cascade/relations
- `blob_versions.object_key -> blobs.object_key ON DELETE CASCADE`.
- Удаление blob удаляет историю версий автоматически.
### 6.3 Transactional boundaries
- `blobStorage.writeBlobTx`: атомарно сохраняет новую версию + snapshot old version + trim.
- `filterRulesStorage.replaceRules`: атомарно `DELETE scope` + `INSERT new set` + update mtime.
- Rollback версии выполняется внутри DB write flow.
### 6.4 Consistency rules
- `etag` вычисляется по SHA-256 body; должен соответствовать текущему blob содержимому.
- `lastModified` и `contentLength` обязательны для корректной cache-конкурентности UI/API.
- `app_filter_rules.position` определяет порядок; запись всегда full-replace.
- `SQLITE_PATH` должен быть persistent volume в production.
- `journal_mode=WAL` обязателен для конкурентного I/O.
---
## 7. FRONTEND RULES (UI ENGINEERING RULESET)
### Структура страниц
- Все маршруты регистрируются централизованно в `App.jsx`.
- Экран = manager/page компонент + общие UI-компоненты (`components/*`).
### State management rules
- Server-state: только React Query (`useQuery/useMutation`).
- UI-state: local component state + Context (`Language`, `Theme`, `Ping`, `Alerts`).
- Запрещено хранить API snapshot в произвольных singleton-объектах вне React Query.
### Data fetching rules
- Только через `src/lib/api.js`.
- Для GET использовать `If-None-Match`/ETag-механику клиента.
- Для write-путей с поддержкой ETag передавать `If-Match`/`etag`.
### Caching strategy
- React Query `staleTime` default 30s.
- Axios in-memory response cache для GET.
- Для `/communities` отключён условный GET (всегда fresh).
### Routing dependencies
- Навигация и route paths должны совпадать (sidebar/horizontal menu).
- Любой новый route требует:
- компонент страницы;
- запись в nav categories;
- route registration (оба layout блока).
### Запрещённые паттерны
- Прямой `fetch` в компонентах (мимо `api.js`).
- Изменение `queryClient` политики точечно без общего обоснования.
- UI-изменения, которые ломают optimistic rollback сценарии.
---
## 8. AI AGENT OPERATING PROTOCOL
### 8.1 Роли агентов
- `architect agent`: проверяет архитектурные границы, планирует миграции/контракты.
- `backend agent`: реализует route/service/storage изменения с сохранением backward compatibility.
- `frontend agent`: реализует UI/state/data-fetch изменения по правилам React Query.
- `refactor agent`: выполняет безопасные структурные изменения с impact map.
- `debug agent`: локализует баги, подтверждает root cause, готовит минимальный fix.
### 8.2 Правила работы агентов
- Перед правками читать: `README.md`, `backend/server.js`, целевой route/service, соответствующий frontend hook/page.
- Изменения планировать от контракта к реализации: API -> service -> storage -> UI.
- При любом endpoint-change проверять:
- формат success/error;
- ETag/headers;
- влияние на React Query keys и optimistic updates.
- Избегать конфликтов:
- не менять shared utility без cross-feature impact check;
- при рефакторинге route переносить логику в service, не наоборот.
### 8.3 SAFE EDITING RULE (обязательный)
Перед изменением кода агент обязан:
1. Найти все зависимости (routes/services/hooks/components/schedulers).
2. Проверить влияние на API (input/output, status codes, headers).
3. Проверить влияние на DB (таблицы, ключи blobs, миграции, транзакции).
4. Проверить UI impact (query keys, route path, optimistic update behavior).
5. Сформировать `plan diff` (что меняется, что не меняется, как верифицируется).
---
## 9. CHANGE MANAGEMENT PROTOCOL
### STEP 1 — ANALYZE
- Определить feature/bug scope.
- Идентифицировать owner-слой (frontend/backend/storage/external).
- Собрать baseline контрактов.
### STEP 2 — IMPACT MAP
- Построить карту зависимостей:
- endpoint -> service -> storage/external;
- endpoint -> frontend hooks -> pages/components.
- Классифицировать риск: low/medium/high.
### STEP 3 — IMPLEMENT PLAN
- Реализовать минимально-инвазивные изменения.
- Сохранять backward-compatible payload где возможно.
- Для high-risk сначала добавить адаптерный слой, потом migration.
### STEP 4 — APPLY PATCH
- Вносить правки атомарными логическими блоками.
- Не смешивать функциональные и косметические изменения.
- Фиксировать invariants в комментариях только при необходимости.
### STEP 5 — VERIFY CONSISTENCY
- Проверить lint/type/build.
- Проверить ключевые API сценарии (read/write/etag/error).
- Проверить UI critical path (list load -> edit -> save -> refresh).
- Проверить scheduler/side effect пути, если затронуты.
---
## 10. DEBUGGING & RECOVERY RULES
### Диагностика ошибок
- Backend:
- проверять structured logs (`pino-http`) с `requestId`;
- проверять метрики (`http_errors_total`, `http_request_duration_seconds`);
- валидировать env для EvoBGP/MikroTik.
- Frontend:
- проверять network ошибки через `apiErrorHandler` + notify payload;
- проверять retry/noRetry и cache behavior.
### Откат изменений
- Код: откат через VCS commit revert.
- Данные:
- blob keys: `/api/history/:resource/rollback` (если поддерживается).
- filters/evobgp resources: rollback через локальный history API не поддерживается; нужен внешний restore plan.
### Изоляция багов
- Сначала локализовать слой (UI/API/Service/Storage/External).
- Воспроизвести минимальный сценарий.
- Проверить контракт на границе слоя перед deep refactor.
### Логирование проблем
- Каждый баг-репорт должен включать:
- requestId/endpoint;
- входной payload (без секретов);
- фактический vs ожидаемый ответ;
- impacted таблицы/ключи.
---
## 11. EXTENSION GUIDE
### Добавление новой фичи (общий шаблон)
1. Добавить/расширить service (доменная логика).
2. Добавить route с валидацией и contract-consistent ответом.
3. Добавить frontend hook в `useApiQuery.js` или отдельный data hook.
4. Подключить UI page/component + route entry.
5. Добавить проверку impact на ETag/cache/retry.
### Расширение API
- Предпочитать additive changes (новые поля/роуты) вместо breaking.
- Для breaking change:
- ввести transitional endpoint или feature flag;
- обновить frontend и consumers синхронно;
- подготовить rollback plan.
### Добавление новой таблицы
- Только новой миграцией `00X_*.sql`.
- Определить:
- primary key + indexes;
- relation/cascade policy;
- transaction boundaries;
- read/write service API.
### Как не ломать текущую систему
- Не удалять legacy aliases без full usage audit.
- Не менять ключи объектов в `blobs` без map миграции.
- Не менять `sendError/sendOk` contract.
- Не обходить `evobgpClient` для BGP-reference данных.
---
## OPERATIONAL CHECKLIST FOR LLM AGENTS
- [ ] Прочитан `README.md` и целевые route/service/frontend файлы.
- [ ] Сформирован `plan diff` и impact map.
- [ ] Проверены API contract invariants (status/errors/headers).
- [ ] Проверены DB invariants (transactions/etag/versioning).
- [ ] Проверен UI flow (query cache + optimistic updates).
- [ ] Выполнены lint/build/ручная smoke-валидация критических сценариев.