> ## Documentation Index
> Fetch the complete documentation index at: https://omniflow-vpn.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# 0003 — Файл OpenAPI и есть контракт

> Почему api/openapi.yaml пишется первым и обе стороны генерируются из него, почему это 3.0.3, а не 3.1, и где генерация заканчивается

**Статус:** принято.

## Контекст

У каждого вызова в этом репозитории два конца: обработчик на Go и вызывающий код
на TypeScript в том же монорепозитории. Поддерживать типы обмена вручную с обеих
сторон — значит сделать расхождение невидимым до момента, когда его увидит
клиент. И монорепозиторий делает расхождение *более* вероятным, а не менее:
участник, меняющий обработчик, может поменять его вызов в том же коммите и нигде
это не зафиксировать.

Второе давление — API публичный. У оператора, который пишет скрипт к
`/v1/admin`, нет доступа к обработчику, поэтому то, что сказано в контракте, и
есть то, под что он пишет код.

## Решение

`api/openapi.yaml` — исходный контракт. Типы сервера на Go генерируются из него
через `oapi-codegen`, а привязки Fetch/SWR на TypeScript и схемы Zod — через
Orval. Ни одна сторона не поддерживает дублирующий тип обмена вручную, и CI
падает, если изменение контракта закоммичено без перегенерации обеих сторон.

Контракт — **OpenAPI 3.0.3**, а не 3.1, потому что у выбранного генератора для Go
нет стабильной поддержки 3.1. Это ограничение инструментария, записанное здесь,
чтобы следующий человек не потратил на его обнаружение полдня.

Существуют три префикса, и они остаются раздельными: `/v1/panel` (cookie сессии
оператора, CSRF, RBAC), `/v1/admin` (bearer-токен, для скриптов и операторского
инструментария в Telegram) и `/v1/account` (cookie сессии клиента, CSRF, без
RBAC). Их не объединяют: при объединении каждый унаследовал бы промежуточный слой
другого, а учётные данные клиента не должны дотягиваться до операторского
маршрута.

Соглашения, общие для всех трёх: ответы об ошибках по RFC 9457, курсорная
пагинация, метки времени в UTC, деньги целыми числами в минорных единицах,
идентификаторы запросов и ключи идемпотентности на изменяющих операциях.

## Последствия

Генерация — шаг сборки с зубами: `bun run generate:api` и следом
`git diff --exit-code` в CI означают, что неперегенерированное изменение
контракта не пройдёт.

Сгенерированный код заканчивается в двух местах, и оба названы здесь, а не
обнаруживаются потом:

* **Сгенерированные типы сервера на Go никем не импортируются.** Обработчики
  декодируют в анонимные структуры и пишут собранные вручную отображения, поэтому
  ответ может разойтись со своей схемой без падения теста. Контракт авторитетен
  для вызывающих, но не проверяется в рантайме по ответам.
* **Панели вызывают общий типизированный транспорт, а не сгенерированные хуки
  SWR.** Генератор Orval с `client: "swr"` выпускает голые вызовы `fetch` и
  игнорирует `override.mutator`, поэтому сгенерированный хук не нёс бы ни cookie
  сессии, ни токен CSRF. Обе стороны нацелены на один и тот же сгенерированный
  контракт; различается только транспорт.

Контракт также пока покрывает не все маршруты `/v1/panel`, и ни одна операция
панели или личного кабинета не ссылается на свою схему безопасности. Эти пробелы
перечислены в [Интеграции с API](https://omniflow-vpn.mintlify.site/ru/integrations/api.md), чтобы тот, кто генерирует
клиент, встретил их раньше, чем это сделает его код.

## Когда пересматривать

* У генератора для Go появляется стабильная поддержка OpenAPI 3.1, и контракт
  может перейти на неё, получив возможности JSON Schema, которых нет в 3.0.3.
* Orval начинает поддерживать mutator для клиента SWR, и тогда панели могут
  использовать сгенерированные хуки, а общий транспорт становится лишним.
* Проверка ответов по контракту оправдывает свою цену — скорее всего как проверка
  во время тестов, прогоняющая обработчики через схему, а не как промежуточный
  слой на пути запроса.

## Смежное

* [Интеграция с API](https://omniflow-vpn.mintlify.site/ru/integrations/api.md) — публичная поверхность, её правила и её пробелы.
* [Технологический стек](https://omniflow-vpn.mintlify.site/ru/architecture/technology.md) — сами генераторы.
* [Политика расширения](https://omniflow-vpn.mintlify.site/ru/integrations/extending.md) — какие части этого контракта стабильны для использования.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.