docs: update EvoBGP architecture plan with detailed REST API section, including general agreements, system endpoints, and prefix module specifications. Enhanced clarity on API structure and added references to OpenAPI documentation.
CI / changes (push) Successful in 7s
CI / go (push) Successful in 20s
CI / openapi (push) Has been skipped
CI / bird2 (push) Successful in 13s

This commit is contained in:
Denozordec
2026-04-05 13:10:38 +07:00
parent 9fd9745723
commit 1a86d6c743
2 changed files with 292 additions and 11 deletions
@@ -1,6 +1,6 @@
---
name: EvoBGP архитектура
overview: Оба профиля по умолчанию на PostgreSQL (один движок, одни миграции). reference — микросервисы + PG + брокер; microVPS — evobgp-all + контейнер PG (жёсткий тюнинг). SQLite — опция только для одного контейнера без PG.
overview: Оба профиля по умолчанию на PostgreSQL (один движок, одни миграции). reference — микросервисы + PG + брокер; microVPS — evobgp-all + контейнер PG (жёсткий тюнинг). SQLite — опция только для одного контейнера без PG. REST API проработан в §7 плана (пути /v1, jobs, бандлы нод); OpenAPI — канон при появлении схемы.
todos:
- id: schema-db
content: "Схема БД: PostgreSQL (основной); опционально SQLite (microVPS single-container); модули, ревизии, jobs"
@@ -54,6 +54,21 @@ Control-plane на **Go**, анонс префиксов через **BIRD**, п
5. [База данных, ETL, ER-схема](#5-база-данных-etl-er-схема)
6. [Модули префиксов и FQDN](#6-модули-префиксов-as-cdn-домены)
7. [REST API](#7-rest-api)
- [7.1. Общие соглашения](#71-общие-соглашения)
- [7.2. Системные и служебные](#72-системные-и-служебные)
- [7.3. Модули префиксов](#73-модули-префиксов-module)
- [7.4. DoH-профили](#74-doh-профили-doh_profile)
- [7.5. BGP community](#75-bgp-community-bgp_community)
- [7.6. Пиры](#76-пиры-bgp_peer)
- [7.7. Спикеры BIRD](#77-спикеры-bird-bgp_speaker)
- [7.8. Ревизии конфигурации](#78-ревизии-конфигурации-config_revision)
- [7.9. Применение конфигурации](#79-применение-конфигурации-deploy-bird)
- [7.10. Задачи](#710-задачи-job_audit)
- [7.11. Реплики и бандлы](#711-реплики-evobgp-node-бандлы)
- [7.12. Глобальные настройки](#712-глобальные-настройки-опционально)
- [7.13. Матрица прав](#713-матрица-прав-роли)
- [7.14. Следующие итерации](#714-следующие-итерации-api)
- [7.15. Связь API с разделами плана](#715-связь-api-с-разделами-плана)
8. [Генерация BIRD и ревизии](#8-генерация-bird-и-ревизии)
9. [Эксплуатация и масштаб пиров](#9-эксплуатация-и-масштаб)
10. [Реплика evobgp-node](#10-реплика-evobgp-node)
@@ -460,15 +475,281 @@ erDiagram
## 7. REST API
Наброски путей, ролей и контрактов вынесены в **[docs/evobgp-api-sketches.md](docs/evobgp-api-sketches.md)** (`/v1`, задачи, бандлы нод).
**Статус:** черновик для согласования и реализации; каноничная машиночитаемая форма — **[docs/openapi.yaml](docs/openapi.yaml)** (по мере заполнения). Ниже — **единая проработка** путей и семантики (консолидация с [docs/evobgp-api-sketches.md](docs/evobgp-api-sketches.md)). Базовый префикс: `**/v1`**. Термины: [§3](#3-логическая-модель-общая-для-обоих-профилей), [§5](#5-база-данных-etl-er-схема), [§6](#6-модули-префиксов-as-cdn-домены).
- `POST /modules/{id}/refresh`
- `POST /apply`, `POST /speakers/{id}/apply` или `/bird/apply`
- `GET /revisions`, `POST /revisions/{id}/rollback`
- `POST|PATCH /peers`, CRUD DoH / community / модулей
- Реплики: `GET /v1/speakers/{id}/bundle/{revision}`, `GET .../revisions/latest`, enrollment нод
- Асинхронно: **202** + `job_id`, `GET /jobs/{id}`
- Auth: API keys / mTLS
### 7.1. Общие соглашения
| Тема | Решение (набросок) |
| ------------------------ | ---------------------------------------------------------------------------------------------------------------------------------- |
| **Аутентификация** | Заголовок `Authorization: Bearer <api_key>` или mTLS на edge; ключи привязаны к tenant и роли. |
| **Multi-tenant** | Все сущности в скоупе tenant: либо из ключа, либо явный префикс `X-Tenant-Id` (только для супер-ролей). |
| **Идентификаторы** | UUID v7 или ULID в URL; в JSON — строки. |
| **Время** | ISO 8601 UTC (`2026-04-03T12:00:00Z`). |
| **Ошибки** | Тело `application/problem+json` (RFC 9457): `type`, `title`, `status`, `detail`, `instance`, опционально `errors[]` по полям. |
| **Идемпотентность** | Для мутаций, создающих задачи или побочные эффекты: заголовок `Idempotency-Key` (опционально обязателен для `POST` apply/refresh). |
| **Пагинация** | `?cursor=<opaque>&limit=50` (cursor-based); ответ: `items`, `next_cursor`, `has_more`. |
| **Асинхронные операции** | `202 Accepted`, заголовок `Location: /v1/jobs/{job_id}`; тело `{ "job_id", "status": "queued" }`. |
| **Версионирование** | Несовместимые изменения — новый префикс `/v2`. |
### 7.2. Системные и служебные
| Метод | Путь | Назначение |
| ----- | ------------- | ------------------------------------------------------------ |
| `GET` | `/v1/health` | Liveness (процесс жив). |
| `GET` | `/v1/ready` | Readiness (БД, брокер при reference, и т.д.). |
| `GET` | `/v1/version` | Версия сборки API и control-plane (`git_sha`, `build_time`). |
### 7.3. Модули префиксов (`module`)
**Связь с продуктом.** В продуктовой формулировке **ASN / CDN / DOMAINS / IP-диапазоны** — это **четыре вида модулей**. Поле `**type`** в `POST /v1/modules` выбирает вид: `AS_PREFIXES`, `CDN_CIDRS`, `DOMAINS` или `**IP_RANGES`**. Дочерние ресурсы: `**as-entries`**, `**cdn-sources**`, `**domain-entries**`; `**ip-range-entries**` — статические **CIDR + `community_id`** (без ASN и без URL). `**module_id**` в пути — идентификатор **конкретного экземпляра** модуля, а не имя типа (согласовано с [§6](#6-модули-префиксов-as-cdn-домены)).
| Метод | Путь | Описание |
| -------- | ------------------------- | ----------------------------------------------------------------- |
| `GET` | `/v1/modules` | Список модулей tenant (фильтры: `?type=`, `?enabled=`). |
| `POST` | `/v1/modules` | Создать модуль. |
| `GET` | `/v1/modules/{module_id}` | Детали модуля. |
| `PATCH` | `/v1/modules/{module_id}` | Частичное обновление (расписание, DoH, приоритет, `enabled`). |
| `DELETE` | `/v1/modules/{module_id}` | Мягкое удаление или `enabled=false` — зафиксировать в реализации. |
**CDN-источники модуля**
| Метод | Путь | Описание |
| -------- | ------------------------------------------------- | --------------------------------------------------------------------- |
| `GET` | `/v1/modules/{module_id}/cdn-sources` | Список строк CDN. |
| `POST` | `/v1/modules/{module_id}/cdn-sources` | Добавить источник (URL + `source_kind` + опционально `community_id`). |
| `PATCH` | `/v1/modules/{module_id}/cdn-sources/{source_id}` | URL, `source_kind`, `community_id`, свой `refresh_interval_sec`. |
| `DELETE` | `/v1/modules/{module_id}/cdn-sources/{source_id}` | Удалить. |
**Записи AS / домены**
| Метод | Путь | Описание |
| -------- | --------------------------------------------------- | --------------------- |
| `GET` | `/v1/modules/{module_id}/as-entries` | Список ASN/префиксов. |
| `POST` | `/v1/modules/{module_id}/as-entries` | Добавить. |
| `PATCH` | `/v1/modules/{module_id}/as-entries/{entry_id}` | Обновить. |
| `DELETE` | `/v1/modules/{module_id}/as-entries/{entry_id}` | Удалить. |
| `GET` | `/v1/modules/{module_id}/domain-entries` | FQDN + community. |
| `POST` | `/v1/modules/{module_id}/domain-entries` | Добавить. |
| `PATCH` | `/v1/modules/{module_id}/domain-entries/{entry_id}` | Обновить. |
| `DELETE` | `/v1/modules/{module_id}/domain-entries/{entry_id}` | Удалить. |
**Записи IP-диапазонов** (только для `type: IP_RANGES`)
| Метод | Путь | Описание |
| -------- | ----------------------------------------------------- | ------------------------------------ |
| `GET` | `/v1/modules/{module_id}/ip-range-entries` | Список CIDR + `community_id`. |
| `POST` | `/v1/modules/{module_id}/ip-range-entries` | Добавить (`prefix`, `community_id`). |
| `PATCH` | `/v1/modules/{module_id}/ip-range-entries/{entry_id}` | Обновить. |
| `DELETE` | `/v1/modules/{module_id}/ip-range-entries/{entry_id}` | Удалить. |
**Refresh (ingest)**
| Метод | Путь | Описание |
| ------ | --------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `POST` | `/v1/modules/{module_id}/refresh` | Запуск ingest для модуля (CDN / DoH / AS по типу). Для `**IP_RANGES`** обычно **не требуется** (данные только в БД); возможен `**204`** / no-op или `**400`**, если тип не поддерживает refresh — зафиксировать в реализации. |
**Пример тела создания модуля (набросок)**
```json
{
"type": "CDN_CIDRS",
"name": "edge-v4",
"enabled": true,
"priority": 10,
"doh_profile_id": null,
"refresh_interval_sec": 3600,
"cron_expr": null,
"default_community_id": "550e8400-e29b-41d4-a716-446655440000"
}
```
Пример модуля `**IP_RANGES**`: `type: "IP_RANGES"`, `doh_profile_id: null`, далее строки через `ip-range-entries` с полями `prefix` (например `203.0.113.0/24`) и `community_id`.
### 7.4. DoH-профили (`doh_profile`)
| Метод | Путь | Описание |
| -------- | ----------------------- | ------------------------------------------------------------------------------------- |
| `GET` | `/v1/doh-profiles` | Список. |
| `POST` | `/v1/doh-profiles` | Создать (URL, таймауты; секрет — ссылка на vault id или отдельный `POST .../secret`). |
| `GET` | `/v1/doh-profiles/{id}` | Детали (без раскрытия секрета). |
| `PATCH` | `/v1/doh-profiles/{id}` | Обновить. |
| `DELETE` | `/v1/doh-profiles/{id}` | Удалить, если не используется модулями. |
### 7.5. BGP community (bgp_community)
| Метод | Путь | Описание |
| -------- | ---------------------- | ------------------------------ |
| `GET` | `/v1/communities` | Список справочника. |
| `POST` | `/v1/communities` | Создать. |
| `GET` | `/v1/communities/{id}` | Детали. |
| `PATCH` | `/v1/communities/{id}` | Обновить. |
| `DELETE` | `/v1/communities/{id}` | Удалить при отсутствии ссылок. |
### 7.6. Пиры (`bgp_peer`)
| Метод | Путь | Описание |
| -------- | ---------------- | ------------------------------------------------------------------------------ |
| `GET` | `/v1/peers` | Список (`?speaker_id=`, пагинация). |
| `POST` | `/v1/peers` | Создать пира. |
| `GET` | `/v1/peers/{id}` | Детали. |
| `PATCH` | `/v1/peers/{id}` | Политики, neighbor, ASN, привязка к `bgp_speaker_id` или `null` = все спикеры. |
| `DELETE` | `/v1/peers/{id}` | Удалить / отключить. |
### 7.7. Спикеры BIRD (`bgp_speaker`)
| Метод | Путь | Описание |
| ------- | ------------------- | ------------------------------------------ |
| `GET` | `/v1/speakers` | Список (master / replica, endpoint). |
| `POST` | `/v1/speakers` | Зарегистрировать спикер (реплика, canary). |
| `GET` | `/v1/speakers/{id}` | Детали + `last_applied_revision_id`. |
| `PATCH` | `/v1/speakers/{id}` | Метаданные, endpoint. |
### 7.8. Ревизии конфигурации (config_revision)
| Метод | Путь | Описание |
| ------ | -------------------------------------- | --------------------------------------------------------------- |
| `GET` | `/v1/revisions` | История ревизий (`?module_id=`, `?limit=`). |
| `GET` | `/v1/revisions/{revision_id}` | Метаданные: хэш, родитель, время, артефакты. |
| `GET` | `/v1/revisions/{revision_id}/prefixes` | Материализованный снимок префиксов (пагинация). |
| `GET` | `/v1/revisions/{revision_id}/preview` | Превью фрагментов BIRD (read-only, без apply). |
| `POST` | `/v1/revisions/{revision_id}/rollback` | Создать **новую** ревизию с содержимым отката; часто `**202`**. |
**Сравнение ревизий (набросок)**
| Метод | Путь | Описание |
| ----- | ---------------------------- | ----------------------------------------------------------------------------- |
| `GET` | `/v1/revisions/{a}/diff/{b}` | Diff префиксов / метаданных (формат зафиксировать: JSON patch или табличный). |
### 7.9. Применение конфигурации (deploy, BIRD)
| Метод | Путь | Описание |
| ------ | ------------------------- | --------------------------------------------------------------------------------------------- |
| `POST` | `/v1/apply` | Применить текущую целевую ревизию на всех спикерах (или по политике по умолчанию). `**202`**. |
| `POST` | `/v1/speakers/{id}/apply` | Применить на одном спикере (canary). `**202`**. |
| `POST` | `/v1/bird/reload` | Опционально: явный мягкий reload политики (если отделён от apply); иначе часть `apply`. |
**Тело `POST /v1/apply` (набросок, опционально)**
```json
{
"revision_id": "01JQXYZ...",
"strategy": "all_speakers",
"dry_run": false
}
```
Связь с безопасным применением: [§13](#13-снижение-рисков-меры-и-процессы) (двухфазный deploy, LKG).
### 7.10. Задачи (job_audit)
| Метод | Путь | Описание |
| ------ | -------------------------- | --------------------------------------------- |
| `GET` | `/v1/jobs` | Список задач (`?status=`, `?kind=`, cursor). |
| `GET` | `/v1/jobs/{job_id}` | Статус, прогресс, ошибка, связанные сущности. |
| `POST` | `/v1/jobs/{job_id}/cancel` | Запрос отмены (best-effort). |
**Пример ответа `GET /v1/jobs/{id}`**
```json
{
"job_id": "01JQXYZ...",
"kind": "module_refresh",
"status": "running",
"idempotency_key": "client-abc-123",
"created_at": "2026-04-03T10:00:00Z",
"started_at": "2026-04-03T10:00:01Z",
"finished_at": null,
"error": null,
"meta": { "module_id": "01JQM..." }
}
```
### 7.11. Реплики evobgp-node: бандлы
Вызываются **нодой** с отдельным ключом / mTLS (роль `node`). См. также [§10](#10-реплика-evobgp-node).
| Метод | Путь | Описание |
| ------ | ------------------------------------------------ | -------------------------------------------------------------------------------------- |
| `GET` | `/v1/speakers/{speaker_id}/revisions/latest` | Указатель на последнюю опубликованную ревизию для ноды. |
| `GET` | `/v1/speakers/{speaker_id}/bundle/{revision_id}` | Скачивание подписанного бандла (архив + `manifest.json` + подпись). |
| `POST` | `/v1/nodes/enroll` | Регистрация ноды (обмен ключами, привязка к `speaker_id`) — детали протокола отдельно. |
Заголовки для бандла: `Content-Type: application/octet-stream` или multipart; целостность по `manifest` (SHA-256) и подписи (например Ed25519) — обязательно на ноде в production ([§13](#13-снижение-рисков-меры-и-процессы)).
### 7.12. Глобальные настройки (опционально)
| Метод | Путь | Описание |
| ------- | -------------- | ------------------------------------------------------- |
| `GET` | `/v1/settings` | KV вроде `global_settings` (лимиты CDN, feature flags). |
| `PATCH` | `/v1/settings` | Частичное обновление (только роль operator). |
### 7.13. Матрица прав (роли)
| Ресурс | `viewer` | `editor` | `operator` | `node` |
| -------------------------- | -------- | -------- | ---------- | ------ |
| GET модули, ревизии, peers | да | да | да | нет* |
| PATCH модули, peers | нет | да | да | нет |
| apply, rollback | нет | нет | да | нет |
| bundle / enroll | нет | нет | нет | да |
Нода не ходит в общий CRUD; только [§7.11](#711-реплики-evobgp-node-бандлы).
### 7.14. Следующие итерации API
- Полная **OpenAPI 3.1** в `docs/openapi.yaml` по этому разделу.
- Webhooks: `POST` на URL клиента по завершении `job` (опционально).
- SSE/WebSocket для стрима статуса долгих jobs.
- Rate limits по ключу и по tenant в ответах (`RateLimit-*` заголовки).
### 7.15. Связь API с разделами плана
| Тема плана | Подраздел §7 |
| ---------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------- |
| REST, jobs, идемпотентность | [7.1](#71-общие-соглашения), [7.10](#710-задачи-job_audit) |
| refresh, apply, rollback, preview, `IP_RANGES` | [7.3](#73-модули-префиксов-module), [7.8](#78-ревизии-конфигурации-config_revision), [7.9](#79-применение-конфигурации-deploy-bird) |
| peers, speakers, communities, DoH | [7.4](#74-doh-профили-doh_profile)[7.7](#77-спикеры-bird-bgp_speaker) |
| bundle API, нода | [7.11](#711-реплики-evobgp-node-бандлы) |
| Контрактные тесты HTTP | [§14](#14-тестирование-bird2-и-матрица-сценариев) + `openapi.yaml` |
Черновик в репозитории [docs/evobgp-api-sketches.md](docs/evobgp-api-sketches.md) держать **синхронным** с §7 при согласовании изменений (или пометить файл указателем на план как единый источник).
---
@@ -644,7 +925,7 @@ Raft, HTTP/`gorqlite`; для HA control-plane; не замена дефолтн
1. **Unit / snapshot (Go):** пакет `internal/birdfmt` — вход из фикстур, выход сравнивается с `*.golden` или `txtar`.
2. **Синтаксис BIRD в CI:** для каждого сценария с `bird.conf` выполняется `**bird -c … -p`** в контейнере с **той же major/minor версией BIRD 2**, что в production ([§13](#13-снижение-рисков-меры-и-процессы)).
3. **Позже:** контрактные тесты HTTP по `docs/openapi.yaml` после реализации `internal/httpapi`.
3. **Позже:** контрактные тесты HTTP по `docs/openapi.yaml` и сценариям из [§7](#7-rest-api) после реализации `internal/httpapi`.
---
+1 -1
View File
@@ -267,4 +267,4 @@
| peers, speakers, communities, DoH | §4 - §7 |
| bundle API, нода | §11 |
Файл плана: `.cursor/plans/evobgp_архитектура_0e73ef02.plan.md`6 REST API).
Файл плана: `.cursor/plans/evobgp_архитектура_0e73ef02.plan.md`7 REST API).