Files

14 KiB

Технический проект. Документ 2: Контракты API (REST)

Проект: АС «Платформа ОПОРА РОССИИ» Стек: FastAPI, единое API для бота и сайта Дата: 26.09.2026 Статус: черновик к согласованию


1. Общие принципы

  • Base URL: https://opora.my-dpr.ru/api/v1
  • Формат: JSON (application/json), файлы — multipart/form-data.
  • Аутентификация: Authorization: Bearer <JWT> (сессия после входа через бота).
  • Версионирование: префикс /v1.
  • Пагинация: ?page=1&per_page=50 → ответ { items, total, page, per_page }.
  • Сортировка/фильтры: ?sort=-created_at&region_id=12&status=new.
  • Идемпотентность: заголовок Idempotency-Key для POST, создающих сущности.
  • Время: ISO 8601 UTC (2026-09-26T12:00:00Z).

Формат ошибки

{
  "error": {
    "code": "validation_error",
    "message": "Поле due_date обязательно",
    "details": { "field": "due_date" }
  }
}

Коды ответов

Код Значение
200 OK
201 Создано
204 Удалено (без тела)
400 Некорректный запрос
401 Не авторизован
403 Нет прав
404 Не найдено
409 Конфликт (например, ссылка уже использована)
422 Ошибка валидации
429 Превышен лимит запросов
500 Внутренняя ошибка

2. Аутентификация

2.1. POST /auth/login-token — выдать одноразовую ссылку (координатор)

Права: coordinator, admin.

// request
{ "region_id": 12, "user_id": null, "ttl_minutes": 60 }
// response 201
{ "id": "uuid", "url": "https://opora.my-dpr.ru/login?token=...", "expires_at": "..." }

2.2. POST /auth/login — вход по одноразовой ссылке

// request
{ "token": "...", "messenger_type": "telegram", "messenger_id": "123456" }
// response 200
{
  "access_token": "jwt",
  "refresh_token": "opaque",
  "expires_at": "...",
  "user": { "id": 1, "full_name": "..." }
}

Ошибки: 409 link_already_used → «Ссылка уже была использована. Запросите новую у координатора».

2.3. POST /auth/refresh — обновить access-токен

// request
{ "refresh_token": "opaque" }
// response 200
{ "access_token": "jwt", "refresh_token": "opaque", "expires_at": "..." }

Правило: refresh-токен ротируемый (при обновлении выдаётся новый, старый инвалидируется).

2.4. POST /auth/logout — завершить сессию

2.5. GET /auth/me — текущий пользователь

{
  "id": 1, "full_name": "Иванов И.И.", "member_type": "member",
  "regions": [{ "id": 12, "name": "ДНР", "is_primary": true }],
  "roles": [{ "code": "region_head", "region_id": 12 }]
}

3. Регионы и карточка

Метод Путь Права Описание
GET /regions авторизован список регионов (фильтр по округу)
GET /regions/{id} авторизован регион
GET /regions/{id}/card авторизован карточка региона
PATCH /regions/{id}/card region_head (своё), admin обновить карточку
GET /regions/{id}/links авторизован ссылки на сообщества/чаты
POST /regions/{id}/links region_head (своё), admin добавить ссылку
PATCH /regions/{id}/links/{linkId} region_head (своё), admin изменить
DELETE /regions/{id}/links/{linkId} region_head (своё), admin удалить
GET /regions/{id}/members авторизован члены региона
GET /regions/{id}/history авторизован история изменений карточки

Пример GET /regions/12/card:

{
  "region": { "id": 12, "name": "Донецкая Народная Республика", "district": "ЮФО" },
  "population": 1200,
  "members_count": 340,
  "residents_count": 45,
  "head": { "id": 5, "full_name": "..." },
  "links": [{ "id": 1, "type": "chat", "title": "Чат ДНР", "url": "..." }],
  "updated_at": "..."
}

4. Цели и метрики

Метод Путь Права Описание
GET /goals авторизован список целей
GET /goals/{id} авторизован цель
GET /goals/{id}/metrics авторизован метрики по цели (регионы/округа)
GET /metrics/regions авторизован метрики по регионам
GET /metrics/districts авторизован агрегаты по округам
GET /metrics/ratings авторизован рейтинг регионов
GET /metrics/red-zone авторизован регионы без прироста
POST /uploads admin загрузить выгрузку
GET /uploads admin список выгрузок

Пример GET /goals/1/metrics:

{
  "goal": { "id": 1, "name": "Рост базы членов", "target_value": 1096 },
  "point0": { "date": "2026-05-08", "value": 1000 },
  "current": { "date": "2026-08-07", "value": 1338 },
  "growth": 338,
  "districts": [
    { "id": 1, "name": "ЮФО", "growth": 365, "regions_with_dynamics": 12, "regions_total": 12 }
  ],
  "freshness_days": 3,
  "auto_update": true
}

Пример GET /metrics/ratings?sort=-growth:

