feat: global platform v2 update

This commit is contained in:
ivannoskov
2025-12-29 10:12:13 +03:00
parent 8e6a1fa83f
commit f64cf02100
84 changed files with 11023 additions and 11486 deletions

525
API_DOCS.md Normal file
View File

@@ -0,0 +1,525 @@
# TGEX Backend API v2
## Аутентификация
**JWT Bearer Token** в заголовке `Authorization: Bearer <token>`
### Получение токена через Telegram Bot
Логика точно такая же как и раньше
### Эндпоинты
| Метод | Эндпоинт | Описание | Auth |
|-------|----------|----------|------|
| `GET` | `/auth/complete` | Обмен временного токена на JWT | ❌ |
| `GET` | `/auth/me` | Получить текущего пользователя | ✅ |
**Response** `/auth/me`:
```json
{
"id": "uuid",
"telegram_id": 123456789,
"username": "string | null"
}
```
---
## Workspaces (Рабочие пространства)
Воркспейсы - изолированные пространства для команд. У пользователя может быть несколько воркспейсов.
| Метод | Эндпоинт | Описание |
|-------|----------|----------|
| `GET` | `/workspaces` | Список воркспейсов пользователя (пагинация) |
| `POST` | `/workspaces` | Создать воркспейс |
| `PATCH` | `/workspaces/{workspace_id}` | Обновить название |
| `DELETE` | `/workspaces/{workspace_id}` | Удалить воркспейс |
**Body** `POST /workspaces`:
```json
{
"name": "string"
}
```
**Response**:
```json
{
"id": "uuid",
"name": "string"
}
```
---
## Workspace Members (Участники воркспейса)
| Метод | Эндпоинт | Описание |
|-------|----------|----------|
| `GET` | `/workspaces/{workspace_id}/members` | Список участников (пагинация) |
| `PUT` | `/workspaces/{workspace_id}/members/{user_id}/permissions` | Обновить права участника |
**Права доступа** (`PermissionKey`):
- `admin_full` - полный доступ
- `projects_read` - чтение проектов
- `projects_write` - запись проектов
- `placements_read` - чтение размещений
- `placements_write` - запись размещений
- `analytics_read` - чтение аналитики
**Scope types**: `project` (ограничение прав на конкретный проект)
**Body** `PUT permissions`:
```json
{
"permissions": [
{
"key": "admin_full"
},
{
"key": "projects_write",
"scopes": [
{"type": "project", "id": "project-uuid"}
]
}
]
}
```
---
## Workspace Invites (Приглашения)
| Метод | Эндпоинт | Описание |
|-------|----------|----------|
| `GET` | `/workspaces/{workspace_id}/invites` | Список приглашений (пагинация) |
| `POST` | `/workspaces/{workspace_id}/invites` | Создать приглашение |
**Body** `POST /invites`:
```json
{
"username": "telegram_username" // без @
}
```
**Статусы приглашения**: `PENDING`, `ACCEPTED`, `REJECTED`
---
## Projects (Проекты / Целевые каналы)
Проекты = целевые Telegram каналы, которые продвигаются. Создаются через Telegram бота.
| Метод | Эндпоинт | Описание |
|-------|----------|----------|
| `GET` | `/workspaces/{workspace_id}/projects` | Список проектов (пагинация) |
**Response**:
```json
{
"id": "uuid",
"telegram_id": -1001234567890,
"title": "string",
"username": "string | null",
"status": "ACTIVE | INACTIVE | ARCHIVED"
}
```
**Управление проектами**: через Telegram бота (добавить/удалить канал)
---
## Channels (Каналы для размещений)
Каталог Telegram каналов, где можно размещать рекламу.
| Метод | Эндпоинт | Описание | Фильтры |
|-------|----------|----------|---------|
| `GET` | `/channels` | Список каналов (пагинация) | `?username=...` |
**Response**:
```json
{
"id": "uuid",
"telegram_id": -1002345678901,
"title": "string",
"username": "string | null",
"description": "string | null",
"subscribers_count": 15000
}
```
---
## Purchase Plan (План закупа)
План закупа - список каналов для покупки рекламы в рамках проекта.
| Метод | Эндпоинт | Описание |
|-------|----------|----------|
| `GET` | `/workspaces/{ws}/projects/{proj}/purchase-plan/channels` | Список каналов плана (пагинация) |
| `POST` | `/workspaces/{ws}/projects/{proj}/purchase-plan/channels` | Добавить канал в план |
| `PATCH` | `/workspaces/{ws}/projects/{proj}/purchase-plan/channels/{id}` | Обновить параметры канала |
| `DELETE` | `/workspaces/{ws}/projects/{proj}/purchase-plan/channels/{id}` | Удалить из плана |
**Body** `POST`:
```json
{
"channel_id": "uuid",
"planned_date": "2025-01-15T12:00:00Z", // optional
"price": 5000.50, // optional
"comment": "string" // optional
}
```
**Body** `PATCH`:
```json
{
"planned_date": "2025-01-15T12:00:00Z", // optional
"price": 5000.50, // optional
"comment": "string" // optional
}
```
**Response**:
```json
{
"id": "uuid",
"status": "PLANNED | COMPLETED | CANCELLED",
"planned_date": "2025-01-15T12:00:00Z | null",
"price": 5000.50,
"comment": "string | null",
"channel": {
"id": "uuid",
"title": "string",
"username": "string | null",
"subscribers_count": 15000
}
}
```
---
## Creatives (Креативы)
Креативы = рекламные материалы (текст с пригласительной ссылкой).
| Метод | Эндпоинт | Описание | Фильтры |
|-------|----------|----------|---------|
| `GET` | `/workspaces/{ws}/creatives` | Список креативов (пагинация) | `?project_id=...&include_archived=false` |
| `GET` | `/workspaces/{ws}/creatives/{id}` | Один креатив | |
| `POST` | `/workspaces/{ws}/creatives?project_id=...` | Создать креатив | |
| `PATCH` | `/workspaces/{ws}/creatives/{id}` | Обновить креатив | |
| `DELETE` | `/workspaces/{ws}/creatives/{id}` | Удалить (архивировать) | |
**Body** `POST/PATCH`:
```json
{
"name": "string",
"text": "Текст с {invite_link} тегом"
}
```
**Response**:
```json
{
"id": "uuid",
"name": "string",
"text": "string",
"status": "ACTIVE | ARCHIVED",
"placements_count": 5
}
```
**Важно**: `{invite_link}` в тексте заменяется на уникальную ссылку при создании размещения.
---
## Placements (Размещения)
Размещения = факт размещения креатива в канале.
| Метод | Эндпоинт | Описание | Фильтры |
|-------|----------|----------|---------|
| `GET` | `/workspaces/{ws}/placements` | Список размещений (пагинация) | `?project_id=...&placement_channel_id=...&creative_id=...&include_archived=false` |
| `GET` | `/workspaces/{ws}/placements/{id}` | Одно размещение | |
| `POST` | `/workspaces/{ws}/placements` | Создать размещение | |
| `PATCH` | `/workspaces/{ws}/placements/{id}` | Обновить размещение | |
| `DELETE` | `/workspaces/{ws}/placements/{id}` | Удалить (архивировать) | |
**Body** `POST`:
```json
{
"project_id": "uuid",
"placement_channel_id": "uuid",
"creative_id": "uuid",
"placement_date": "2025-01-15T12:00:00Z",
"cost": 5000.50, // optional
"comment": "string", // optional
"ad_post_url": "https://t.me/channel/123", // optional
"invite_link_type": "PUBLIC | APPROVAL"
}
```
**Body** `PATCH`:
```json
{
"placement_date": "2025-01-15T12:00:00Z", // optional
"cost": 5000.50, // optional
"comment": "string", // optional
"ad_post_url": "https://t.me/channel/123" // optional
}
```
**Response**:
```json
{
"id": "uuid",
"placement_date": "2025-01-15T12:00:00Z",
"cost": 5000.50,
"comment": "string | null",
"ad_post_url": "string | null",
"invite_link_type": "PUBLIC | APPROVAL",
"invite_link": "https://t.me/+UniqueCode",
"status": "ACTIVE | ARCHIVED",
"subscriptions_count": 42,
"views_count": 1850,
"views_availability": "UNKNOWN | AVAILABLE | UNAVAILABLE | MANUAL",
"last_views_fetch_at": "2025-01-15T14:30:00Z",
"project": {
"id": "uuid",
"title": "string",
"username": "string | null"
},
"placement_channel": {
"id": "uuid",
"title": "string",
"username": "string | null",
"subscribers_count": 15000
},
"creative": {
"id": "uuid",
"name": "string"
}
}
```
**Типы пригласительных ссылок**:
- `PUBLIC` - открытая ссылка
- `APPROVAL` - с одобрением через бота
**Статус просмотров**:
- `UNKNOWN` - еще не проверялось
- `AVAILABLE` - просмотры доступны (автообновление)
- `UNAVAILABLE` - нет доступа к просмотрам
- `MANUAL` - ручной ввод
---
## Views History (История просмотров)
| Метод | Эндпоинт | Описание | Фильтры |
|-------|----------|----------|---------|
| `GET` | `/workspaces/{ws}/placements/{id}/views/history` | История просмотров (пагинация) | `?from_date=...&to_date=...` |
**Response**:
```json
{
"id": "uuid",
"views_count": 1850,
"fetched_at": "2025-01-15T14:30:00Z"
}
```
---
## Analytics (Аналитика)
Все эндпоинты поддерживают фильтр `?project_id=...` для конкретного проекта.
### Аналитика размещений
| Метод | Эндпоинт | Описание |
|-------|----------|----------|
| `GET` | `/workspaces/{ws}/analytics/placements` | Аналитика по размещениям (пагинация) |
**Response**:
```json
{
"placement_id": "uuid",
"placement_channel_title": "string",
"placement_channel_username": "string | null",
"creative_name": "string",
"placement_date": "2025-01-15T12:00:00Z",
"cost": 5000.50,
"subscriptions_count": 42,
"views_count": 1850,
"cps": 119.05, // cost per subscription
"cpm": 2702.70 // cost per mille views
}
```
### Аналитика креативов
| Метод | Эндпоинт | Описание |
|-------|----------|----------|
| `GET` | `/workspaces/{ws}/analytics/creatives` | Аналитика по креативам (пагинация) |
**Response**:
```json
{
"creative_id": "uuid",
"creative_name": "string",
"placements_count": 5,
"total_cost": 25000.00,
"total_subscriptions": 210,
"total_views": 9250,
"avg_cps": 119.05,
"avg_cpm": 2702.70
}
```
### Аналитика каналов
| Метод | Эндпоинт | Описание |
|-------|----------|----------|
| `GET` | `/workspaces/{ws}/analytics/channels` | Аналитика по каналам (пагинация) |
**Response**:
```json
{
"channel_id": "uuid",
"channel_title": "string",
"channel_username": "string | null",
"placements_count": 3,
"total_cost": 15000.00,
"total_subscriptions": 126,
"total_views": 5550,
"avg_cps": 119.05,
"avg_cpm": 2702.70
}
```
### Аналитика расходов
| Метод | Эндпоинт | Описание | Фильтры |
|-------|----------|----------|---------|
| `GET` | `/workspaces/{ws}/analytics/spending` | Динамика расходов | `?date_from=...&date_to=...&grouping=DAY\|WEEK\|MONTH` |
**Response**:
```json
{
"items": [
{
"date": "2025-01-15",
"cost": 5000.50,
"subscriptions": 42,
"views": 1850
}
],
"total_cost": 25000.00,
"total_subscriptions": 210,
"total_views": 9250
}
```
**Группировка** (`DateGrouping`): `DAY`, `WEEK`, `MONTH`
---
## Пагинация
Все эндпоинты с пагинацией возвращают:
```json
{
"items": [...],
"total": 42,
"page": 1,
"size": 50,
"pages": 1
}
```
**Query параметры**: `?page=1&size=50`
---
## Статусы и Enum
### WorkspaceUserStatus
- `ACTIVE` - активный участник
- `INVITED` - приглашён, но не принял
### WorkspaceInviteStatus
- `PENDING` - ожидает принятия
- `ACCEPTED` - принято
- `REJECTED` - отклонено
### ProjectStatus / ChannelStatus
- `ACTIVE` - активен
- `INACTIVE` - неактивен
- `ARCHIVED` - архивирован
### CreativeStatus / PlacementStatus
- `ACTIVE` - активен
- `ARCHIVED` - архивирован
### PurchasePlanStatus
- `PLANNED` - запланирован
- `COMPLETED` - завершён
- `CANCELLED` - отменён
### InviteLinkType
- `PUBLIC` - открытая ссылка
- `APPROVAL` - с одобрением бота
### PostViewsAvailability
- `UNKNOWN` - неизвестно (ещё не проверялось)
- `AVAILABLE` - доступны (автообновление)
- `UNAVAILABLE` - недоступны
- `MANUAL` - ручной ввод
---
## Коды ошибок HTTP
- `200` - OK
- `201` - Created
- `204` - No Content (успешное удаление)
- `400` - Bad Request (валидация)
- `401` - Unauthorized (нет токена)
- `403` - Forbidden (нет прав)
- `404` - Not Found
- `500` - Internal Server Error
**Формат ошибки**:
```json
{
"detail": "Error message"
}
```
---
## Особенности
1. **Все UUID в формате**: `xxxxxxxx-xxxx-4xxx-xxxx-xxxxxxxxxxxx`
2. **Даты в ISO 8601**: `2025-01-15T12:00:00Z` (UTC)
3. **Метрики автообновляются**: просмотры обновляются воркером каждые 60 секунд (если `views_availability = AVAILABLE`)
4. **Подписки отслеживаются**: через Telegram бота при присоединении по invite_link
5. **Права проверяются**: все эндпоинты под воркспейсами требуют соответствующих прав
6. **Soft delete**: удаление = архивирование (статус `ARCHIVED`)
---
## Telegram Bot Integration
- Создание проектов (добавление целевых каналов)
- Создание креативов через диалог
- Приглашения в воркспейсы
- Отслеживание подписок через invite links
- Начальная аутентификация (`/start` → временный токен)