Files
PnvPanel/docs/api-design.md
T

15 KiB
Raw Blame History

API Design

REST поверх HTTP/JSON, авторизация — Authorization: Bearer <access-token> (кроме публичных). Ошибки — application/problem+json (ProblemDetails). Пагинация — ?page=&pageSize=, ответ PagedList<T> (items, total, page, pageSize). Все даты — ISO-8601 UTC.

Базовый префикс: /api (без версионирования в MVP — единый фронт+бек; версии введём при необходимости). Ниже — контракт MVP (может уточняться при реализации).

Auth

Метод Путь Роль Описание
POST /api/auth/register Регистрация { username, password }
POST /api/auth/login Вход { username, password } → access (body) + refresh (httpOnly cookie)
POST /api/auth/refresh Обновление access по refresh-cookie (ротация)
POST /api/auth/logout user Отзыв refresh-токена
POST /api/auth/change-password user Смена пароля { currentPassword, newPassword }
GET /api/auth/me user Текущий профиль + роль + isActivated + telegramLinked
DELETE /api/auth/me user Самоудаление аккаунта (отзыв всех конфигов + удаление данных; аудит анонимизируется)

Вход по username. Email в системе не используется. Забыт пароль: при привязанном Telegram — восстановление через бота; иначе — сброс админом (см. Admin).

Auth — Telegram (привязка и passwordless-вход)

Метод Путь Роль Описание
POST /api/auth/telegram/link-token user Создать токен привязки → { deepLink, qr, expiresAt }
POST /api/auth/telegram/unlink user Отвязать Telegram от аккаунта
POST /api/auth/telegram/login-request Инициировать вход → { requestId, deepLink, qr, expiresAt }
GET /api/auth/telegram/login-request/{id} Статус запроса; при Approved выдаёт access + refresh-cookie

GET …/login-request/{id} (поллинг; альтернатива — событие SignalR) → варианты ответа:

// ожидание
{ "status": "Pending" }
// подтверждено — выпуск токенов (refresh уходит в httpOnly cookie), запрос → Consumed
{ "status": "Approved", "accessToken": "…", "expiresAt": "…", "user": { "id": "…", "roles": ["User"] } }
// отклонено / истекло
{ "status": "Rejected" }   //  | "Expired"

Сами апдейты Telegram (/start, кнопки) обрабатывает in-process бот (long polling), а не HTTP-эндпоинты. Контракты команд бота — в telegram-bot.md.

Configs (пользователь)

Метод Путь Роль Описание
GET /api/inbounds/available user Инбаунды, доступные роли пользователя (для выбора при создании)
GET /api/configs user Список своих конфигов (пагинация)
POST /api/configs user Создать конфиг { inboundId, label?, deviceLimit? } (проверки: активирован, квота роли, доступ роли к инбаунду)
PATCH /api/configs/{id} user Изменить { label?, deviceLimit? } (deviceLimit → limitIp в 3x-ui)
GET /api/configs/{id} user Детали конфига (метка, трафик, устройства, статус)
GET /api/configs/{id}/link user Connection string + subscriptionUrl + QR-payload
POST /api/configs/{id}/rotate user Перевыпустить конфиг (новый UUID/ссылка; квоту не тратит)
DELETE /api/configs/{id} user Отозвать конфиг (удаляет клиента в 3x-ui)
GET /api/subscription user URL агрегированной подписки пользователя (все активные конфиги)

POST /api/configs201 Created:

{
  "id": "…", "protocol": "Vless", "location": "DE",
  "link": "vless://…", "subscriptionUrl": "https://…/sub/…",
  "trafficLimitBytes": 53687091200, "expiresAt": "2026-08-01T00:00:00Z",
  "status": "Active"
}

Apps — каталог приложений

Метод Путь Роль Описание
GET /api/apps user Включённые приложения, сгруппированы по ОС (для страницы инструкций)
GET /api/admin/apps admin Все приложения (вкл. выключенные)
POST /api/admin/apps admin Добавить { name, downloadUrl, operatingSystem, description?, iconUrl?, sortOrder? }
PUT /api/admin/apps/{id} admin Изменить приложение (в т.ч. isEnabled)
DELETE /api/admin/apps/{id} admin Удалить приложение

GET /api/apps → пример:

{
  "Android": [ { "id": "…", "name": "v2rayNG", "downloadUrl": "https://…", "iconUrl": null } ],
  "iOS":     [ { "id": "…", "name": "Hiddify",  "downloadUrl": "https://…", "iconUrl": null } ]
}

