diff --git a/AI_READY_DEVELOPMENT_SPEC.md b/AI_READY_DEVELOPMENT_SPEC.md new file mode 100644 index 0000000..faac732 --- /dev/null +++ b/AI_READY_DEVELOPMENT_SPEC.md @@ -0,0 +1,482 @@ +# 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-.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-.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-валидация критических сценариев. +