CI / changes (push) Successful in 8s
CI / commitlint (push) Has been skipped
CI / openapi (push) Successful in 27s
CI / web (push) Successful in 36s
CI / go (push) Successful in 54s
CI / bird2 (push) Successful in 16s
CI / release (push) Successful in 3m46s
- Enhanced AGENTS.md to include post-editing commands for Go code, specifying the use of `gofmt -w`, `go vet ./...`, and `scripts/lint-go.ps1`. - Updated engineering rules in .cursor/rules/engineering.mdc to clarify the linting process and ensure consistency in Go code formatting. - Improved documentation for CI checks related to Go code style and linting.
245 lines
11 KiB
Plaintext
245 lines
11 KiB
Plaintext
---
|
||
description: Инженерные правила EvoBGP — Go, API, migrations, общие стандарты
|
||
alwaysApply: true
|
||
---
|
||
|
||
# Engineering Guidelines — EvoBGP
|
||
|
||
Специализированные правила: **Web UI** → `.cursor/rules/web-shadcn.mdc`; **BIRD2 / BGP / IP** → `.cursor/rules/networking-bird.mdc`.
|
||
|
||
Карта репозитория: `AGENTS.md`, `docs/architecture.md`. HTTP-контракт: `docs/openapi.yaml`.
|
||
|
||
---
|
||
|
||
## Architecture
|
||
|
||
**ARCH-01** | MUST | Новая persistence-логика — метод `store.Backend` + реализации в `repository` и `store.Memory`; SQL не в `httpapi`.
|
||
*Rationale:* единая абстракция данных.
|
||
*Проверка:* CI `scripts/lint-httpapi.sh`; grep SQL в `internal/httpapi` — отсутствие.
|
||
|
||
**ARCH-02** | MUST | HTTP-маршруты только в `internal/httpapi`; регистрация через `http.ServeMux` с паттернами `METHOD /v1/...`.
|
||
*Rationale:* один слой REST.
|
||
*Проверка:* маршруты только в `routes.go`, `routes_crud.go`.
|
||
|
||
**ARCH-03** | MUST | Долгие операции (refresh, apply, rollback) — `jobs.Registry`; ответ `202` + `job_id` где задано OpenAPI.
|
||
*Rationale:* не блокировать HTTP worker.
|
||
*Проверка:* OpenAPI + handlers.
|
||
|
||
**ARCH-04** | MUST | Кросс-процессные воркеры — HTTP к API или общая БД; не shared memory (кроме `evobgp-all`).
|
||
*Rationale:* `jobs.Registry` in-process only.
|
||
*Проверка:* `docs/architecture.md`; review.
|
||
|
||
**ARCH-05** | MUST | `birdfmt` не импортирует `httpapi` / `store`.
|
||
*Rationale:* направление зависимостей вниз.
|
||
*Проверка:* `go list -deps` / review imports.
|
||
|
||
**ARCH-06** | MUST | Точки входа `cmd/*` — тонкий `main`: config, wiring, signal/shutdown; без бизнес-логики.
|
||
*Rationale:* тестируемость `internal/`.
|
||
*Проверка:* review `main.go`.
|
||
|
||
**ARCH-07** | MUST | Инициализация store + jobs для API и воркеров — `httpapi.BootstrapWorkers`.
|
||
*Rationale:* единый wiring.
|
||
*Проверка:* `bootstrap.go`.
|
||
|
||
**ARCH-08** | MUST | Ingest+render префиксов — `internal/pipeline`; генерация BIRD-текста — `internal/birdfmt`.
|
||
*Rationale:* разделение data plane / control plane.
|
||
*Проверка:* review пакетов.
|
||
|
||
**ARCH-09** | NEVER | Прямой доступ handler'ов к `pgxpool` для CRUD; только `store.Backend`.
|
||
*Rationale:* абстракция бэкенда.
|
||
*Проверка:* review `httpapi`.
|
||
|
||
**ARCH-10** | MUST | Подпись бандлов — `internal/bundle` + `internal/signing`; не дублировать crypto в handlers.
|
||
*Rationale:* единая криптография артефактов.
|
||
*Проверка:* review.
|
||
|
||
---
|
||
|
||
## Code Style
|
||
|
||
**STYLE-01** | MUST | Go-код после `gofmt`; перед PR — `go vet ./...`. Агент после правок Go: `gofmt -w` на изменённых файлах + `golangci-lint run` (или `scripts/lint-go.*`) до exit 0.
|
||
*Rationale:* CI job `go` включает golangci-lint (gofmt).
|
||
*Проверка:* CI job `go`; `.cursor/rules/engineering.mdc` STYLE-01.
|
||
|
||
**STYLE-02** | MUST | Экспортируемые типы/функции публичных пакетов — godoc-комментарий.
|
||
*Rationale:* навигация по API пакетов.
|
||
*Проверка:* review.
|
||
|
||
**STYLE-03** | NEVER | `panic` в `internal/*` вне `init` и тестов.
|
||
*Rationale:* предсказуемые ошибки.
|
||
*Проверка:* grep `panic(`.
|
||
|
||
**STYLE-04** | MUST | Ошибки пакетов с префиксом (`birdfmt:`, `db:`, `httpapi:`) и `%w` при оборачивании.
|
||
*Rationale:* трассировка.
|
||
*Проверка:* review.
|
||
|
||
**STYLE-05** | MUST | HTTP-ошибки — `writeProblem` / `writeJSON` (`application/problem+json` для 4xx/5xx).
|
||
*Rationale:* RFC 9457, OpenAPI.
|
||
*Проверка:* `problem.go`; CI `scripts/lint-httpapi.sh` (5xx и 4xx store/cdn/csv).
|
||
|
||
**STYLE-06** | MUST | JSON полей HTTP DTO согласованы с `docs/openapi.yaml`.
|
||
*Rationale:* контракт API.
|
||
*Проверка:* OpenAPI diff + review.
|
||
|
||
---
|
||
|
||
## Dependency Management
|
||
|
||
**DEP-01** | MUST | Go-зависимости — через `go get` / `go.mod`; версия Go как в `go.mod` и CI (1.24).
|
||
*Проверка:* `go.mod`, `.gitea/workflows/ci.yaml`.
|
||
|
||
**DEP-02** | NEVER | Vendor-копирование без явного решения в репозитории.
|
||
*Проверка:* review.
|
||
|
||
**DEP-03** | MUST | Миграции схемы — пары `.up.sql`/`.down.sql` для **postgres** и **sqlite**, синхронная нумерация.
|
||
*Проверка:* `migrations/postgres/`, `migrations/sqlite/`.
|
||
|
||
**DEP-04** | MUST | Web UI-библиотеки — только экосистема shadcn-svelte/bits-ui (см. `web-shadcn.mdc`).
|
||
*Проверка:* `web/package.json` review.
|
||
|
||
---
|
||
|
||
## Error Handling
|
||
|
||
**ERR-01** | MUST | HTTP 5xx — без сырого `err.Error()` клиенту; detail через `writeProblem`.
|
||
*Проверка:* review handlers.
|
||
|
||
**ERR-02** | MUST | Публичные функции I/O — `(T, error)`; `errors.Is`/`errors.As` для sentinel.
|
||
*Проверка:* review.
|
||
|
||
**ERR-03** | MUST | `context.Context` — первый аргумент для I/O; таймауты на внешние HTTP (CDN, DoH, RIPEstat).
|
||
*Проверка:* `pipeline`, `bootstrap.go`.
|
||
|
||
---
|
||
|
||
## Testing
|
||
|
||
**TEST-01** | MUST | Перед PR: `go test ./... -race -count=1`.
|
||
*Проверка:* CI job `go`.
|
||
|
||
**TEST-02** | MUST | Табличные тесты — эталон для `birdfmt`, `pipeline`, `bundle`.
|
||
*Проверка:* `*_test.go`.
|
||
|
||
**TEST-03** | MUST | Новые BIRD-сценарии в `internal/birdfmt/testdata/scenarios/*/bird.conf` + `bird -p`.
|
||
*Проверка:* CI job `bird2`.
|
||
|
||
**TEST-04** | MUST | Изменения `web/` — локально **`npm run check` и `npm run lint`** (обе команды, exit 0); CI job `web` в `.gitea/workflows/ci.yaml`. Агент: при fail lint — `npx prettier --write` затем повтор. Только `check` не заменяет `lint`.
|
||
*Проверка:* CI job `web`; `.cursor/rules/web-shadcn.mdc` WEB-19.
|
||
|
||
**TEST-05** | MUST | Изменения OpenAPI — `npx @redocly/cli lint docs/openapi.yaml`.
|
||
*Проверка:* CI job `openapi`.
|
||
|
||
---
|
||
|
||
## Documentation
|
||
|
||
**DOC-01** | MUST | Пользовательская документация в `docs/` — на русском.
|
||
*Проверка:* review.
|
||
|
||
**DOC-02** | MUST | Изменение HTTP API: сначала `docs/openapi.yaml`, затем handlers/store, затем `docs/api.md` при необходимости.
|
||
*Проверка:* PR diff order.
|
||
|
||
**DOC-03** | MUST | Расхождение spec/код — явно в `docs/access.md` или description операции OpenAPI.
|
||
*Проверка:* review (напр. `X-Tenant-Id`).
|
||
|
||
**DOC-04** | NEVER | Дублировать длинные фрагменты OpenAPI в комментариях; ссылка на путь/operationId.
|
||
*Проверка:* review.
|
||
|
||
---
|
||
|
||
## Naming Conventions
|
||
|
||
**NAME-01** | MUST | Бинарники: `cmd/evobgp-<role>/main.go`.
|
||
*Проверка:* `cmd/`.
|
||
|
||
**NAME-02** | MUST | Env-переменные: префикс `EVOBGP_`.
|
||
*Проверка:* `internal/config`, `docs/access.md`.
|
||
|
||
**NAME-03** | MUST | Job kinds — константы в `internal/jobs/worker.go` (`module_refresh`, …).
|
||
*Проверка:* grep `Kind`.
|
||
|
||
**NAME-04** | MUST | ID сущностей — UUID-строки; tenant только из API-ключа (auth context), не из недокументированных заголовков.
|
||
*Проверка:* `auth.go`, `docs/access.md`.
|
||
|
||
---
|
||
|
||
## Performance
|
||
|
||
**PERF-01** | MUST | Списки API — пагинация `cursor` + `limit`; не unbounded выборки в handlers.
|
||
*Проверка:* OpenAPI + store methods.
|
||
|
||
**PERF-02** | MUST | CDN HTTP — переиспользуемый `http.Client` с таймаутом (45s в bootstrap).
|
||
*Проверка:* `bootstrap.go`.
|
||
|
||
**PERF-03** | MUST | Новые метрики — `internal/observability`, экспорт `/metrics`.
|
||
*Проверка:* review.
|
||
|
||
---
|
||
|
||
## Security
|
||
|
||
**SEC-01** | NEVER | Секреты, API-ключи, токены в Git.
|
||
*Проверка:* review; `docs/access.md`.
|
||
|
||
**SEC-02** | NEVER | `EVOBGP_DEV_INSECURE=1` в production.
|
||
*Проверка:* ops review.
|
||
|
||
**SEC-03** | MUST | Роль `node` — только node API; CRUD — `403` для `node`.
|
||
*Проверка:* `auth.go`, handlers.
|
||
|
||
**SEC-04** | MUST | apply/rollback/settings — operator (или выше по `roleLevel`).
|
||
*Проверка:* review handlers.
|
||
|
||
**SEC-05** | MUST | Бандл на ноде — `verify-bundle` перед `apply-bundle`.
|
||
*Проверка:* `docs/access.md`.
|
||
|
||
**SEC-06** | MUST | CORS — явный whitelist `EVOBGP_CORS_ORIGINS`.
|
||
*Проверка:* `cors.go`.
|
||
|
||
---
|
||
|
||
## Documentation Sync Rules
|
||
|
||
| Область | Источник |
|
||
|---------|----------|
|
||
| Go / net/http | https://go.dev/doc/ |
|
||
| pgx v5 | https://pkg.go.dev/github.com/jackc/pgx/v5 |
|
||
| OpenAPI / problem+json | `docs/openapi.yaml`, RFC 9457 |
|
||
| Svelte / Kit | https://svelte.dev/docs , https://kit.svelte.dev/docs |
|
||
| shadcn-svelte | https://shadcn-svelte.com/docs |
|
||
| BIRD 2 | https://bird.network.cz/?get_doc |
|
||
| Prometheus Go | https://pkg.go.dev/github.com/prometheus/client_golang |
|
||
|
||
**DOC-SYNC-01** | MUST | Новый API библиотеки — сверка версии в `go.mod`/`package.json` с официальной документацией.
|
||
**DOC-SYNC-02** | NEVER | Устаревшие примеры (Svelte 4 `export let`, deprecated pgx).
|
||
**DOC-SYNC-03** | MUST | Конфликт docs: **OpenAPI (HTTP)** → **код** → обзорные `docs/`; `.cursor/plans/` не контракт.
|
||
**DOC-SYNC-04** | MUST | Сомнения по Svelte — Svelte MCP / `npm run check`.
|
||
**DOC-SYNC-05** | MUST | BIRD — официальная документация BIRD2 + `networking-bird.mdc` + `go test ./internal/birdfmt/...`.
|
||
|
||
Приоритет при сомнениях — **официальные источники**, не блоги и не «память модели».
|
||
|
||
---
|
||
|
||
## Enforcement Strategy
|
||
|
||
**CI (Gitea):** OpenAPI lint; `go vet`, `go test -race`, build `cmd/*`; `bird -p` на scenarios; Docker bake на push.
|
||
|
||
**Локально перед PR:**
|
||
|
||
```powershell
|
||
go vet ./...
|
||
go test ./... -race -count=1
|
||
npx @redocly/cli lint docs/openapi.yaml
|
||
# web: cd web; npm run check; npm run lint (или scripts/lint-web.ps1)
|
||
# go fmt/lint: gofmt -w <files>; scripts/lint-go.ps1 (gofmt + vet + golangci-lint)
|
||
# birdfmt: go test ./internal/birdfmt/... -count=1
|
||
```
|
||
|
||
**CI (Gitea):** job `web` (check + lint); job `go`: `go vet`, `scripts/lint-httpapi.sh` (ARCH-01, ERR-01), `scripts/check-migrations-pair.sh` (DEP-03), `golangci-lint`, `go test -race`, build `cmd/*`.
|
||
|
||
**Рекомендуется локально:** `.golangci.yml`; `.pre-commit-config.yaml` (gofmt + prettier web).
|
||
|
||
**Только code review:** слои SQL; роли; idempotency; OpenAPI bodies; secrets в compose.
|
||
|
||
**Известные ограничения:** `X-Tenant-Id` в OpenAPI не реализован в handlers; `jobs.Registry` не shared между процессами API и отдельными воркерами без HTTP.
|