Activation (пользователь)

Метод Путь Роль Описание
GET /api/activation/status user Статус активации + текущий Pending-запрос (если есть)
POST /api/activation/request user Запросить активацию { comment? } (напр. «я Никита»)

GET /api/configs для неактивированного пользователя вернёт пустой список; POST /api/configs до активации → 403 (или 409 с кодом NotActivated).

Admin — Activation, Roles

Метод Путь Роль Описание
GET /api/admin/activation-requests admin Список запросов активации (фильтр по статусу)
POST /api/admin/activation-requests/{id}/approve admin Одобрить → пользователь активирован
POST /api/admin/activation-requests/{id}/reject admin Отклонить { reason? }
GET /api/admin/roles admin Список ролей с квотами
POST /api/admin/roles admin Создать роль { name, maxConfigs }
PUT /api/admin/roles/{id} admin Изменить роль (напр. maxConfigs)
DELETE /api/admin/roles/{id} admin Удалить роль (нельзя системные admin/user)
PATCH /api/admin/users/{id}/role admin Сменить роль пользователю { roleId } (ровно одна)
PATCH /api/admin/users/{id}/activation admin Активировать/деактивировать напрямую { isActivated }

Admin — Nodes

Метод Путь Роль Описание
GET /api/admin/nodes admin Список нод + статусы
POST /api/admin/nodes admin Подключить ноду { name, baseAddress, username, password, location }
PUT /api/admin/nodes/{id} admin Изменить ноду (в т.ч. isEnabled)
DELETE /api/admin/nodes/{id} admin Удалить ноду
POST /api/admin/nodes/{id}/sync admin Пересинхронизировать inbounds с 3x-ui
POST /api/admin/nodes/{id}/probe admin Проверить доступность

Admin — Inbounds

Метод Путь Роль Описание
GET /api/admin/inbounds admin Список inbounds (по нодам) + allowedRoleIds, displayName
PUT /api/admin/inbounds/{id}/publish admin Опубликовать/снять { isPublished, displayName?, allowedRoleIds[], maxClients? }

Admin — Users & Stats

Метод Путь Роль Описание
GET /api/admin/users admin Пользователи (пагинация, поиск)
PATCH /api/admin/users/{id}/block admin Блокировать/разблокировать { isBlocked } (при блоке — отключить конфиги в 3x-ui)
POST /api/admin/users/{id}/reset-password admin Сбросить пароль пользователю без привязки Telegram (выдать временный/задать новый)
GET /api/admin/users/{id}/configs admin Конфиги пользователя
DELETE /api/admin/configs/{id} admin Принудительно отозвать любой конфиг
GET /api/admin/stats admin Сводная статистика (пользователи, конфиги, трафик)
GET /api/admin/audit admin Журнал действий (AuditLog, пагинация, фильтры)

Public — Subscription

Метод Путь Роль Описание
GET /sub/{token} Подписка (base64-список ссылок). Токен — либо AppUser.SubscriptionToken (все активные конфиги юзера), либо VpnConfig.SubscriptionToken (один конфиг). Без /api.

Rate-limited; отключённые/отозванные конфиги в выдачу не попадают; неизвестный/погашенный токен → 404. Ответ отдаёт заголовок Subscription-Userinfo (upload/download/total/expire) — клиенты (v2rayN/Nekoray и т.п.) показывают остаток трафика/срок. Также profile-update-interval.

SignalR — Hub /hubs/panel

Авторизация — тем же JWT (query access_token или заголовок). Группы: user:{userId}, admins.

Server → Client

Событие Payload Кому
configTrafficUpdated { configId, usedUpBytes, usedDownBytes, limitBytes } владельцу
configStatusChanged { configId, status } владельцу
nodeStatusChanged { nodeId, status, lastSyncAt } admins
activationRequested { requestId, userId, username, comment, createdAt } admins
userActivated { userId } владельцу

Client → Server

MVP — клиент только слушает (группировка по пользователю на сервере при подключении по UserId из JWT).

Коды ошибок

Код Когда
400 Ошибка валидации (errors в ProblemDetails)
401 Нет/просрочен токен
403 Нет прав (роль/владение/не активирован/роль без доступа к инбаунду)
404 Ресурс не найден
409 Конфликт домена (превышена квота роли, дубликат, уже есть Pending-запрос активации)
422 Нарушение инварианта домена
429 Rate limit
502 Ошибка/недоступность ноды 3x-ui (при необходимости)