docs: Added Api documentation
AI GENERATED
This commit is contained in:
1 parent
1a7a78971b
commit
ac6d49bcda
1 file changed
+459
@@ -0,0 +1,459 @@
|
||||
# REST API: система автоматизированной email-рассылки
|
||||
|
||||
## 1. Базовые параметры
|
||||
|
||||
- Base URL: `https://api.example.com/api/v1`
|
||||
- Протокол: HTTPS
|
||||
- Формат: JSON
|
||||
- Авторизация: `Authorization: Bearer <access_token>`
|
||||
- Дата и время: ISO 8601, UTC
|
||||
|
||||
### Бизнес-правила
|
||||
|
||||
1. Одна компания — один аккаунт и один адрес отправителя, заданный при регистрации.
|
||||
2. У компании может быть только одна незавершённая задача (`draft`, `queued`, `running`, `paused`).
|
||||
3. Новая задача разрешена после `completed`, `failed` или `cancelled`.
|
||||
4. Каждая задача принадлежит авторизованной компании; сервер проверяет доступ к каждому ресурсу.
|
||||
5. Каждому получателю отправляется каждое письмо из списка по порядку. Количество отправок = количество получателей × количество писем.
|
||||
6. Отправка выполняется фоновым обработчиком.
|
||||
7. Нужно исключать отписавшихся адресатов и учитывать согласие на рассылку.
|
||||
|
||||
## 2. Архитектура
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
A[Клиент] <-->|HTTPS / REST / JSON| B[Backend API]
|
||||
B <--> C[(База данных)]
|
||||
B --> D[Очередь задач]
|
||||
D --> E[Фоновый обработчик]
|
||||
E --> F[SMTP / почтовый провайдер]
|
||||
F -. События доставки .-> B
|
||||
```
|
||||
|
||||
## 3. Общие ошибки
|
||||
|
||||
```json
|
||||
{
|
||||
"error": {
|
||||
"code": "VALIDATION_ERROR",
|
||||
"message": "Проверьте переданные данные.",
|
||||
"details": {
|
||||
"interval_seconds": "Значение должно быть больше нуля."
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
| HTTP-код | Значение |
|
||||
|---|---|
|
||||
| `200` | Успешный запрос |
|
||||
| `201` | Ресурс создан |
|
||||
| `202` | Запрос принят в обработку |
|
||||
| `400` | Некорректный запрос |
|
||||
| `401` | Требуется авторизация |
|
||||
| `403` | Нет доступа |
|
||||
| `404` | Ресурс не найден |
|
||||
| `409` | Конфликт состояния |
|
||||
| `422` | Ошибка бизнес-валидации |
|
||||
| `429` | Превышен лимит запросов |
|
||||
| `500` | Внутренняя ошибка сервера |
|
||||
|
||||
## 4. Регистрация и авторизация
|
||||
|
||||
### `POST /auth/register` — регистрация компании
|
||||
|
||||
**Request**
|
||||
|
||||
```json
|
||||
{
|
||||
"company_name": "ООО Пример",
|
||||
"email": "mail@example.com",
|
||||
"password": "strong-account-password"
|
||||
}
|
||||
```
|
||||
|
||||
**Response `201`**
|
||||
|
||||
```json
|
||||
{
|
||||
"user": {
|
||||
"id": "usr_123",
|
||||
"company_name": "ООО Пример",
|
||||
"email": "mail@example.com",
|
||||
"sender_email": "mail@example.com"
|
||||
},
|
||||
"access_token": "eyJhbGciOi...",
|
||||
"token_type": "Bearer"
|
||||
}
|
||||
```
|
||||
|
||||
### `POST /auth/login` — вход
|
||||
|
||||
**Request**
|
||||
|
||||
```json
|
||||
{
|
||||
"email": "mail@example.com",
|
||||
"password": "strong-account-password"
|
||||
}
|
||||
```
|
||||
|
||||
**Response `200`**
|
||||
|
||||
```json
|
||||
{
|
||||
"access_token": "eyJhbGciOi...",
|
||||
"token_type": "Bearer"
|
||||
}
|
||||
```
|
||||
|
||||
### `GET /me` — данные компании
|
||||
|
||||
**Response `200`**
|
||||
|
||||
```json
|
||||
{
|
||||
"id": "usr_123",
|
||||
"company_name": "ООО Пример",
|
||||
"email": "mail@example.com",
|
||||
"sender_email": "mail@example.com",
|
||||
"smtp_configured": true
|
||||
}
|
||||
```
|
||||
|
||||
## 5. SMTP-настройки
|
||||
|
||||
### `PUT /me/smtp-settings` — настроить почтовое подключение
|
||||
|
||||
**Request**
|
||||
|
||||
```json
|
||||
{
|
||||
"host": "smtp.example.com",
|
||||
"port": 587,
|
||||
"encryption": "STARTTLS",
|
||||
"username": "mail@example.com",
|
||||
"password": "mail-provider-app-password"
|
||||
}
|
||||
```
|
||||
|
||||
**Response `200`**
|
||||
|
||||
```json
|
||||
{
|
||||
"status": "configured",
|
||||
"sender_email": "mail@example.com"
|
||||
}
|
||||
```
|
||||
|
||||
`sender_email` задаётся при регистрации и не передаётся в настройках SMTP. SMTP-пароль не возвращается клиенту и хранится на сервере в защищённом виде. Пароль аккаунта приложения и SMTP-пароль — разные секреты.
|
||||
|
||||
## 6. Задачи рассылки
|
||||
|
||||
### `POST /campaigns` — создать задачу
|
||||
|
||||
**Request**
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "Осенняя рассылка",
|
||||
"interval_seconds": 60
|
||||
}
|
||||
```
|
||||
|
||||
**Response `201`**
|
||||
|
||||
```json
|
||||
{
|
||||
"id": "cmp_456",
|
||||
"name": "Осенняя рассылка",
|
||||
"status": "draft",
|
||||
"interval_seconds": 60,
|
||||
"recipients_count": 0,
|
||||
"messages_count": 0
|
||||
}
|
||||
```
|
||||
|
||||
Если уже существует незавершённая задача — `409 Conflict`:
|
||||
|
||||
```json
|
||||
{
|
||||
"error": {
|
||||
"code": "ACTIVE_CAMPAIGN_EXISTS",
|
||||
"message": "У компании уже есть незавершённая задача рассылки."
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Ограничение должно обеспечиваться на сервере с учётом параллельных запросов.
|
||||
|
||||
### `GET /campaigns/current` — текущая незавершённая задача
|
||||
|
||||
**Response `200`**
|
||||
|
||||
```json
|
||||
{
|
||||
"id": "cmp_456",
|
||||
"name": "Осенняя рассылка",
|
||||
"status": "draft",
|
||||
"interval_seconds": 60,
|
||||
"recipients_count": 2,
|
||||
"messages_count": 1
|
||||
}
|
||||
```
|
||||
|
||||
Если активной задачи нет — `404 Not Found`.
|
||||
|
||||
### `PATCH /campaigns/{campaign_id}` — изменить параметры
|
||||
|
||||
**Request**
|
||||
|
||||
```json
|
||||
{
|
||||
"interval_seconds": 120
|
||||
}
|
||||
```
|
||||
|
||||
**Response `200`**
|
||||
|
||||
```json
|
||||
{
|
||||
"id": "cmp_456",
|
||||
"interval_seconds": 120,
|
||||
"status": "draft"
|
||||
}
|
||||
```
|
||||
|
||||
Изменение параметров разрешено в состоянии `draft`.
|
||||
|
||||
## 7. Получатели
|
||||
|
||||
### `PUT /campaigns/{campaign_id}/recipients` — заменить список получателей
|
||||
|
||||
**Request**
|
||||
|
||||
```json
|
||||
{
|
||||
"recipients": [
|
||||
{ "email": "client1@example.com", "name": "Иван" },
|
||||
{ "email": "client2@example.com", "name": "Анна" }
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
**Response `200`**
|
||||
|
||||
```json
|
||||
{
|
||||
"campaign_id": "cmp_456",
|
||||
"total": 2,
|
||||
"added": 2,
|
||||
"invalid": 0,
|
||||
"duplicates": 0
|
||||
}
|
||||
```
|
||||
|
||||
Проверять формат адресов, устранять дубликаты и исключать адреса, отписавшиеся от рассылки.
|
||||
|
||||
### `POST /campaigns/{campaign_id}/recipients/import` — импорт CSV (опционально)
|
||||
|
||||
## 8. Письма
|
||||
|
||||
### `PUT /campaigns/{campaign_id}/messages` — заменить список писем
|
||||
|
||||
**Request**
|
||||
|
||||
```json
|
||||
{
|
||||
"messages": [
|
||||
{
|
||||
"subject": "Предложение для вашей компании",
|
||||
"body_text": "Здравствуйте! Предлагаем ознакомиться с нашими услугами."
|
||||
},
|
||||
{
|
||||
"subject": "Дополнительная информация",
|
||||
"body_text": "Здравствуйте! Отправляем дополнительную информацию."
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
**Response `200`**
|
||||
|
||||
```json
|
||||
{
|
||||
"campaign_id": "cmp_456",
|
||||
"messages_count": 2,
|
||||
"status": "draft"
|
||||
}
|
||||
```
|
||||
|
||||
`PUT` заменяет весь список. `body_text` — текст письма; поле `body_html` можно добавить при необходимости.
|
||||
|
||||
## 9. Управление рассылкой
|
||||
|
||||
### `POST /campaigns/{campaign_id}/start` — запуск
|
||||
|
||||
**Response `202`**
|
||||
|
||||
```json
|
||||
{
|
||||
"campaign_id": "cmp_456",
|
||||
"status": "queued",
|
||||
"total_emails": 4
|
||||
}
|
||||
```
|
||||
|
||||
Перед запуском проверить SMTP, право использовать адрес отправителя, наличие получателей и писем, корректность параметров и отсутствие другой незавершённой задачи. Запуск создаёт задания в очереди; отправка выполняется фоновым обработчиком.
|
||||
|
||||
### `POST /campaigns/{campaign_id}/pause` — пауза
|
||||
|
||||
**Response**
|
||||
|
||||
```json
|
||||
{
|
||||
"campaign_id": "cmp_456",
|
||||
"status": "paused"
|
||||
}
|
||||
```
|
||||
|
||||
### `POST /campaigns/{campaign_id}/resume` — продолжить
|
||||
|
||||
**Response**
|
||||
|
||||
```json
|
||||
{
|
||||
"campaign_id": "cmp_456",
|
||||
"status": "running"
|
||||
}
|
||||
```
|
||||
|
||||
### `POST /campaigns/{campaign_id}/cancel` — отменить
|
||||
|
||||
**Response**
|
||||
|
||||
```json
|
||||
{
|
||||
"campaign_id": "cmp_456",
|
||||
"status": "cancelled"
|
||||
}
|
||||
```
|
||||
|
||||
Отмена останавливает оставшуюся очередь; уже отправленные письма отозвать нельзя. Сервер проверяет допустимость перехода между состояниями.
|
||||
|
||||
## 10. Статус и прогресс
|
||||
|
||||
### `GET /campaigns/{campaign_id}/status`
|
||||
|
||||
**Response `200`**
|
||||
|
||||
```json
|
||||
{
|
||||
"campaign_id": "cmp_456",
|
||||
"status": "running",
|
||||
"progress": {
|
||||
"total": 200,
|
||||
"processed": 75,
|
||||
"queued": 125,
|
||||
"accepted": 72,
|
||||
"failed": 3
|
||||
},
|
||||
"started_at": "2026-10-23T18:00:00Z"
|
||||
}
|
||||
```
|
||||
|
||||
- `total` — всего запланировано отправок.
|
||||
- `processed` — отправки, для которых зафиксирован результат обработки.
|
||||
- `queued` — отправки в очереди.
|
||||
- `accepted` — письма приняты почтовой стороной к дальнейшей обработке.
|
||||
- `failed` — отправки, завершившиеся ошибкой на уровне обработки.
|
||||
|
||||
Клиент может опрашивать endpoint с интервалом 3–5 секунд. Повторные попытки не должны повторно увеличивать счётчики одной отправки.
|
||||
|
||||
## 11. Отчёт и отдельные отправки
|
||||
|
||||
### `GET /campaigns/{campaign_id}/report` — итоговый отчёт
|
||||
|
||||
**Response `200`**
|
||||
|
||||
```json
|
||||
{
|
||||
"campaign_id": "cmp_456",
|
||||
"status": "completed",
|
||||
"summary": {
|
||||
"total": 200,
|
||||
"accepted": 198,
|
||||
"delivered": 190,
|
||||
"bounced": 8,
|
||||
"spam_complaints": 2,
|
||||
"unknown": 0
|
||||
},
|
||||
"completed_at": "2026-10-23T22:00:00Z"
|
||||
}
|
||||
```
|
||||
|
||||
| Поле | Значение |
|
||||
|---|---|
|
||||
| `total` | Запланировано отправок |
|
||||
| `accepted` | Почтовый сервис принял письмо |
|
||||
| `delivered` | Получено подтверждение приёма сервером получателя |
|
||||
| `bounced` | Письмо возвращено или отклонено |
|
||||
| `spam_complaints` | Зарегистрированные жалобы на спам |
|
||||
| `unknown` | Итоговый статус неизвестен |
|
||||
|
||||
Для `delivered`, `bounced` и `spam_complaints` нужны события или вебхуки почтового провайдера. SMTP-подтверждение отправки не доказывает попадание письма во «Входящие»; жалобы на спам не равны числу писем, помещённых фильтрами в папку «Спам».
|
||||
|
||||
### `GET /campaigns/{campaign_id}/deliveries?status=bounced&limit=50` — отдельные отправки
|
||||
|
||||
**Response `200`**
|
||||
|
||||
```json
|
||||
{
|
||||
"campaign_id": "cmp_456",
|
||||
"items": [
|
||||
{
|
||||
"recipient_email": "client1@example.com",
|
||||
"message_subject": "Предложение для вашей компании",
|
||||
"status": "bounced",
|
||||
"reason": "Mailbox unavailable",
|
||||
"attempted_at": "2026-10-23T18:10:00Z"
|
||||
}
|
||||
],
|
||||
"limit": 50,
|
||||
"next_cursor": null
|
||||
}
|
||||
```
|
||||
|
||||
## 12. Состояния задачи
|
||||
|
||||
| Состояние | Значение | Разрешить новую задачу |
|
||||
|---|---|---|
|
||||
| `draft` | Настройка | Нет |
|
||||
| `queued` | В очереди | Нет |
|
||||
| `running` | Выполняется | Нет |
|
||||
| `paused` | Приостановлена | Нет |
|
||||
| `completed` | Завершена | Да |
|
||||
| `failed` | Ошибка выполнения | Да |
|
||||
| `cancelled` | Отменена | Да |
|
||||
|
||||
## 13. Сводный список endpoint-ов
|
||||
|
||||
| Метод | Endpoint | Назначение |
|
||||
|---|---|---|
|
||||
| `POST` | `/auth/register` | Регистрация |
|
||||
| `POST` | `/auth/login` | Вход |
|
||||
| `GET` | `/me` | Данные компании |
|
||||
| `PUT` | `/me/smtp-settings` | Настройки SMTP |
|
||||
| `POST` | `/campaigns` | Создать задачу |
|
||||
| `GET` | `/campaigns/current` | Текущая незавершённая задача |
|
||||
| `PATCH` | `/campaigns/{campaign_id}` | Изменить параметры задачи |
|
||||
| `PUT` | `/campaigns/{campaign_id}/recipients` | Заменить список получателей |
|
||||
| `POST` | `/campaigns/{campaign_id}/recipients/import` | Импорт CSV, опционально |
|
||||
| `PUT` | `/campaigns/{campaign_id}/messages` | Заменить список писем |
|
||||
| `POST` | `/campaigns/{campaign_id}/start` | Запустить рассылку |
|
||||
| `POST` | `/campaigns/{campaign_id}/pause` | Приостановить |
|
||||
| `POST` | `/campaigns/{campaign_id}/resume` | Продолжить |
|
||||
| `POST` | `/campaigns/{campaign_id}/cancel` | Отменить |
|
||||
| `GET` | `/campaigns/{campaign_id}/status` | Статус и прогресс |
|
||||
| `GET` | `/campaigns/{campaign_id}/report` | Итоговый отчёт |
|
||||
| `GET` | `/campaigns/{campaign_id}/deliveries` | Отдельные отправки |
|
||||
Reference in new issue
Block a user