{
  "items": [
    { "region_id": 77, "name": "Москва", "growth": 224, "has_dynamics": true },
    { "region_id": 2, "name": "Башкортостан", "growth": 217, "has_dynamics": true }
  ],
  "total": 89
}

5. Задачи (трекер)

Метод Путь Права Описание
GET /tasks авторизован список (фильтры: мои, регион, просроченные)
POST /tasks авторизован создать
GET /tasks/{id} авторизован задача
PATCH /tasks/{id} автор/исполнитель/admin изменить (в т.ч. статус)
DELETE /tasks/{id} автор/admin удалить (мягко)
GET /tasks/{id}/comments авторизован комментарии
POST /tasks/{id}/comments авторизован добавить комментарий

Пример POST /tasks:

// request
{
  "title": "Подготовить отчёт по приросту",
  "description": "...",
  "due_date": "2026-10-01",
  "priority": "high",
  "region_id": 12,
  "assignee_user_id": 5
}
// response 201
{ "id": 101, "status": "new", "created_at": "..." }

Статусы: new → in_progress → review → done.


6. Артефакты

Метод Путь Права Описание
POST /artifacts авторизован загрузить файл (multipart)
GET /artifacts авторизован список (фильтр по региону/цели/задаче)
GET /artifacts/{id} авторизован метаданные
GET /artifacts/{id}/download авторизован скачать (presigned URL)
DELETE /artifacts/{id} автор/admin удалить

Ограничения: до 50 МБ, типы: изображения, PDF, DOCX, XLSX (п. 4.2.8.1 ТЗ).


7. База знаний

Метод Путь Права
GET /knowledge/articles авторизован
GET /knowledge/articles/{id} авторизован
GET /knowledge/categories авторизован

8. Календарь событий

Метод Путь Права
GET /events авторизован
GET /events/{id} авторизован
POST /events/{id}/reminders авторизован

9. Запросы (заявки)

Метод Путь Права Описание
GET /requests авторизован список (свои / по региону / все для admin)
POST /requests авторизован создать заявку
GET /requests/{id} авторизован заявка
PATCH /requests/{id} admin/coordinator изменить статус
POST /requests/{id}/comments авторизован комментарий

Типы: join, access, event, support.


10. Советы от регионов

Метод Путь Права Описание
GET /advices авторизован список (публичные)
POST /advices region_head (при наличии динамики) опубликовать совет
PATCH /advices/{id} автор/admin скрыть/изменить

11. Рассылки (администрирование)

Метод Путь Права Описание
GET /broadcasts admin список
POST /broadcasts admin создать (из шаблона)
GET /broadcasts/{id} admin статус и прогресс
POST /broadcasts/{id}/send admin запустить
GET /broadcast-templates admin шаблоны
PATCH /broadcast-templates/{id} admin редактировать текст

Пример GET /broadcasts/5:

{
  "id": 5, "type": "rating", "status": "sending",
  "total": 10000, "sent": 4200, "failed": 12,
  "started_at": "...", "finished_at": null
}

12. История платформы

Метод Путь Права
GET /history авторизован (публичная лента)

13. Ассистент «Зам»

Метод Путь Права Описание
GET /assistant/config владелец настройки ассистента
PATCH /assistant/config владелец включить/ограничить
GET /assistant/actions владелец журнал действий ассистента

Пример PATCH /assistant/config:

{ "enabled": true, "permissions": { "publish": true, "delete": false } }

14. Администрирование

Метод Путь Права Описание
GET /users admin список пользователей
PATCH /users/{id} admin изменить (роль, статус, регион)
POST /users/{id}/roles admin выдать роль
DELETE /users/{id}/roles/{roleId} admin отозвать роль
GET /audit admin журнал аудита

15. Взаимодействие с ботом

Бот использует то же API (сервисный токен) для:

  • выдачи одноразовых ссылок (POST /auth/login-token);
  • подтверждения входа;
  • отправки рассылок (через Celery, не напрямую);
  • команд /start, /login, /requests, /regions, /goals, /events, /help.

Внутренний webhook бота: POST /internal/bot/telegram и POST /internal/bot/max (проверка подписи, только localhost).


16. Ограничения и лимиты

Область Лимит
Аутентификация 10 запросов/мин на IP
Общие запросы 100 запросов/мин на пользователя
Загрузка файлов 50 МБ, 20 файлов/час
Рассылки батчами, не более 30 сообщений/сек на канал

17. Принятые решения и открытые вопросы

Принято:

  1. JWT — access-токен сроком 1 месяц + refresh-токен (ротируемый). Эндпоинт POST /auth/refresh.
    • Рекомендация по безопасности: для продакшена желательно сократить access-токен (например, до 1 часа) и держать длинным refresh; при текущем решении компромисс — короткий срок хранения сессий и журналирование.
  2. Сервисный токен бота — отдельный тип токена (системный актор), не роль пользователя.
  3. Вебхуки MAX — проверяем после подтверждения возможностей MAX Bot API.

Открыто:

  1. Presigned URL — срок жизни ссылок на скачивание артефактов (предложение: 15 минут).

18. Следующий документ

  • Документ 3: макеты экранов (mobile-first).